Skip to content

Commit 0b370e8

Browse files
fix(shell): improve menu construction performance
close #153
1 parent 028958c commit 0b370e8

5 files changed

Lines changed: 48 additions & 8 deletions

File tree

src/shell/contextmenu/contextmenu.cc

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
#include "../logger.h"
1515

16+
#include "../entry.h"
17+
1618
#include <consoleapi.h>
1719
#include <debugapi.h>
1820
#include <future>
@@ -34,8 +36,7 @@ owner_draw_menu_info getBitmapFromOwnerDraw(MENUITEMINFOW *menuItemInfo,
3436
measureItem.itemID = menuItemInfo->wID;
3537
measureItem.itemData = (ULONG_PTR)(menuItemInfo->dwItemData);
3638

37-
SendMessageW(hwnd, WM_MEASUREITEM, 0,
38-
reinterpret_cast<LPARAM>(&measureItem));
39+
SendMessageW(hwnd, WM_MEASUREITEM, 0, reinterpret_cast<LPARAM>(&measureItem));
3940

4041
result.width = measureItem.itemWidth;
4142
result.height = measureItem.itemHeight;
@@ -70,7 +71,7 @@ owner_draw_menu_info getBitmapFromOwnerDraw(MENUITEMINFOW *menuItemInfo,
7071
drawItem.itemData = (ULONG_PTR)(menuItemInfo->dwItemData);
7172

7273
SendMessageW(hwnd, WM_DRAWITEM, 0,
73-
reinterpret_cast<LPARAM>(&drawItem)); // 发送绘制消息
74+
reinterpret_cast<LPARAM>(&drawItem)); // 发送绘制消息
7475

7576
result.bitmap = CreateCompatibleBitmap(hdc, result.width, result.height);
7677
if (!result.bitmap) {
@@ -130,7 +131,8 @@ menu menu::construct_with_hmenu(HMENU hMenu, HWND hWnd, bool is_top) {
130131
continue;
131132
}
132133

133-
if ((info.fType & MFT_OWNERDRAW) && config::current->context_menu.experimental_ownerdraw_support) {
134+
if ((info.fType & MFT_OWNERDRAW) &&
135+
config::current->context_menu.experimental_ownerdraw_support) {
134136
auto od = getBitmapFromOwnerDraw(&info, hWnd);
135137
if (od.width && od.height) {
136138
item.owner_draw = od;
@@ -149,9 +151,17 @@ menu menu::construct_with_hmenu(HMENU hMenu, HWND hWnd, bool is_top) {
149151
if (info.hSubMenu) {
150152
PostMessageW(hWnd, WM_INITMENUPOPUP,
151153
reinterpret_cast<WPARAM>(info.hSubMenu), 0xFFFFFFFF);
152-
item.submenu =
153-
[data = menu::construct_with_hmenu(info.hSubMenu, hWnd, false)](
154-
std::shared_ptr<menu_widget> mw) { mw->init_from_data(data); };
154+
auto main_thread_id = GetCurrentThreadId();
155+
item.submenu = [=](std::shared_ptr<menu_widget> mw) {
156+
auto task = [&]() {
157+
mw->init_from_data(
158+
menu::construct_with_hmenu(info.hSubMenu, hWnd, false));
159+
};
160+
if (main_thread_id == GetCurrentThreadId())
161+
task();
162+
else
163+
entry::main_window_loop_hook.add_task(task).wait();
164+
};
155165
} else {
156166
item.action = [=]() mutable {
157167
menu_render::current.value()->selected_menu = info.wID;

src/shell/script/quickjspp.cc

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,24 @@
22

33
namespace qjs {
44
thread_local Context *Context::current;
5-
}
5+
void wait_with_msgloop(std::function<void()> f) {
6+
auto this_thread = GetCurrentThreadId();
7+
bool completed_flag = false;
8+
auto thread_wait = std::thread([=, &completed_flag]() {
9+
f();
10+
completed_flag = true;
11+
PostThreadMessageW(this_thread, WM_NULL, 0, 0);
12+
});
13+
14+
MSG msg;
15+
while (GetMessageW(&msg, nullptr, 0, 0)) {
16+
TranslateMessage(&msg);
17+
DispatchMessageW(&msg);
18+
19+
if (completed_flag) {
20+
break;
21+
}
22+
}
23+
thread_wait.join();
24+
}
25+
} // namespace qjs

src/shell/script/quickjspp.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ inline void setCurrentContext(JSContext *);
4545
inline JSContext *getContextFromWrapped(Context *);
4646
inline std::weak_ptr<Context> weakFromContext(JSContext *);
4747

48+
void wait_with_msgloop(std::function<void()> f);
4849
/** Exception type.
4950
* Indicates that exception has occured in JS context.
5051
*/
@@ -1853,6 +1854,7 @@ struct js_traits<std::function<R(Args...)>, int> {
18531854
auto &ctx = Context::get(jsfun_obj.ctx);
18541855
std::promise<std::expected<JSValue, exception>> promise;
18551856
auto future = promise.get_future();
1857+
18561858
auto work = [&]() {
18571859
const int argc = sizeof...(Args);
18581860
JSValue argv[std::max(1, argc)];
@@ -1874,6 +1876,7 @@ struct js_traits<std::function<R(Args...)>, int> {
18741876
work();
18751877
}
18761878

1879+
wait_with_msgloop([&future]() { future.wait(); });
18771880
auto result = future.get();
18781881
if (!result)
18791882
throw result.error();

src/shell/window_proc_hook.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,9 @@ window_proc_hook::~window_proc_hook() {
4646
uninstall();
4747
}
4848
}
49+
void window_proc_hook::send_null() {
50+
if (hwnd) {
51+
PostMessageW((HWND)hwnd, WM_NULL, 0, 0);
52+
}
53+
}
4954
} // namespace mb_shell

src/shell/window_proc_hook.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,13 @@ namespace mb_shell {
1515
std::vector<std::function<void(void*, void*, size_t, size_t, size_t)>> hooks;
1616
std::queue<std::function<void()>> tasks;
1717

18+
void send_null();
1819
auto add_task(auto&& f) -> std::future<std::invoke_result_t<decltype(f)>> {
1920
using return_type = std::invoke_result_t<decltype(f)>;
2021
auto task = std::make_shared<std::packaged_task<return_type()>>(std::forward<decltype(f)>(f));
2122
std::future<return_type> res = task->get_future();
2223
tasks.emplace([task]() { (*task)(); });
24+
send_null();
2325
return res;
2426
}
2527

0 commit comments

Comments
 (0)