Skip to content

Commit 8e7d07e

Browse files
refactor(shell): run renderer in a different thread
close #217 close #155
1 parent ea3e89a commit 8e7d07e

File tree

4 files changed

+40
-12
lines changed

4 files changed

+40
-12
lines changed

src/shell/contextmenu/hooks.cc

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,20 @@
22
#include "../config.h"
33
#include "contextmenu.h"
44
#include "menu_render.h"
5+
#include "../script/quickjspp.hpp"
6+
#include "../entry.h"
57

68
#include "blook/blook.h"
79
#include <atlcomcli.h>
810
#include <shobjidl_core.h>
11+
#include <thread>
912

1013
#define NOMINMAX
1114
#define WIN32_LEAN_AND_MEAN
1215
#include "Windows.h"
1316
#include "shlobj_core.h"
1417

18+
1519
std::atomic_bool mb_shell::context_menu_hooks::has_active_menu = false;
1620

1721
void mb_shell::context_menu_hooks::install_common_hook() {
@@ -22,6 +26,8 @@ void mb_shell::context_menu_hooks::install_common_hook() {
2226
auto NtUserTrackPopupMenu = win32u.value()->exports("NtUserTrackPopupMenuEx");
2327
static auto NtUserTrackHook = NtUserTrackPopupMenu->inline_hook();
2428

29+
static auto renderer = task_queue{};
30+
2531
NtUserTrackHook->install(+[](HMENU hMenu, int64_t uFlags, int64_t x,
2632
int64_t y, HWND hWnd, int64_t lptpm) {
2733
if (GetPropW(hWnd, L"COwnerDrawPopupMenu_This") &&
@@ -30,24 +36,38 @@ void mb_shell::context_menu_hooks::install_common_hook() {
3036
hWnd, lptpm);
3137
}
3238

39+
entry::main_window_loop_hook.install(hWnd);
3340
has_active_menu = true;
3441

3542
perf_counter perf("TrackPopupMenuEx");
3643
menu menu = menu::construct_with_hmenu(hMenu, hWnd);
3744
perf.end("construct_with_hmenu");
38-
auto menu_render = menu_render::create(x, y, menu);
39-
menu_render.rt->last_time = menu_render.rt->clock.now();
40-
perf.end("menu_render::create");
41-
menu_render.rt->start_loop();
45+
46+
auto selected_menu_future = renderer
47+
.add_task([&]() {
48+
auto menu_render = menu_render::create(x, y, menu);
49+
menu_render.rt->last_time = menu_render.rt->clock.now();
50+
51+
perf.end("menu_render::create");
52+
menu_render.rt->start_loop();
53+
54+
return menu_render.selected_menu;
55+
});
56+
57+
qjs::wait_with_msgloop([&]() {
58+
selected_menu_future.wait();
59+
});
60+
61+
auto selected_menu = selected_menu_future.get();
4262

4363
has_active_menu = false;
4464

45-
if (menu_render.selected_menu && !(uFlags & TPM_NONOTIFY)) {
46-
PostMessageW(hWnd, WM_COMMAND, *menu_render.selected_menu, 0);
65+
if (selected_menu && !(uFlags & TPM_NONOTIFY)) {
66+
PostMessageW(hWnd, WM_COMMAND, *selected_menu, 0);
4767
PostMessageW(hWnd, WM_NULL, 0, 0);
4868
}
4969

50-
return (int32_t)menu_render.selected_menu.value_or(0);
70+
return (int32_t)selected_menu.value_or(0);
5171
});
5272
}
5373

@@ -115,7 +135,7 @@ void mb_shell::context_menu_hooks::install_SHCreateDefaultContextMenu_hook() {
115135
int pcmType = 0;
116136
UpgradeContextMenu(pdcm, reinterpret_cast<void **>(&pcm2), &pcmType);
117137

118-
IContextMenu* pCM(pcm2);
138+
IContextMenu *pCM(pcm2);
119139

120140
HMENU hmenu = CreatePopupMenu();
121141
pCM->QueryContextMenu(hmenu, 0, 1, 0x7FFF, CMF_EXPLORE | CMF_CANRENAME);

src/shell/contextmenu/menu_render.cc

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
#include "Windows.h"
33
#include "menu_widget.h"
44

5+
#include "../entry.h"
6+
#include "../logger.h"
57
#include "../script/binding_types.hpp"
68
#include "ui.h"
79
#include <mutex>
810
#include <thread>
911

10-
#include "../logger.h"
11-
1212
namespace mb_shell {
1313
std::optional<menu_render *> menu_render::current{};
1414
menu_render menu_render::create(int x, int y, menu menu) {
@@ -49,8 +49,6 @@ menu_render menu_render::create(int x, int y, menu menu) {
4949
return rt;
5050
}();
5151
auto render = menu_render(rt, std::nullopt);
52-
auto current_js_context = std::make_shared<js::js_menu_context>(
53-
js::js_menu_context::$from_window(menu.parent_window));
5452

5553
rt->parent = menu.parent_window;
5654

@@ -81,6 +79,14 @@ menu_render menu_render::create(int x, int y, menu menu) {
8179
// convert the x and y to the window coordinates
8280
x - monitor_info.rcMonitor.left, y - monitor_info.rcMonitor.top);
8381
rt->root->children.push_back(menu_wid);
82+
auto current_js_context =
83+
entry::main_window_loop_hook
84+
.add_task([&]() {
85+
return std::make_shared<js::js_menu_context>(
86+
js::js_menu_context::$from_window(menu.parent_window));
87+
})
88+
.get();
89+
8490
js::menu_info_basic_js menu_info{
8591
.menu = std::make_shared<js::menu_controller>(menu_wid->menu_wid),
8692
.context = current_js_context};

src/shell/contextmenu/menu_render.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "../utils.h"
33
#include "contextmenu.h"
44
#include "ui.h"
5+
#include <memory>
56
#include <optional>
67

78
namespace mb_shell {

src/shell/window_proc_hook.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace mb_shell {
1717

1818
void send_null();
1919
auto add_task(auto&& f) -> std::future<std::invoke_result_t<decltype(f)>> {
20+
if (!installed) throw std::runtime_error("Hook not installed");
2021
using return_type = std::invoke_result_t<decltype(f)>;
2122
auto task = std::make_shared<std::packaged_task<return_type()>>(std::forward<decltype(f)>(f));
2223
std::future<return_type> res = task->get_future();

0 commit comments

Comments
 (0)