summaryrefslogtreecommitdiffstats
path: root/platform/windows
diff options
context:
space:
mode:
Diffstat (limited to 'platform/windows')
-rw-r--r--platform/windows/SCsub34
-rw-r--r--platform/windows/detect.py89
-rw-r--r--platform/windows/display_server_windows.cpp615
-rw-r--r--platform/windows/display_server_windows.h28
-rw-r--r--platform/windows/export/export_plugin.cpp2
-rw-r--r--platform/windows/godot.natvis149
-rw-r--r--platform/windows/godot_res.rc14
-rw-r--r--platform/windows/godot_res_wrap.rc14
-rw-r--r--platform/windows/godot_windows.cpp4
-rw-r--r--platform/windows/key_mapping_windows.cpp23
-rw-r--r--platform/windows/key_mapping_windows.h1
-rw-r--r--platform/windows/msvs.py20
-rw-r--r--platform/windows/os_windows.h7
-rw-r--r--platform/windows/platform_windows_builders.py28
-rw-r--r--platform/windows/rendering_context_driver_vulkan_windows.cpp (renamed from platform/windows/vulkan_context_win.cpp)44
-rw-r--r--platform/windows/rendering_context_driver_vulkan_windows.h (renamed from platform/windows/vulkan_context_win.h)23
16 files changed, 897 insertions, 198 deletions
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 0549e408a7..34c8f8e7a1 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -3,9 +3,12 @@
Import("env")
import os
+from pathlib import Path
from platform_methods import run_in_subprocess
import platform_windows_builders
+sources = []
+
common_win = [
"godot_windows.cpp",
"crash_handler_windows.cpp",
@@ -15,23 +18,38 @@ common_win = [
"joypad_windows.cpp",
"tts_windows.cpp",
"windows_terminal_logger.cpp",
- "vulkan_context_win.cpp",
"gl_manager_windows_native.cpp",
"gl_manager_windows_angle.cpp",
"wgl_detect_version.cpp",
+ "rendering_context_driver_vulkan_windows.cpp",
]
common_win_wrap = [
"console_wrapper_windows.cpp",
]
+
+def arrange_program_clean(prog):
+ """
+ Given an SCons program, arrange for output files SCons doesn't know about
+ to be cleaned when SCons is called with --clean
+ """
+ extensions_to_clean = [".ilk", ".exp", ".pdb", ".lib"]
+ for program in prog:
+ executable_stem = Path(program.name).stem
+ extra_files_to_clean = [f"#bin/{executable_stem}{extension}" for extension in extensions_to_clean]
+ Clean(prog, extra_files_to_clean)
+
+
res_file = "godot_res.rc"
res_target = "godot_res" + env["OBJSUFFIX"]
res_obj = env.RES(res_target, res_file)
-sources = common_win + res_obj
+env.add_source_files(sources, common_win)
+sources += res_obj
prog = env.add_program("#bin/godot", sources, PROGSUFFIX=env["PROGSUFFIX"])
+arrange_program_clean(prog)
# Build console wrapper app.
if env["windows_subsystem"] == "gui":
@@ -48,7 +66,9 @@ if env["windows_subsystem"] == "gui":
env_wrap.Append(LIBS=["version"])
prog_wrap = env_wrap.add_program("#bin/godot", common_win_wrap + res_wrap_obj, PROGSUFFIX=env["PROGSUFFIX_WRAP"])
+ arrange_program_clean(prog_wrap)
env_wrap.Depends(prog_wrap, prog)
+ sources += common_win_wrap + res_wrap_obj
# Microsoft Visual Studio Project Generation
if env["vsproj"]:
@@ -81,7 +101,7 @@ if env["d3d12"]:
arch_bin_dir = "#bin/" + env["arch"]
# DXC
- if env["dxc_path"] != "":
+ if env["dxc_path"] != "" and os.path.exists(env["dxc_path"]):
dxc_dll = "dxil.dll"
# Whether this one is loaded from arch-specific directory or not can be determined at runtime.
# Let's copy to both and let the user decide the distribution model.
@@ -93,7 +113,7 @@ if env["d3d12"]:
)
# Agility SDK
- if env["agility_sdk_path"] != "":
+ if env["agility_sdk_path"] != "" and os.path.exists(env["agility_sdk_path"]):
agility_dlls = ["D3D12Core.dll", "d3d12SDKLayers.dll"]
# Whether these are loaded from arch-specific directory or not has to be known at build time.
target_dir = arch_bin_dir if env["agility_sdk_multiarch"] else "#bin"
@@ -105,7 +125,7 @@ if env["d3d12"]:
)
# PIX
- if env["pix_path"] != "":
+ if env["use_pix"]:
pix_dll = "WinPixEventRuntime.dll"
env.Command(
"#bin/" + pix_dll,
@@ -114,7 +134,9 @@ if env["d3d12"]:
)
if not os.getenv("VCINSTALLDIR"):
- if env["debug_symbols"] and env["separate_debug_symbols"]:
+ if env["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))
+
+env.platform_sources += sources
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index bc04057793..0619e62563 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -164,6 +164,22 @@ def get_opts():
mingw = os.getenv("MINGW_PREFIX", "")
+ # Direct3D 12 SDK dependencies folder.
+ d3d12_deps_folder = os.getenv("LOCALAPPDATA")
+ if d3d12_deps_folder:
+ d3d12_deps_folder = os.path.join(d3d12_deps_folder, "Godot", "build_deps")
+ else:
+ # Cross-compiling, the deps install script puts things in `bin`.
+ # Getting an absolute path to it is a bit hacky in Python.
+ try:
+ import inspect
+
+ caller_frame = inspect.stack()[1]
+ caller_script_dir = os.path.dirname(os.path.abspath(caller_frame[1]))
+ d3d12_deps_folder = os.path.join(caller_script_dir, "bin", "build_deps")
+ except: # Give up.
+ d3d12_deps_folder = ""
+
return [
("mingw_prefix", "MinGW prefix", mingw),
# Targeted Windows version: 7 (and later), minimum supported version
@@ -188,15 +204,32 @@ def get_opts():
BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False),
("angle_libs", "Path to the ANGLE static libraries", ""),
# Direct3D 12 support.
- ("mesa_libs", "Path to the MESA/NIR static libraries (required for D3D12)", ""),
- ("dxc_path", "Path to the DirectX Shader Compiler distribution (required for D3D12)", ""),
- ("agility_sdk_path", "Path to the Agility SDK distribution (optional for D3D12)", ""),
+ (
+ "mesa_libs",
+ "Path to the MESA/NIR static libraries (required for D3D12)",
+ os.path.join(d3d12_deps_folder, "mesa"),
+ ),
+ (
+ "dxc_path",
+ "Path to the DirectX Shader Compiler distribution (required for D3D12)",
+ os.path.join(d3d12_deps_folder, "dxc"),
+ ),
+ (
+ "agility_sdk_path",
+ "Path to the Agility SDK distribution (optional for D3D12)",
+ os.path.join(d3d12_deps_folder, "agility_sdk"),
+ ),
BoolVariable(
"agility_sdk_multiarch",
"Whether the Agility SDK DLLs will be stored in arch-specific subdirectories",
False,
),
- ("pix_path", "Path to the PIX runtime distribution (optional for D3D12)", ""),
+ BoolVariable("use_pix", "Use PIX (Performance tuning and debugging for DirectX 12) runtime", False),
+ (
+ "pix_path",
+ "Path to the PIX runtime distribution (optional for D3D12)",
+ os.path.join(d3d12_deps_folder, "pix"),
+ ),
]
@@ -441,8 +474,14 @@ def configure_msvc(env, vcvars_msvc_config):
LIBS += ["vulkan"]
if env["d3d12"]:
- if env["dxc_path"] == "":
- print("The Direct3D 12 rendering driver requires dxc_path to be set.")
+ # Check whether we have d3d12 dependencies installed.
+ if not os.path.exists(env["mesa_libs"]):
+ print("The Direct3D 12 rendering driver requires dependencies to be installed.")
+ print(r"You can install them by running `python misc\scripts\install_d3d12_sdk_windows.py`.")
+ print("See the documentation for more information:")
+ print(
+ "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
+ )
sys.exit(255)
env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"])
@@ -453,18 +492,16 @@ def configure_msvc(env, vcvars_msvc_config):
if env["target"] == "release_debug":
env.Append(CXXFLAGS=["/bigobj"])
- arch_subdir = "arm64" if env["arch"] == "arm64" else "x64"
-
# PIX
- if env["pix_path"] != "":
+ if not env["arch"] in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]):
+ env["use_pix"] = False
+
+ if env["use_pix"]:
+ arch_subdir = "arm64" if env["arch"] == "arm64" else "x64"
+
env.Append(LIBPATH=[env["pix_path"] + "/bin/" + arch_subdir])
LIBS += ["WinPixEventRuntime"]
- # Mesa
- if env["mesa_libs"] == "":
- print("The Direct3D 12 rendering driver requires mesa_libs to be set.")
- sys.exit(255)
-
env.Append(LIBPATH=[env["mesa_libs"] + "/bin"])
LIBS += ["libNIR.windows." + env["arch"]]
@@ -662,21 +699,29 @@ def configure_mingw(env):
env.Append(LIBS=["vulkan"])
if env["d3d12"]:
+ # Check whether we have d3d12 dependencies installed.
+ if not os.path.exists(env["mesa_libs"]):
+ print("The Direct3D 12 rendering driver requires dependencies to be installed.")
+ print(r"You can install them by running `python misc\scripts\install_d3d12_sdk_windows.py`.")
+ print("See the documentation for more information:")
+ print(
+ "https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html"
+ )
+ sys.exit(255)
+
env.AppendUnique(CPPDEFINES=["D3D12_ENABLED", "RD_ENABLED"])
env.Append(LIBS=["d3d12", "dxgi", "dxguid"])
- arch_subdir = "arm64" if env["arch"] == "arm64" else "x64"
-
# PIX
- if env["pix_path"] != "":
+ if not env["arch"] in ["x86_64", "arm64"] or env["pix_path"] == "" or not os.path.exists(env["pix_path"]):
+ env["use_pix"] = False
+
+ if env["use_pix"]:
+ arch_subdir = "arm64" if env["arch"] == "arm64" else "x64"
+
env.Append(LIBPATH=[env["pix_path"] + "/bin/" + arch_subdir])
env.Append(LIBS=["WinPixEventRuntime"])
- # Mesa
- if env["mesa_libs"] == "":
- print("The Direct3D 12 rendering driver requires mesa_libs to be set.")
- sys.exit(255)
-
env.Append(LIBPATH=[env["mesa_libs"] + "/bin"])
env.Append(LIBS=["libNIR.windows." + env["arch"]])
env.Append(LIBS=["version"]) # Mesa dependency.
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index fbf01e4e8b..96e2f95abd 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -39,6 +39,12 @@
#include "main/main.h"
#include "scene/resources/atlas_texture.h"
+#if defined(VULKAN_ENABLED)
+#include "rendering_context_driver_vulkan_windows.h"
+#endif
+#if defined(D3D12_ENABLED)
+#include "drivers/d3d12/rendering_context_driver_d3d12.h"
+#endif
#if defined(GLES3_ENABLED)
#include "drivers/gles3/rasterizer_gles3.h"
#endif
@@ -53,6 +59,12 @@
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20
#endif
+#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1
+#define DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 19
+#endif
+
+#define WM_INDICATOR_CALLBACK_MESSAGE (WM_USER + 1)
+
#if defined(__GNUC__)
// Workaround GCC warning from -Wcast-function-type.
#define GetProcAddress (void *)GetProcAddress
@@ -98,6 +110,7 @@ bool DisplayServerWindows::has_feature(Feature p_feature) const {
case FEATURE_KEEP_SCREEN_ON:
case FEATURE_TEXT_TO_SPEECH:
case FEATURE_SCREEN_CAPTURE:
+ case FEATURE_STATUS_INDICATOR:
return true;
default:
return false;
@@ -166,20 +179,26 @@ DisplayServer::WindowID DisplayServerWindows::_get_focused_window_or_popup() con
void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window) {
use_raw_input = true;
- RAWINPUTDEVICE rid[1] = {};
- rid[0].usUsagePage = 0x01;
- rid[0].usUsage = 0x02;
+ RAWINPUTDEVICE rid[2] = {};
+ rid[0].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
+ rid[0].usUsage = 0x02; // HID_USAGE_GENERIC_MOUSE
rid[0].dwFlags = 0;
+ rid[1].usUsagePage = 0x01; // HID_USAGE_PAGE_GENERIC
+ rid[1].usUsage = 0x06; // HID_USAGE_GENERIC_KEYBOARD
+ rid[1].dwFlags = 0;
+
if (p_target_window != INVALID_WINDOW_ID && windows.has(p_target_window)) {
// Follow the defined window
rid[0].hwndTarget = windows[p_target_window].hWnd;
+ rid[1].hwndTarget = windows[p_target_window].hWnd;
} else {
// Follow the keyboard focus
rid[0].hwndTarget = 0;
+ rid[1].hwndTarget = 0;
}
- if (RegisterRawInputDevices(rid, 1, sizeof(rid[0])) == FALSE) {
+ if (RegisterRawInputDevices(rid, 2, sizeof(rid[0])) == FALSE) {
// Registration failed.
use_raw_input = false;
}
@@ -220,7 +239,142 @@ void DisplayServerWindows::tts_stop() {
tts->stop();
}
+// Silence warning due to a COM API weirdness.
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+class FileDialogEventHandler : public IFileDialogEvents, public IFileDialogControlEvents {
+ LONG ref_count = 1;
+ int ctl_id = 1;
+
+ HashMap<int, String> ctls;
+ Dictionary selected;
+ String root;
+
+public:
+ // IUnknown methods
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppv) {
+ static const QITAB qit[] = {
+#ifdef __MINGW32__
+ { &__uuidof(IFileDialogEvents), static_cast<decltype(qit[0].dwOffset)>(OFFSETOFCLASS(IFileDialogEvents, FileDialogEventHandler)) },
+ { &__uuidof(IFileDialogControlEvents), static_cast<decltype(qit[0].dwOffset)>(OFFSETOFCLASS(IFileDialogControlEvents, FileDialogEventHandler)) },
+#else
+ QITABENT(FileDialogEventHandler, IFileDialogEvents),
+ QITABENT(FileDialogEventHandler, IFileDialogControlEvents),
+#endif
+ { 0, 0 },
+ };
+ return QISearch(this, qit, riid, ppv);
+ }
+
+ ULONG STDMETHODCALLTYPE AddRef() {
+ return InterlockedIncrement(&ref_count);
+ }
+
+ ULONG STDMETHODCALLTYPE Release() {
+ long ref = InterlockedDecrement(&ref_count);
+ if (!ref) {
+ delete this;
+ }
+ return ref;
+ }
+
+ // IFileDialogEvents methods
+ HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog *) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialog *) { return S_OK; };
+
+ HRESULT STDMETHODCALLTYPE OnFolderChanging(IFileDialog *p_pfd, IShellItem *p_item) {
+ if (root.is_empty()) {
+ return S_OK;
+ }
+
+ LPWSTR lpw_path = nullptr;
+ p_item->GetDisplayName(SIGDN_FILESYSPATH, &lpw_path);
+ if (!lpw_path) {
+ return S_FALSE;
+ }
+ String path = String::utf16((const char16_t *)lpw_path).simplify_path();
+ if (!path.begins_with(root.simplify_path())) {
+ return S_FALSE;
+ }
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE OnHelp(IFileDialog *) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialog *) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnShareViolation(IFileDialog *, IShellItem *, FDE_SHAREVIOLATION_RESPONSE *) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialog *pfd) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialog *, IShellItem *, FDE_OVERWRITE_RESPONSE *) { return S_OK; };
+
+ // IFileDialogControlEvents methods
+ HRESULT STDMETHODCALLTYPE OnItemSelected(IFileDialogCustomize *p_pfdc, DWORD p_ctl_id, DWORD p_item_idx) {
+ if (ctls.has(p_ctl_id)) {
+ selected[ctls[p_ctl_id]] = (int)p_item_idx;
+ }
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE OnButtonClicked(IFileDialogCustomize *, DWORD) { return S_OK; };
+ HRESULT STDMETHODCALLTYPE OnCheckButtonToggled(IFileDialogCustomize *p_pfdc, DWORD p_ctl_id, BOOL p_checked) {
+ if (ctls.has(p_ctl_id)) {
+ selected[ctls[p_ctl_id]] = (bool)p_checked;
+ }
+ return S_OK;
+ }
+ HRESULT STDMETHODCALLTYPE OnControlActivating(IFileDialogCustomize *, DWORD) { return S_OK; };
+
+ Dictionary get_selected() {
+ return selected;
+ }
+
+ void set_root(const String &p_root) {
+ root = p_root;
+ }
+
+ void add_option(IFileDialogCustomize *p_pfdc, const String &p_name, const Vector<String> &p_options, int p_default) {
+ int gid = ctl_id++;
+ int cid = ctl_id++;
+
+ if (p_options.size() == 0) {
+ // Add check box.
+ p_pfdc->StartVisualGroup(gid, L"");
+ p_pfdc->AddCheckButton(cid, (LPCWSTR)p_name.utf16().get_data(), p_default);
+ p_pfdc->SetControlState(cid, CDCS_VISIBLE | CDCS_ENABLED);
+ p_pfdc->EndVisualGroup();
+ selected[p_name] = (bool)p_default;
+ } else {
+ // Add combo box.
+ p_pfdc->StartVisualGroup(gid, (LPCWSTR)p_name.utf16().get_data());
+ p_pfdc->AddComboBox(cid);
+ p_pfdc->SetControlState(cid, CDCS_VISIBLE | CDCS_ENABLED);
+ for (int i = 0; i < p_options.size(); i++) {
+ p_pfdc->AddControlItem(cid, i, (LPCWSTR)p_options[i].utf16().get_data());
+ }
+ p_pfdc->SetSelectedControlItem(cid, p_default);
+ p_pfdc->EndVisualGroup();
+ selected[p_name] = p_default;
+ }
+ ctls[cid] = p_name;
+ }
+
+ virtual ~FileDialogEventHandler(){};
+};
+
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif
+
Error DisplayServerWindows::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
+ return _file_dialog_with_options_show(p_title, p_current_directory, String(), p_filename, p_show_hidden, p_mode, p_filters, TypedArray<Dictionary>(), p_callback, false);
+}
+
+Error DisplayServerWindows::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) {
+ return _file_dialog_with_options_show(p_title, p_current_directory, p_root, p_filename, p_show_hidden, p_mode, p_filters, p_options, p_callback, true);
+}
+
+Error DisplayServerWindows::_file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb) {
_THREAD_SAFE_METHOD_
ERR_FAIL_INDEX_V(int(p_mode), FILE_DIALOG_MODE_SAVE_MAX, FAILED);
@@ -270,6 +424,31 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_IFileOpenDialog, (void **)&pfd);
}
if (SUCCEEDED(hr)) {
+ IFileDialogEvents *pfde = nullptr;
+ FileDialogEventHandler *event_handler = new FileDialogEventHandler();
+ hr = event_handler->QueryInterface(IID_PPV_ARGS(&pfde));
+
+ DWORD cookie = 0;
+ hr = pfd->Advise(pfde, &cookie);
+
+ IFileDialogCustomize *pfdc = nullptr;
+ hr = pfd->QueryInterface(IID_PPV_ARGS(&pfdc));
+
+ for (int i = 0; i < p_options.size(); i++) {
+ const Dictionary &item = p_options[i];
+ if (!item.has("name") || !item.has("values") || !item.has("default")) {
+ continue;
+ }
+ const String &name = item["name"];
+ const Vector<String> &options = item["values"];
+ int default_idx = item["default"];
+
+ event_handler->add_option(pfdc, name, options, default_idx);
+ }
+ event_handler->set_root(p_root);
+
+ pfdc->Release();
+
DWORD flags;
pfd->GetOptions(&flags);
if (p_mode == FILE_DIALOG_MODE_OPEN_FILES) {
@@ -307,8 +486,18 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
}
hr = pfd->Show(windows[window_id].hWnd);
+ pfd->Unadvise(cookie);
+
+ Dictionary options = event_handler->get_selected();
+
+ pfde->Release();
+ event_handler->Release();
+
UINT index = 0;
pfd->GetFileTypeIndex(&index);
+ if (index > 0) {
+ index = index - 1;
+ }
if (SUCCEEDED(hr)) {
Vector<String> file_names;
@@ -347,30 +536,60 @@ Error DisplayServerWindows::file_dialog_show(const String &p_title, const String
}
}
if (!p_callback.is_null()) {
- Variant v_result = true;
- Variant v_files = file_names;
- Variant v_index = index;
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &v_result, &v_files, &v_index };
-
- p_callback.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ if (p_options_in_cb) {
+ Variant v_result = true;
+ Variant v_files = file_names;
+ Variant v_index = index;
+ Variant v_opt = options;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
+
+ p_callback.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 4, ce)));
+ }
+ } else {
+ Variant v_result = true;
+ Variant v_files = file_names;
+ Variant v_index = index;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ p_callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ }
}
}
} else {
if (!p_callback.is_null()) {
- Variant v_result = false;
- Variant v_files = Vector<String>();
- Variant v_index = index;
- Variant ret;
- Callable::CallError ce;
- const Variant *args[3] = { &v_result, &v_files, &v_index };
-
- p_callback.callp(args, 3, ret, ce);
- if (ce.error != Callable::CallError::CALL_OK) {
- ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ if (p_options_in_cb) {
+ Variant v_result = false;
+ Variant v_files = Vector<String>();
+ Variant v_index = index;
+ Variant v_opt = options;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[4] = { &v_result, &v_files, &v_index, &v_opt };
+
+ p_callback.callp(args, 4, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 4, ce)));
+ }
+ } else {
+ Variant v_result = false;
+ Variant v_files = Vector<String>();
+ Variant v_index = index;
+ Variant ret;
+ Callable::CallError ce;
+ const Variant *args[3] = { &v_result, &v_files, &v_index };
+
+ p_callback.callp(args, 3, ret, ce);
+ if (ce.error != Callable::CallError::CALL_OK) {
+ ERR_PRINT(vformat("Failed to execute file dialogs callback: %s.", Variant::get_callable_error_text(p_callback, args, 3, ce)));
+ }
}
}
}
@@ -551,8 +770,7 @@ Ref<Image> DisplayServerWindows::clipboard_get_image() const {
pba.append(rgbquad->rgbReserved);
}
}
- image.instantiate();
- image->create_from_data(info->biWidth, info->biHeight, false, Image::Format::FORMAT_RGBA8, pba);
+ image = Image::create_from_data(info->biWidth, info->biHeight, false, Image::Format::FORMAT_RGBA8, pba);
GlobalUnlock(mem);
}
@@ -1082,6 +1300,11 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
if (mainwindow_icon) {
SendMessage(windows[window_id].hWnd, WM_SETICON, ICON_BIG, (LPARAM)mainwindow_icon);
}
+#ifdef RD_ENABLED
+ if (rendering_device) {
+ rendering_device->screen_create(window_id);
+ }
+#endif
return window_id;
}
@@ -1136,8 +1359,12 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
}
#ifdef RD_ENABLED
- if (context_rd) {
- context_rd->window_destroy(p_window);
+ if (rendering_device) {
+ rendering_device->screen_free(p_window);
+ }
+
+ if (rendering_context) {
+ rendering_context->window_destroy(p_window);
}
#endif
#ifdef GLES3_ENABLED
@@ -1568,8 +1795,8 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
wd.height = h;
#if defined(RD_ENABLED)
- if (context_rd) {
- context_rd->window_resize(p_window, w, h);
+ if (rendering_context) {
+ rendering_context->window_set_size(p_window, w, h);
}
#endif
#if defined(GLES3_ENABLED)
@@ -1949,6 +2176,10 @@ bool DisplayServerWindows::window_is_focused(WindowID p_window) const {
return wd.window_focused;
}
+DisplayServerWindows::WindowID DisplayServerWindows::get_focused_window() const {
+ return last_focused_window;
+}
+
bool DisplayServerWindows::window_can_draw(WindowID p_window) const {
_THREAD_SAFE_METHOD_
@@ -2615,11 +2846,177 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
}
}
+DisplayServer::IndicatorID DisplayServerWindows::create_status_indicator(const Ref<Image> &p_icon, const String &p_tooltip, const Callable &p_callback) {
+ HICON hicon = nullptr;
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0) {
+ Ref<Image> img = p_icon;
+ if (img != icon) {
+ img = img->duplicate();
+ img->convert(Image::FORMAT_RGBA8);
+ }
+
+ int w = img->get_width();
+ int h = img->get_height();
+
+ // Create temporary bitmap buffer.
+ int icon_len = 40 + h * w * 4;
+ Vector<BYTE> v;
+ v.resize(icon_len);
+ BYTE *icon_bmp = v.ptrw();
+
+ encode_uint32(40, &icon_bmp[0]);
+ encode_uint32(w, &icon_bmp[4]);
+ encode_uint32(h * 2, &icon_bmp[8]);
+ encode_uint16(1, &icon_bmp[12]);
+ encode_uint16(32, &icon_bmp[14]);
+ encode_uint32(BI_RGB, &icon_bmp[16]);
+ encode_uint32(w * h * 4, &icon_bmp[20]);
+ encode_uint32(0, &icon_bmp[24]);
+ encode_uint32(0, &icon_bmp[28]);
+ encode_uint32(0, &icon_bmp[32]);
+ encode_uint32(0, &icon_bmp[36]);
+
+ uint8_t *wr = &icon_bmp[40];
+ const uint8_t *r = img->get_data().ptr();
+
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
+ uint8_t *wpx = &wr[(i * w + j) * 4];
+ wpx[0] = rpx[2];
+ wpx[1] = rpx[1];
+ wpx[2] = rpx[0];
+ wpx[3] = rpx[3];
+ }
+ }
+
+ hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
+ }
+
+ IndicatorData idat;
+ idat.callback = p_callback;
+
+ NOTIFYICONDATAW ndat;
+ ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
+ ndat.cbSize = sizeof(NOTIFYICONDATAW);
+ ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
+ ndat.uID = indicator_id_counter;
+ ndat.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
+ ndat.uCallbackMessage = WM_INDICATOR_CALLBACK_MESSAGE;
+ ndat.hIcon = hicon;
+ memcpy(ndat.szTip, p_tooltip.utf16().ptr(), MIN(p_tooltip.utf16().length(), 127) * sizeof(WCHAR));
+ ndat.uVersion = NOTIFYICON_VERSION;
+
+ Shell_NotifyIconW(NIM_ADD, &ndat);
+ Shell_NotifyIconW(NIM_SETVERSION, &ndat);
+
+ IndicatorID iid = indicator_id_counter++;
+ indicators[iid] = idat;
+
+ return iid;
+}
+
+void DisplayServerWindows::status_indicator_set_icon(IndicatorID p_id, const Ref<Image> &p_icon) {
+ ERR_FAIL_COND(!indicators.has(p_id));
+
+ HICON hicon = nullptr;
+ if (p_icon.is_valid() && p_icon->get_width() > 0 && p_icon->get_height() > 0) {
+ Ref<Image> img = p_icon;
+ if (img != icon) {
+ img = img->duplicate();
+ img->convert(Image::FORMAT_RGBA8);
+ }
+
+ int w = img->get_width();
+ int h = img->get_height();
+
+ // Create temporary bitmap buffer.
+ int icon_len = 40 + h * w * 4;
+ Vector<BYTE> v;
+ v.resize(icon_len);
+ BYTE *icon_bmp = v.ptrw();
+
+ encode_uint32(40, &icon_bmp[0]);
+ encode_uint32(w, &icon_bmp[4]);
+ encode_uint32(h * 2, &icon_bmp[8]);
+ encode_uint16(1, &icon_bmp[12]);
+ encode_uint16(32, &icon_bmp[14]);
+ encode_uint32(BI_RGB, &icon_bmp[16]);
+ encode_uint32(w * h * 4, &icon_bmp[20]);
+ encode_uint32(0, &icon_bmp[24]);
+ encode_uint32(0, &icon_bmp[28]);
+ encode_uint32(0, &icon_bmp[32]);
+ encode_uint32(0, &icon_bmp[36]);
+
+ uint8_t *wr = &icon_bmp[40];
+ const uint8_t *r = img->get_data().ptr();
+
+ for (int i = 0; i < h; i++) {
+ for (int j = 0; j < w; j++) {
+ const uint8_t *rpx = &r[((h - i - 1) * w + j) * 4];
+ uint8_t *wpx = &wr[(i * w + j) * 4];
+ wpx[0] = rpx[2];
+ wpx[1] = rpx[1];
+ wpx[2] = rpx[0];
+ wpx[3] = rpx[3];
+ }
+ }
+
+ hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
+ }
+
+ NOTIFYICONDATAW ndat;
+ ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
+ ndat.cbSize = sizeof(NOTIFYICONDATAW);
+ ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
+ ndat.uID = p_id;
+ ndat.uFlags = NIF_ICON;
+ ndat.hIcon = hicon;
+ ndat.uVersion = NOTIFYICON_VERSION;
+
+ Shell_NotifyIconW(NIM_MODIFY, &ndat);
+}
+
+void DisplayServerWindows::status_indicator_set_tooltip(IndicatorID p_id, const String &p_tooltip) {
+ ERR_FAIL_COND(!indicators.has(p_id));
+
+ NOTIFYICONDATAW ndat;
+ ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
+ ndat.cbSize = sizeof(NOTIFYICONDATAW);
+ ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
+ ndat.uID = p_id;
+ ndat.uFlags = NIF_TIP;
+ memcpy(ndat.szTip, p_tooltip.utf16().ptr(), MIN(p_tooltip.utf16().length(), 127) * sizeof(WCHAR));
+ ndat.uVersion = NOTIFYICON_VERSION;
+
+ Shell_NotifyIconW(NIM_MODIFY, &ndat);
+}
+
+void DisplayServerWindows::status_indicator_set_callback(IndicatorID p_id, const Callable &p_callback) {
+ ERR_FAIL_COND(!indicators.has(p_id));
+
+ indicators[p_id].callback = p_callback;
+}
+
+void DisplayServerWindows::delete_status_indicator(IndicatorID p_id) {
+ ERR_FAIL_COND(!indicators.has(p_id));
+
+ NOTIFYICONDATAW ndat;
+ ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
+ ndat.cbSize = sizeof(NOTIFYICONDATAW);
+ ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
+ ndat.uID = p_id;
+ ndat.uVersion = NOTIFYICON_VERSION;
+
+ Shell_NotifyIconW(NIM_DELETE, &ndat);
+ indicators.erase(p_id);
+}
+
void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(RD_ENABLED)
- if (context_rd) {
- context_rd->set_vsync_mode(p_window, p_vsync_mode);
+ if (rendering_context) {
+ rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
}
#endif
@@ -2636,8 +3033,8 @@ void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn
DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(RD_ENABLED)
- if (context_rd) {
- return context_rd->get_vsync_mode(p_window);
+ if (rendering_context) {
+ return rendering_context->window_get_vsync_mode(p_window);
}
#endif
@@ -2700,6 +3097,7 @@ void DisplayServerWindows::_drag_event(WindowID p_window, float p_x, float p_y,
event->set_index(idx);
event->set_position(Vector2(p_x, p_y));
event->set_relative(Vector2(p_x, p_y) - curr->get());
+ event->set_relative_screen_position(event->get_relative());
Input::get_singleton()->parse_input_event(event);
@@ -2960,6 +3358,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Process window messages.
switch (uMsg) {
+ case WM_CREATE: {
+ if (is_dark_mode_supported() && dark_title_available) {
+ BOOL value = is_dark_mode();
+
+ ::DwmSetWindowAttribute(windows[window_id].hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ SendMessageW(windows[window_id].hWnd, WM_PAINT, 0, 0);
+ }
+ } break;
case WM_NCPAINT: {
if (RenderingServer::get_singleton() && (windows[window_id].borderless || (windows[window_id].fullscreen && windows[window_id].multiwindow_fs))) {
Color color = RenderingServer::get_singleton()->get_default_clear_color();
@@ -3092,14 +3498,14 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
if (lParam && CompareStringOrdinal(reinterpret_cast<LPCWCH>(lParam), -1, L"ImmersiveColorSet", -1, true) == CSTR_EQUAL) {
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
- ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ ::DwmSetWindowAttribute(windows[window_id].hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
}
} break;
case WM_THEMECHANGED: {
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
- ::DwmSetWindowAttribute(windows[window_id].hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ ::DwmSetWindowAttribute(windows[window_id].hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
} break;
case WM_SYSCOMMAND: // Intercept system commands.
@@ -3115,6 +3521,30 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
}
} break;
+ case WM_INDICATOR_CALLBACK_MESSAGE: {
+ if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN || lParam == WM_MBUTTONDOWN || lParam == WM_XBUTTONDOWN) {
+ IndicatorID iid = (IndicatorID)wParam;
+ MouseButton mb = MouseButton::LEFT;
+ if (lParam == WM_RBUTTONDOWN) {
+ mb = MouseButton::RIGHT;
+ } else if (lParam == WM_MBUTTONDOWN) {
+ mb = MouseButton::MIDDLE;
+ } else if (lParam == WM_XBUTTONDOWN) {
+ mb = MouseButton::MB_XBUTTON1;
+ }
+ if (indicators.has(iid)) {
+ if (indicators[iid].callback.is_valid()) {
+ Variant v_button = mb;
+ Variant v_pos = mouse_get_position();
+ Variant *v_args[2] = { &v_button, &v_pos };
+ Variant ret;
+ Callable::CallError ce;
+ indicators[iid].callback.callp((const Variant **)&v_args, 2, ret, ce);
+ }
+ }
+ return 0;
+ }
+ } break;
case WM_CLOSE: // Did we receive a close message?
{
if (windows[window_id].focus_timer_id != 0U) {
@@ -3138,7 +3568,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
} break;
case WM_INPUT: {
- if (mouse_mode != MOUSE_MODE_CAPTURED || !use_raw_input) {
+ if (!use_raw_input) {
break;
}
@@ -3156,7 +3586,32 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
RAWINPUT *raw = (RAWINPUT *)lpb;
- if (raw->header.dwType == RIM_TYPEMOUSE) {
+ if (raw->header.dwType == RIM_TYPEKEYBOARD) {
+ if (raw->data.keyboard.VKey == VK_SHIFT) {
+ // If multiple Shifts are held down at the same time,
+ // Windows natively only sends a KEYUP for the last one to be released.
+ if (raw->data.keyboard.Flags & RI_KEY_BREAK) {
+ if (GetAsyncKeyState(VK_SHIFT) < 0) {
+ // A Shift is released, but another Shift is still held
+ ERR_BREAK(key_event_pos >= KEY_EVENT_BUFFER_SIZE);
+
+ KeyEvent ke;
+ ke.shift = false;
+ ke.alt = alt_mem;
+ ke.control = control_mem;
+ ke.meta = meta_mem;
+ ke.uMsg = WM_KEYUP;
+ ke.window_id = window_id;
+
+ ke.wParam = VK_SHIFT;
+ // data.keyboard.MakeCode -> 0x2A - left shift, 0x36 - right shift.
+ // Bit 30 -> key was previously down, bit 31 -> key is being released.
+ ke.lParam = raw->data.keyboard.MakeCode << 16 | 1 << 30 | 1 << 31;
+ key_event_buffer[key_event_pos++] = ke;
+ }
+ }
+ }
+ } else if (mouse_mode == MOUSE_MODE_CAPTURED && raw->header.dwType == RIM_TYPEMOUSE) {
Ref<InputEventMouseMotion> mm;
mm.instantiate();
@@ -3179,6 +3634,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
mm->set_position(c);
mm->set_global_position(c);
mm->set_velocity(Vector2(0, 0));
+ mm->set_screen_velocity(Vector2(0, 0));
if (raw->data.mouse.usFlags == MOUSE_MOVE_RELATIVE) {
mm->set_relative(Vector2(raw->data.mouse.lLastX, raw->data.mouse.lLastY));
@@ -3203,6 +3659,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
old_x = coords.x;
old_y = coords.y;
}
+ mm->set_relative_screen_position(mm->get_relative());
if ((windows[window_id].window_has_focus || windows[window_id].is_popup) && mm->get_relative() != Vector2()) {
Input::get_singleton()->parse_input_event(mm);
@@ -3290,6 +3747,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
+ mm->set_screen_velocity(mm->get_velocity());
if (old_invalid) {
old_x = mm->get_position().x;
@@ -3298,6 +3756,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
+ mm->set_relative_screen_position(mm->get_relative());
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) {
@@ -3437,6 +3896,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
+ mm->set_screen_velocity(mm->get_velocity());
if (old_invalid) {
old_x = mm->get_position().x;
@@ -3445,6 +3905,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
+ mm->set_relative_screen_position(mm->get_relative());
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) {
@@ -3556,6 +4017,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
mm->set_velocity(Input::get_singleton()->get_last_mouse_velocity());
+ mm->set_screen_velocity(mm->get_velocity());
if (old_invalid) {
old_x = mm->get_position().x;
@@ -3564,6 +4026,7 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
}
mm->set_relative(Vector2(mm->get_position() - Vector2(old_x, old_y)));
+ mm->set_relative_screen_position(mm->get_relative());
old_x = mm->get_position().x;
old_y = mm->get_position().y;
@@ -3800,9 +4263,9 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
rect_changed = true;
}
#if defined(RD_ENABLED)
- if (context_rd && window.context_created) {
+ if (rendering_context && window.context_created) {
// Note: Trigger resize event to update swapchains when window is minimized/restored, even if size is not changed.
- context_rd->window_resize(window_id, window.width, window.height);
+ rendering_context->window_set_size(window_id, window.width, window.height);
}
#endif
}
@@ -4161,6 +4624,7 @@ void DisplayServerWindows::_process_key_events() {
}
Key key_label = keycode;
Key physical_keycode = KeyMappingWindows::get_scansym((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24));
+ KeyLocation location = KeyMappingWindows::get_location((ke.lParam >> 16) & 0xFF, ke.lParam & (1 << 24));
static BYTE keyboard_state[256];
memset(keyboard_state, 0, 256);
@@ -4187,6 +4651,7 @@ void DisplayServerWindows::_process_key_events() {
}
k->set_keycode(keycode);
k->set_physical_keycode(physical_keycode);
+ k->set_location(location);
k->set_key_label(key_label);
if (i + 1 < key_event_pos && key_event_buffer[i + 1].uMsg == WM_CHAR) {
@@ -4352,17 +4817,17 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
if (is_dark_mode_supported() && dark_title_available) {
BOOL value = is_dark_mode();
- ::DwmSetWindowAttribute(wd.hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
+ ::DwmSetWindowAttribute(wd.hWnd, use_legacy_dark_mode_before_20H1 ? DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 : DWMWA_USE_IMMERSIVE_DARK_MODE, &value, sizeof(value));
}
#ifdef RD_ENABLED
- if (context_rd) {
+ if (rendering_context) {
union {
#ifdef VULKAN_ENABLED
- VulkanContextWindows::WindowPlatformData vulkan;
+ RenderingContextDriverVulkanWindows::WindowPlatformData vulkan;
#endif
#ifdef D3D12_ENABLED
- D3D12Context::WindowPlatformData d3d12;
+ RenderingContextDriverD3D12::WindowPlatformData d3d12;
#endif
} wpd;
#ifdef VULKAN_ENABLED
@@ -4376,12 +4841,16 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
wpd.d3d12.window = wd.hWnd;
}
#endif
- if (context_rd->window_create(id, p_vsync_mode, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top, &wpd) != OK) {
- memdelete(context_rd);
- context_rd = nullptr;
+ if (rendering_context->window_create(id, &wpd) != OK) {
+ ERR_PRINT(vformat("Failed to create %s window.", rendering_driver));
+ memdelete(rendering_context);
+ rendering_context = nullptr;
windows.erase(id);
- ERR_FAIL_V_MSG(INVALID_WINDOW_ID, vformat("Failed to create %s Window.", context_rd->get_api_name()));
+ return INVALID_WINDOW_ID;
}
+
+ rendering_context->window_set_size(id, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top);
+ rendering_context->window_set_vsync_mode(id, p_vsync_mode);
wd.context_created = true;
}
#endif
@@ -4490,6 +4959,7 @@ WTEnablePtr DisplayServerWindows::wintab_WTEnable = nullptr;
// UXTheme API.
bool DisplayServerWindows::dark_title_available = false;
+bool DisplayServerWindows::use_legacy_dark_mode_before_20H1 = false;
bool DisplayServerWindows::ux_theme_available = false;
ShouldAppsUseDarkModePtr DisplayServerWindows::ShouldAppsUseDarkMode = nullptr;
GetImmersiveColorFromColorSetExPtr DisplayServerWindows::GetImmersiveColorFromColorSetEx = nullptr;
@@ -4673,8 +5143,11 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98));
ux_theme_available = ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference;
- if (os_ver.dwBuildNumber >= 22000) {
+ if (os_ver.dwBuildNumber >= 18363) {
dark_title_available = true;
+ if (os_ver.dwBuildNumber < 19041) {
+ use_legacy_dark_mode_before_20H1 = true;
+ }
}
}
@@ -4750,19 +5223,19 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
#if defined(RD_ENABLED)
#if defined(VULKAN_ENABLED)
if (rendering_driver == "vulkan") {
- context_rd = memnew(VulkanContextWindows);
+ rendering_context = memnew(RenderingContextDriverVulkanWindows);
}
#endif
#if defined(D3D12_ENABLED)
if (rendering_driver == "d3d12") {
- context_rd = memnew(D3D12Context);
+ rendering_context = memnew(RenderingContextDriverD3D12);
}
#endif
- if (context_rd) {
- if (context_rd->initialize() != OK) {
- memdelete(context_rd);
- context_rd = nullptr;
+ if (rendering_context) {
+ if (rendering_context->initialize() != OK) {
+ memdelete(rendering_context);
+ rendering_context = nullptr;
r_error = ERR_UNAVAILABLE;
return;
}
@@ -4862,9 +5335,10 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
show_window(MAIN_WINDOW_ID);
#if defined(RD_ENABLED)
- if (context_rd) {
+ if (rendering_context) {
rendering_device = memnew(RenderingDevice);
- rendering_device->initialize(context_rd);
+ rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+ rendering_device->screen_create(MAIN_WINDOW_ID);
RendererCompositorRD::make_current();
}
@@ -4958,6 +5432,18 @@ DisplayServerWindows::~DisplayServerWindows() {
cursors_cache.clear();
+ // Destroy all status indicators.
+ for (HashMap<IndicatorID, IndicatorData>::Iterator E = indicators.begin(); E;) {
+ NOTIFYICONDATAW ndat;
+ ZeroMemory(&ndat, sizeof(NOTIFYICONDATAW));
+ ndat.cbSize = sizeof(NOTIFYICONDATAW);
+ ndat.hWnd = windows[MAIN_WINDOW_ID].hWnd;
+ ndat.uID = E->key;
+ ndat.uVersion = NOTIFYICON_VERSION;
+
+ Shell_NotifyIconW(NIM_DELETE, &ndat);
+ }
+
if (mouse_monitor) {
UnhookWindowsHookEx(mouse_monitor);
}
@@ -4976,8 +5462,12 @@ DisplayServerWindows::~DisplayServerWindows() {
if (windows.has(MAIN_WINDOW_ID)) {
#ifdef RD_ENABLED
- if (context_rd) {
- context_rd->window_destroy(MAIN_WINDOW_ID);
+ if (rendering_device) {
+ rendering_device->screen_free(MAIN_WINDOW_ID);
+ }
+
+ if (rendering_context) {
+ rendering_context->window_destroy(MAIN_WINDOW_ID);
}
#endif
if (wintab_available && windows[MAIN_WINDOW_ID].wtctx) {
@@ -4989,14 +5479,13 @@ DisplayServerWindows::~DisplayServerWindows() {
#ifdef RD_ENABLED
if (rendering_device) {
- rendering_device->finalize();
memdelete(rendering_device);
rendering_device = nullptr;
}
- if (context_rd) {
- memdelete(context_rd);
- context_rd = nullptr;
+ if (rendering_context) {
+ memdelete(rendering_context);
+ rendering_context = nullptr;
}
#endif
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 29c2460c10..e66c533da5 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -54,13 +54,6 @@
#if defined(RD_ENABLED)
#include "servers/rendering/rendering_device.h"
-
-#if defined(VULKAN_ENABLED)
-#include "vulkan_context_win.h"
-#endif
-#if defined(D3D12_ENABLED)
-#include "drivers/d3d12/d3d12_context.h"
-#endif
#endif
#if defined(GLES3_ENABLED)
@@ -294,6 +287,7 @@ class DisplayServerWindows : public DisplayServer {
// UXTheme API
static bool dark_title_available;
+ static bool use_legacy_dark_mode_before_20H1;
static bool ux_theme_available;
static ShouldAppsUseDarkModePtr ShouldAppsUseDarkMode;
static GetImmersiveColorFromColorSetExPtr GetImmersiveColorFromColorSetEx;
@@ -348,7 +342,7 @@ class DisplayServerWindows : public DisplayServer {
#endif
#if defined(RD_ENABLED)
- ApiContextRD *context_rd = nullptr;
+ RenderingContextDriver *rendering_context = nullptr;
RenderingDevice *rendering_device = nullptr;
#endif
@@ -453,6 +447,13 @@ class DisplayServerWindows : public DisplayServer {
WNDPROC user_proc = nullptr;
+ struct IndicatorData {
+ Callable callback;
+ };
+
+ IndicatorID indicator_id_counter = 0;
+ HashMap<IndicatorID, IndicatorData> indicators;
+
void _send_window_event(const WindowData &wd, WindowEvent p_event);
void _get_window_style(bool p_main_window, bool p_fullscreen, bool p_multiwindow_fs, bool p_borderless, bool p_resizable, bool p_maximized, bool p_no_activate_focus, DWORD &r_style, DWORD &r_style_ex);
@@ -497,6 +498,8 @@ class DisplayServerWindows : public DisplayServer {
LRESULT _handle_early_window_message(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Point2i _get_screens_origin() const;
+ Error _file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback, bool p_options_in_cb);
+
public:
LRESULT WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam);
@@ -521,6 +524,7 @@ public:
virtual Color get_accent_color() const override;
virtual Error file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) override;
+ virtual Error file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) override;
virtual void mouse_set_mode(MouseMode p_mode) override;
virtual MouseMode mouse_get_mode() const override;
@@ -611,6 +615,8 @@ public:
virtual void window_move_to_foreground(WindowID p_window = MAIN_WINDOW_ID) override;
virtual bool window_is_focused(WindowID p_window = MAIN_WINDOW_ID) const override;
+ virtual WindowID get_focused_window() const override;
+
virtual bool window_can_draw(WindowID p_window = MAIN_WINDOW_ID) const override;
virtual bool can_any_window_draw() const override;
@@ -656,6 +662,12 @@ public:
virtual void set_native_icon(const String &p_filename) override;
virtual void set_icon(const Ref<Image> &p_icon) override;
+ virtual IndicatorID create_status_indicator(const Ref<Image> &p_icon, const String &p_tooltip, const Callable &p_callback) override;
+ virtual void status_indicator_set_icon(IndicatorID p_id, const Ref<Image> &p_icon) override;
+ virtual void status_indicator_set_tooltip(IndicatorID p_id, const String &p_tooltip) override;
+ virtual void status_indicator_set_callback(IndicatorID p_id, const Callable &p_callback) override;
+ virtual void delete_status_indicator(IndicatorID p_id) override;
+
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_position, const Vector2i &p_resolution, int p_screen, Error &r_error);
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index 418f38c127..6cdd370bfe 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -37,9 +37,9 @@
#include "core/io/image_loader.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
-#include "editor/editor_scale.h"
#include "editor/editor_string_names.h"
#include "editor/export/editor_export.h"
+#include "editor/themes/editor_scale.h"
#include "modules/modules_enabled.gen.h" // For svg.
#ifdef MODULE_SVG_ENABLED
diff --git a/platform/windows/godot.natvis b/platform/windows/godot.natvis
index 36b0919185..d049ed9a3d 100644
--- a/platform/windows/godot.natvis
+++ b/platform/windows/godot.natvis
@@ -2,14 +2,46 @@
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="Vector&lt;*&gt;">
<Expand>
- <Item Name="[size]">_cowdata._ptr ? (((const unsigned int *)(_cowdata._ptr))[-1]) : 0</Item>
+ <Item Name="[size]">_cowdata._ptr ? (((const unsigned long long *)(_cowdata._ptr))[-1]) : 0</Item>
<ArrayItems>
- <Size>_cowdata._ptr ? (((const unsigned int *)(_cowdata._ptr))[-1]) : 0</Size>
- <ValuePointer>_cowdata._ptr</ValuePointer>
+ <Size>_cowdata._ptr ? (((const unsigned long long *)(_cowdata._ptr))[-1]) : 0</Size>
+ <ValuePointer>($T1 *) _cowdata._ptr</ValuePointer>
</ArrayItems>
</Expand>
</Type>
+ <Type Name="Array">
+ <Expand>
+ <Item Name="[size]">_p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Item>
+ <ArrayItems>
+ <Size>_p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Size>
+ <ValuePointer>(Variant *) _p->array._cowdata._ptr</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="TypedArray&lt;*&gt;">
+ <Expand>
+ <Item Name="[size]"> _p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Item>
+ <ArrayItems>
+ <Size>_p->array._cowdata._ptr ? (((const unsigned long long *)(_p->array._cowdata._ptr))[-1]) : 0</Size>
+ <ValuePointer >(Variant *) _p->array._cowdata._ptr</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="Dictionary">
+ <Expand>
+ <Item Name="[size]">_p &amp;&amp; _p->variant_map.head_element ? _p->variant_map.num_elements : 0</Item>
+ <LinkedListItems>
+ <Size>_p &amp;&amp; _p->variant_map.head_element ? _p->variant_map.num_elements : 0</Size>
+ <HeadPointer>_p ? _p->variant_map.head_element : nullptr</HeadPointer>
+ <NextPointer>next</NextPointer>
+ <ValueNode Name="[{data.key}]">(*this),view(MapHelper)</ValueNode>
+ </LinkedListItems>
+ </Expand>
+ </Type>
+
<Type Name="LocalVector&lt;*&gt;">
<Expand>
<Item Name="[size]">count</Item>
@@ -32,23 +64,85 @@
</Expand>
</Type>
- <Type Name="HashMap&lt;*,*&gt;">
+ <Type Name="NodePath">
+ <DisplayString Condition="!data">[empty]</DisplayString>
+ <DisplayString Condition="!!data">{{[absolute] = {data->absolute} [path] = {data->path,view(NodePathHelper)} [subpath] = {data->subpath,view(NodePathHelper)}}}</DisplayString>
+ <Expand>
+ <Item Name="[path]">data->path,view(NodePathHelper)</Item>
+ <Item Name="[subpath]">data->subpath,view(NodePathHelper)</Item>
+ <Item Name="[absolute]">data->absolute</Item>
+ </Expand>
+ </Type>
+
+ <Type Name="Vector&lt;StringName&gt;" IncludeView="NodePathHelper">
+ <Expand>
+ <ArrayItems>
+ <Size>_cowdata._ptr ? (((const unsigned long long *)(_cowdata._ptr))[-1]) : 0</Size>
+ <ValuePointer>((StringName *)_cowdata._ptr),view(NodePathHelper)</ValuePointer>
+ </ArrayItems>
+ </Expand>
+ </Type>
+
+ <Type Name="StringName" IncludeView="NodePathHelper">
+ <DisplayString Condition="_data &amp;&amp; _data->cname">{_data->cname,s8b}</DisplayString>
+ <DisplayString Condition="_data &amp;&amp; !_data->cname">{_data->name,s32b}</DisplayString>
+ <DisplayString Condition="!_data">[empty]</DisplayString>
+ <StringView Condition="_data &amp;&amp; _data->cname">_data->cname,s8b</StringView>
+ <StringView Condition="_data &amp;&amp; !_data->cname">_data->name,s32b</StringView>
+ </Type>
+
+ <Type Name="HashMapElement&lt;*,*&gt;">
+ <DisplayString>{{Key = {($T1 *) &amp;data.key} Value = {($T2 *) &amp;data.value}}}</DisplayString>
+ <Expand>
+ <Item Name="[key]">($T1 *) &amp;data.key</Item>
+ <Item Name="[value]">($T2 *) &amp;data.value</Item>
+ </Expand>
+ </Type>
+
+ <!-- elements displayed by index -->
+ <Type Name="HashMap&lt;*,*,*,*,*&gt;" Priority="Medium">
+ <Expand>
+ <Item Name="[size]">head_element ? num_elements : 0</Item>
+ <LinkedListItems>
+ <Size>head_element ? num_elements : 0</Size>
+ <HeadPointer>head_element</HeadPointer>
+ <NextPointer>next</NextPointer>
+ <ValueNode>(*this)</ValueNode>
+ </LinkedListItems>
+ </Expand>
+ </Type>
+
+ <!-- elements by key:value -->
+ <!-- show elements by index by specifying "ShowElementsByIndex"-->
+ <Type Name="HashMap&lt;*,*,*,*,*&gt;" ExcludeView="ShowElementsByIndex" Priority="MediumHigh">
<Expand>
- <Item Name="[size]">num_elements</Item>
+ <Item Name="[size]">head_element ? num_elements : 0</Item>
<LinkedListItems>
- <Size>num_elements</Size>
+ <Size>head_element ? num_elements : 0</Size>
<HeadPointer>head_element</HeadPointer>
<NextPointer>next</NextPointer>
- <ValueNode>data</ValueNode>
+ <ValueNode Name="[{data.key}]">(*this),view(MapHelper)</ValueNode>
</LinkedListItems>
</Expand>
</Type>
+ <Type Name="KeyValue&lt;*,*&gt;" IncludeView="MapHelper">
+ <DisplayString>{value}</DisplayString>
+ </Type>
+
+ <Type Name="HashMapElement&lt;*,*&gt;" IncludeView="MapHelper">
+ <DisplayString>{data.value}</DisplayString>
+ <Expand>
+ <Item Name="[key]" >($T1 *) &amp;data.key</Item>
+ <Item Name="[value]">($T2 *) &amp;data.value</Item>
+ </Expand>
+ </Type>
+
<Type Name="VMap&lt;*,*&gt;">
<Expand>
- <Item Condition="_cowdata._ptr" Name="[size]">*(reinterpret_cast&lt;int*&gt;(_cowdata._ptr) - 1)</Item>
+ <Item Condition="_cowdata._ptr" Name="[size]">*(reinterpret_cast&lt;long long*&gt;(_cowdata._ptr) - 1)</Item>
<ArrayItems Condition="_cowdata._ptr">
- <Size>*(reinterpret_cast&lt;int*&gt;(_cowdata._ptr) - 1)</Size>
+ <Size>*(reinterpret_cast&lt;long long*&gt;(_cowdata._ptr) - 1)</Size>
<ValuePointer>reinterpret_cast&lt;VMap&lt;$T1,$T2&gt;::Pair*&gt;(_cowdata._ptr)</ValuePointer>
</ArrayItems>
</Expand>
@@ -58,11 +152,6 @@
<DisplayString Condition="dynamic_cast&lt;CallableCustomMethodPointerBase*&gt;(key.custom)">{dynamic_cast&lt;CallableCustomMethodPointerBase*&gt;(key.custom)->text}</DisplayString>
</Type>
- <!-- requires PR 64364
- <Type Name="GDScriptThreadContext">
- <DisplayString Condition="_is_main == true">main thread {_debug_thread_id}</DisplayString>
- </Type>
- -->
<Type Name="Variant">
<DisplayString Condition="type == Variant::NIL">nil</DisplayString>
@@ -82,22 +171,22 @@
<DisplayString Condition="type == Variant::PLANE">{*(Plane *)_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::STRING_NAME">{*(StringName *)_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::OBJECT">{*(Object *)_data._mem}</DisplayString>
+ <DisplayString Condition="type == Variant::OBJECT">{*(*reinterpret_cast&lt;ObjData*&gt;(&amp;_data._mem[0])).obj}</DisplayString>
<DisplayString Condition="type == Variant::DICTIONARY">{*(Dictionary *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::ARRAY">{*(Array *)_data._mem}</DisplayString>
<DisplayString Condition="type == Variant::PACKED_BYTE_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;unsigned char&gt;*&gt;(_data.packed_array)->array}</DisplayString>
<DisplayString Condition="type == Variant::PACKED_INT32_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;int&gt;*&gt;(_data.packed_array)->array}</DisplayString>
- <!-- broken, will show incorrect data
- <DisplayString Condition="type == Variant::PACKED_INT64_ARRAY">{*(PackedInt64Array *)_data._mem}</DisplayString>
- -->
+ <DisplayString Condition="type == Variant::PACKED_INT64_ARRAY">{*reinterpret_cast&lt;PackedInt64Array *&gt;(&amp;_data.packed_array[1])}</DisplayString>
<DisplayString Condition="type == Variant::PACKED_FLOAT32_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;float&gt;*&gt;(_data.packed_array)->array}</DisplayString>
<DisplayString Condition="type == Variant::PACKED_FLOAT64_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;double&gt;*&gt;(_data.packed_array)->array}</DisplayString>
<DisplayString Condition="type == Variant::PACKED_STRING_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;String&gt;*&gt;(_data.packed_array)->array}</DisplayString>
<DisplayString Condition="type == Variant::PACKED_VECTOR2_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;Vector2&gt;*&gt;(_data.packed_array)->array}</DisplayString>
<DisplayString Condition="type == Variant::PACKED_VECTOR3_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;Vector3&gt;*&gt;(_data.packed_array)->array}</DisplayString>
<DisplayString Condition="type == Variant::PACKED_COLOR_ARRAY">{reinterpret_cast&lt;const Variant::PackedArrayRef&lt;Color&gt;*&gt;(_data.packed_array)->array}</DisplayString>
+ <DisplayString Condition="type &lt; 0 || type >= Variant::VARIANT_MAX">[INVALID]</DisplayString>
<StringView Condition="type == Variant::STRING &amp;&amp; ((String *)(_data._mem))->_cowdata._ptr">((String *)(_data._mem))->_cowdata._ptr,s32</StringView>
@@ -116,20 +205,22 @@
<Item Name="[value]" Condition="type == Variant::PLANE">*(Plane *)_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::STRING_NAME">*(StringName *)_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::OBJECT">*(Object *)_data._mem</Item>
+ <Item Name="[value]" Condition="type == Variant::OBJECT">*(*reinterpret_cast&lt;ObjData*&gt;(&amp;_data._mem[0])).obj</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::PACKED_BYTE_ARRAY">reinterpret_cast&lt;const Variant::PackedArrayRef&lt;unsigned char&gt;*&gt;(_data.packed_array)->array</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>
+ <Item Name="[value]" Condition="type == Variant::PACKED_INT32_ARRAY">reinterpret_cast&lt;const Variant::PackedArrayRef&lt;int&gt;*&gt;(_data.packed_array)->array</Item>
+ <Item Name="[value]" Condition="type == Variant::PACKED_INT64_ARRAY">*reinterpret_cast&lt;PackedInt64Array *&gt;(&amp;_data.packed_array[1])</Item>
+ <Item Name="[value]" Condition="type == Variant::PACKED_FLOAT32_ARRAY">reinterpret_cast&lt;const Variant::PackedArrayRef&lt;float&gt;*&gt;(_data.packed_array)->array</Item>
+ <Item Name="[value]" Condition="type == Variant::PACKED_FLOAT64_ARRAY">reinterpret_cast&lt;const Variant::PackedArrayRef&lt;double&gt;*&gt;(_data.packed_array)->array</Item>
+ <Item Name="[value]" Condition="type == Variant::PACKED_STRING_ARRAY">reinterpret_cast&lt;const Variant::PackedArrayRef&lt;String&gt;*&gt;(_data.packed_array)->array</Item>
+ <Item Name="[value]" Condition="type == Variant::PACKED_VECTOR2_ARRAY">reinterpret_cast&lt;const Variant::PackedArrayRef&lt;Vector2&gt;*&gt;(_data.packed_array)->array</Item>
+ <Item Name="[value]" Condition="type == Variant::PACKED_VECTOR3_ARRAY">reinterpret_cast&lt;const Variant::PackedArrayRef&lt;Vector3&gt;*&gt;(_data.packed_array)->array</Item>
+ <Item Name="[value]" Condition="type == Variant::PACKED_COLOR_ARRAY">reinterpret_cast&lt;const Variant::PackedArrayRef&lt;Color&gt;*&gt;(_data.packed_array)->array</Item>
+
</Expand>
</Type>
@@ -148,10 +239,10 @@
</Type>
<Type Name="StringName">
- <DisplayString Condition="_data &amp;&amp; _data->cname">{_data->cname}</DisplayString>
+ <DisplayString Condition="_data &amp;&amp; _data->cname">{_data->cname,na}</DisplayString>
<DisplayString Condition="_data &amp;&amp; !_data->cname">{_data->name,s32}</DisplayString>
<DisplayString Condition="!_data">[empty]</DisplayString>
- <StringView Condition="_data &amp;&amp; _data->cname">_data->cname</StringView>
+ <StringView Condition="_data &amp;&amp; _data->cname">_data->cname,na</StringView>
<StringView Condition="_data &amp;&amp; !_data->cname">_data->name,s32</StringView>
</Type>
diff --git a/platform/windows/godot_res.rc b/platform/windows/godot_res.rc
index 0593c8b069..8187c0c936 100644
--- a/platform/windows/godot_res.rc
+++ b/platform/windows/godot_res.rc
@@ -1,16 +1,12 @@
#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
+FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+FILEOS 4
+FILETYPE 1
BEGIN
BLOCK "StringFileInfo"
BEGIN
@@ -21,7 +17,7 @@ BEGIN
VALUE "FileVersion", VERSION_NUMBER
VALUE "ProductName", VERSION_NAME
VALUE "Licence", "MIT"
- VALUE "LegalCopyright", "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur and contributors"
+ VALUE "LegalCopyright", "(c) 2007-present Juan Linietsky, Ariel Manzur and Godot Engine contributors"
VALUE "Info", "https://godotengine.org"
VALUE "ProductVersion", VERSION_FULL_BUILD
END
diff --git a/platform/windows/godot_res_wrap.rc b/platform/windows/godot_res_wrap.rc
index 9dd29afe51..27ad26cbc5 100644
--- a/platform/windows/godot_res_wrap.rc
+++ b/platform/windows/godot_res_wrap.rc
@@ -1,16 +1,12 @@
#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_console.ico
1 VERSIONINFO
-FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
-PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
-FILEOS 4
-FILETYPE 1
+FILEVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,VERSION_PATCH,0
+FILEOS 4
+FILETYPE 1
BEGIN
BLOCK "StringFileInfo"
BEGIN
@@ -21,7 +17,7 @@ BEGIN
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 "LegalCopyright", "(c) 2007-present Juan Linietsky, Ariel Manzur and Godot Engine contributors"
VALUE "Info", "https://godotengine.org"
VALUE "ProductVersion", VERSION_FULL_BUILD
END
diff --git a/platform/windows/godot_windows.cpp b/platform/windows/godot_windows.cpp
index 8d63b1747e..f86ecd87fb 100644
--- a/platform/windows/godot_windows.cpp
+++ b/platform/windows/godot_windows.cpp
@@ -36,7 +36,7 @@
#include <stdio.h>
// For export templates, add a section; the exporter will patch it to enclose
-// the data appended to the executable (bundled PCK)
+// the data appended to the executable (bundled PCK).
#ifndef TOOLS_ENABLED
#if defined _MSC_VER
#pragma section("pck", read)
@@ -45,7 +45,7 @@ __declspec(allocate("pck")) static char dummy[8] = { 0 };
// Dummy function to prevent LTO from discarding "pck" section.
extern "C" char *__cdecl pck_section_dummy_call() {
return &dummy[0];
-};
+}
#if defined _AMD64_
#pragma comment(linker, "/include:pck_section_dummy_call")
#elif defined _X86_
diff --git a/platform/windows/key_mapping_windows.cpp b/platform/windows/key_mapping_windows.cpp
index b376854c0c..20905d0fe9 100644
--- a/platform/windows/key_mapping_windows.cpp
+++ b/platform/windows/key_mapping_windows.cpp
@@ -46,6 +46,7 @@ HashMap<unsigned int, Key, HashMapHasherKeys> vk_map;
HashMap<unsigned int, Key, HashMapHasherKeys> scansym_map;
HashMap<Key, unsigned int, HashMapHasherKeys> scansym_map_inv;
HashMap<unsigned int, Key, HashMapHasherKeys> scansym_map_ext;
+HashMap<unsigned int, KeyLocation, HashMapHasherKeys> location_map;
void KeyMappingWindows::initialize() {
// VK_LBUTTON (0x01)
@@ -380,6 +381,15 @@ void KeyMappingWindows::initialize() {
scansym_map_ext[0x6C] = Key::LAUNCHMAIL;
scansym_map_ext[0x6D] = Key::LAUNCHMEDIA;
scansym_map_ext[0x78] = Key::MEDIARECORD;
+
+ // Scancode to physical location map.
+ // Shift.
+ location_map[0x2A] = KeyLocation::LEFT;
+ location_map[0x36] = KeyLocation::RIGHT;
+ // Meta.
+ location_map[0x5B] = KeyLocation::LEFT;
+ location_map[0x5C] = KeyLocation::RIGHT;
+ // Ctrl and Alt must be handled differently.
}
Key KeyMappingWindows::get_keysym(unsigned int p_code) {
@@ -424,3 +434,16 @@ bool KeyMappingWindows::is_extended_key(unsigned int p_code) {
p_code == VK_RIGHT ||
p_code == VK_DOWN;
}
+
+KeyLocation KeyMappingWindows::get_location(unsigned int p_code, bool p_extended) {
+ // Right- ctrl and alt have the same scancode as left, but are in the extended keys.
+ const Key *key = scansym_map.getptr(p_code);
+ if (key && (*key == Key::CTRL || *key == Key::ALT)) {
+ return p_extended ? KeyLocation::RIGHT : KeyLocation::LEFT;
+ }
+ const KeyLocation *location = location_map.getptr(p_code);
+ if (location) {
+ return *location;
+ }
+ return KeyLocation::UNSPECIFIED;
+}
diff --git a/platform/windows/key_mapping_windows.h b/platform/windows/key_mapping_windows.h
index a98aa7ed68..e6f184a2cc 100644
--- a/platform/windows/key_mapping_windows.h
+++ b/platform/windows/key_mapping_windows.h
@@ -47,6 +47,7 @@ public:
static unsigned int get_scancode(Key p_keycode);
static Key get_scansym(unsigned int p_code, bool p_extended);
static bool is_extended_key(unsigned int p_code);
+ static KeyLocation get_location(unsigned int p_code, bool p_extended);
};
#endif // KEY_MAPPING_WINDOWS_H
diff --git a/platform/windows/msvs.py b/platform/windows/msvs.py
new file mode 100644
index 0000000000..2d5ebe811a
--- /dev/null
+++ b/platform/windows/msvs.py
@@ -0,0 +1,20 @@
+import methods
+
+
+# Tuples with the name of the arch that will be used in VS, mapped to our internal arch names.
+# For Windows platforms, Win32 is what VS wants. For other platforms, it can be different.
+def get_platforms():
+ return [("Win32", "x86_32"), ("x64", "x86_64")]
+
+
+def get_configurations():
+ return ["editor", "template_debug", "template_release"]
+
+
+def get_build_prefix(env):
+ batch_file = methods.find_visual_c_batch_file(env)
+ return [
+ "set &quot;plat=$(PlatformTarget)&quot;",
+ "(if &quot;$(PlatformTarget)&quot;==&quot;x64&quot; (set &quot;plat=x86_amd64&quot;))",
+ f"call &quot;{batch_file}&quot; !plat!",
+ ]
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 35b88acd26..056696ae2f 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -48,13 +48,6 @@
#if defined(RD_ENABLED)
#include "servers/rendering/rendering_device.h"
-
-#if defined(VULKAN_ENABLED)
-#include "vulkan_context_win.h"
-#endif
-#if defined(D3D12_ENABLED)
-#include "drivers/d3d12/d3d12_context.h"
-#endif
#endif
#include <io.h>
diff --git a/platform/windows/platform_windows_builders.py b/platform/windows/platform_windows_builders.py
index 51652fa814..652dc06acf 100644
--- a/platform/windows/platform_windows_builders.py
+++ b/platform/windows/platform_windows_builders.py
@@ -10,19 +10,21 @@ from platform_methods import subprocess_main
def make_debug_mingw(target, source, env):
- mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
- if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
- os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
- else:
- os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
- if try_cmd("strip --version", env["mingw_prefix"], env["arch"]):
- os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0]))
- else:
- os.system("strip --strip-debug --strip-unneeded {0}".format(target[0]))
- if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
- os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
- else:
- os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
+ # Force separate debug symbols if executable size is larger than 1.9 GB.
+ if env["separate_debug_symbols"] or os.stat(target[0]).st_size >= 2040109465:
+ mingw_bin_prefix = get_mingw_bin_prefix(env["mingw_prefix"], env["arch"])
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
+ else:
+ os.system("objcopy --only-keep-debug {0} {0}.debugsymbols".format(target[0]))
+ if try_cmd("strip --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "strip --strip-debug --strip-unneeded {0}".format(target[0]))
+ else:
+ os.system("strip --strip-debug --strip-unneeded {0}".format(target[0]))
+ if try_cmd("objcopy --version", env["mingw_prefix"], env["arch"]):
+ os.system(mingw_bin_prefix + "objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
+ else:
+ os.system("objcopy --add-gnu-debuglink={0}.debugsymbols {0}".format(target[0]))
if __name__ == "__main__":
diff --git a/platform/windows/vulkan_context_win.cpp b/platform/windows/rendering_context_driver_vulkan_windows.cpp
index 69f8dc23fb..f968ffc1d7 100644
--- a/platform/windows/vulkan_context_win.cpp
+++ b/platform/windows/rendering_context_driver_vulkan_windows.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_win.cpp */
+/* rendering_context_driver_vulkan_windows.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -30,7 +30,9 @@
#if defined(WINDOWS_ENABLED) && defined(VULKAN_ENABLED)
-#include "vulkan_context_win.h"
+#include "core/os/os.h"
+
+#include "rendering_context_driver_vulkan_windows.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -38,32 +40,36 @@
#include <vulkan/vulkan.h>
#endif
-const char *VulkanContextWindows::_get_platform_surface_extension() const {
+const char *RenderingContextDriverVulkanWindows::_get_platform_surface_extension() const {
return VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
}
-Error VulkanContextWindows::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
- const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
-
- VkWin32SurfaceCreateInfoKHR createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
- createInfo.hinstance = wpd->instance;
- createInfo.hwnd = wpd->window;
-
- VkSurfaceKHR surface = VK_NULL_HANDLE;
- VkResult err = vkCreateWin32SurfaceKHR(get_instance(), &createInfo, nullptr, &surface);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
- return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
-}
-
-VulkanContextWindows::VulkanContextWindows() {
+RenderingContextDriverVulkanWindows::RenderingContextDriverVulkanWindows() {
// Workaround for Vulkan not working on setups with AMD integrated graphics + NVIDIA dedicated GPU (GH-57708).
// This prevents using AMD integrated graphics with Vulkan entirely, but it allows the engine to start
// even on outdated/broken driver setups.
OS::get_singleton()->set_environment("DISABLE_LAYER_AMD_SWITCHABLE_GRAPHICS_1", "1");
}
-VulkanContextWindows::~VulkanContextWindows() {
+RenderingContextDriverVulkanWindows::~RenderingContextDriverVulkanWindows() {
+ // Does nothing.
+}
+
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanWindows::surface_create(const void *p_platform_data) {
+ const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
+
+ VkWin32SurfaceCreateInfoKHR create_info = {};
+ create_info.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR;
+ create_info.hinstance = wpd->instance;
+ create_info.hwnd = wpd->window;
+
+ VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+ VkResult err = vkCreateWin32SurfaceKHR(instance_get(), &create_info, nullptr, &vk_surface);
+ ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
+
+ Surface *surface = memnew(Surface);
+ surface->vk_surface = vk_surface;
+ return SurfaceID(surface);
}
#endif // WINDOWS_ENABLED && VULKAN_ENABLED
diff --git a/platform/windows/vulkan_context_win.h b/platform/windows/rendering_context_driver_vulkan_windows.h
index 29ab1d45c3..34546c9ea6 100644
--- a/platform/windows/vulkan_context_win.h
+++ b/platform/windows/rendering_context_driver_vulkan_windows.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_win.h */
+/* rendering_context_driver_vulkan_windows.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,30 +28,33 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef VULKAN_CONTEXT_WIN_H
-#define VULKAN_CONTEXT_WIN_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_WINDOWS_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_WINDOWS_H
#ifdef VULKAN_ENABLED
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
-class VulkanContextWindows : public VulkanContext {
- virtual const char *_get_platform_surface_extension() const;
+class RenderingContextDriverVulkanWindows : public RenderingContextDriverVulkan {
+private:
+ const char *_get_platform_surface_extension() const override final;
+
+protected:
+ SurfaceID surface_create(const void *p_platform_data) override final;
public:
struct WindowPlatformData {
HWND window;
HINSTANCE instance;
};
- virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
- VulkanContextWindows();
- ~VulkanContextWindows();
+ RenderingContextDriverVulkanWindows();
+ ~RenderingContextDriverVulkanWindows() override final;
};
#endif // VULKAN_ENABLED
-#endif // VULKAN_CONTEXT_WIN_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_WINDOWS_H