This commit is contained in:
2026-04-25 20:03:34 +08:00
parent 05919064bb
commit 8138726c04
11 changed files with 889 additions and 704 deletions

72
cleonos/c/apps/uwm/uwm.h Normal file
View File

@@ -0,0 +1,72 @@
#ifndef CLEONOS_UWM_H
#define CLEONOS_UWM_H
#include "../cmd_runtime.h"
#define USH_UWM_WINDOW_COUNT 3U
#define USH_UWM_TTY_DISPLAY 1ULL
#define USH_UWM_TITLE_DRAG_HEIGHT 18
#define USH_UWM_MOVE_STEP 12
#define USH_UWM_EVENT_BUDGET 128ULL
#define USH_UWM_STARTUP_KEY_DRAIN_MAX 256ULL
#define USH_UWM_MIN_WINDOW_W 180
#define USH_UWM_MIN_WINDOW_H 120
#define USH_UWM_TOP_CLAMP_Y 24
#define USH_UWM_KEY_LEFT 1ULL
#define USH_UWM_KEY_RIGHT 2ULL
#define USH_UWM_KEY_UP 3ULL
#define USH_UWM_KEY_DOWN 4ULL
typedef unsigned int ush_uwm_u32;
typedef struct ush_uwm_window {
u64 id;
int x;
int y;
int w;
int h;
ush_uwm_u32 color;
ush_uwm_u32 *pixels;
u64 pixel_count;
int alive;
} ush_uwm_window;
typedef struct ush_uwm_session {
int screen_w;
int screen_h;
int active_window;
int dragging;
int drag_window;
int drag_offset_x;
int drag_offset_y;
u64 tty_before;
int tty_switched;
ush_uwm_window windows[USH_UWM_WINDOW_COUNT];
} ush_uwm_session;
int ush_uwm_window_index_valid(int index);
int ush_uwm_clampi(int value, int min_value, int max_value);
int ush_uwm_u64_as_i32(u64 raw);
void ush_uwm_drain_startup_keys(void);
void ush_uwm_render_content(ush_uwm_window *win);
int ush_uwm_alloc_pixels(ush_uwm_window *win);
int ush_uwm_create_window(ush_uwm_window *win);
int ush_uwm_present_window(const ush_uwm_window *win);
void ush_uwm_destroy_window(ush_uwm_window *win);
int ush_uwm_window_move_clamped(ush_uwm_session *sess, int index, int target_x, int target_y);
void ush_uwm_set_active(ush_uwm_session *sess, int index);
void ush_uwm_focus_next(ush_uwm_session *sess);
void ush_uwm_handle_event(ush_uwm_session *sess, int window_index, const cleonos_wm_event *event, int *running);
int ush_uwm_loop(ush_uwm_session *sess);
int ush_uwm_prepare_session(ush_uwm_session *sess);
int ush_uwm_start(ush_uwm_session *sess);
void ush_uwm_stop(ush_uwm_session *sess);
int ush_uwm_switch_to_display_tty(ush_uwm_session *sess);
void ush_uwm_restore_tty(ush_uwm_session *sess);
int ush_cmd_uwm(const char *arg);
#endif

View File

@@ -0,0 +1,213 @@
#include "uwm.h"
static void ush_uwm_usage(void) {
ush_writeln("usage: uwm");
ush_writeln("wm mode: kernel compositor + user window manager");
ush_writeln("keys: q quit, tab focus next, 1/2/3 focus, wasd/arrow move");
ush_writeln("mouse: drag focused window by title bar");
}
static int ush_uwm_parse_args(const char *arg) {
char first[USH_PATH_MAX];
const char *rest = "";
if (arg == (const char *)0 || arg[0] == '\0') {
return 1;
}
if (ush_split_first_and_rest(arg, first, (u64)sizeof(first), &rest) == 0) {
return 0;
}
if (rest != (const char *)0 && rest[0] != '\0') {
return 0;
}
if (ush_streq(first, "--help") != 0 || ush_streq(first, "-h") != 0) {
return 2;
}
return 0;
}
int ush_uwm_prepare_session(ush_uwm_session *sess) {
cleonos_fb_info fb;
int i;
int base_w;
int base_h;
const int x_offsets[USH_UWM_WINDOW_COUNT] = {64, 220, 380};
const int y_offsets[USH_UWM_WINDOW_COUNT] = {80, 140, 220};
const ush_uwm_u32 colors[USH_UWM_WINDOW_COUNT] = {0x002B3C66UL, 0x00385C7AUL, 0x004A7288UL};
if (sess == (ush_uwm_session *)0) {
return 0;
}
ush_zero(sess, (u64)sizeof(*sess));
if (cleonos_sys_fb_info(&fb) == 0ULL || fb.width == 0ULL || fb.height == 0ULL || fb.bpp != 32ULL) {
return 0;
}
if (fb.width > 4096ULL || fb.height > 4096ULL) {
return 0;
}
sess->screen_w = (int)fb.width;
sess->screen_h = (int)fb.height;
sess->active_window = 0;
sess->dragging = 0;
sess->drag_window = -1;
sess->drag_offset_x = 0;
sess->drag_offset_y = 0;
sess->tty_before = cleonos_sys_tty_active();
sess->tty_switched = 0;
base_w = sess->screen_w / 3;
base_h = sess->screen_h / 3;
if (base_w < USH_UWM_MIN_WINDOW_W) {
base_w = USH_UWM_MIN_WINDOW_W;
}
if (base_h < USH_UWM_MIN_WINDOW_H) {
base_h = USH_UWM_MIN_WINDOW_H;
}
if (base_w > sess->screen_w - 40) {
base_w = sess->screen_w - 40;
}
if (base_h > sess->screen_h - 40) {
base_h = sess->screen_h - 40;
}
for (i = 0; i < (int)USH_UWM_WINDOW_COUNT; i++) {
ush_uwm_window *win = &sess->windows[i];
int max_x = sess->screen_w - base_w;
int max_y = sess->screen_h - base_h;
if (max_x < 0) {
max_x = 0;
}
if (max_y < 0) {
max_y = 0;
}
win->id = 0ULL;
win->x = ush_uwm_clampi(x_offsets[i], 0, max_x);
win->y = ush_uwm_clampi(y_offsets[i], USH_UWM_TOP_CLAMP_Y, max_y);
win->w = base_w;
win->h = base_h;
win->color = colors[i];
win->pixels = (ush_uwm_u32 *)0;
win->pixel_count = 0ULL;
win->alive = 0;
}
return 1;
}
int ush_uwm_start(ush_uwm_session *sess) {
int i;
if (sess == (ush_uwm_session *)0) {
return 0;
}
for (i = 0; i < (int)USH_UWM_WINDOW_COUNT; i++) {
ush_uwm_window *win = &sess->windows[i];
if (ush_uwm_alloc_pixels(win) == 0) {
return 0;
}
if (ush_uwm_create_window(win) == 0) {
return 0;
}
ush_uwm_render_content(win);
if (ush_uwm_present_window(win) == 0) {
return 0;
}
}
sess->active_window = (int)USH_UWM_WINDOW_COUNT - 1;
ush_uwm_set_active(sess, sess->active_window);
return 1;
}
void ush_uwm_stop(ush_uwm_session *sess) {
int i;
if (sess == (ush_uwm_session *)0) {
return;
}
for (i = 0; i < (int)USH_UWM_WINDOW_COUNT; i++) {
ush_uwm_destroy_window(&sess->windows[i]);
}
}
int ush_uwm_switch_to_display_tty(ush_uwm_session *sess) {
if (sess == (ush_uwm_session *)0) {
return 0;
}
if (sess->tty_before != USH_UWM_TTY_DISPLAY) {
(void)cleonos_sys_tty_switch(USH_UWM_TTY_DISPLAY);
sess->tty_switched = 1;
}
return 1;
}
void ush_uwm_restore_tty(ush_uwm_session *sess) {
if (sess == (ush_uwm_session *)0) {
return;
}
if (sess->tty_switched != 0) {
(void)cleonos_sys_tty_switch(sess->tty_before);
sess->tty_switched = 0;
}
}
int ush_cmd_uwm(const char *arg) {
ush_uwm_session sess;
int parse_result;
int success = 0;
parse_result = ush_uwm_parse_args(arg);
if (parse_result == 2) {
ush_uwm_usage();
return 1;
}
if (parse_result == 0) {
ush_uwm_usage();
return 0;
}
if (ush_uwm_prepare_session(&sess) == 0) {
ush_writeln("uwm: framebuffer unavailable");
return 0;
}
ush_uwm_drain_startup_keys();
(void)ush_uwm_switch_to_display_tty(&sess);
if (ush_uwm_start(&sess) == 0) {
ush_uwm_stop(&sess);
ush_uwm_restore_tty(&sess);
ush_writeln("uwm: kernel wm unavailable or init failed");
return 0;
}
ush_writeln("uwm: kernel window framework online");
ush_writeln("uwm: q quit | tab focus | 1/2/3 focus | wasd/arrow move");
if (ush_uwm_loop(&sess) != 0) {
success = 1;
}
ush_uwm_stop(&sess);
ush_uwm_restore_tty(&sess);
ush_writeln("uwm: exit");
return success;
}

View File

@@ -0,0 +1,184 @@
#include "uwm.h"
static void ush_uwm_handle_key_event(ush_uwm_session *sess, u64 key, int *running) {
int idx = 0;
int dx = 0;
int dy = 0;
if (sess == (ush_uwm_session *)0 || running == (int *)0) {
return;
}
if (key == (u64)'q' || key == (u64)'Q') {
*running = 0;
return;
}
if (key == (u64)'\t') {
ush_uwm_focus_next(sess);
return;
}
if (key >= (u64)'1' && key <= (u64)'3') {
int candidate = (int)(key - (u64)'1');
if (ush_uwm_window_index_valid(candidate) != 0) {
ush_uwm_set_active(sess, candidate);
}
return;
}
idx = sess->active_window;
if (ush_uwm_window_index_valid(idx) == 0 || sess->windows[idx].alive == 0) {
return;
}
if (key == (u64)'a' || key == (u64)'A' || key == USH_UWM_KEY_LEFT) {
dx = -USH_UWM_MOVE_STEP;
} else if (key == (u64)'d' || key == (u64)'D' || key == USH_UWM_KEY_RIGHT) {
dx = USH_UWM_MOVE_STEP;
} else if (key == (u64)'w' || key == (u64)'W' || key == USH_UWM_KEY_UP) {
dy = -USH_UWM_MOVE_STEP;
} else if (key == (u64)'s' || key == (u64)'S' || key == USH_UWM_KEY_DOWN) {
dy = USH_UWM_MOVE_STEP;
}
if (dx != 0 || dy != 0) {
(void)ush_uwm_window_move_clamped(sess, idx, sess->windows[idx].x + dx, sess->windows[idx].y + dy);
}
}
static void ush_uwm_handle_mouse_button(ush_uwm_session *sess, int window_index, const cleonos_wm_event *event) {
u64 buttons;
u64 changed;
int local_x;
int local_y;
int left_changed;
int left_down;
if (sess == (ush_uwm_session *)0 || event == (const cleonos_wm_event *)0 ||
ush_uwm_window_index_valid(window_index) == 0) {
return;
}
buttons = event->arg0;
changed = event->arg1;
local_x = ush_uwm_u64_as_i32(event->arg2);
local_y = ush_uwm_u64_as_i32(event->arg3);
left_changed = ((changed & 0x1ULL) != 0ULL) ? 1 : 0;
left_down = ((buttons & 0x1ULL) != 0ULL) ? 1 : 0;
if (left_changed == 0) {
return;
}
if (left_down != 0) {
if (local_y >= 0 && local_y < USH_UWM_TITLE_DRAG_HEIGHT) {
sess->dragging = 1;
sess->drag_window = window_index;
sess->drag_offset_x = local_x;
sess->drag_offset_y = local_y;
sess->active_window = window_index;
}
} else if (sess->dragging != 0 && sess->drag_window == window_index) {
sess->dragging = 0;
}
}
static void ush_uwm_handle_mouse_move(ush_uwm_session *sess, int window_index, const cleonos_wm_event *event) {
int global_x;
int global_y;
int new_x;
int new_y;
if (sess == (ush_uwm_session *)0 || event == (const cleonos_wm_event *)0 ||
ush_uwm_window_index_valid(window_index) == 0) {
return;
}
if (sess->dragging == 0 || sess->drag_window != window_index) {
return;
}
global_x = ush_uwm_u64_as_i32(event->arg0);
global_y = ush_uwm_u64_as_i32(event->arg1);
new_x = global_x - sess->drag_offset_x;
new_y = global_y - sess->drag_offset_y;
(void)ush_uwm_window_move_clamped(sess, window_index, new_x, new_y);
}
void ush_uwm_handle_event(ush_uwm_session *sess, int window_index, const cleonos_wm_event *event, int *running) {
if (sess == (ush_uwm_session *)0 || event == (const cleonos_wm_event *)0 || running == (int *)0 ||
ush_uwm_window_index_valid(window_index) == 0) {
return;
}
switch (event->type) {
case CLEONOS_WM_EVENT_FOCUS_GAINED:
sess->active_window = window_index;
break;
case CLEONOS_WM_EVENT_FOCUS_LOST:
if (sess->drag_window == window_index) {
sess->dragging = 0;
}
break;
case CLEONOS_WM_EVENT_KEY:
ush_uwm_handle_key_event(sess, event->arg0, running);
break;
case CLEONOS_WM_EVENT_MOUSE_MOVE:
ush_uwm_handle_mouse_move(sess, window_index, event);
break;
case CLEONOS_WM_EVENT_MOUSE_BUTTON:
ush_uwm_handle_mouse_button(sess, window_index, event);
break;
default:
break;
}
}
int ush_uwm_loop(ush_uwm_session *sess) {
int running = 1;
if (sess == (ush_uwm_session *)0) {
return 0;
}
while (running != 0) {
int i;
for (i = 0; i < (int)USH_UWM_WINDOW_COUNT; i++) {
ush_uwm_window *win = &sess->windows[i];
u64 budget = 0ULL;
if (win->alive == 0 || win->id == 0ULL) {
continue;
}
while (budget < USH_UWM_EVENT_BUDGET) {
cleonos_wm_event event;
ush_zero(&event, (u64)sizeof(event));
if (cleonos_sys_wm_poll_event(win->id, &event) == 0ULL) {
break;
}
ush_uwm_handle_event(sess, i, &event, &running);
if (running == 0) {
break;
}
budget++;
}
if (running == 0) {
break;
}
}
if (running == 0) {
break;
}
(void)cleonos_sys_yield();
}
return 1;
}

View File

@@ -0,0 +1,42 @@
#include "uwm.h"
int ush_uwm_window_index_valid(int index) {
return (index >= 0 && index < (int)USH_UWM_WINDOW_COUNT) ? 1 : 0;
}
int ush_uwm_clampi(int value, int min_value, int max_value) {
if (value < min_value) {
return min_value;
}
if (value > max_value) {
return max_value;
}
return value;
}
int ush_uwm_u64_as_i32(u64 raw) {
i64 value = (i64)raw;
if (value < (-2147483647LL - 1LL)) {
return -2147483647 - 1;
}
if (value > 2147483647LL) {
return 2147483647;
}
return (int)value;
}
void ush_uwm_drain_startup_keys(void) {
u64 drained = 0ULL;
while (drained < USH_UWM_STARTUP_KEY_DRAIN_MAX) {
if (cleonos_sys_kbd_get_char() == (u64)-1) {
break;
}
drained++;
}
}

View File

@@ -0,0 +1,227 @@
#include "uwm.h"
static void ush_uwm_fill_rect(ush_uwm_window *win, int x, int y, int w, int h, ush_uwm_u32 color) {
int left;
int top;
int right;
int bottom;
int row;
if (win == (ush_uwm_window *)0 || win->pixels == (ush_uwm_u32 *)0 || win->w <= 0 || win->h <= 0 || w <= 0 ||
h <= 0) {
return;
}
left = x;
top = y;
right = x + w;
bottom = y + h;
if (left < 0) {
left = 0;
}
if (top < 0) {
top = 0;
}
if (right > win->w) {
right = win->w;
}
if (bottom > win->h) {
bottom = win->h;
}
if (left >= right || top >= bottom) {
return;
}
for (row = top; row < bottom; row++) {
u64 base = (u64)(unsigned int)row * (u64)(unsigned int)win->w;
int col;
for (col = left; col < right; col++) {
u64 idx = base + (u64)(unsigned int)col;
if (idx >= win->pixel_count) {
return;
}
win->pixels[idx] = color;
}
}
}
void ush_uwm_render_content(ush_uwm_window *win) {
int y;
if (win == (ush_uwm_window *)0 || win->pixels == (ush_uwm_u32 *)0) {
return;
}
ush_uwm_fill_rect(win, 0, 0, win->w, win->h, win->color);
ush_uwm_fill_rect(win, 0, 0, win->w, 18, 0x001A1F2BUL);
ush_uwm_fill_rect(win, 8, 5, 8, 8, 0x00FFD166UL);
ush_uwm_fill_rect(win, win->w - 18, 5, 10, 8, 0x00E76F51UL);
for (y = 30; y < win->h; y += 22) {
ush_uwm_fill_rect(win, 10, y, win->w - 20, 1, 0x003F4D62UL);
}
}
int ush_uwm_alloc_pixels(ush_uwm_window *win) {
u64 count;
u64 bytes;
if (win == (ush_uwm_window *)0 || win->w <= 0 || win->h <= 0) {
return 0;
}
count = (u64)(unsigned int)win->w * (u64)(unsigned int)win->h;
if (count == 0ULL || count > (((u64)-1) / 4ULL)) {
return 0;
}
bytes = count * 4ULL;
win->pixels = (ush_uwm_u32 *)malloc((size_t)bytes);
if (win->pixels == (ush_uwm_u32 *)0) {
return 0;
}
win->pixel_count = count;
ush_zero(win->pixels, bytes);
return 1;
}
int ush_uwm_create_window(ush_uwm_window *win) {
cleonos_wm_create_req req;
if (win == (ush_uwm_window *)0) {
return 0;
}
req.x = (u64)(i64)win->x;
req.y = (u64)(i64)win->y;
req.width = (u64)(unsigned int)win->w;
req.height = (u64)(unsigned int)win->h;
req.flags = 0ULL;
win->id = cleonos_sys_wm_create(&req);
if (win->id == 0ULL) {
return 0;
}
win->alive = 1;
return 1;
}
int ush_uwm_present_window(const ush_uwm_window *win) {
cleonos_wm_present_req req;
if (win == (const ush_uwm_window *)0 || win->alive == 0 || win->id == 0ULL ||
win->pixels == (ush_uwm_u32 *)0) {
return 0;
}
req.window_id = win->id;
req.pixels_ptr = (u64)(usize)win->pixels;
req.src_width = (u64)(unsigned int)win->w;
req.src_height = (u64)(unsigned int)win->h;
req.src_pitch_bytes = (u64)(unsigned int)win->w * 4ULL;
return (cleonos_sys_wm_present(&req) != 0ULL) ? 1 : 0;
}
void ush_uwm_destroy_window(ush_uwm_window *win) {
if (win == (ush_uwm_window *)0) {
return;
}
if (win->id != 0ULL) {
(void)cleonos_sys_wm_destroy(win->id);
}
if (win->pixels != (ush_uwm_u32 *)0) {
free(win->pixels);
}
win->id = 0ULL;
win->pixels = (ush_uwm_u32 *)0;
win->pixel_count = 0ULL;
win->alive = 0;
}
int ush_uwm_window_move_clamped(ush_uwm_session *sess, int index, int target_x, int target_y) {
ush_uwm_window *win;
cleonos_wm_move_req req;
int max_x;
int max_y;
int new_x;
int new_y;
if (sess == (ush_uwm_session *)0 || ush_uwm_window_index_valid(index) == 0) {
return 0;
}
win = &sess->windows[index];
if (win->alive == 0 || win->id == 0ULL) {
return 0;
}
max_x = sess->screen_w - win->w;
max_y = sess->screen_h - win->h;
if (max_x < 0) {
max_x = 0;
}
if (max_y < 0) {
max_y = 0;
}
new_x = ush_uwm_clampi(target_x, 0, max_x);
new_y = ush_uwm_clampi(target_y, USH_UWM_TOP_CLAMP_Y, max_y);
req.window_id = win->id;
req.x = (u64)(i64)new_x;
req.y = (u64)(i64)new_y;
if (cleonos_sys_wm_move(&req) == 0ULL) {
return 0;
}
win->x = new_x;
win->y = new_y;
return 1;
}
void ush_uwm_set_active(ush_uwm_session *sess, int index) {
ush_uwm_window *win;
if (sess == (ush_uwm_session *)0 || ush_uwm_window_index_valid(index) == 0) {
return;
}
win = &sess->windows[index];
if (win->alive == 0 || win->id == 0ULL) {
return;
}
if (cleonos_sys_wm_set_focus(win->id) != 0ULL) {
sess->active_window = index;
}
}
void ush_uwm_focus_next(ush_uwm_session *sess) {
int start;
int i;
if (sess == (ush_uwm_session *)0) {
return;
}
if (ush_uwm_window_index_valid(sess->active_window) != 0) {
start = sess->active_window;
} else {
start = 0;
}
for (i = 1; i <= (int)USH_UWM_WINDOW_COUNT; i++) {
int idx = (start + i) % (int)USH_UWM_WINDOW_COUNT;
if (sess->windows[idx].alive != 0) {
ush_uwm_set_active(sess, idx);
return;
}
}
}

View File

@@ -1,684 +1,4 @@
#include "cmd_runtime.h"
#define USH_UWM_WINDOW_COUNT 3ULL
#define USH_UWM_TITLE_HEIGHT 18
#define USH_UWM_BORDER_THICKNESS 2
#define USH_UWM_WINDOW_MIN_W 120
#define USH_UWM_WINDOW_MIN_H 80
#define USH_UWM_STARTUP_KEY_DRAIN_MAX 256ULL
#define USH_UWM_BLIT_MAX_FAIL_STREAK 30ULL
#define USH_UWM_KEY_LEFT 1
#define USH_UWM_KEY_RIGHT 2
#define USH_UWM_KEY_UP 3
#define USH_UWM_KEY_DOWN 4
#define USH_UWM_COLOR_BG 0x00161D2BUL
#define USH_UWM_COLOR_PANEL 0x00263352UL
#define USH_UWM_COLOR_CURSOR 0x00FFFFFFUL
#define USH_UWM_COLOR_CURSOR_SHADOW 0x00000000UL
#define USH_UWM_COLOR_BORDER_ACTIVE 0x00FFD166UL
#define USH_UWM_COLOR_BORDER_INACTIVE 0x004A566EL
#define USH_UWM_COLOR_TITLE_ACTIVE 0x005A77B7UL
#define USH_UWM_COLOR_TITLE_INACTIVE 0x00394C78UL
typedef unsigned int ush_uwm_u32;
typedef struct ush_uwm_window {
int x;
int y;
int w;
int h;
ush_uwm_u32 body_color;
} ush_uwm_window;
typedef struct ush_uwm_runtime {
cleonos_fb_info fb;
ush_uwm_u32 *canvas;
u64 canvas_pixels;
int screen_w;
int screen_h;
int mouse_x;
int mouse_y;
u64 mouse_buttons;
int mouse_ready;
} ush_uwm_runtime;
static int ush_uwm_window_index_valid(int index) {
return (index >= 0 && index < (int)USH_UWM_WINDOW_COUNT) ? 1 : 0;
}
static void ush_uwm_z_order_sanitize(int *z_order) {
int seen[USH_UWM_WINDOW_COUNT];
int fill_index = 0;
u64 i;
if (z_order == (int *)0) {
return;
}
for (i = 0ULL; i < USH_UWM_WINDOW_COUNT; i++) {
seen[i] = 0;
}
for (i = 0ULL; i < USH_UWM_WINDOW_COUNT; i++) {
int value = z_order[i];
if (ush_uwm_window_index_valid(value) != 0 && seen[(u64)value] == 0) {
seen[(u64)value] = 1;
continue;
}
while (fill_index < (int)USH_UWM_WINDOW_COUNT && seen[(u64)fill_index] != 0) {
fill_index++;
}
if (fill_index >= (int)USH_UWM_WINDOW_COUNT) {
fill_index = (int)USH_UWM_WINDOW_COUNT - 1;
}
z_order[i] = fill_index;
seen[(u64)fill_index] = 1;
}
}
static int ush_uwm_runtime_sane(const ush_uwm_runtime *rt) {
u64 min_pixels;
if (rt == (const ush_uwm_runtime *)0 || rt->canvas == (ush_uwm_u32 *)0) {
return 0;
}
if (rt->screen_w <= 0 || rt->screen_h <= 0 || rt->screen_w > 4096 || rt->screen_h > 4096) {
return 0;
}
min_pixels = (u64)(unsigned int)rt->screen_w * (u64)(unsigned int)rt->screen_h;
if (rt->canvas_pixels < min_pixels) {
return 0;
}
return 1;
}
static int ush_uwm_clampi(int value, int min_value, int max_value) {
if (value < min_value) {
return min_value;
}
if (value > max_value) {
return max_value;
}
return value;
}
static int ush_uwm_u64_to_i32_sat(u64 value) {
if (value > 0x7FFFFFFFULL) {
return 0x7FFFFFFF;
}
return (int)value;
}
static void ush_uwm_fill_rect(ush_uwm_runtime *rt, int x, int y, int w, int h, ush_uwm_u32 color) {
int left;
int top;
int right;
int bottom;
int row;
if (ush_uwm_runtime_sane(rt) == 0 || w <= 0 || h <= 0) {
return;
}
left = x;
top = y;
right = x + w;
bottom = y + h;
if (left < 0) {
left = 0;
}
if (top < 0) {
top = 0;
}
if (right > rt->screen_w) {
right = rt->screen_w;
}
if (bottom > rt->screen_h) {
bottom = rt->screen_h;
}
if (left >= right || top >= bottom) {
return;
}
for (row = top; row < bottom; row++) {
u64 offset = ((u64)(unsigned int)row * (u64)(unsigned int)rt->screen_w) + (u64)(unsigned int)left;
u64 max_pixels = rt->canvas_pixels;
int col;
if (offset >= max_pixels) {
break;
}
for (col = left; col < right; col++) {
if (offset >= max_pixels) {
break;
}
rt->canvas[offset++] = color;
}
}
}
static void ush_uwm_draw_window(ush_uwm_runtime *rt, const ush_uwm_window *win, int active) {
ush_uwm_u32 border_color = (active != 0) ? USH_UWM_COLOR_BORDER_ACTIVE : USH_UWM_COLOR_BORDER_INACTIVE;
ush_uwm_u32 title_color = (active != 0) ? USH_UWM_COLOR_TITLE_ACTIVE : USH_UWM_COLOR_TITLE_INACTIVE;
int title_h;
if (rt == (ush_uwm_runtime *)0 || win == (const ush_uwm_window *)0) {
return;
}
title_h = USH_UWM_TITLE_HEIGHT;
if (title_h > win->h) {
title_h = win->h;
}
ush_uwm_fill_rect(rt, win->x, win->y, win->w, win->h, border_color);
ush_uwm_fill_rect(rt, win->x + USH_UWM_BORDER_THICKNESS, win->y + USH_UWM_BORDER_THICKNESS,
win->w - (USH_UWM_BORDER_THICKNESS * 2), title_h - USH_UWM_BORDER_THICKNESS, title_color);
ush_uwm_fill_rect(rt, win->x + USH_UWM_BORDER_THICKNESS, win->y + title_h, win->w - (USH_UWM_BORDER_THICKNESS * 2),
win->h - title_h - USH_UWM_BORDER_THICKNESS, win->body_color);
ush_uwm_fill_rect(rt, win->x + win->w - 16, win->y + 4, 10, 10, 0x00E76F51UL);
}
static void ush_uwm_draw_cursor(ush_uwm_runtime *rt, int x, int y) {
int i;
if (rt == (ush_uwm_runtime *)0) {
return;
}
for (i = -6; i <= 6; i++) {
ush_uwm_fill_rect(rt, x + i, y, 1, 1, (i == 0) ? USH_UWM_COLOR_CURSOR : USH_UWM_COLOR_CURSOR_SHADOW);
ush_uwm_fill_rect(rt, x, y + i, 1, 1, (i == 0) ? USH_UWM_COLOR_CURSOR : USH_UWM_COLOR_CURSOR_SHADOW);
}
ush_uwm_fill_rect(rt, x - 1, y - 1, 3, 3, USH_UWM_COLOR_CURSOR);
}
static void ush_uwm_draw_background(ush_uwm_runtime *rt) {
int y;
if (rt == (ush_uwm_runtime *)0) {
return;
}
ush_uwm_fill_rect(rt, 0, 0, rt->screen_w, rt->screen_h, USH_UWM_COLOR_BG);
ush_uwm_fill_rect(rt, 0, 0, rt->screen_w, 30, USH_UWM_COLOR_PANEL);
for (y = 60; y < rt->screen_h; y += 40) {
ush_uwm_fill_rect(rt, 0, y, rt->screen_w, 1, 0x001E283BUL);
}
}
static int ush_uwm_window_hit_title(const ush_uwm_window *win, int x, int y) {
int title_h;
if (win == (const ush_uwm_window *)0) {
return 0;
}
title_h = USH_UWM_TITLE_HEIGHT;
if (title_h > win->h) {
title_h = win->h;
}
if (x < win->x || y < win->y) {
return 0;
}
if (x >= win->x + win->w || y >= win->y + title_h) {
return 0;
}
return 1;
}
static void ush_uwm_bring_to_front(int *z_order, u64 count, int window_index) {
u64 i;
u64 pos = count;
if (z_order == (int *)0 || count == 0ULL || ush_uwm_window_index_valid(window_index) == 0) {
return;
}
for (i = 0ULL; i < count; i++) {
if (z_order[i] == window_index) {
pos = i;
break;
}
}
if (pos >= count || pos + 1ULL >= count) {
return;
}
for (i = pos; i + 1ULL < count; i++) {
z_order[i] = z_order[i + 1ULL];
}
z_order[count - 1ULL] = window_index;
}
static int ush_uwm_cycle_focus(const int *z_order, u64 count, int active_window) {
u64 i;
u64 pos = 0ULL;
if (z_order == (const int *)0 || count == 0ULL) {
return 0;
}
if (ush_uwm_window_index_valid(active_window) == 0) {
return z_order[count - 1ULL];
}
for (i = 0ULL; i < count; i++) {
if (z_order[i] == active_window) {
pos = i;
break;
}
}
return z_order[(pos + 1ULL) % count];
}
static int ush_uwm_poll_mouse(ush_uwm_runtime *rt) {
cleonos_mouse_state ms;
int max_x;
int max_y;
if (rt == (ush_uwm_runtime *)0) {
return 0;
}
ush_zero(&ms, (u64)sizeof(ms));
if (cleonos_sys_mouse_state(&ms) == 0ULL) {
return 0;
}
rt->mouse_buttons = ms.buttons;
rt->mouse_ready = (ms.ready != 0ULL) ? 1 : 0;
if (rt->screen_w <= 0 || rt->screen_h <= 0) {
return rt->mouse_ready;
}
max_x = rt->screen_w - 1;
max_y = rt->screen_h - 1;
rt->mouse_x = ush_uwm_clampi(ush_uwm_u64_to_i32_sat(ms.x), 0, max_x);
rt->mouse_y = ush_uwm_clampi(ush_uwm_u64_to_i32_sat(ms.y), 0, max_y);
return rt->mouse_ready;
}
static int ush_uwm_present(ush_uwm_runtime *rt) {
cleonos_fb_blit_req req;
if (ush_uwm_runtime_sane(rt) == 0) {
return 0;
}
req.pixels_ptr = (u64)(usize)rt->canvas;
req.src_width = (u64)(unsigned int)rt->screen_w;
req.src_height = (u64)(unsigned int)rt->screen_h;
req.src_pitch_bytes = (u64)(unsigned int)rt->screen_w * 4ULL;
req.dst_x = 0ULL;
req.dst_y = 0ULL;
req.scale = 1ULL;
return (cleonos_sys_fb_blit(&req) != 0ULL) ? 1 : 0;
}
static u64 ush_uwm_drain_startup_keys(void) {
u64 drained = 0ULL;
while (drained < USH_UWM_STARTUP_KEY_DRAIN_MAX) {
u64 key = cleonos_sys_kbd_get_char();
if (key == (u64)-1) {
break;
}
drained++;
}
return drained;
}
/* return: 0 fail, 1 ok, 2 help */
static int ush_uwm_parse_args(const char *arg) {
char first[USH_PATH_MAX];
const char *rest = "";
if (arg == (const char *)0 || arg[0] == '\0') {
return 1;
}
if (ush_split_first_and_rest(arg, first, (u64)sizeof(first), &rest) == 0) {
return 0;
}
if (rest != (const char *)0 && rest[0] != '\0') {
return 0;
}
if (ush_streq(first, "--help") != 0 || ush_streq(first, "-h") != 0) {
return 2;
}
return 0;
}
static void ush_uwm_usage(void) {
ush_writeln("usage: uwm");
ush_writeln("keys: q quit, tab cycle focus, wasd move active window");
ush_writeln("mouse: drag window by title bar");
}
static int ush_cmd_uwm(const char *arg) {
ush_uwm_runtime rt;
ush_uwm_window windows[USH_UWM_WINDOW_COUNT];
int z_order[USH_UWM_WINDOW_COUNT];
int active_window = 0;
int dragging = 0;
int drag_window = 0;
int drag_offset_x = 0;
int drag_offset_y = 0;
u64 prev_buttons = 0ULL;
u64 blit_fail_streak = 0ULL;
int running = 1;
int parse_result;
u64 drained_keys;
parse_result = ush_uwm_parse_args(arg);
if (parse_result == 2) {
ush_uwm_usage();
return 1;
}
if (parse_result == 0) {
ush_uwm_usage();
return 0;
}
ush_zero(&rt, (u64)sizeof(rt));
if (cleonos_sys_fb_info(&rt.fb) == 0ULL || rt.fb.width == 0ULL || rt.fb.height == 0ULL || rt.fb.bpp != 32ULL) {
ush_writeln("uwm: framebuffer unavailable");
return 0;
}
if (rt.fb.width > 4096ULL || rt.fb.height > 4096ULL) {
ush_writeln("uwm: framebuffer too large");
return 0;
}
rt.screen_w = (int)rt.fb.width;
rt.screen_h = (int)rt.fb.height;
rt.canvas_pixels = rt.fb.width * rt.fb.height;
rt.canvas = (ush_uwm_u32 *)malloc((size_t)(rt.canvas_pixels * 4ULL));
if (rt.canvas == (ush_uwm_u32 *)0) {
ush_writeln("uwm: framebuffer buffer alloc failed");
return 0;
}
windows[0].x = 50;
windows[0].y = 70;
windows[0].w = rt.screen_w / 3;
windows[0].h = rt.screen_h / 3;
windows[0].body_color = 0x002C3E6BUL;
windows[1].x = 180;
windows[1].y = 140;
windows[1].w = rt.screen_w / 3;
windows[1].h = rt.screen_h / 3;
windows[1].body_color = 0x003F5B7EUL;
windows[2].x = 310;
windows[2].y = 210;
windows[2].w = rt.screen_w / 3;
windows[2].h = rt.screen_h / 3;
windows[2].body_color = 0x00506F89UL;
z_order[0] = 0;
z_order[1] = 1;
z_order[2] = 2;
active_window = 2;
{
u64 i;
for (i = 0ULL; i < USH_UWM_WINDOW_COUNT; i++) {
int max_w = rt.screen_w - 20;
int max_h = rt.screen_h - 40;
if (max_w < USH_UWM_WINDOW_MIN_W) {
max_w = USH_UWM_WINDOW_MIN_W;
}
if (max_h < USH_UWM_WINDOW_MIN_H) {
max_h = USH_UWM_WINDOW_MIN_H;
}
if (windows[i].w < USH_UWM_WINDOW_MIN_W) {
windows[i].w = USH_UWM_WINDOW_MIN_W;
}
if (windows[i].h < USH_UWM_WINDOW_MIN_H) {
windows[i].h = USH_UWM_WINDOW_MIN_H;
}
if (windows[i].w > max_w) {
windows[i].w = max_w;
}
if (windows[i].h > max_h) {
windows[i].h = max_h;
}
}
}
rt.mouse_x = rt.screen_w / 2;
rt.mouse_y = rt.screen_h / 2;
rt.mouse_buttons = 0ULL;
rt.mouse_ready = 0;
ush_writeln("uwm: enter user window manager");
ush_writeln("uwm: q quit, tab focus, wasd move, drag title bar with mouse");
(void)cleonos_sys_fb_clear(USH_UWM_COLOR_BG);
drained_keys = ush_uwm_drain_startup_keys();
if (drained_keys > 0ULL) {
ush_writeln("uwm: stale keyboard input discarded");
}
while (running != 0) {
u64 key;
int left_down;
int left_press;
int left_release;
if (ush_uwm_runtime_sane(&rt) == 0) {
free(rt.canvas);
ush_writeln("uwm: runtime state corrupted");
return 0;
}
ush_uwm_z_order_sanitize(z_order);
if (ush_uwm_window_index_valid(active_window) == 0) {
active_window = z_order[USH_UWM_WINDOW_COUNT - 1ULL];
}
if (ush_uwm_window_index_valid(drag_window) == 0) {
dragging = 0;
drag_window = active_window;
}
(void)ush_uwm_poll_mouse(&rt);
for (;;) {
key = cleonos_sys_kbd_get_char();
if (key == (u64)-1) {
break;
}
if (key == (u64)'q' || key == (u64)'Q') {
running = 0;
break;
}
if (key == 27ULL) {
continue;
}
if (key == (u64)'\t') {
active_window = ush_uwm_cycle_focus(z_order, USH_UWM_WINDOW_COUNT, active_window);
if (ush_uwm_window_index_valid(active_window) != 0) {
ush_uwm_bring_to_front(z_order, USH_UWM_WINDOW_COUNT, active_window);
}
continue;
}
if (ush_uwm_window_index_valid(active_window) == 0) {
continue;
}
if (key == (u64)'a' || key == (u64)'A') {
windows[active_window].x -= 8;
} else if (key == (u64)'d' || key == (u64)'D') {
windows[active_window].x += 8;
} else if (key == (u64)'w' || key == (u64)'W') {
windows[active_window].y -= 8;
} else if (key == (u64)'s' || key == (u64)'S') {
windows[active_window].y += 8;
} else if (key == USH_UWM_KEY_LEFT) {
rt.mouse_x -= 10;
} else if (key == USH_UWM_KEY_RIGHT) {
rt.mouse_x += 10;
} else if (key == USH_UWM_KEY_UP) {
rt.mouse_y -= 10;
} else if (key == USH_UWM_KEY_DOWN) {
rt.mouse_y += 10;
}
}
if (running == 0) {
break;
}
left_down = ((rt.mouse_buttons & 0x01ULL) != 0ULL) ? 1 : 0;
left_press = (left_down != 0 && (prev_buttons & 0x01ULL) == 0ULL) ? 1 : 0;
left_release = (left_down == 0 && (prev_buttons & 0x01ULL) != 0ULL) ? 1 : 0;
if (left_press != 0) {
int hit = -1;
i64 z;
for (z = (i64)USH_UWM_WINDOW_COUNT - 1LL; z >= 0LL; z--) {
int win_index = z_order[(u64)z];
if (ush_uwm_window_index_valid(win_index) == 0) {
continue;
}
if (ush_uwm_window_hit_title(&windows[win_index], rt.mouse_x, rt.mouse_y) != 0) {
hit = win_index;
break;
}
}
if (hit >= 0) {
active_window = hit;
ush_uwm_bring_to_front(z_order, USH_UWM_WINDOW_COUNT, hit);
dragging = 1;
drag_window = hit;
drag_offset_x = rt.mouse_x - windows[hit].x;
drag_offset_y = rt.mouse_y - windows[hit].y;
}
}
if (left_release != 0) {
dragging = 0;
}
if (dragging != 0 && left_down != 0 && ush_uwm_window_index_valid(drag_window) != 0) {
int new_x = rt.mouse_x - drag_offset_x;
int new_y = rt.mouse_y - drag_offset_y;
int max_x = rt.screen_w - windows[drag_window].w;
int max_y = rt.screen_h - windows[drag_window].h;
int min_y = (max_y >= 30) ? 30 : 0;
if (max_x < 0) {
max_x = 0;
}
if (max_y < 0) {
max_y = 0;
}
windows[drag_window].x = ush_uwm_clampi(new_x, 0, max_x);
windows[drag_window].y = ush_uwm_clampi(new_y, min_y, max_y);
}
if (ush_uwm_window_index_valid(active_window) != 0) {
int max_x = rt.screen_w - windows[active_window].w;
int max_y = rt.screen_h - windows[active_window].h;
int min_y = (max_y >= 30) ? 30 : 0;
if (max_x < 0) {
max_x = 0;
}
if (max_y < 0) {
max_y = 0;
}
windows[active_window].x = ush_uwm_clampi(windows[active_window].x, 0, max_x);
windows[active_window].y = ush_uwm_clampi(windows[active_window].y, min_y, max_y);
}
rt.mouse_x = ush_uwm_clampi(rt.mouse_x, 0, rt.screen_w - 1);
rt.mouse_y = ush_uwm_clampi(rt.mouse_y, 0, rt.screen_h - 1);
ush_uwm_draw_background(&rt);
{
u64 i;
for (i = 0ULL; i < USH_UWM_WINDOW_COUNT; i++) {
int win_index = z_order[i];
if (ush_uwm_window_index_valid(win_index) == 0) {
continue;
}
int is_active = (win_index == active_window) ? 1 : 0;
ush_uwm_draw_window(&rt, &windows[win_index], is_active);
}
}
ush_uwm_draw_cursor(&rt, rt.mouse_x, rt.mouse_y);
if (ush_uwm_present(&rt) == 0) {
blit_fail_streak++;
if (blit_fail_streak == 1ULL) {
ush_writeln("uwm: framebuffer blit failed, retrying");
}
if (blit_fail_streak >= USH_UWM_BLIT_MAX_FAIL_STREAK) {
free(rt.canvas);
ush_writeln("uwm: framebuffer blit failed too many times");
return 0;
}
(void)cleonos_sys_sleep_ticks(1ULL);
continue;
}
blit_fail_streak = 0ULL;
prev_buttons = rt.mouse_buttons;
(void)cleonos_sys_sleep_ticks(1ULL);
}
(void)cleonos_sys_fb_clear(0x00000000ULL);
free(rt.canvas);
ush_writeln("uwm: exit");
return 1;
}
#include "uwm/uwm.h"
int cleonos_app_main(int argc, char **argv, char **envp) {
ush_cmd_ctx ctx;

View File

@@ -58,6 +58,42 @@ typedef struct cleonos_mouse_state {
u64 ready;
} cleonos_mouse_state;
#define CLEONOS_WM_EVENT_FOCUS_GAINED 1ULL
#define CLEONOS_WM_EVENT_FOCUS_LOST 2ULL
#define CLEONOS_WM_EVENT_KEY 3ULL
#define CLEONOS_WM_EVENT_MOUSE_MOVE 4ULL
#define CLEONOS_WM_EVENT_MOUSE_BUTTON 5ULL
typedef struct cleonos_wm_event {
u64 type;
u64 arg0;
u64 arg1;
u64 arg2;
u64 arg3;
} cleonos_wm_event;
typedef struct cleonos_wm_create_req {
u64 x;
u64 y;
u64 width;
u64 height;
u64 flags;
} cleonos_wm_create_req;
typedef struct cleonos_wm_present_req {
u64 window_id;
u64 pixels_ptr;
u64 src_width;
u64 src_height;
u64 src_pitch_bytes;
} cleonos_wm_present_req;
typedef struct cleonos_wm_move_req {
u64 window_id;
u64 x;
u64 y;
} cleonos_wm_move_req;
typedef struct cleonos_fb_blit_req {
u64 pixels_ptr;
u64 src_width;
@@ -211,6 +247,12 @@ typedef struct cleonos_net_tcp_recv_req {
#define CLEONOS_SYSCALL_NET_TCP_RECV 105ULL
#define CLEONOS_SYSCALL_NET_TCP_CLOSE 106ULL
#define CLEONOS_SYSCALL_MOUSE_STATE 107ULL
#define CLEONOS_SYSCALL_WM_CREATE 108ULL
#define CLEONOS_SYSCALL_WM_DESTROY 109ULL
#define CLEONOS_SYSCALL_WM_PRESENT 110ULL
#define CLEONOS_SYSCALL_WM_POLL_EVENT 111ULL
#define CLEONOS_SYSCALL_WM_MOVE 112ULL
#define CLEONOS_SYSCALL_WM_SET_FOCUS 113ULL
u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
u64 cleonos_sys_log_write(const char *message, u64 length);
@@ -321,5 +363,11 @@ u64 cleonos_sys_net_tcp_send(const cleonos_net_tcp_send_req *req);
u64 cleonos_sys_net_tcp_recv(cleonos_net_tcp_recv_req *req);
u64 cleonos_sys_net_tcp_close(u64 poll_budget);
u64 cleonos_sys_mouse_state(cleonos_mouse_state *out_state);
u64 cleonos_sys_wm_create(const cleonos_wm_create_req *req);
u64 cleonos_sys_wm_destroy(u64 window_id);
u64 cleonos_sys_wm_present(const cleonos_wm_present_req *req);
u64 cleonos_sys_wm_poll_event(u64 window_id, cleonos_wm_event *out_event);
u64 cleonos_sys_wm_move(const cleonos_wm_move_req *req);
u64 cleonos_sys_wm_set_focus(u64 window_id);
#endif

View File

@@ -463,3 +463,27 @@ u64 cleonos_sys_net_tcp_close(u64 poll_budget) {
u64 cleonos_sys_mouse_state(cleonos_mouse_state *out_state) {
return cleonos_syscall(CLEONOS_SYSCALL_MOUSE_STATE, (u64)out_state, 0ULL, 0ULL);
}
u64 cleonos_sys_wm_create(const cleonos_wm_create_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_WM_CREATE, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_wm_destroy(u64 window_id) {
return cleonos_syscall(CLEONOS_SYSCALL_WM_DESTROY, window_id, 0ULL, 0ULL);
}
u64 cleonos_sys_wm_present(const cleonos_wm_present_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_WM_PRESENT, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_wm_poll_event(u64 window_id, cleonos_wm_event *out_event) {
return cleonos_syscall(CLEONOS_SYSCALL_WM_POLL_EVENT, window_id, (u64)out_event, 0ULL);
}
u64 cleonos_sys_wm_move(const cleonos_wm_move_req *req) {
return cleonos_syscall(CLEONOS_SYSCALL_WM_MOVE, (u64)req, 0ULL, 0ULL);
}
u64 cleonos_sys_wm_set_focus(u64 window_id) {
return cleonos_syscall(CLEONOS_SYSCALL_WM_SET_FOCUS, window_id, 0ULL, 0ULL);
}

2
clks

Submodule clks updated: 80c2e781eb...6a38167568

View File

@@ -83,7 +83,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `/proc/<pid>`:指定 PID 快照文本
- `/proc` 为只读;写入类 syscall 不支持。
## 4. Syscall 列表0~107
## 4. Syscall 列表0~113
### 0 `CLEONOS_SYSCALL_LOG_WRITE`
@@ -819,6 +819,58 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `buttons` 位掩码:`bit0=left``bit1=right``bit2=middle`
- `ready=1` 表示鼠标设备已上线;`ready=0` 时坐标/按键可能为默认值。
### 108 `CLEONOS_SYSCALL_WM_CREATE`
- 参数:
- `arg0`: `const struct { u64 x; u64 y; u64 width; u64 height; u64 flags; } *req`
- 返回:成功返回非零 `window_id`,失败返回 `0`
- 说明:
- 创建一个由内核合成的窗口(当前在 TTY2 桌面合成器上显示)。
- `x/y` 为有符号坐标(按 `i64` 解释),`width/height` 为像素尺寸。
### 109 `CLEONOS_SYSCALL_WM_DESTROY`
- 参数:
- `arg0`: `u64 window_id`
- 返回:成功 `1`,失败 `0`
- 说明:销毁窗口并回收其事件队列与内核缓冲。
### 110 `CLEONOS_SYSCALL_WM_PRESENT`
- 参数:
- `arg0`: `const struct { u64 window_id; u64 pixels_ptr; u64 src_width; u64 src_height; u64 src_pitch_bytes; } *req`
- 返回:成功 `1`,失败 `0`
- 说明:
- 将用户态 ARGB/RGB32 像素缓冲提交到指定窗口内容区。
- 当前要求 `src_width/src_height` 与创建窗口时一致。
### 111 `CLEONOS_SYSCALL_WM_POLL_EVENT`
- 参数:
- `arg0`: `u64 window_id`
- `arg1`: `struct cleonos_wm_event *out_event`
- 返回:有事件时返回 `1` 并写入事件;无事件或失败返回 `0`
- 事件类型:
- `1` = `FOCUS_GAINED`
- `2` = `FOCUS_LOST`
- `3` = `KEY``arg0` 为按键值)
- `4` = `MOUSE_MOVE``arg0/arg1` 为全局坐标,`arg2/arg3` 为窗口局部坐标)
- `5` = `MOUSE_BUTTON``arg0` 为按钮状态位掩码,`arg1` 为变化掩码)
### 112 `CLEONOS_SYSCALL_WM_MOVE`
- 参数:
- `arg0`: `const struct { u64 window_id; u64 x; u64 y; } *req`
- 返回:成功 `1`,失败 `0`
- 说明:移动窗口到目标坐标(坐标按 `i64` 解释,内核会进行边界裁剪)。
### 113 `CLEONOS_SYSCALL_WM_SET_FOCUS`
- 参数:
- `arg0`: `u64 window_id`
- 返回:成功 `1`,失败 `0`
- 说明:将目标窗口置为焦点并提升到顶层 z-order。
## 5. 用户态封装函数
用户态封装位于:
@@ -855,6 +907,8 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `cleonos_sys_net_udp_send()` / `cleonos_sys_net_udp_recv()`
- `cleonos_sys_net_tcp_connect()` / `cleonos_sys_net_tcp_send()` / `cleonos_sys_net_tcp_recv()` / `cleonos_sys_net_tcp_close()`
- `cleonos_sys_mouse_state()`
- `cleonos_sys_wm_create()` / `cleonos_sys_wm_destroy()` / `cleonos_sys_wm_present()`
- `cleonos_sys_wm_poll_event()` / `cleonos_sys_wm_move()` / `cleonos_sys_wm_set_focus()`
## 6. 开发注意事项
@@ -865,7 +919,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
## 7. Wine 兼容说明
- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..107`(含 `DL_*``FB_*``KERNEL_VERSION``DISK_*``NET_*``MOUSE_STATE`)。
- `wine/cleonos_wine_lib/runner.py` 当前已覆盖到 `0..113`(含 `DL_*``FB_*``KERNEL_VERSION``DISK_*``NET_*``MOUSE_STATE``WM_*`)。
- `DL_*``77..79`)在 Wine 中为“可运行兼容”实现:
- `DL_OPEN`:加载 guest ELF 到当前 Unicorn 地址空间,返回稳定 `handle`,并做引用计数。
- `DL_SYM`:解析 ELF `SYMTAB/DYNSYM` 并返回 guest 可调用地址。
@@ -884,6 +938,7 @@ u64 cleonos_syscall(u64 id, u64 arg0, u64 arg1, u64 arg2);
- `DISK_READ_SECTOR`/`DISK_WRITE_SECTOR``93..94`)在 Wine 中已实现为 512B 原始扇区读写host 文件后端)。
- 网络 syscall`95..106`)在 Wine 当前为兼容占位实现(统一返回 `0`);即 Wine 运行模式下不会提供真实网络收发。
- `MOUSE_STATE``107`)在 Wine 中为基础兼容实现:可返回指针数据结构;未启用窗口鼠标事件时 `ready` 可能为 `0`
- `WM_*``108..113`)在 Wine 当前为兼容占位实现(统一返回 `0`);不会创建真实窗口服务。
- Wine 在运行时崩溃场景下会生成与内核一致格式的“信号编码退出状态”,可通过 `WAITPID` 读取。
- Wine 当前音频 syscall 为占位实现:`AUDIO_AVAILABLE=0``AUDIO_PLAY_TONE=0``AUDIO_STOP=1`
- Wine 版本号策略固定为 `85.0.0-wine`(历史兼容号;不会随 syscall 扩展继续增长)。

2
kit

Submodule kit updated: 1e7b5aa8d2...58fa3d6d1a