Skip to content

Commit 740df74

Browse files
feat(menu): no longer run js when shown by show_at in js
1 parent 2579de2 commit 740df74

File tree

5 files changed

+172
-154
lines changed

5 files changed

+172
-154
lines changed

src/shell/contextmenu/contextmenu.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct menu {
2222
bool is_top = true);
2323
};
2424

25-
std::optional<int> track_popup_menu(menu menu, int x, int y, std::function<void(menu_render&)> on_before_show = {});
25+
std::optional<int> track_popup_menu(menu menu, int x, int y, std::function<void(menu_render&)> on_before_show = {}, bool run_js = true);
2626

2727
struct owner_draw_menu_info {
2828
HBITMAP bitmap;

src/shell/contextmenu/hooks.cc

Lines changed: 38 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -21,39 +21,46 @@ static auto renderer_thread = mb_shell::task_queue{};
2121

2222
std::optional<int>
2323
mb_shell::track_popup_menu(mb_shell::menu menu, int x, int y,
24-
std::function<void(menu_render &)> on_before_show) {
24+
std::function<void(menu_render &)> on_before_show, bool run_js) {
2525
auto thread_id_orig = GetCurrentThreadId();
2626
auto selected_menu_future = renderer_thread.add_task([&]() {
27-
perf_counter perf("mb_shell::track_popup_menu");
28-
auto menu_render = menu_render::create(x, y, menu);
29-
menu_render.rt->last_time = menu_render.rt->clock.now();
30-
perf.end("menu_render::create");
31-
32-
static HWND window = nullptr;
33-
window = (HWND)menu_render.rt->hwnd();
34-
// set keyboard hook to handle keyboard input
35-
auto hook = SetWindowsHookExW(
36-
WH_KEYBOARD,
37-
[](int nCode, WPARAM wParam, LPARAM lParam) -> LRESULT {
38-
if (nCode == HC_ACTION) {
39-
PostMessageW(window,
40-
lParam == WM_KEYDOWN ? WM_KEYDOWN : WM_KEYUP,
41-
wParam, lParam);
42-
return 1;
43-
}
44-
return CallNextHookEx(NULL, nCode, wParam, lParam);
45-
},
46-
NULL, thread_id_orig);
47-
48-
SetWindowLongPtrW(window, GWL_EXSTYLE,
49-
GetWindowLongPtrW(window, GWL_EXSTYLE) |
50-
WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW);
51-
if (on_before_show)
52-
on_before_show(menu_render);
53-
menu_render.rt->start_loop();
54-
UnhookWindowsHookEx(hook);
55-
56-
return menu_render.selected_menu;
27+
try {
28+
perf_counter perf("mb_shell::track_popup_menu");
29+
auto menu_render = menu_render::create(x, y, menu, run_js);
30+
menu_render.rt->last_time = menu_render.rt->clock.now();
31+
perf.end("menu_render::create");
32+
33+
static HWND window = nullptr;
34+
window = (HWND)menu_render.rt->hwnd();
35+
// set keyboard hook to handle keyboard input
36+
auto hook = SetWindowsHookExW(
37+
WH_KEYBOARD,
38+
[](int nCode, WPARAM wParam, LPARAM lParam) -> LRESULT {
39+
if (nCode == HC_ACTION) {
40+
PostMessageW(window,
41+
lParam == WM_KEYDOWN ? WM_KEYDOWN
42+
: WM_KEYUP,
43+
wParam, lParam);
44+
return 1;
45+
}
46+
return CallNextHookEx(NULL, nCode, wParam, lParam);
47+
},
48+
NULL, thread_id_orig);
49+
50+
SetWindowLongPtrW(window, GWL_EXSTYLE,
51+
GetWindowLongPtrW(window, GWL_EXSTYLE) |
52+
WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW);
53+
if (on_before_show)
54+
on_before_show(menu_render);
55+
menu_render.rt->start_loop();
56+
UnhookWindowsHookEx(hook);
57+
58+
return menu_render.selected_menu;
59+
} catch (std::exception &e) {
60+
std::cerr << "Exception in track_popup_menu: " << e.what()
61+
<< std::endl;
62+
return std::optional<int>{};
63+
}
5764
});
5865
qjs::wait_with_msgloop([&]() { selected_menu_future.wait(); });
5966

src/shell/contextmenu/menu_render.cc

Lines changed: 111 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -4,134 +4,140 @@
44
#include "Windows.h"
55
#include "menu_widget.h"
66

7+
#include "breeze_ui/ui.h"
78
#include "shell/entry.h"
89
#include "shell/logger.h"
910
#include "shell/script/binding_types.hpp"
10-
#include "breeze_ui/ui.h"
1111
#include <mutex>
1212
#include <thread>
1313

14+
1415
namespace mb_shell {
1516
std::optional<menu_render *> menu_render::current{};
16-
menu_render menu_render::create(int x, int y, menu menu) {
17-
if (auto res = ui::render_target::init_global(); !res) {
18-
MessageBoxW(NULL, L"Failed to initialize global render target", L"Error",
19-
MB_ICONERROR);
20-
return {nullptr, std::nullopt};
21-
}
22-
23-
static auto rt = []() {
24-
static window_proc_hook glfw_proc_hook;
25-
auto rt = std::make_shared<ui::render_target>();
26-
rt->transparent = true;
27-
rt->no_activate = true;
28-
rt->capture_all_input = true;
29-
rt->decorated = false;
30-
rt->topmost = true;
31-
rt->vsync = config::current->context_menu.vsync;
32-
33-
if (config::current->avoid_resize_ui) {
34-
rt->width = 3840;
35-
rt->height = 2159;
17+
menu_render menu_render::create(int x, int y, menu menu, bool run_js) {
18+
if (auto res = ui::render_target::init_global(); !res) {
19+
MessageBoxW(NULL, L"Failed to initialize global render target",
20+
L"Error", MB_ICONERROR);
21+
return {nullptr, std::nullopt};
3622
}
3723

38-
if (auto res = rt->init(); !res) {
39-
MessageBoxW(NULL, L"Failed to initialize render target", L"Error",
40-
MB_ICONERROR);
24+
static auto rt = []() {
25+
static window_proc_hook glfw_proc_hook;
26+
auto rt = std::make_shared<ui::render_target>();
27+
rt->transparent = true;
28+
rt->no_activate = true;
29+
rt->capture_all_input = true;
30+
rt->decorated = false;
31+
rt->topmost = true;
32+
rt->vsync = config::current->context_menu.vsync;
33+
34+
if (config::current->avoid_resize_ui) {
35+
rt->width = 3840;
36+
rt->height = 2159;
37+
}
38+
39+
if (auto res = rt->init(); !res) {
40+
MessageBoxW(NULL, L"Failed to initialize render target", L"Error",
41+
MB_ICONERROR);
42+
}
43+
44+
glfw_proc_hook.install(rt->hwnd());
45+
SetCapture((HWND)rt->hwnd());
46+
glfw_proc_hook.hooks.push_back([](void *hwnd, void *original_proc,
47+
size_t msg, size_t wparam,
48+
size_t lparam) -> std::optional<int> {
49+
if (msg == WM_MOUSEACTIVATE) {
50+
return MA_NOACTIVATE;
51+
}
52+
53+
return std::nullopt;
54+
});
55+
56+
config::current->apply_fonts_to_nvg(rt->nvg);
57+
return rt;
58+
}();
59+
auto render = menu_render(rt, std::nullopt);
60+
61+
rt->parent = menu.parent_window;
62+
63+
// get the monitor in which the menu is being shown
64+
auto monitor = MonitorFromPoint({x, y}, MONITOR_DEFAULTTONEAREST);
65+
MONITORINFOEX monitor_info;
66+
monitor_info.cbSize = sizeof(MONITORINFOEX);
67+
GetMonitorInfo(monitor, &monitor_info);
68+
69+
// set the position of the window to fullscreen in this monitor + padding
70+
71+
dbgout("Monitor: {} {} {} {}", monitor_info.rcMonitor.left,
72+
monitor_info.rcMonitor.top, monitor_info.rcMonitor.right,
73+
monitor_info.rcMonitor.bottom);
74+
75+
rt->set_position(monitor_info.rcMonitor.left + 1,
76+
monitor_info.rcMonitor.top + 1);
77+
if (!config::current->avoid_resize_ui)
78+
rt->resize(
79+
monitor_info.rcMonitor.right - monitor_info.rcMonitor.left - 2,
80+
monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top - 2);
81+
82+
glfwMakeContextCurrent(rt->window);
83+
glfwSwapInterval(config::current->context_menu.vsync ? 1 : 0);
84+
85+
rt->show();
86+
auto menu_wid = std::make_shared<mouse_menu_widget_main>(
87+
menu,
88+
// convert the x and y to the window coordinates
89+
x - monitor_info.rcMonitor.left, y - monitor_info.rcMonitor.top);
90+
rt->root->children.push_back(menu_wid);
91+
auto current_js_context =
92+
entry::main_window_loop_hook
93+
.add_task([&]() {
94+
return std::make_shared<js::js_menu_context>(
95+
js::js_menu_context::$from_window(menu.parent_window));
96+
})
97+
.get();
98+
99+
js::menu_info_basic_js menu_info{
100+
.menu = std::make_shared<js::menu_controller>(menu_wid->menu_wid),
101+
.context = current_js_context};
102+
103+
if (run_js) {
104+
dbgout("[perf] JS plugins start");
105+
auto before_js = rt->clock.now();
106+
for (auto &listener : menu_callbacks_js) {
107+
listener->operator()(menu_info);
108+
}
109+
dbgout("[perf] JS plugins costed {}ms",
110+
std::chrono::duration_cast<std::chrono::milliseconds>(
111+
rt->clock.now() - before_js)
112+
.count());
113+
} else {
114+
dbgout("Skipped running JS");
41115
}
42116

43-
glfw_proc_hook.install(rt->hwnd());
44-
SetCapture((HWND)rt->hwnd());
45-
glfw_proc_hook.hooks.push_back([](void *hwnd, void *original_proc,
46-
size_t msg, size_t wparam,
47-
size_t lparam) -> std::optional<int> {
48-
if (msg == WM_MOUSEACTIVATE) {
49-
return MA_NOACTIVATE;
50-
}
51-
52-
return std::nullopt;
53-
});
54-
55-
config::current->apply_fonts_to_nvg(rt->nvg);
56-
return rt;
57-
}();
58-
auto render = menu_render(rt, std::nullopt);
59-
60-
rt->parent = menu.parent_window;
61-
62-
// get the monitor in which the menu is being shown
63-
auto monitor = MonitorFromPoint({x, y}, MONITOR_DEFAULTTONEAREST);
64-
MONITORINFOEX monitor_info;
65-
monitor_info.cbSize = sizeof(MONITORINFOEX);
66-
GetMonitorInfo(monitor, &monitor_info);
67-
68-
// set the position of the window to fullscreen in this monitor + padding
69-
70-
dbgout("Monitor: {} {} {} {}", monitor_info.rcMonitor.left,
71-
monitor_info.rcMonitor.top, monitor_info.rcMonitor.right,
72-
monitor_info.rcMonitor.bottom);
73-
74-
rt->set_position(monitor_info.rcMonitor.left + 1,
75-
monitor_info.rcMonitor.top + 1);
76-
if (!config::current->avoid_resize_ui)
77-
rt->resize(monitor_info.rcMonitor.right - monitor_info.rcMonitor.left - 2,
78-
monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top - 2);
79-
80-
glfwMakeContextCurrent(rt->window);
81-
glfwSwapInterval(config::current->context_menu.vsync ? 1 : 0);
82-
83-
rt->show();
84-
auto menu_wid = std::make_shared<mouse_menu_widget_main>(
85-
menu,
86-
// convert the x and y to the window coordinates
87-
x - monitor_info.rcMonitor.left, y - monitor_info.rcMonitor.top);
88-
rt->root->children.push_back(menu_wid);
89-
auto current_js_context =
90-
entry::main_window_loop_hook
91-
.add_task([&]() {
92-
return std::make_shared<js::js_menu_context>(
93-
js::js_menu_context::$from_window(menu.parent_window));
94-
})
95-
.get();
96-
97-
js::menu_info_basic_js menu_info{
98-
.menu = std::make_shared<js::menu_controller>(menu_wid->menu_wid),
99-
.context = current_js_context};
100-
101-
dbgout("[perf] JS plugins start");
102-
auto before_js = rt->clock.now();
103-
for (auto &listener : menu_callbacks_js) {
104-
listener->operator()(menu_info);
105-
}
106-
dbgout("[perf] JS plugins costed {}ms",
107-
std::chrono::duration_cast<std::chrono::milliseconds>(rt->clock.now() -
108-
before_js)
109-
.count());
110-
111-
dbgout("Current menu: {}", menu_render::current.has_value());
112-
return render;
117+
dbgout("Current menu: {}", menu_render::current.has_value());
118+
return render;
113119
}
114120

115121
menu_render::menu_render(std::shared_ptr<ui::render_target> rt,
116122
std::optional<int> selected_menu)
117123
: rt(std::move(rt)), selected_menu(selected_menu) {
118-
current = this;
124+
current = this;
119125
}
120126
menu_render::~menu_render() {
121-
if (this->rt) {
122-
current = nullptr;
123-
}
127+
if (this->rt) {
128+
current = nullptr;
129+
}
124130
}
125131
menu_render::menu_render(menu_render &&t) {
126-
current = this;
132+
current = this;
127133

128-
rt = std::move(t.rt);
129-
selected_menu = std::move(t.selected_menu);
134+
rt = std::move(t.rt);
135+
selected_menu = std::move(t.selected_menu);
130136
}
131137
menu_render &menu_render::operator=(menu_render &&t) {
132-
current = this;
133-
rt = std::move(t.rt);
134-
selected_menu = std::move(t.selected_menu);
135-
return *this;
138+
current = this;
139+
rt = std::move(t.rt);
140+
selected_menu = std::move(t.selected_menu);
141+
return *this;
136142
}
137143
}; // namespace mb_shell
Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,26 @@
11
#pragma once
2-
#include "shell/utils.h"
3-
#include "contextmenu.h"
42
#include "breeze_ui/ui.h"
3+
#include "contextmenu.h"
4+
#include "shell/utils.h"
55
#include <memory>
66
#include <optional>
77

8+
89
namespace mb_shell {
910
struct menu_render {
10-
std::shared_ptr<ui::render_target> rt;
11-
std::optional<int32_t> selected_menu;
12-
bool light_color = is_light_mode();
13-
static std::optional<menu_render *> current;
11+
std::shared_ptr<ui::render_target> rt;
12+
std::optional<int32_t> selected_menu;
13+
bool light_color = is_light_mode();
14+
static std::optional<menu_render *> current;
1415

15-
menu_render() = delete;
16-
menu_render(std::shared_ptr<ui::render_target> rt,
17-
std::optional<int> selected_menu);
16+
menu_render() = delete;
17+
menu_render(std::shared_ptr<ui::render_target> rt,
18+
std::optional<int> selected_menu);
1819

19-
~menu_render();
20-
const menu_render &operator=(const menu_render &) = delete;
21-
menu_render(menu_render &&t);
22-
menu_render &operator=(menu_render &&t);
23-
static menu_render create(int x, int y, menu menu);
20+
~menu_render();
21+
const menu_render &operator=(const menu_render &) = delete;
22+
menu_render(menu_render &&t);
23+
menu_render &operator=(menu_render &&t);
24+
static menu_render create(int x, int y, menu menu, bool run_js = true);
2425
};
2526
} // namespace mb_shell

0 commit comments

Comments
 (0)