mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 10:40:00 +00:00
Stage 25
This commit is contained in:
@@ -89,21 +89,73 @@ struct clks_framebuffer_info clks_fb_info(void) {
|
|||||||
return clks_fb.info;
|
return clks_fb.info;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clks_fb_clear(u32 rgb) {
|
void clks_fb_draw_pixel(u32 x, u32 y, u32 rgb) {
|
||||||
u32 x;
|
clks_fb_put_pixel(x, y, rgb);
|
||||||
u32 y;
|
}
|
||||||
|
|
||||||
|
clks_bool clks_fb_read_pixel(u32 x, u32 y, u32 *out_rgb) {
|
||||||
|
volatile u8 *row;
|
||||||
|
volatile u32 *pixel;
|
||||||
|
|
||||||
|
if (out_rgb == CLKS_NULL) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_fb.ready == CLKS_FALSE) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_fb.info.bpp != 32) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
row = clks_fb.address + ((usize)y * (usize)clks_fb.info.pitch);
|
||||||
|
pixel = (volatile u32 *)(row + ((usize)x * 4U));
|
||||||
|
*out_rgb = *pixel;
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clks_fb_fill_rect(u32 x, u32 y, u32 width, u32 height, u32 rgb) {
|
||||||
|
u32 px;
|
||||||
|
u32 py;
|
||||||
|
u32 end_x;
|
||||||
|
u32 end_y;
|
||||||
|
u64 end_x64;
|
||||||
|
u64 end_y64;
|
||||||
|
|
||||||
if (clks_fb.ready == CLKS_FALSE) {
|
if (clks_fb.ready == CLKS_FALSE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (y = 0U; y < clks_fb.info.height; y++) {
|
if (width == 0U || height == 0U) {
|
||||||
for (x = 0U; x < clks_fb.info.width; x++) {
|
return;
|
||||||
clks_fb_put_pixel(x, y, rgb);
|
}
|
||||||
|
|
||||||
|
if (x >= clks_fb.info.width || y >= clks_fb.info.height) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
end_x64 = (u64)x + (u64)width;
|
||||||
|
end_y64 = (u64)y + (u64)height;
|
||||||
|
|
||||||
|
end_x = (end_x64 > (u64)clks_fb.info.width) ? clks_fb.info.width : (u32)end_x64;
|
||||||
|
end_y = (end_y64 > (u64)clks_fb.info.height) ? clks_fb.info.height : (u32)end_y64;
|
||||||
|
|
||||||
|
for (py = y; py < end_y; py++) {
|
||||||
|
for (px = x; px < end_x; px++) {
|
||||||
|
clks_fb_put_pixel(px, py, rgb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clks_fb_clear(u32 rgb) {
|
||||||
|
clks_fb_fill_rect(0U, 0U, clks_fb.info.width, clks_fb.info.height, rgb);
|
||||||
|
}
|
||||||
|
|
||||||
void clks_fb_scroll_up(u32 pixel_rows, u32 fill_rgb) {
|
void clks_fb_scroll_up(u32 pixel_rows, u32 fill_rgb) {
|
||||||
usize row_bytes;
|
usize row_bytes;
|
||||||
usize move_bytes;
|
usize move_bytes;
|
||||||
|
|||||||
10
clks/include/clks/desktop.h
Normal file
10
clks/include/clks/desktop.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef CLKS_DESKTOP_H
|
||||||
|
#define CLKS_DESKTOP_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
void clks_desktop_init(void);
|
||||||
|
void clks_desktop_tick(u64 tick);
|
||||||
|
clks_bool clks_desktop_ready(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -16,9 +16,12 @@ clks_bool clks_fb_ready(void);
|
|||||||
struct clks_framebuffer_info clks_fb_info(void);
|
struct clks_framebuffer_info clks_fb_info(void);
|
||||||
void clks_fb_clear(u32 rgb);
|
void clks_fb_clear(u32 rgb);
|
||||||
void clks_fb_scroll_up(u32 pixel_rows, u32 fill_rgb);
|
void clks_fb_scroll_up(u32 pixel_rows, u32 fill_rgb);
|
||||||
|
void clks_fb_draw_pixel(u32 x, u32 y, u32 rgb);
|
||||||
|
clks_bool clks_fb_read_pixel(u32 x, u32 y, u32 *out_rgb);
|
||||||
|
void clks_fb_fill_rect(u32 x, u32 y, u32 width, u32 height, u32 rgb);
|
||||||
void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb);
|
void clks_fb_draw_char(u32 x, u32 y, char ch, u32 fg_rgb, u32 bg_rgb);
|
||||||
clks_bool clks_fb_load_psf_font(const void *blob, u64 blob_size);
|
clks_bool clks_fb_load_psf_font(const void *blob, u64 blob_size);
|
||||||
u32 clks_fb_cell_width(void);
|
u32 clks_fb_cell_width(void);
|
||||||
u32 clks_fb_cell_height(void);
|
u32 clks_fb_cell_height(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
25
clks/include/clks/mouse.h
Normal file
25
clks/include/clks/mouse.h
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#ifndef CLKS_MOUSE_H
|
||||||
|
#define CLKS_MOUSE_H
|
||||||
|
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#define CLKS_MOUSE_BTN_LEFT 0x01U
|
||||||
|
#define CLKS_MOUSE_BTN_RIGHT 0x02U
|
||||||
|
#define CLKS_MOUSE_BTN_MIDDLE 0x04U
|
||||||
|
|
||||||
|
struct clks_mouse_state {
|
||||||
|
i32 x;
|
||||||
|
i32 y;
|
||||||
|
u8 buttons;
|
||||||
|
u64 packet_count;
|
||||||
|
clks_bool ready;
|
||||||
|
};
|
||||||
|
|
||||||
|
void clks_mouse_init(void);
|
||||||
|
void clks_mouse_handle_byte(u8 data_byte);
|
||||||
|
void clks_mouse_snapshot(struct clks_mouse_state *out_state);
|
||||||
|
clks_bool clks_mouse_ready(void);
|
||||||
|
u64 clks_mouse_packet_count(void);
|
||||||
|
u64 clks_mouse_drop_count(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
406
clks/kernel/desktop.c
Normal file
406
clks/kernel/desktop.c
Normal file
@@ -0,0 +1,406 @@
|
|||||||
|
#include <clks/desktop.h>
|
||||||
|
#include <clks/framebuffer.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/mouse.h>
|
||||||
|
#include <clks/tty.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#define CLKS_DESKTOP_TTY_INDEX 1U
|
||||||
|
|
||||||
|
#define CLKS_DESKTOP_BG_COLOR 0x001B2430U
|
||||||
|
#define CLKS_DESKTOP_TOPBAR_COLOR 0x00293447U
|
||||||
|
#define CLKS_DESKTOP_DOCK_COLOR 0x00232C3AU
|
||||||
|
#define CLKS_DESKTOP_WINDOW_COLOR 0x00313E52U
|
||||||
|
#define CLKS_DESKTOP_TITLE_COLOR 0x003B4A61U
|
||||||
|
#define CLKS_DESKTOP_TEXT_FG 0x00E6EDF7U
|
||||||
|
#define CLKS_DESKTOP_TEXT_BG 0x003B4A61U
|
||||||
|
|
||||||
|
#define CLKS_DESKTOP_CURSOR_FILL 0x00F5F8FFU
|
||||||
|
#define CLKS_DESKTOP_CURSOR_OUTLINE 0x00101010U
|
||||||
|
#define CLKS_DESKTOP_CURSOR_ACTIVE 0x00FFCE6EU
|
||||||
|
#define CLKS_DESKTOP_CURSOR_W 16U
|
||||||
|
#define CLKS_DESKTOP_CURSOR_H 16U
|
||||||
|
|
||||||
|
struct clks_desktop_layout {
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
u32 topbar_h;
|
||||||
|
u32 dock_w;
|
||||||
|
u32 win_x;
|
||||||
|
u32 win_y;
|
||||||
|
u32 win_w;
|
||||||
|
u32 win_h;
|
||||||
|
u32 win_title_h;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct clks_desktop_layout clks_desktop = {
|
||||||
|
.width = 0U,
|
||||||
|
.height = 0U,
|
||||||
|
.topbar_h = 32U,
|
||||||
|
.dock_w = 72U,
|
||||||
|
.win_x = 0U,
|
||||||
|
.win_y = 0U,
|
||||||
|
.win_w = 0U,
|
||||||
|
.win_h = 0U,
|
||||||
|
.win_title_h = 28U,
|
||||||
|
};
|
||||||
|
|
||||||
|
static clks_bool clks_desktop_ready_flag = CLKS_FALSE;
|
||||||
|
static clks_bool clks_desktop_active_last = CLKS_FALSE;
|
||||||
|
static clks_bool clks_desktop_scene_drawn = CLKS_FALSE;
|
||||||
|
static clks_bool clks_desktop_cursor_drawn = CLKS_FALSE;
|
||||||
|
static i32 clks_desktop_last_mouse_x = -1;
|
||||||
|
static i32 clks_desktop_last_mouse_y = -1;
|
||||||
|
static u8 clks_desktop_last_buttons = 0U;
|
||||||
|
static clks_bool clks_desktop_last_ready = CLKS_FALSE;
|
||||||
|
static u32 clks_desktop_cursor_under[CLKS_DESKTOP_CURSOR_W * CLKS_DESKTOP_CURSOR_H];
|
||||||
|
|
||||||
|
static void clks_desktop_draw_text(u32 x, u32 y, const char *text, u32 fg, u32 bg) {
|
||||||
|
u32 step;
|
||||||
|
usize i = 0U;
|
||||||
|
|
||||||
|
if (text == CLKS_NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
step = clks_fb_cell_width();
|
||||||
|
|
||||||
|
if (step == 0U) {
|
||||||
|
step = 8U;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (text[i] != '\0') {
|
||||||
|
clks_fb_draw_char(x + ((u32)i * step), y, text[i], fg, bg);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static clks_bool clks_desktop_in_bounds(i32 x, i32 y) {
|
||||||
|
if (x < 0 || y < 0) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((u32)x >= clks_desktop.width || (u32)y >= clks_desktop.height) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clks_desktop_compute_layout(void) {
|
||||||
|
struct clks_framebuffer_info info = clks_fb_info();
|
||||||
|
u32 right_margin;
|
||||||
|
u32 bottom_margin;
|
||||||
|
|
||||||
|
clks_desktop.width = info.width;
|
||||||
|
clks_desktop.height = info.height;
|
||||||
|
|
||||||
|
if (clks_desktop.topbar_h >= clks_desktop.height) {
|
||||||
|
clks_desktop.topbar_h = clks_desktop.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.dock_w >= clks_desktop.width) {
|
||||||
|
clks_desktop.dock_w = clks_desktop.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_desktop.win_x = clks_desktop.width / 6U;
|
||||||
|
clks_desktop.win_y = clks_desktop.height / 6U;
|
||||||
|
|
||||||
|
if (clks_desktop.win_x < 96U) {
|
||||||
|
clks_desktop.win_x = 96U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.win_y < 72U) {
|
||||||
|
clks_desktop.win_y = 72U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.win_x >= clks_desktop.width) {
|
||||||
|
clks_desktop.win_x = clks_desktop.width > 0U ? (clks_desktop.width - 1U) : 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.win_y >= clks_desktop.height) {
|
||||||
|
clks_desktop.win_y = clks_desktop.height > 0U ? (clks_desktop.height - 1U) : 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
right_margin = clks_desktop.width / 10U;
|
||||||
|
bottom_margin = clks_desktop.height / 8U;
|
||||||
|
|
||||||
|
if (right_margin < 48U) {
|
||||||
|
right_margin = 48U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bottom_margin < 48U) {
|
||||||
|
bottom_margin = 48U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.width > clks_desktop.win_x + right_margin) {
|
||||||
|
clks_desktop.win_w = clks_desktop.width - clks_desktop.win_x - right_margin;
|
||||||
|
} else {
|
||||||
|
clks_desktop.win_w = clks_desktop.width - clks_desktop.win_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.height > clks_desktop.win_y + bottom_margin) {
|
||||||
|
clks_desktop.win_h = clks_desktop.height - clks_desktop.win_y - bottom_margin;
|
||||||
|
} else {
|
||||||
|
clks_desktop.win_h = clks_desktop.height - clks_desktop.win_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.win_w < 220U) {
|
||||||
|
clks_desktop.win_w = (clks_desktop.width > (clks_desktop.win_x + 20U))
|
||||||
|
? (clks_desktop.width - clks_desktop.win_x - 20U)
|
||||||
|
: (clks_desktop.width - clks_desktop.win_x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.win_h < 140U) {
|
||||||
|
clks_desktop.win_h = (clks_desktop.height > (clks_desktop.win_y + 20U))
|
||||||
|
? (clks_desktop.height - clks_desktop.win_y - 20U)
|
||||||
|
: (clks_desktop.height - clks_desktop.win_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.win_w > (clks_desktop.width - clks_desktop.win_x)) {
|
||||||
|
clks_desktop.win_w = clks_desktop.width - clks_desktop.win_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.win_h > (clks_desktop.height - clks_desktop.win_y)) {
|
||||||
|
clks_desktop.win_h = clks_desktop.height - clks_desktop.win_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.win_title_h >= clks_desktop.win_h) {
|
||||||
|
clks_desktop.win_title_h = clks_desktop.win_h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clks_desktop_draw_status_widgets(const struct clks_mouse_state *mouse) {
|
||||||
|
u32 ready_x = 0U;
|
||||||
|
u32 left_x = 0U;
|
||||||
|
|
||||||
|
if (mouse == CLKS_NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.width > 28U) {
|
||||||
|
ready_x = clks_desktop.width - 28U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.width > 46U) {
|
||||||
|
left_x = clks_desktop.width - 46U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouse->ready == CLKS_TRUE) {
|
||||||
|
clks_fb_fill_rect(ready_x, 10U, 10U, 10U, 0x006FE18BU);
|
||||||
|
} else {
|
||||||
|
clks_fb_fill_rect(ready_x, 10U, 10U, 10U, 0x00E06A6AU);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((mouse->buttons & CLKS_MOUSE_BTN_LEFT) != 0U) {
|
||||||
|
clks_fb_fill_rect(left_x, 10U, 10U, 10U, 0x00FFCE6EU);
|
||||||
|
} else {
|
||||||
|
clks_fb_fill_rect(left_x, 10U, 10U, 10U, 0x004A5568U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clks_desktop_draw_static_scene(const struct clks_mouse_state *mouse) {
|
||||||
|
clks_fb_clear(CLKS_DESKTOP_BG_COLOR);
|
||||||
|
|
||||||
|
if (clks_desktop.topbar_h > 0U) {
|
||||||
|
clks_fb_fill_rect(0U, 0U, clks_desktop.width, clks_desktop.topbar_h, CLKS_DESKTOP_TOPBAR_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop.height > clks_desktop.topbar_h) {
|
||||||
|
clks_fb_fill_rect(0U, clks_desktop.topbar_h, clks_desktop.dock_w,
|
||||||
|
clks_desktop.height - clks_desktop.topbar_h, CLKS_DESKTOP_DOCK_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_fb_fill_rect(clks_desktop.win_x, clks_desktop.win_y, clks_desktop.win_w, clks_desktop.win_h,
|
||||||
|
CLKS_DESKTOP_WINDOW_COLOR);
|
||||||
|
clks_fb_fill_rect(clks_desktop.win_x, clks_desktop.win_y, clks_desktop.win_w, clks_desktop.win_title_h,
|
||||||
|
CLKS_DESKTOP_TITLE_COLOR);
|
||||||
|
|
||||||
|
clks_desktop_draw_text(12U, 6U, "CLeonOS Desktop TTY2", CLKS_DESKTOP_TEXT_FG, CLKS_DESKTOP_TOPBAR_COLOR);
|
||||||
|
clks_desktop_draw_text(clks_desktop.win_x + 12U, clks_desktop.win_y + 6U, "Mouse Input Ready",
|
||||||
|
CLKS_DESKTOP_TEXT_FG, CLKS_DESKTOP_TITLE_COLOR);
|
||||||
|
clks_desktop_draw_text(clks_desktop.win_x + 16U, clks_desktop.win_y + clks_desktop.win_title_h + 16U,
|
||||||
|
"Stage25: Alt+F2 desktop, Alt+F1 shell", CLKS_DESKTOP_TEXT_FG, CLKS_DESKTOP_WINDOW_COLOR);
|
||||||
|
|
||||||
|
clks_desktop_draw_status_widgets(mouse);
|
||||||
|
clks_desktop_scene_drawn = CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static clks_bool clks_desktop_cursor_pixel(u32 lx, u32 ly, u8 buttons, u32 *out_color) {
|
||||||
|
u32 fill = CLKS_DESKTOP_CURSOR_FILL;
|
||||||
|
|
||||||
|
if (out_color == CLKS_NULL) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((buttons & CLKS_MOUSE_BTN_LEFT) != 0U) {
|
||||||
|
fill = CLKS_DESKTOP_CURSOR_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ly < 12U) {
|
||||||
|
u32 span = (ly / 2U) + 1U;
|
||||||
|
|
||||||
|
if (lx < span) {
|
||||||
|
clks_bool border = (lx == 0U || (lx + 1U) == span || ly == 11U) ? CLKS_TRUE : CLKS_FALSE;
|
||||||
|
*out_color = (border == CLKS_TRUE) ? CLKS_DESKTOP_CURSOR_OUTLINE : fill;
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ly >= 8U && ly < 16U && lx >= 2U && lx < 5U) {
|
||||||
|
clks_bool border = (lx == 2U || lx == 4U || ly == 15U) ? CLKS_TRUE : CLKS_FALSE;
|
||||||
|
*out_color = (border == CLKS_TRUE) ? CLKS_DESKTOP_CURSOR_OUTLINE : fill;
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clks_desktop_capture_cursor_under(i32 x, i32 y) {
|
||||||
|
u32 ly;
|
||||||
|
|
||||||
|
for (ly = 0U; ly < CLKS_DESKTOP_CURSOR_H; ly++) {
|
||||||
|
u32 lx;
|
||||||
|
|
||||||
|
for (lx = 0U; lx < CLKS_DESKTOP_CURSOR_W; lx++) {
|
||||||
|
i32 gx = x + (i32)lx;
|
||||||
|
i32 gy = y + (i32)ly;
|
||||||
|
usize idx = ((usize)ly * (usize)CLKS_DESKTOP_CURSOR_W) + (usize)lx;
|
||||||
|
u32 pixel = CLKS_DESKTOP_BG_COLOR;
|
||||||
|
|
||||||
|
if (clks_desktop_in_bounds(gx, gy) == CLKS_TRUE) {
|
||||||
|
(void)clks_fb_read_pixel((u32)gx, (u32)gy, &pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_desktop_cursor_under[idx] = pixel;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clks_desktop_restore_cursor_under(void) {
|
||||||
|
u32 ly;
|
||||||
|
|
||||||
|
if (clks_desktop_cursor_drawn == CLKS_FALSE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ly = 0U; ly < CLKS_DESKTOP_CURSOR_H; ly++) {
|
||||||
|
u32 lx;
|
||||||
|
|
||||||
|
for (lx = 0U; lx < CLKS_DESKTOP_CURSOR_W; lx++) {
|
||||||
|
i32 gx = clks_desktop_last_mouse_x + (i32)lx;
|
||||||
|
i32 gy = clks_desktop_last_mouse_y + (i32)ly;
|
||||||
|
usize idx = ((usize)ly * (usize)CLKS_DESKTOP_CURSOR_W) + (usize)lx;
|
||||||
|
|
||||||
|
if (clks_desktop_in_bounds(gx, gy) == CLKS_TRUE) {
|
||||||
|
clks_fb_draw_pixel((u32)gx, (u32)gy, clks_desktop_cursor_under[idx]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_desktop_cursor_drawn = CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clks_desktop_draw_cursor(i32 x, i32 y, u8 buttons) {
|
||||||
|
u32 ly;
|
||||||
|
|
||||||
|
for (ly = 0U; ly < CLKS_DESKTOP_CURSOR_H; ly++) {
|
||||||
|
u32 lx;
|
||||||
|
|
||||||
|
for (lx = 0U; lx < CLKS_DESKTOP_CURSOR_W; lx++) {
|
||||||
|
i32 gx = x + (i32)lx;
|
||||||
|
i32 gy = y + (i32)ly;
|
||||||
|
u32 color = 0U;
|
||||||
|
|
||||||
|
if (clks_desktop_cursor_pixel(lx, ly, buttons, &color) == CLKS_FALSE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_desktop_in_bounds(gx, gy) == CLKS_TRUE) {
|
||||||
|
clks_fb_draw_pixel((u32)gx, (u32)gy, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_desktop_cursor_drawn = CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clks_desktop_present_cursor(const struct clks_mouse_state *mouse) {
|
||||||
|
if (mouse == CLKS_NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_desktop_restore_cursor_under();
|
||||||
|
clks_desktop_capture_cursor_under(mouse->x, mouse->y);
|
||||||
|
clks_desktop_draw_cursor(mouse->x, mouse->y, mouse->buttons);
|
||||||
|
|
||||||
|
clks_desktop_last_mouse_x = mouse->x;
|
||||||
|
clks_desktop_last_mouse_y = mouse->y;
|
||||||
|
clks_desktop_last_buttons = mouse->buttons;
|
||||||
|
clks_desktop_last_ready = mouse->ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clks_desktop_init(void) {
|
||||||
|
if (clks_fb_ready() == CLKS_FALSE) {
|
||||||
|
clks_desktop_ready_flag = CLKS_FALSE;
|
||||||
|
clks_log(CLKS_LOG_WARN, "DESK", "FRAMEBUFFER NOT READY; DESKTOP DISABLED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_desktop_compute_layout();
|
||||||
|
clks_desktop_ready_flag = CLKS_TRUE;
|
||||||
|
clks_desktop_active_last = CLKS_FALSE;
|
||||||
|
clks_desktop_scene_drawn = CLKS_FALSE;
|
||||||
|
clks_desktop_cursor_drawn = CLKS_FALSE;
|
||||||
|
clks_desktop_last_mouse_x = -1;
|
||||||
|
clks_desktop_last_mouse_y = -1;
|
||||||
|
clks_desktop_last_buttons = 0U;
|
||||||
|
clks_desktop_last_ready = CLKS_FALSE;
|
||||||
|
|
||||||
|
clks_log(CLKS_LOG_INFO, "DESK", "TTY2 DESKTOP ONLINE");
|
||||||
|
clks_log(CLKS_LOG_INFO, "DESK", "MOUSE-FIRST MODE ENABLED");
|
||||||
|
}
|
||||||
|
|
||||||
|
void clks_desktop_tick(u64 tick) {
|
||||||
|
struct clks_mouse_state mouse = {0, 0, 0U, 0ULL, CLKS_FALSE};
|
||||||
|
|
||||||
|
(void)tick;
|
||||||
|
|
||||||
|
if (clks_desktop_ready_flag == CLKS_FALSE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_tty_active() != CLKS_DESKTOP_TTY_INDEX) {
|
||||||
|
clks_desktop_active_last = CLKS_FALSE;
|
||||||
|
clks_desktop_scene_drawn = CLKS_FALSE;
|
||||||
|
clks_desktop_cursor_drawn = CLKS_FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_mouse_snapshot(&mouse);
|
||||||
|
|
||||||
|
if (clks_desktop_active_last == CLKS_FALSE || clks_desktop_scene_drawn == CLKS_FALSE) {
|
||||||
|
clks_desktop_compute_layout();
|
||||||
|
clks_desktop_draw_static_scene(&mouse);
|
||||||
|
clks_desktop_present_cursor(&mouse);
|
||||||
|
clks_desktop_active_last = CLKS_TRUE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouse.ready != clks_desktop_last_ready || mouse.buttons != clks_desktop_last_buttons) {
|
||||||
|
clks_desktop_draw_status_widgets(&mouse);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouse.x != clks_desktop_last_mouse_x || mouse.y != clks_desktop_last_mouse_y ||
|
||||||
|
mouse.buttons != clks_desktop_last_buttons) {
|
||||||
|
clks_desktop_present_cursor(&mouse);
|
||||||
|
} else {
|
||||||
|
clks_desktop_last_ready = mouse.ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_desktop_active_last = CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_bool clks_desktop_ready(void) {
|
||||||
|
return clks_desktop_ready_flag;
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <clks/interrupts.h>
|
#include <clks/interrupts.h>
|
||||||
#include <clks/log.h>
|
#include <clks/log.h>
|
||||||
#include <clks/keyboard.h>
|
#include <clks/keyboard.h>
|
||||||
|
#include <clks/mouse.h>
|
||||||
#include <clks/panic.h>
|
#include <clks/panic.h>
|
||||||
#include <clks/scheduler.h>
|
#include <clks/scheduler.h>
|
||||||
#include <clks/syscall.h>
|
#include <clks/syscall.h>
|
||||||
@@ -21,6 +22,7 @@
|
|||||||
#define CLKS_IRQ_BASE 32U
|
#define CLKS_IRQ_BASE 32U
|
||||||
#define CLKS_IRQ_TIMER 32U
|
#define CLKS_IRQ_TIMER 32U
|
||||||
#define CLKS_IRQ_KEYBOARD 33U
|
#define CLKS_IRQ_KEYBOARD 33U
|
||||||
|
#define CLKS_IRQ_MOUSE 44U
|
||||||
#define CLKS_IRQ_LAST 47U
|
#define CLKS_IRQ_LAST 47U
|
||||||
#define CLKS_SYSCALL_VECTOR 128U
|
#define CLKS_SYSCALL_VECTOR 128U
|
||||||
|
|
||||||
@@ -198,8 +200,8 @@ static void clks_pic_remap_and_mask(void) {
|
|||||||
(void)master_mask;
|
(void)master_mask;
|
||||||
(void)slave_mask;
|
(void)slave_mask;
|
||||||
|
|
||||||
clks_outb(CLKS_PIC1_DATA, 0xFCU);
|
clks_outb(CLKS_PIC1_DATA, 0xF8U);
|
||||||
clks_outb(CLKS_PIC2_DATA, 0xFFU);
|
clks_outb(CLKS_PIC2_DATA, 0xEFU);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clks_pic_send_eoi(u64 vector) {
|
static void clks_pic_send_eoi(u64 vector) {
|
||||||
@@ -259,6 +261,11 @@ void clks_interrupt_dispatch(struct clks_interrupt_frame *frame) {
|
|||||||
u8 scancode = clks_inb(CLKS_PS2_DATA_PORT);
|
u8 scancode = clks_inb(CLKS_PS2_DATA_PORT);
|
||||||
clks_keyboard_handle_scancode(scancode);
|
clks_keyboard_handle_scancode(scancode);
|
||||||
}
|
}
|
||||||
|
} else if (vector == CLKS_IRQ_MOUSE) {
|
||||||
|
if (clks_ps2_has_output() == CLKS_TRUE) {
|
||||||
|
u8 data_byte = clks_inb(CLKS_PS2_DATA_PORT);
|
||||||
|
clks_mouse_handle_byte(data_byte);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vector >= CLKS_IRQ_BASE && vector <= CLKS_IRQ_LAST) {
|
if (vector >= CLKS_IRQ_BASE && vector <= CLKS_IRQ_LAST) {
|
||||||
|
|||||||
@@ -101,6 +101,10 @@ static clks_bool clks_keyboard_queue_push(char ch) {
|
|||||||
return CLKS_TRUE;
|
return CLKS_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static clks_bool clks_keyboard_shell_input_enabled(void) {
|
||||||
|
return (clks_tty_active() == 0U) ? CLKS_TRUE : CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static char clks_keyboard_translate_scancode(u8 code) {
|
static char clks_keyboard_translate_scancode(u8 code) {
|
||||||
clks_bool shift_active = (clks_kbd_lshift_down == CLKS_TRUE || clks_kbd_rshift_down == CLKS_TRUE)
|
clks_bool shift_active = (clks_kbd_lshift_down == CLKS_TRUE || clks_kbd_rshift_down == CLKS_TRUE)
|
||||||
? CLKS_TRUE
|
? CLKS_TRUE
|
||||||
@@ -169,7 +173,7 @@ void clks_keyboard_handle_scancode(u8 scancode) {
|
|||||||
char ext = clks_keyboard_translate_ext_scancode(code);
|
char ext = clks_keyboard_translate_ext_scancode(code);
|
||||||
clks_kbd_e0_prefix = CLKS_FALSE;
|
clks_kbd_e0_prefix = CLKS_FALSE;
|
||||||
|
|
||||||
if (ext != '\0') {
|
if (ext != '\0' && clks_keyboard_shell_input_enabled() == CLKS_TRUE) {
|
||||||
if (clks_keyboard_queue_push(ext) == CLKS_TRUE) {
|
if (clks_keyboard_queue_push(ext) == CLKS_TRUE) {
|
||||||
clks_shell_pump_input(1U);
|
clks_shell_pump_input(1U);
|
||||||
}
|
}
|
||||||
@@ -199,7 +203,7 @@ void clks_keyboard_handle_scancode(u8 scancode) {
|
|||||||
{
|
{
|
||||||
char translated = clks_keyboard_translate_scancode(code);
|
char translated = clks_keyboard_translate_scancode(code);
|
||||||
|
|
||||||
if (translated != '\0') {
|
if (translated != '\0' && clks_keyboard_shell_input_enabled() == CLKS_TRUE) {
|
||||||
if (clks_keyboard_queue_push(translated) == CLKS_TRUE) {
|
if (clks_keyboard_queue_push(translated) == CLKS_TRUE) {
|
||||||
clks_shell_pump_input(1U);
|
clks_shell_pump_input(1U);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <clks/boot.h>
|
#include <clks/boot.h>
|
||||||
#include <clks/cpu.h>
|
#include <clks/cpu.h>
|
||||||
|
#include <clks/desktop.h>
|
||||||
#include <clks/driver.h>
|
#include <clks/driver.h>
|
||||||
#include <clks/elfrunner.h>
|
#include <clks/elfrunner.h>
|
||||||
#include <clks/exec.h>
|
#include <clks/exec.h>
|
||||||
@@ -13,6 +14,7 @@
|
|||||||
#include <clks/kelf.h>
|
#include <clks/kelf.h>
|
||||||
#include <clks/kernel.h>
|
#include <clks/kernel.h>
|
||||||
#include <clks/log.h>
|
#include <clks/log.h>
|
||||||
|
#include <clks/mouse.h>
|
||||||
#include <clks/pmm.h>
|
#include <clks/pmm.h>
|
||||||
#include <clks/scheduler.h>
|
#include <clks/scheduler.h>
|
||||||
#include <clks/serial.h>
|
#include <clks/serial.h>
|
||||||
@@ -65,6 +67,7 @@ static void clks_task_kelfd(u64 tick) {
|
|||||||
static void clks_task_usrd(u64 tick) {
|
static void clks_task_usrd(u64 tick) {
|
||||||
clks_service_heartbeat(CLKS_SERVICE_USER, tick);
|
clks_service_heartbeat(CLKS_SERVICE_USER, tick);
|
||||||
clks_userland_tick(tick);
|
clks_userland_tick(tick);
|
||||||
|
clks_desktop_tick(tick);
|
||||||
clks_tty_tick(tick);
|
clks_tty_tick(tick);
|
||||||
clks_shell_tick(tick);
|
clks_shell_tick(tick);
|
||||||
}
|
}
|
||||||
@@ -96,7 +99,7 @@ void clks_kernel_main(void) {
|
|||||||
clks_tty_init();
|
clks_tty_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS Stage24 START");
|
clks_log(CLKS_LOG_INFO, "BOOT", "CLEONOS Stage25 START");
|
||||||
|
|
||||||
if (boot_fb == CLKS_NULL) {
|
if (boot_fb == CLKS_NULL) {
|
||||||
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
|
clks_log(CLKS_LOG_WARN, "VIDEO", "NO FRAMEBUFFER FROM LIMINE");
|
||||||
@@ -172,6 +175,8 @@ void clks_kernel_main(void) {
|
|||||||
|
|
||||||
clks_exec_init();
|
clks_exec_init();
|
||||||
clks_keyboard_init();
|
clks_keyboard_init();
|
||||||
|
clks_mouse_init();
|
||||||
|
clks_desktop_init();
|
||||||
|
|
||||||
if (clks_userland_init() == CLKS_FALSE) {
|
if (clks_userland_init() == CLKS_FALSE) {
|
||||||
clks_log(CLKS_LOG_ERROR, "USER", "USERLAND INIT FAILED");
|
clks_log(CLKS_LOG_ERROR, "USER", "USERLAND INIT FAILED");
|
||||||
|
|||||||
308
clks/kernel/mouse.c
Normal file
308
clks/kernel/mouse.c
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
#include <clks/framebuffer.h>
|
||||||
|
#include <clks/log.h>
|
||||||
|
#include <clks/mouse.h>
|
||||||
|
#include <clks/types.h>
|
||||||
|
|
||||||
|
#define CLKS_PS2_DATA_PORT 0x60U
|
||||||
|
#define CLKS_PS2_STATUS_PORT 0x64U
|
||||||
|
#define CLKS_PS2_CMD_PORT 0x64U
|
||||||
|
#define CLKS_PS2_STATUS_OBF 0x01U
|
||||||
|
#define CLKS_PS2_STATUS_IBF 0x02U
|
||||||
|
|
||||||
|
#define CLKS_PS2_CMD_ENABLE_AUX 0xA8U
|
||||||
|
#define CLKS_PS2_CMD_READ_CFG 0x20U
|
||||||
|
#define CLKS_PS2_CMD_WRITE_CFG 0x60U
|
||||||
|
#define CLKS_PS2_CMD_WRITE_AUX 0xD4U
|
||||||
|
|
||||||
|
#define CLKS_PS2_MOUSE_CMD_RESET_DEFAULTS 0xF6U
|
||||||
|
#define CLKS_PS2_MOUSE_CMD_ENABLE_STREAM 0xF4U
|
||||||
|
#define CLKS_PS2_MOUSE_ACK 0xFAU
|
||||||
|
|
||||||
|
#define CLKS_MOUSE_IO_TIMEOUT 100000U
|
||||||
|
#define CLKS_MOUSE_DRAIN_MAX 64U
|
||||||
|
#define CLKS_MOUSE_SYNC_BIT 0x08U
|
||||||
|
#define CLKS_MOUSE_OVERFLOW_MASK 0xC0U
|
||||||
|
#define CLKS_MOUSE_BUTTON_MASK 0x07U
|
||||||
|
|
||||||
|
struct clks_mouse_runtime {
|
||||||
|
i32 x;
|
||||||
|
i32 y;
|
||||||
|
u32 max_x;
|
||||||
|
u32 max_y;
|
||||||
|
u8 buttons;
|
||||||
|
u8 packet[3];
|
||||||
|
u8 packet_index;
|
||||||
|
u64 packet_count;
|
||||||
|
u64 drop_count;
|
||||||
|
clks_bool ready;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct clks_mouse_runtime clks_mouse = {
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.max_x = 0U,
|
||||||
|
.max_y = 0U,
|
||||||
|
.buttons = 0U,
|
||||||
|
.packet = {0U, 0U, 0U},
|
||||||
|
.packet_index = 0U,
|
||||||
|
.packet_count = 0ULL,
|
||||||
|
.drop_count = 0ULL,
|
||||||
|
.ready = CLKS_FALSE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void clks_mouse_outb(u16 port, u8 value) {
|
||||||
|
__asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u8 clks_mouse_inb(u16 port) {
|
||||||
|
u8 value;
|
||||||
|
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static clks_bool clks_mouse_wait_input_empty(void) {
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0U; i < CLKS_MOUSE_IO_TIMEOUT; i++) {
|
||||||
|
if ((clks_mouse_inb(CLKS_PS2_STATUS_PORT) & CLKS_PS2_STATUS_IBF) == 0U) {
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static clks_bool clks_mouse_wait_output_ready(void) {
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0U; i < CLKS_MOUSE_IO_TIMEOUT; i++) {
|
||||||
|
if ((clks_mouse_inb(CLKS_PS2_STATUS_PORT) & CLKS_PS2_STATUS_OBF) != 0U) {
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static clks_bool clks_mouse_write_cmd(u8 cmd) {
|
||||||
|
if (clks_mouse_wait_input_empty() == CLKS_FALSE) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_mouse_outb(CLKS_PS2_CMD_PORT, cmd);
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static clks_bool clks_mouse_write_data(u8 value) {
|
||||||
|
if (clks_mouse_wait_input_empty() == CLKS_FALSE) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_mouse_outb(CLKS_PS2_DATA_PORT, value);
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static clks_bool clks_mouse_read_data(u8 *out_value) {
|
||||||
|
if (out_value == CLKS_NULL) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_mouse_wait_output_ready() == CLKS_FALSE) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_value = clks_mouse_inb(CLKS_PS2_DATA_PORT);
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clks_mouse_drain_output(void) {
|
||||||
|
u32 i;
|
||||||
|
|
||||||
|
for (i = 0U; i < CLKS_MOUSE_DRAIN_MAX; i++) {
|
||||||
|
if ((clks_mouse_inb(CLKS_PS2_STATUS_PORT) & CLKS_PS2_STATUS_OBF) == 0U) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)clks_mouse_inb(CLKS_PS2_DATA_PORT);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static clks_bool clks_mouse_send_device_cmd(u8 cmd, u8 *out_ack) {
|
||||||
|
u8 ack = 0U;
|
||||||
|
|
||||||
|
if (clks_mouse_write_cmd(CLKS_PS2_CMD_WRITE_AUX) == CLKS_FALSE) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_mouse_write_data(cmd) == CLKS_FALSE) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_mouse_read_data(&ack) == CLKS_FALSE) {
|
||||||
|
return CLKS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_ack != CLKS_NULL) {
|
||||||
|
*out_ack = ack;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CLKS_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void clks_mouse_reset_runtime(void) {
|
||||||
|
struct clks_framebuffer_info info;
|
||||||
|
|
||||||
|
clks_mouse.x = 0;
|
||||||
|
clks_mouse.y = 0;
|
||||||
|
clks_mouse.max_x = 0U;
|
||||||
|
clks_mouse.max_y = 0U;
|
||||||
|
clks_mouse.buttons = 0U;
|
||||||
|
clks_mouse.packet[0] = 0U;
|
||||||
|
clks_mouse.packet[1] = 0U;
|
||||||
|
clks_mouse.packet[2] = 0U;
|
||||||
|
clks_mouse.packet_index = 0U;
|
||||||
|
clks_mouse.packet_count = 0ULL;
|
||||||
|
clks_mouse.drop_count = 0ULL;
|
||||||
|
clks_mouse.ready = CLKS_FALSE;
|
||||||
|
|
||||||
|
if (clks_fb_ready() == CLKS_TRUE) {
|
||||||
|
info = clks_fb_info();
|
||||||
|
|
||||||
|
if (info.width > 0U) {
|
||||||
|
clks_mouse.max_x = info.width - 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.height > 0U) {
|
||||||
|
clks_mouse.max_y = info.height - 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_mouse.x = (i32)(clks_mouse.max_x / 2U);
|
||||||
|
clks_mouse.y = (i32)(clks_mouse.max_y / 2U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clks_mouse_init(void) {
|
||||||
|
u8 config = 0U;
|
||||||
|
u8 ack = 0U;
|
||||||
|
|
||||||
|
clks_mouse_reset_runtime();
|
||||||
|
clks_mouse_drain_output();
|
||||||
|
|
||||||
|
if (clks_mouse_write_cmd(CLKS_PS2_CMD_ENABLE_AUX) == CLKS_FALSE) {
|
||||||
|
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 ENABLE AUX FAILED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_mouse_write_cmd(CLKS_PS2_CMD_READ_CFG) == CLKS_FALSE ||
|
||||||
|
clks_mouse_read_data(&config) == CLKS_FALSE) {
|
||||||
|
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 READ CFG FAILED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
config |= 0x02U;
|
||||||
|
config &= (u8)~0x20U;
|
||||||
|
|
||||||
|
if (clks_mouse_write_cmd(CLKS_PS2_CMD_WRITE_CFG) == CLKS_FALSE ||
|
||||||
|
clks_mouse_write_data(config) == CLKS_FALSE) {
|
||||||
|
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 WRITE CFG FAILED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_mouse_send_device_cmd(CLKS_PS2_MOUSE_CMD_RESET_DEFAULTS, &ack) == CLKS_FALSE ||
|
||||||
|
ack != CLKS_PS2_MOUSE_ACK) {
|
||||||
|
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 RESET DEFAULTS FAILED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_mouse_send_device_cmd(CLKS_PS2_MOUSE_CMD_ENABLE_STREAM, &ack) == CLKS_FALSE ||
|
||||||
|
ack != CLKS_PS2_MOUSE_ACK) {
|
||||||
|
clks_log(CLKS_LOG_WARN, "MOUSE", "PS2 ENABLE STREAM FAILED");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_mouse.ready = CLKS_TRUE;
|
||||||
|
clks_log(CLKS_LOG_INFO, "MOUSE", "PS2 POINTER ONLINE");
|
||||||
|
clks_log_hex(CLKS_LOG_INFO, "MOUSE", "MAX_X", (u64)clks_mouse.max_x);
|
||||||
|
clks_log_hex(CLKS_LOG_INFO, "MOUSE", "MAX_Y", (u64)clks_mouse.max_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clks_mouse_handle_byte(u8 data_byte) {
|
||||||
|
i32 dx;
|
||||||
|
i32 dy;
|
||||||
|
i32 next_x;
|
||||||
|
i32 next_y;
|
||||||
|
u8 status;
|
||||||
|
|
||||||
|
if (clks_mouse.ready == CLKS_FALSE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clks_mouse.packet_index == 0U && (data_byte & CLKS_MOUSE_SYNC_BIT) == 0U) {
|
||||||
|
clks_mouse.drop_count++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_mouse.packet[clks_mouse.packet_index] = data_byte;
|
||||||
|
clks_mouse.packet_index++;
|
||||||
|
|
||||||
|
if (clks_mouse.packet_index < 3U) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_mouse.packet_index = 0U;
|
||||||
|
clks_mouse.packet_count++;
|
||||||
|
|
||||||
|
status = clks_mouse.packet[0];
|
||||||
|
clks_mouse.buttons = (u8)(status & CLKS_MOUSE_BUTTON_MASK);
|
||||||
|
|
||||||
|
if ((status & CLKS_MOUSE_OVERFLOW_MASK) != 0U) {
|
||||||
|
clks_mouse.drop_count++;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dx = (i32)((i8)clks_mouse.packet[1]);
|
||||||
|
dy = (i32)((i8)clks_mouse.packet[2]);
|
||||||
|
|
||||||
|
next_x = clks_mouse.x + dx;
|
||||||
|
next_y = clks_mouse.y - dy;
|
||||||
|
|
||||||
|
if (next_x < 0) {
|
||||||
|
clks_mouse.x = 0;
|
||||||
|
} else if ((u32)next_x > clks_mouse.max_x) {
|
||||||
|
clks_mouse.x = (i32)clks_mouse.max_x;
|
||||||
|
} else {
|
||||||
|
clks_mouse.x = next_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next_y < 0) {
|
||||||
|
clks_mouse.y = 0;
|
||||||
|
} else if ((u32)next_y > clks_mouse.max_y) {
|
||||||
|
clks_mouse.y = (i32)clks_mouse.max_y;
|
||||||
|
} else {
|
||||||
|
clks_mouse.y = next_y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clks_mouse_snapshot(struct clks_mouse_state *out_state) {
|
||||||
|
if (out_state == CLKS_NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
out_state->x = clks_mouse.x;
|
||||||
|
out_state->y = clks_mouse.y;
|
||||||
|
out_state->buttons = clks_mouse.buttons;
|
||||||
|
out_state->packet_count = clks_mouse.packet_count;
|
||||||
|
out_state->ready = clks_mouse.ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
clks_bool clks_mouse_ready(void) {
|
||||||
|
return clks_mouse.ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 clks_mouse_packet_count(void) {
|
||||||
|
return clks_mouse.packet_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 clks_mouse_drop_count(void) {
|
||||||
|
return clks_mouse.drop_count;
|
||||||
|
}
|
||||||
@@ -11,6 +11,7 @@
|
|||||||
#define CLKS_TTY_BG 0x00101010U
|
#define CLKS_TTY_BG 0x00101010U
|
||||||
#define CLKS_TTY_CURSOR_BLINK_INTERVAL_TICKS 5ULL
|
#define CLKS_TTY_CURSOR_BLINK_INTERVAL_TICKS 5ULL
|
||||||
#define CLKS_TTY_BLINK_TICK_UNSET 0xFFFFFFFFFFFFFFFFULL
|
#define CLKS_TTY_BLINK_TICK_UNSET 0xFFFFFFFFFFFFFFFFULL
|
||||||
|
#define CLKS_TTY_DESKTOP_INDEX 1U
|
||||||
|
|
||||||
static char clks_tty_cells[CLKS_TTY_COUNT][CLKS_TTY_MAX_ROWS][CLKS_TTY_MAX_COLS];
|
static char clks_tty_cells[CLKS_TTY_COUNT][CLKS_TTY_MAX_ROWS][CLKS_TTY_MAX_COLS];
|
||||||
static u32 clks_tty_cursor_row[CLKS_TTY_COUNT];
|
static u32 clks_tty_cursor_row[CLKS_TTY_COUNT];
|
||||||
@@ -72,6 +73,11 @@ static void clks_tty_draw_cursor(void) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clks_tty_active_index == CLKS_TTY_DESKTOP_INDEX) {
|
||||||
|
clks_tty_cursor_visible = CLKS_FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
row = clks_tty_cursor_row[clks_tty_active_index];
|
row = clks_tty_cursor_row[clks_tty_active_index];
|
||||||
col = clks_tty_cursor_col[clks_tty_active_index];
|
col = clks_tty_cursor_col[clks_tty_active_index];
|
||||||
|
|
||||||
@@ -311,6 +317,11 @@ void clks_tty_tick(u64 tick) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clks_tty_active_index == CLKS_TTY_DESKTOP_INDEX) {
|
||||||
|
clks_tty_cursor_visible = CLKS_FALSE;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (clks_tty_blink_last_tick == CLKS_TTY_BLINK_TICK_UNSET) {
|
if (clks_tty_blink_last_tick == CLKS_TTY_BLINK_TICK_UNSET) {
|
||||||
clks_tty_blink_last_tick = tick;
|
clks_tty_blink_last_tick = tick;
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@
|
|||||||
- `stage22.md`
|
- `stage22.md`
|
||||||
- `stage23.md`
|
- `stage23.md`
|
||||||
- `stage24.md`
|
- `stage24.md`
|
||||||
|
- `stage25.md`
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
- Stage docs use a fixed template: goal, implementation, acceptance criteria, build targets, QEMU command, and debugging notes.
|
- Stage docs use a fixed template: goal, implementation, acceptance criteria, build targets, QEMU command, and debugging notes.
|
||||||
- Stages 16~19 are currently not documented in this folder; add them later using the same template to keep history continuous.
|
- Stages 16~19 are currently not documented in this folder; add them later using the same template to keep history continuous.
|
||||||
|
|||||||
64
docs/stage25.md
Normal file
64
docs/stage25.md
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# CLeonOS Stage25
|
||||||
|
|
||||||
|
## Stage Goal
|
||||||
|
- Make `tty2` (Alt+F2) enter a basic desktop environment.
|
||||||
|
- Add first-step mouse support (PS/2 mouse IRQ and on-screen pointer).
|
||||||
|
- Keep kernel shell on `tty1` (Alt+F1) unchanged.
|
||||||
|
|
||||||
|
## What Was Implemented
|
||||||
|
- New kernel modules:
|
||||||
|
- `clks/kernel/mouse.c`
|
||||||
|
- `clks/kernel/desktop.c`
|
||||||
|
- New public headers:
|
||||||
|
- `clks/include/clks/mouse.h`
|
||||||
|
- `clks/include/clks/desktop.h`
|
||||||
|
- Interrupt and PIC updates:
|
||||||
|
- Enable PIC cascade + mouse IRQ line.
|
||||||
|
- Route IRQ12 (`vector 44`) to mouse byte handler.
|
||||||
|
- PS/2 mouse bring-up:
|
||||||
|
- Enable aux device.
|
||||||
|
- Set controller config for mouse IRQ.
|
||||||
|
- Send mouse commands (`F6`, `F4`) and verify ACK.
|
||||||
|
- Decode 3-byte PS/2 packets into X/Y/buttons.
|
||||||
|
- Desktop on tty2:
|
||||||
|
- `clks_desktop_tick()` renders a simple graphical desktop scene.
|
||||||
|
- Draw software mouse cursor and button state indicator.
|
||||||
|
- Refresh when pointer changes and periodically to keep desktop clean.
|
||||||
|
- TTY adjustments:
|
||||||
|
- Disable text cursor blinking on `tty2` to avoid desktop overlay artifacts.
|
||||||
|
- Keyboard routing adjustment:
|
||||||
|
- Shell input queue only accepts character input while active TTY is `tty1` (index 0).
|
||||||
|
- Alt+F1..F4 switching remains available globally.
|
||||||
|
- Framebuffer primitives:
|
||||||
|
- Added `clks_fb_draw_pixel()` and `clks_fb_fill_rect()` for desktop rendering.
|
||||||
|
- Kernel flow integration:
|
||||||
|
- Stage banner -> `CLEONOS Stage25 START`.
|
||||||
|
- Initialize mouse + desktop during boot.
|
||||||
|
- Call desktop tick in `usrd` task.
|
||||||
|
|
||||||
|
## Acceptance Criteria
|
||||||
|
- Boot log shows `CLEONOS Stage25 START`.
|
||||||
|
- Alt+F1 enters shell TTY; shell input works as before.
|
||||||
|
- Alt+F2 switches to desktop view (non-text UI).
|
||||||
|
- Mouse movement updates on-screen pointer in tty2.
|
||||||
|
- Left mouse button changes pointer/indicator state.
|
||||||
|
|
||||||
|
## Build Targets
|
||||||
|
- `make setup`
|
||||||
|
- `make userapps`
|
||||||
|
- `make iso`
|
||||||
|
- `make run`
|
||||||
|
- `make debug`
|
||||||
|
|
||||||
|
## QEMU Command
|
||||||
|
- `qemu-system-x86_64 -M q35 -m 1024M -cdrom build/CLeonOS-x86_64.iso -serial stdio`
|
||||||
|
|
||||||
|
## Common Bugs and Debugging
|
||||||
|
- Desktop not visible after Alt+F2:
|
||||||
|
- Check `clks_desktop_init()` log lines and confirm framebuffer is ready.
|
||||||
|
- Mouse pointer does not move:
|
||||||
|
- Check mouse init logs (`PS2 POINTER ONLINE`) and IRQ12 routing in `interrupts.c`.
|
||||||
|
- Frequent text artifacts on desktop:
|
||||||
|
- Ensure desktop periodic redraw is active in `clks_desktop_tick()`.
|
||||||
|
- Shell unexpectedly receives input while on desktop:
|
||||||
|
- Verify keyboard routing guard uses `clks_tty_active() == 0`.
|
||||||
Reference in New Issue
Block a user