2026-10-01 23:13:42 +08:00
|
|
|
|
/* launcher.c — 统一启动器 + 外部 ELF 加载 + PE 窗口运行时(M0 自 main.c 平移)
|
|
|
|
|
|
*/
|
|
|
|
|
|
#include "desktop.h"
|
|
|
|
|
|
|
|
|
|
|
|
/* ============================================================
|
|
|
|
|
|
* 外部 ELF 加载
|
|
|
|
|
|
* ============================================================ */
|
|
|
|
|
|
|
|
|
|
|
|
#define DT_ELFCLASS64 2
|
|
|
|
|
|
#define DT_EM_X86_64 62
|
|
|
|
|
|
#define DT_PT_LOAD 1
|
|
|
|
|
|
#define DT_PT_DYNAMIC 2
|
|
|
|
|
|
#define DT_DT_RELA 7
|
|
|
|
|
|
#define DT_DT_RELASZ 8
|
|
|
|
|
|
#define DT_R_X86_64_RELATIVE 8
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct { u8 ident[16]; u16 type,machine; u32 ver; u64 entry,phoff,shoff; u32 flags; u16 ehsize,phentsize,phnum,shentsize,shnum,shstrndx; } dt_elf64_ehdr;
|
|
|
|
|
|
typedef struct { u32 type,flags; u64 offset,vaddr,paddr,filesz,memsz,align; } dt_elf64_phdr;
|
|
|
|
|
|
typedef struct { i64 tag; u64 val; } dt_elf64_dyn;
|
|
|
|
|
|
typedef struct { u64 offset; u64 info; i64 addend; } dt_elf64_rela;
|
|
|
|
|
|
|
|
|
|
|
|
static u8 g_elf_image[1048576]; /* 1 MiB:settings.elf 内存映像 ~493KB(中文字体位图 BSS),256KB 不够 */
|
|
|
|
|
|
|
|
|
|
|
|
static int dt_load_elf(u8 *data, u32 data_size, void **entry_out) {
|
|
|
|
|
|
const dt_elf64_ehdr *eh = (const dt_elf64_ehdr *)data;
|
|
|
|
|
|
if (data_size < sizeof(dt_elf64_ehdr)) return -1;
|
|
|
|
|
|
if (eh->ident[0] != 0x7F || eh->ident[4] != DT_ELFCLASS64) return -2;
|
|
|
|
|
|
if (eh->machine != DT_EM_X86_64) return -3;
|
|
|
|
|
|
u64 min_vaddr = ~0ULL, max_vaddr = 0;
|
|
|
|
|
|
u32 lc = 0;
|
|
|
|
|
|
for (u16 i = 0; i < eh->phnum; i++) {
|
|
|
|
|
|
const dt_elf64_phdr *ph = (const dt_elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
|
|
|
|
|
if (ph->type != DT_PT_LOAD) continue;
|
|
|
|
|
|
if (ph->filesz > ph->memsz) return -4;
|
|
|
|
|
|
if (ph->vaddr < min_vaddr) min_vaddr = ph->vaddr;
|
|
|
|
|
|
if (ph->vaddr + ph->memsz > max_vaddr) max_vaddr = ph->vaddr + ph->memsz;
|
|
|
|
|
|
lc++;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!lc || min_vaddr == ~0ULL) return -5;
|
|
|
|
|
|
u64 isize = (max_vaddr - min_vaddr + 0xFFF) & ~0xFFFULL;
|
|
|
|
|
|
if (isize > sizeof(g_elf_image)) return -6;
|
|
|
|
|
|
u8 *image = g_elf_image;
|
|
|
|
|
|
for (u64 i = 0; i < isize; i++) image[i] = 0;
|
|
|
|
|
|
for (u16 i = 0; i < eh->phnum; i++) {
|
|
|
|
|
|
const dt_elf64_phdr *ph = (const dt_elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
|
|
|
|
|
if (ph->type != DT_PT_LOAD) continue;
|
|
|
|
|
|
u64 off = ph->vaddr - min_vaddr;
|
|
|
|
|
|
for (u64 j = 0; j < ph->filesz; j++)
|
|
|
|
|
|
image[off + j] = data[ph->offset + j];
|
|
|
|
|
|
}
|
|
|
|
|
|
for (u16 i = 0; i < eh->phnum; i++) {
|
|
|
|
|
|
const dt_elf64_phdr *ph = (const dt_elf64_phdr *)(data + eh->phoff + (u64)i * eh->phentsize);
|
|
|
|
|
|
if (ph->type != DT_PT_DYNAMIC) continue;
|
|
|
|
|
|
const dt_elf64_dyn *dyn = (const dt_elf64_dyn *)(data + ph->offset);
|
|
|
|
|
|
u64 rela_off = 0, rela_sz = 0;
|
|
|
|
|
|
for (u32 j = 0; j < ph->filesz / sizeof(dt_elf64_dyn); j++) {
|
|
|
|
|
|
if (dyn[j].tag == DT_DT_RELA) rela_off = dyn[j].val;
|
|
|
|
|
|
else if (dyn[j].tag == DT_DT_RELASZ) rela_sz = dyn[j].val;
|
|
|
|
|
|
else if (dyn[j].tag == 0) break;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (rela_off && rela_sz) {
|
|
|
|
|
|
const dt_elf64_rela *r = (const dt_elf64_rela *)(data + rela_off);
|
|
|
|
|
|
u32 rn = (u32)(rela_sz / sizeof(dt_elf64_rela));
|
|
|
|
|
|
u64 load_bias = (u64)image - min_vaddr; /* 与 DSK loader 一致 */
|
|
|
|
|
|
for (u32 j = 0; j < rn; j++) {
|
|
|
|
|
|
u32 type = (u32)(r[j].info & 0xFFFFFFFF);
|
|
|
|
|
|
if (type == DT_R_X86_64_RELATIVE) {
|
|
|
|
|
|
/* 原 BUG: val = min_vaddr + addend,指针被写成低地址绝对值,
|
|
|
|
|
|
* 导致 settings.elf 等模块内 .data 中的字符串指针全部失效 */
|
|
|
|
|
|
if (r[j].offset < min_vaddr || r[j].offset >= min_vaddr + isize) continue;
|
|
|
|
|
|
u64 target = r[j].offset - min_vaddr;
|
|
|
|
|
|
u64 val = load_bias + (u64)r[j].addend;
|
|
|
|
|
|
*(u64 *)(image + target) = val;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
*entry_out = (void *)(image + (eh->entry - min_vaddr));
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void launch_external_elf(const char *name11) {
|
|
|
|
|
|
u8 *data = 0; u32 size = 0;
|
|
|
|
|
|
if (f32_read_root_file_w(name11, &data, &size) != 0) {
|
|
|
|
|
|
slog("elf not found");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
void *entry = 0;
|
|
|
|
|
|
if (dt_load_elf(data, size, &entry) != 0) {
|
|
|
|
|
|
slog("elf load failed");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
slog("launching external elf");
|
|
|
|
|
|
void (*elf_entry)(const dsk_boot_context *) = (void (*)(const dsk_boot_context *))entry;
|
|
|
|
|
|
elf_entry(g_boot_ctx);
|
|
|
|
|
|
g_cursor_saved = 0;
|
|
|
|
|
|
g_cursor_old_x = -1; g_cursor_old_y = -1;
|
|
|
|
|
|
files_refresh(); /* 外部应用可能改动了磁盘 */
|
|
|
|
|
|
redraw_all();
|
|
|
|
|
|
slog("external elf returned");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ============================================================
|
|
|
|
|
|
* 应用启动(单实例聚焦策略)
|
|
|
|
|
|
* ============================================================ */
|
|
|
|
|
|
|
|
|
|
|
|
void fill_app_ctx(app_ctx *ctx, desktop_window *win) {
|
|
|
|
|
|
int tb = win_titlebar_h();
|
|
|
|
|
|
ctx->fb = &g_fb;
|
|
|
|
|
|
ctx->win = win;
|
|
|
|
|
|
ctx->client_x = win->x + BORDER_W;
|
|
|
|
|
|
ctx->client_y = win->y + tb;
|
|
|
|
|
|
ctx->client_w = win->w - 2 * BORDER_W;
|
|
|
|
|
|
ctx->client_h = win->h - tb - BORDER_W;
|
|
|
|
|
|
ctx->should_exit = 0;
|
|
|
|
|
|
ctx->block_read = g_block_read;
|
|
|
|
|
|
ctx->block_write = g_block_write;
|
|
|
|
|
|
ctx->kernel_api = g_kernel_api;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void launch_app(int app_id) {
|
|
|
|
|
|
if (app_id < 0 || app_id >= g_app_count) return;
|
|
|
|
|
|
app_descriptor *app = &g_apps[app_id];
|
|
|
|
|
|
|
|
|
|
|
|
/* VSCode Phase 5: Linux guest 应用走 exec_async 共享启动路径 */
|
|
|
|
|
|
if (app->linux_path) {
|
|
|
|
|
|
launch_linux_app(app_id);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* P5d: Windows PE 应用走 run_windowed 桌面嵌入路径 */
|
|
|
|
|
|
if (app->pe_file) {
|
|
|
|
|
|
launch_pe_app(app_id);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (app->elf_name) {
|
|
|
|
|
|
launch_external_elf(app->elf_name);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (!app->on_create) return;
|
|
|
|
|
|
|
|
|
|
|
|
/* 单实例:已有同类窗口则聚焦并迁移到当前工作区 */
|
|
|
|
|
|
for (int i = 0; i < g_win_count; i++) {
|
|
|
|
|
|
if (g_windows[i].app_id == app_id && g_windows[i].visible) {
|
|
|
|
|
|
g_windows[i].ws = g_ws_cur;
|
|
|
|
|
|
win_focus(&g_windows[i]);
|
|
|
|
|
|
slog("focus existing app window");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int top = KATE_TOPBAR_H, bot = (int)g_fb_h - KATE_TASKBAR_H;
|
|
|
|
|
|
int wx = ICON_PAD + g_win_count * 30;
|
|
|
|
|
|
int wy = top + 8 + g_win_count * 30;
|
|
|
|
|
|
if (wx + (int)app->default_w > (int)g_fb_w - 20) wx = ICON_PAD;
|
|
|
|
|
|
if (wy + (int)app->default_h > bot - 20) wy = top + 8;
|
|
|
|
|
|
|
|
|
|
|
|
desktop_window *win = win_create(app_id, app->display_name,
|
|
|
|
|
|
wx, wy, (int)app->default_w, (int)app->default_h);
|
|
|
|
|
|
if (!win) return;
|
|
|
|
|
|
|
|
|
|
|
|
app_ctx ctx;
|
|
|
|
|
|
fill_app_ctx(&ctx, win);
|
|
|
|
|
|
|
|
|
|
|
|
win->app_state = app->on_create(&ctx);
|
|
|
|
|
|
win->dirty = 1;
|
|
|
|
|
|
|
|
|
|
|
|
/* 直接显示窗口(去掉打开动画以避免卡顿和闪屏) */
|
|
|
|
|
|
|
|
|
|
|
|
slog("app launched");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ============================================================
|
|
|
|
|
|
* P5d: PE 窗口运行时(run_windowed 桌面嵌入)
|
|
|
|
|
|
*
|
|
|
|
|
|
* 协作模型(契约见 utsm/pe.h pe_window_host):
|
|
|
|
|
|
* launch_pe_app 创建受管窗口并把客户区大小的内存 surface 交给 shim,
|
|
|
|
|
|
* 随后阻塞在 pe_service.run_windowed。PE 消息空转(GetMessage/
|
|
|
|
|
|
* PeekMessage 无消息)时 shim 回调 pe_pump_cb,由它驱动 desktop 一帧:
|
|
|
|
|
|
* 采集 PS/2 输入(PE 窗口聚焦时经 inject_* 注入,否则走桌面正常路径)、
|
|
|
|
|
|
* redraw_all + flip。关闭 = inject WM_CLOSE(win_close_request),
|
|
|
|
|
|
* PE 自愿退出后 run_windowed 返回,launch_pe_app 收尾销毁窗口。
|
|
|
|
|
|
*
|
|
|
|
|
|
* 注意:pump 运行在 PE 的 1MB 大栈上,desktop 帧代码栈用量远小于此;
|
|
|
|
|
|
* pump 内禁止再次调用 run/run_windowed(launch_pe_app 以 g_pe_running 拒绝)。
|
|
|
|
|
|
* ============================================================ */
|
|
|
|
|
|
|
|
|
|
|
|
/* PE 运行时状态 */
|
|
|
|
|
|
int g_pe_running = 0;
|
|
|
|
|
|
int g_pe_win_id = -1;
|
|
|
|
|
|
u8 *g_pe_surf = 0;
|
|
|
|
|
|
int g_pe_surf_w = 0, g_pe_surf_h = 0;
|
|
|
|
|
|
static int g_pe_state_dummy = 0; /* draw_desktop_page 要求 app_state 非空 */
|
|
|
|
|
|
|
|
|
|
|
|
/* PE 窗口 on_draw:把 shim 渲染的 surface blit 到客户区(32bpp 行拷贝) */
|
|
|
|
|
|
void pe_win_on_draw(void *state, app_ctx *ctx) {
|
|
|
|
|
|
(void)state;
|
|
|
|
|
|
if (!g_pe_surf) return;
|
|
|
|
|
|
int w = (g_pe_surf_w < ctx->client_w) ? g_pe_surf_w : ctx->client_w;
|
|
|
|
|
|
int h = (g_pe_surf_h < ctx->client_h) ? g_pe_surf_h : ctx->client_h;
|
|
|
|
|
|
if (w <= 0 || h <= 0) return;
|
|
|
|
|
|
u8 *dst0 = (u8 *)g_fb.fb + (u64)ctx->client_y * g_fb_pitch
|
|
|
|
|
|
+ (u64)ctx->client_x * 4;
|
|
|
|
|
|
u32 sp = (u32)g_pe_surf_w * 4;
|
|
|
|
|
|
for (int r = 0; r < h; r++) {
|
|
|
|
|
|
u32 *d = (u32 *)(dst0 + (u64)r * g_fb_pitch);
|
|
|
|
|
|
const u32 *s = (const u32 *)(g_pe_surf + (u64)r * sp);
|
|
|
|
|
|
for (int c = 0; c < w; c++) d[c] = s[c] | 0xFF000000u;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* PE 消息空转让出点:驱动 desktop 一帧。返回 0 继续,非 0 请求 PE 退出。 */
|
|
|
|
|
|
static int pe_pump_cb(void *ud) {
|
|
|
|
|
|
int win_id = (int)(u64)ud;
|
|
|
|
|
|
int moved = 0;
|
|
|
|
|
|
while (ps2_mouse_poll()) moved = 1;
|
|
|
|
|
|
|
|
|
|
|
|
desktop_window *pw = win_find(win_id);
|
|
|
|
|
|
if (!pw) return 1; /* 窗口已销毁:请求 PE 退出 */
|
|
|
|
|
|
|
|
|
|
|
|
int pe_focused = (g_page == 3 && pw->focused && pw->ws == g_ws_cur &&
|
|
|
|
|
|
!g_taskview && !g_ctx_open);
|
|
|
|
|
|
|
|
|
|
|
|
/* 鼠标注入:PE 窗口聚焦且光标在客户区内 → surface 局部坐标 + 按钮位 */
|
|
|
|
|
|
int pe_tb = win_titlebar_h();
|
|
|
|
|
|
int cx0 = pw->x + BORDER_W, cy0 = pw->y + pe_tb;
|
|
|
|
|
|
int ccw = pw->w - 2 * BORDER_W, cch = pw->h - pe_tb - BORDER_W;
|
|
|
|
|
|
if (pe_focused && g_pe_svc->inject_pointer &&
|
|
|
|
|
|
g_mouse_x >= cx0 && g_mouse_x < cx0 + ccw &&
|
|
|
|
|
|
g_mouse_y >= cy0 && g_mouse_y < cy0 + cch) {
|
|
|
|
|
|
g_pe_svc->inject_pointer(g_mouse_x - cx0, g_mouse_y - cy0,
|
|
|
|
|
|
(u32)(g_mouse_btn & 3));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 点击/释放走桌面正常路径(聚焦、标题栏拖拽、关闭按钮→win_close_request、
|
|
|
|
|
|
* 其他窗口/图标)。双击其他 PE 图标会被 launch_pe_app 的 g_pe_running 拒绝。 */
|
|
|
|
|
|
if (g_left_pressed) { g_left_pressed = 0; on_left_press(); }
|
|
|
|
|
|
if (g_right_pressed) { g_right_pressed = 0; on_right_press(); }
|
|
|
|
|
|
if (g_left_released) {
|
|
|
|
|
|
g_left_released = 0;
|
|
|
|
|
|
if (g_dragging || g_drag_slider) {
|
|
|
|
|
|
g_dragging = 0; g_drag_win = -1; g_drag_slider = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pw = win_find(win_id); /* 点击可能重排窗口数组 */
|
|
|
|
|
|
if (!pw) return 1;
|
|
|
|
|
|
pe_focused = (g_page == 3 && pw->focused && pw->ws == g_ws_cur &&
|
|
|
|
|
|
!g_taskview && !g_ctx_open);
|
|
|
|
|
|
|
|
|
|
|
|
/* 窗口/滑块拖拽(与主循环相同的钳位) */
|
|
|
|
|
|
if (moved && g_dragging && g_drag_win == win_id) {
|
|
|
|
|
|
pw->x = g_mouse_x - g_drag_off_x;
|
|
|
|
|
|
pw->y = g_mouse_y - g_drag_off_y;
|
|
|
|
|
|
if (pw->y < KATE_TOPBAR_H) pw->y = KATE_TOPBAR_H;
|
|
|
|
|
|
if (pw->x < 0 - pw->w + 40) pw->x = 0 - pw->w + 40;
|
|
|
|
|
|
if (pw->x > (int)g_fb_w - 40) pw->x = (int)g_fb_w - 40;
|
|
|
|
|
|
if (pw->y > (int)g_fb_h - KATE_TASKBAR_H - 20)
|
|
|
|
|
|
pw->y = (int)g_fb_h - KATE_TASKBAR_H - 20;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (moved && g_drag_slider == 1) slider_set(g_vol_rect, &g_vol, g_mouse_x);
|
|
|
|
|
|
if (moved && g_drag_slider == 2) slider_set(g_bri_rect, &g_bright, g_mouse_x);
|
|
|
|
|
|
|
|
|
|
|
|
/* 键盘:PE 聚焦时注入(shim 内部合成 KEYUP/CHAR/修饰键),
|
|
|
|
|
|
* Ctrl+Tab 保留给宿主切页;否则走桌面正常路径。 */
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
|
u8 st = inb(0x64);
|
|
|
|
|
|
if (!(st & 1) || (st & 0x20)) break;
|
|
|
|
|
|
u8 sc = inb(0x60);
|
|
|
|
|
|
if (pe_focused && g_pe_svc->inject_scancode) {
|
|
|
|
|
|
if (sc == 0xE0) { g_e0 = 1; continue; }
|
|
|
|
|
|
/* 宿主侧同步跟踪修饰键(Ctrl+Tab 切页判定用) */
|
|
|
|
|
|
if (sc == 0x2A || sc == 0x36) g_shift = 1;
|
|
|
|
|
|
if (sc == 0xAA || sc == 0xB6) g_shift = 0;
|
|
|
|
|
|
if (sc == 0x1D) g_ctrl = 1;
|
|
|
|
|
|
if (sc == 0x9D) g_ctrl = 0;
|
|
|
|
|
|
if (g_ctrl && sc == 0x0F) {
|
|
|
|
|
|
/* 切页前补修饰键释放,防止 PE 侧卡键 */
|
|
|
|
|
|
g_pe_svc->inject_scancode(0x9D, 0);
|
|
|
|
|
|
g_pe_svc->inject_scancode(0xAA, 0);
|
|
|
|
|
|
g_pe_svc->inject_scancode(0xB8, 0);
|
|
|
|
|
|
g_e0 = 0;
|
|
|
|
|
|
handle_key(sc);
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
g_pe_svc->inject_scancode(sc, g_e0);
|
|
|
|
|
|
g_e0 = 0;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
handle_key(sc);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (g_quit) return 1; /* 任务栏 QUIT:请求 PE 退出 */
|
|
|
|
|
|
|
|
|
|
|
|
/* 驱动一帧(redraw_all 内含 PE surface blit 与光标绘制) */
|
|
|
|
|
|
redraw_all();
|
|
|
|
|
|
flip_buffer();
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 启动 PE 应用:读 exe → 建窗口 → run_windowed 阻塞运行 → 退出后销毁窗口 */
|
|
|
|
|
|
void launch_pe_app(int app_id) {
|
|
|
|
|
|
app_descriptor *app = &g_apps[app_id];
|
|
|
|
|
|
if (!g_pe_svc || !g_pe_svc->run_windowed) {
|
|
|
|
|
|
slog("pe: service unavailable");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (g_pe_running) {
|
|
|
|
|
|
slog("pe: another PE window is running");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
u8 *data = 0; u32 size = 0;
|
|
|
|
|
|
if (f32_read_path_lfn_w(app->pe_file, &data, &size) != 0) {
|
|
|
|
|
|
slog("pe: exe not found");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 窗口布局:与 launch_app 相同的级联策略 */
|
|
|
|
|
|
int top = KATE_TOPBAR_H, bot = (int)g_fb_h - KATE_TASKBAR_H;
|
|
|
|
|
|
int wx = ICON_PAD + g_win_count * 30;
|
|
|
|
|
|
int wy = top + 8 + g_win_count * 30;
|
|
|
|
|
|
if (wx + (int)app->default_w > (int)g_fb_w - 20) wx = ICON_PAD;
|
|
|
|
|
|
if (wy + (int)app->default_h > bot - 20) wy = top + 8;
|
|
|
|
|
|
|
|
|
|
|
|
desktop_window *win = win_create(app_id, app->display_name,
|
|
|
|
|
|
wx, wy, (int)app->default_w, (int)app->default_h);
|
|
|
|
|
|
if (!win) return;
|
|
|
|
|
|
int win_id = win->id;
|
|
|
|
|
|
|
|
|
|
|
|
int cw = (int)app->default_w - 2 * BORDER_W;
|
|
|
|
|
|
int ch = (int)app->default_h - KATE_TITLEBAR_H - BORDER_W;
|
|
|
|
|
|
if (cw <= 0 || ch <= 0 || (u64)cw * (u64)ch * 4 > PE_SURFACE_MAX) {
|
|
|
|
|
|
win_destroy(win);
|
|
|
|
|
|
slog("pe: client area too large for surface");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
g_pe_surf = (u8 *)PE_SURFACE_ADDR;
|
|
|
|
|
|
g_pe_surf_w = cw; g_pe_surf_h = ch;
|
|
|
|
|
|
/* 初始化为深色底:PE 窗口未覆盖区域不残留脏数据 */
|
|
|
|
|
|
{
|
|
|
|
|
|
u32 *p = (u32 *)g_pe_surf;
|
|
|
|
|
|
u64 n = (u64)cw * (u64)ch;
|
2026-10-04 15:53:04 +08:00
|
|
|
|
for (u64 i = 0; i < n; i++) p[i] = 0xFFF3F4F6u;
|
2026-10-01 23:13:42 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
win->app_state = &g_pe_state_dummy; /* draw_desktop_page 要求非空才调 on_draw */
|
|
|
|
|
|
g_pe_win_id = win_id;
|
|
|
|
|
|
g_pe_running = 1;
|
|
|
|
|
|
slog("pe: run_windowed");
|
|
|
|
|
|
|
|
|
|
|
|
/* cmdline:"file.exe args"(GetCommandLineA 返回值) */
|
|
|
|
|
|
static char cmdline[160];
|
|
|
|
|
|
kstrcpy(cmdline, app->pe_file, (int)sizeof(cmdline));
|
|
|
|
|
|
if (app->pe_args && app->pe_args[0]) {
|
|
|
|
|
|
kstrcat(cmdline, " ", (int)sizeof(cmdline));
|
|
|
|
|
|
kstrcat(cmdline, app->pe_args, (int)sizeof(cmdline));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
pe_window_host host;
|
|
|
|
|
|
host.pump = pe_pump_cb;
|
|
|
|
|
|
host.ud = (void *)(u64)win_id; /* 传 id:窗口数组重排不悬空 */
|
|
|
|
|
|
host.surface = g_pe_surf;
|
|
|
|
|
|
host.width = (u32)cw;
|
|
|
|
|
|
host.height = (u32)ch;
|
|
|
|
|
|
host.pitch = (u32)cw * 4;
|
|
|
|
|
|
|
|
|
|
|
|
u64 exit_code = 0;
|
|
|
|
|
|
g_pe_svc->run_windowed(data, size, cmdline, &exit_code, &host);
|
|
|
|
|
|
|
|
|
|
|
|
g_pe_running = 0;
|
|
|
|
|
|
g_pe_win_id = -1;
|
|
|
|
|
|
g_pe_surf = 0;
|
|
|
|
|
|
|
|
|
|
|
|
/* PE 已退出:销毁宿主窗口并全屏重绘 */
|
|
|
|
|
|
desktop_window *w2 = win_find(win_id);
|
|
|
|
|
|
if (w2) win_destroy(w2);
|
|
|
|
|
|
files_refresh(); /* PE 可能改动了磁盘 */
|
|
|
|
|
|
g_full_redraw = 1;
|
|
|
|
|
|
redraw_all();
|
|
|
|
|
|
flip_buffer();
|
|
|
|
|
|
slog("pe: exited");
|
|
|
|
|
|
}
|