Skip to content

Commit fe01776

Browse files
authored
Merge pull request godotengine#89540 from bruvzg/menu_fix_string_read
[NativeMenu] Fix changes lost due to incorrect rebase (menu goes under task bar, dark mode, item text get, docs) and check to ensure help menu is not using native menu on Windows.
2 parents 68ad520 + ebb19c4 commit fe01776

File tree

5 files changed

+70
-14
lines changed

5 files changed

+70
-14
lines changed

doc/classes/NativeMenu.xml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
An [param accelerator] can optionally be defined, which is a keyboard shortcut that can be pressed to trigger the menu button even if it's not currently open. The [param accelerator] is generally a combination of [enum KeyModifierMask]s and [enum Key]s using bitwise OR such as [code]KEY_MASK_CTRL | KEY_A[/code] ([kbd]Ctrl + A[/kbd]).
5454
[b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag].
5555
[b]Note:[/b] This method is implemented on macOS and Windows.
56-
[b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows.
56+
[b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored.
5757
</description>
5858
</method>
5959
<method name="add_icon_check_item">
@@ -72,7 +72,7 @@
7272
An [param accelerator] can optionally be defined, which is a keyboard shortcut that can be pressed to trigger the menu button even if it's not currently open. The [param accelerator] is generally a combination of [enum KeyModifierMask]s and [enum Key]s using bitwise OR such as [code]KEY_MASK_CTRL | KEY_A[/code] ([kbd]Ctrl + A[/kbd]).
7373
[b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag].
7474
[b]Note:[/b] This method is implemented on macOS and Windows.
75-
[b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows.
75+
[b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored.
7676
</description>
7777
</method>
7878
<method name="add_icon_item">
@@ -91,7 +91,7 @@
9191
An [param accelerator] can optionally be defined, which is a keyboard shortcut that can be pressed to trigger the menu button even if it's not currently open. The [param accelerator] is generally a combination of [enum KeyModifierMask]s and [enum Key]s using bitwise OR such as [code]KEY_MASK_CTRL | KEY_A[/code] ([kbd]Ctrl + A[/kbd]).
9292
[b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag].
9393
[b]Note:[/b] This method is implemented on macOS and Windows.
94-
[b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows.
94+
[b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored.
9595
</description>
9696
</method>
9797
<method name="add_icon_radio_check_item">
@@ -111,7 +111,7 @@
111111
[b]Note:[/b] Radio-checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it.
112112
[b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag].
113113
[b]Note:[/b] This method is implemented on macOS and Windows.
114-
[b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows.
114+
[b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored.
115115
</description>
116116
</method>
117117
<method name="add_item">
@@ -129,7 +129,7 @@
129129
An [param accelerator] can optionally be defined, which is a keyboard shortcut that can be pressed to trigger the menu button even if it's not currently open. The [param accelerator] is generally a combination of [enum KeyModifierMask]s and [enum Key]s using bitwise OR such as [code]KEY_MASK_CTRL | KEY_A[/code] ([kbd]Ctrl + A[/kbd]).
130130
[b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag].
131131
[b]Note:[/b] This method is implemented on macOS and Windows.
132-
[b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows.
132+
[b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored.
133133
</description>
134134
</method>
135135
<method name="add_multistate_item">
@@ -151,7 +151,7 @@
151151
[b]Note:[/b] By default, there's no indication of the current item state, it should be changed manually.
152152
[b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag].
153153
[b]Note:[/b] This method is implemented on macOS and Windows.
154-
[b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows.
154+
[b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored.
155155
</description>
156156
</method>
157157
<method name="add_radio_check_item">
@@ -170,7 +170,7 @@
170170
[b]Note:[/b] Radio-checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually. See [method set_item_checked] for more info on how to control it.
171171
[b]Note:[/b] The [param callback] and [param key_callback] Callables need to accept exactly one Variant parameter, the parameter passed to the Callables will be the value passed to [param tag].
172172
[b]Note:[/b] This method is implemented on macOS and Windows.
173-
[b]Note:[/b] [param accelerator] and [param key_callback] are ignored on Windows.
173+
[b]Note:[/b] On Windows, [param accelerator] and [param key_callback] are ignored.
174174
</description>
175175
</method>
176176
<method name="add_separator">
@@ -496,7 +496,7 @@
496496
<param index="0" name="rid" type="RID" />
497497
<param index="1" name="is_rtl" type="bool" />
498498
<description>
499-
Sets the menu text layout directtion.
499+
Sets the menu text layout direction from right-to-left if [param is_rtl] is [code]true[/code].
500500
[b]Note:[/b] This method is implemented on macOS and Windows.
501501
</description>
502502
</method>

editor/editor_node.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6754,7 +6754,7 @@ EditorNode::EditorNode() {
67546754
ED_SHORTCUT_AND_COMMAND("editor/editor_settings", TTR("Editor Settings..."));
67556755
ED_SHORTCUT_OVERRIDE("editor/editor_settings", "macos", KeyModifierMask::META + Key::COMMA);
67566756
#ifdef MACOS_ENABLED
6757-
if (global_menu) {
6757+
if (global_menu && NativeMenu::get_singleton()->has_system_menu(NativeMenu::APPLICATION_MENU_ID)) {
67586758
apple_menu = memnew(PopupMenu);
67596759
apple_menu->set_system_menu(NativeMenu::APPLICATION_MENU_ID);
67606760
main_menu->add_child(apple_menu);
@@ -6879,7 +6879,9 @@ EditorNode::EditorNode() {
68796879

68806880
help_menu = memnew(PopupMenu);
68816881
help_menu->set_name(TTR("Help"));
6882-
help_menu->set_system_menu(NativeMenu::HELP_MENU_ID);
6882+
if (global_menu && NativeMenu::get_singleton()->has_system_menu(NativeMenu::HELP_MENU_ID)) {
6883+
help_menu->set_system_menu(NativeMenu::HELP_MENU_ID);
6884+
}
68836885
main_menu->add_child(help_menu);
68846886

68856887
help_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));

platform/windows/display_server_windows.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5497,6 +5497,32 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
54975497
GetImmersiveColorFromColorSetEx = (GetImmersiveColorFromColorSetExPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(95));
54985498
GetImmersiveColorTypeFromName = (GetImmersiveColorTypeFromNamePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(96));
54995499
GetImmersiveUserColorSetPreference = (GetImmersiveUserColorSetPreferencePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(98));
5500+
if (os_ver.dwBuildNumber >= 17763) {
5501+
AllowDarkModeForAppPtr AllowDarkModeForApp = nullptr;
5502+
SetPreferredAppModePtr SetPreferredAppMode = nullptr;
5503+
FlushMenuThemesPtr FlushMenuThemes = nullptr;
5504+
if (os_ver.dwBuildNumber < 18362) {
5505+
AllowDarkModeForApp = (AllowDarkModeForAppPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(135));
5506+
} else {
5507+
SetPreferredAppMode = (SetPreferredAppModePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(135));
5508+
FlushMenuThemes = (FlushMenuThemesPtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(136));
5509+
}
5510+
RefreshImmersiveColorPolicyStatePtr RefreshImmersiveColorPolicyState = (RefreshImmersiveColorPolicyStatePtr)GetProcAddress(ux_theme_lib, MAKEINTRESOURCEA(104));
5511+
if (ShouldAppsUseDarkMode) {
5512+
bool dark_mode = ShouldAppsUseDarkMode();
5513+
if (SetPreferredAppMode) {
5514+
SetPreferredAppMode(dark_mode ? APPMODE_ALLOWDARK : APPMODE_DEFAULT);
5515+
} else if (AllowDarkModeForApp) {
5516+
AllowDarkModeForApp(dark_mode);
5517+
}
5518+
if (RefreshImmersiveColorPolicyState) {
5519+
RefreshImmersiveColorPolicyState();
5520+
}
5521+
if (FlushMenuThemes) {
5522+
FlushMenuThemes();
5523+
}
5524+
}
5525+
}
55005526

55015527
ux_theme_available = ShouldAppsUseDarkMode && GetImmersiveColorFromColorSetEx && GetImmersiveColorTypeFromName && GetImmersiveUserColorSetPreference;
55025528
if (os_ver.dwBuildNumber >= 18363) {

platform/windows/display_server_windows.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,11 +154,23 @@ typedef UINT(WINAPI *WTInfoPtr)(UINT p_category, UINT p_index, LPVOID p_output);
154154
typedef BOOL(WINAPI *WTPacketPtr)(HANDLE p_ctx, UINT p_param, LPVOID p_packets);
155155
typedef BOOL(WINAPI *WTEnablePtr)(HANDLE p_ctx, BOOL p_enable);
156156

157+
enum PreferredAppMode {
158+
APPMODE_DEFAULT = 0,
159+
APPMODE_ALLOWDARK = 1,
160+
APPMODE_FORCEDARK = 2,
161+
APPMODE_FORCELIGHT = 3,
162+
APPMODE_MAX = 4
163+
};
164+
157165
typedef bool(WINAPI *ShouldAppsUseDarkModePtr)();
158166
typedef DWORD(WINAPI *GetImmersiveColorFromColorSetExPtr)(UINT dwImmersiveColorSet, UINT dwImmersiveColorType, bool bIgnoreHighContrast, UINT dwHighContrastCacheMode);
159167
typedef int(WINAPI *GetImmersiveColorTypeFromNamePtr)(const WCHAR *name);
160168
typedef int(WINAPI *GetImmersiveUserColorSetPreferencePtr)(bool bForceCheckRegistry, bool bSkipCheckOnFail);
161169
typedef HRESULT(WINAPI *RtlGetVersionPtr)(OSVERSIONINFOW *lpVersionInformation);
170+
typedef bool(WINAPI *AllowDarkModeForAppPtr)(bool darkMode);
171+
typedef PreferredAppMode(WINAPI *SetPreferredAppModePtr)(PreferredAppMode appMode);
172+
typedef void(WINAPI *RefreshImmersiveColorPolicyStatePtr)();
173+
typedef void(WINAPI *FlushMenuThemesPtr)();
162174

163175
// Windows Ink API
164176
#ifndef POINTER_STRUCTURES

platform/windows/native_menu_windows.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ RID NativeMenuWindows::create_menu() {
141141
ZeroMemory(&menu_info, sizeof(menu_info));
142142
menu_info.cbSize = sizeof(menu_info);
143143
menu_info.fMask = MIM_STYLE;
144-
menu_info.dwStyle = MNS_NOTIFYBYPOS | MNS_MODELESS;
144+
menu_info.dwStyle = MNS_NOTIFYBYPOS;
145145
SetMenuInfo(md->menu, &menu_info);
146146

147147
RID rid = menus.make_rid(md);
@@ -189,7 +189,9 @@ void NativeMenuWindows::popup(const RID &p_rid, const Vector2i &p_position) {
189189
if (md->is_rtl) {
190190
flags |= TPM_LAYOUTRTL;
191191
}
192+
SetForegroundWindow(hwnd);
192193
TrackPopupMenuEx(md->menu, flags, p_position.x, p_position.y, hwnd, nullptr);
194+
PostMessage(hwnd, WM_NULL, 0, 0);
193195
}
194196

195197
void NativeMenuWindows::set_interface_direction(const RID &p_rid, bool p_is_rtl) {
@@ -556,9 +558,16 @@ int NativeMenuWindows::find_item_index_with_text(const RID &p_rid, const String
556558
ZeroMemory(&item, sizeof(item));
557559
item.cbSize = sizeof(item);
558560
item.fMask = MIIM_STRING;
561+
item.dwTypeData = nullptr;
559562
if (GetMenuItemInfoW(md->menu, i, true, &item)) {
560-
if (String::utf16((const char16_t *)item.dwTypeData) == p_text) {
561-
return i;
563+
item.cch++;
564+
Char16String str;
565+
str.resize(item.cch);
566+
item.dwTypeData = (LPWSTR)str.ptrw();
567+
if (GetMenuItemInfoW(md->menu, i, true, &item)) {
568+
if (String::utf16((const char16_t *)str.get_data()) == p_text) {
569+
return i;
570+
}
562571
}
563572
}
564573
}
@@ -700,8 +709,15 @@ String NativeMenuWindows::get_item_text(const RID &p_rid, int p_idx) const {
700709
ZeroMemory(&item, sizeof(item));
701710
item.cbSize = sizeof(item);
702711
item.fMask = MIIM_STRING;
712+
item.dwTypeData = nullptr;
703713
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
704-
return String::utf16((const char16_t *)item.dwTypeData);
714+
item.cch++;
715+
Char16String str;
716+
str.resize(item.cch);
717+
item.dwTypeData = (LPWSTR)str.ptrw();
718+
if (GetMenuItemInfoW(md->menu, p_idx, true, &item)) {
719+
return String::utf16((const char16_t *)str.get_data());
720+
}
705721
}
706722
return String();
707723
}

0 commit comments

Comments
 (0)