Files
SUB-OS/gui/gui_wm.c
T
subhobhai943 4568a9ab4e feat(gui): Upgrade to high-res 800x600, sharp 8x16 font, IRQ12 PS/2 mouse driver, and polished window manager
- Upgrade resolution to 800x600 @ 32bpp TrueColor with Bochs/QEMU VBE LFB
- Implement full 8042 Aux PS/2 mouse controller driver on IRQ 12 (vector 44) with packet decode and bounds clamping
- Add high-definition 8x16 font rasterizer with text drop shadows for sharp typography
- Upgrade to smooth 16x24 anti-aliased cursor with dark slate outline and drop shadow
- Increase titlebars to 24px and taskbar to 32px with modern desktop styling
- Re-architect applications (SysMon, Terminal, Explorer, Calc, Paint, About) for spacious high-res display
2026-08-21 03:18:38 +05:30

293 lines
9.6 KiB
C

// SUB-OS Window Manager (SUB-WM) Compositor
#include <gui/gui_wm.h>
#include <lib/string.h>
#include <mm/kmalloc.h>
static gui_window_t g_windows[GUI_MAX_WINDOWS];
static int g_window_order[GUI_MAX_WINDOWS]; // Z-order (top window is at index g_num_windows - 1)
static int g_num_windows = 0;
static int g_next_win_id = 1;
static int g_drag_win_id = -1;
static bool g_prev_btn_left = false;
void gui_wm_init(void) {
memset(g_windows, 0, sizeof(g_windows));
g_num_windows = 0;
g_next_win_id = 1;
g_drag_win_id = -1;
g_prev_btn_left = false;
}
gui_window_t* gui_wm_create_window(const char* title, int x, int y, int w, int h) {
if (g_num_windows >= GUI_MAX_WINDOWS) return NULL;
int slot = -1;
for (int i = 0; i < GUI_MAX_WINDOWS; i++) {
if (g_windows[i].id == 0) {
slot = i;
break;
}
}
if (slot == -1) return NULL;
gui_window_t* win = &g_windows[slot];
win->id = g_next_win_id++;
strncpy(win->title, title ? title : "Window", sizeof(win->title) - 1);
win->x = x;
win->y = y;
win->width = (w > 100) ? w : 100;
win->height = (h > 60) ? h : 60;
win->visible = true;
win->minimized = false;
win->active = true;
win->is_dragging = false;
win->user_data = NULL;
win->paint = NULL;
win->handle_event = NULL;
g_window_order[g_num_windows] = win->id;
g_num_windows++;
gui_wm_focus_window(win->id);
return win;
}
void gui_wm_destroy_window(int win_id) {
int idx = -1;
for (int i = 0; i < g_num_windows; i++) {
if (g_window_order[i] == win_id) {
idx = i;
break;
}
}
if (idx != -1) {
for (int i = idx; i < g_num_windows - 1; i++) {
g_window_order[i] = g_window_order[i + 1];
}
g_num_windows--;
}
for (int i = 0; i < GUI_MAX_WINDOWS; i++) {
if (g_windows[i].id == win_id) {
if (g_windows[i].handle_event) {
gui_event_t ev = { .type = GUI_EVENT_CLOSE };
g_windows[i].handle_event(&g_windows[i], &ev);
}
memset(&g_windows[i], 0, sizeof(gui_window_t));
break;
}
}
if (g_num_windows > 0) {
gui_wm_focus_window(g_window_order[g_num_windows - 1]);
}
}
void gui_wm_focus_window(int win_id) {
int idx = -1;
for (int i = 0; i < g_num_windows; i++) {
if (g_window_order[i] == win_id) {
idx = i;
break;
}
}
if (idx != -1 && idx != g_num_windows - 1) {
int target = g_window_order[idx];
for (int i = idx; i < g_num_windows - 1; i++) {
g_window_order[i] = g_window_order[i + 1];
}
g_window_order[g_num_windows - 1] = target;
}
for (int i = 0; i < GUI_MAX_WINDOWS; i++) {
if (g_windows[i].id != 0) {
bool is_active = (g_windows[i].id == win_id);
if (g_windows[i].active != is_active) {
g_windows[i].active = is_active;
if (is_active && g_windows[i].handle_event) {
gui_event_t ev = { .type = GUI_EVENT_FOCUS };
g_windows[i].handle_event(&g_windows[i], &ev);
}
}
}
}
}
gui_window_t* gui_wm_get_window(int win_id) {
for (int i = 0; i < GUI_MAX_WINDOWS; i++) {
if (g_windows[i].id == win_id) return &g_windows[i];
}
return NULL;
}
gui_window_t* gui_wm_get_active_window(void) {
if (g_num_windows == 0) return NULL;
int top_id = g_window_order[g_num_windows - 1];
return gui_wm_get_window(top_id);
}
int gui_wm_get_window_count(void) {
return g_num_windows;
}
void gui_wm_handle_mouse(int mx, int my, bool btn_left, bool btn_right) {
// Handle ongoing drag
if (g_drag_win_id != -1) {
if (!btn_left) {
gui_window_t* win = gui_wm_get_window(g_drag_win_id);
if (win) win->is_dragging = false;
g_drag_win_id = -1;
} else {
gui_window_t* win = gui_wm_get_window(g_drag_win_id);
if (win) {
win->x = mx - win->drag_off_x;
win->y = my - win->drag_off_y;
if (win->y < 0) win->y = 0;
if (win->x + win->width < 40) win->x = 40 - win->width;
}
g_prev_btn_left = btn_left;
return;
}
}
// Process top-down clicks
if (btn_left && !g_prev_btn_left) {
for (int i = g_num_windows - 1; i >= 0; i--) {
int win_id = g_window_order[i];
gui_window_t* win = gui_wm_get_window(win_id);
if (!win || !win->visible || win->minimized) continue;
// Check titlebar hit
if (mx >= win->x && mx < win->x + win->width &&
my >= win->y && my < win->y + GUI_TITLEBAR_HEIGHT) {
gui_wm_focus_window(win->id);
// Close button [X] at (win->x + win->width - 20, win->y + 5, 14x14)
if (mx >= win->x + win->width - 20 && mx <= win->x + win->width - 6) {
gui_wm_destroy_window(win->id);
g_prev_btn_left = btn_left;
return;
}
// Titlebar drag start
g_drag_win_id = win->id;
win->is_dragging = true;
win->drag_off_x = mx - win->x;
win->drag_off_y = my - win->y;
g_prev_btn_left = btn_left;
return;
}
// Check client area hit
if (mx >= win->x && mx < win->x + win->width &&
my >= win->y + GUI_TITLEBAR_HEIGHT && my < win->y + win->height) {
gui_wm_focus_window(win->id);
if (win->handle_event) {
gui_event_t ev = {
.type = GUI_EVENT_MOUSE_DOWN,
.mouse_x = mx,
.mouse_y = my,
.rel_x = mx - win->x,
.rel_y = my - (win->y + GUI_TITLEBAR_HEIGHT),
.btn_left = btn_left,
.btn_right = btn_right
};
win->handle_event(win, &ev);
}
g_prev_btn_left = btn_left;
return;
}
}
} else if (!btn_left && g_prev_btn_left) {
// Mouse Up event
gui_window_t* active = gui_wm_get_active_window();
if (active && active->handle_event) {
gui_event_t ev = {
.type = GUI_EVENT_MOUSE_UP,
.mouse_x = mx,
.mouse_y = my,
.rel_x = mx - active->x,
.rel_y = my - (active->y + GUI_TITLEBAR_HEIGHT),
.btn_left = btn_left,
.btn_right = btn_right
};
active->handle_event(active, &ev);
}
} else {
// Mouse Move event
gui_window_t* active = gui_wm_get_active_window();
if (active && active->handle_event) {
gui_event_t ev = {
.type = GUI_EVENT_MOUSE_MOVE,
.mouse_x = mx,
.mouse_y = my,
.rel_x = mx - active->x,
.rel_y = my - (active->y + GUI_TITLEBAR_HEIGHT),
.btn_left = btn_left,
.btn_right = btn_right
};
active->handle_event(active, &ev);
}
}
g_prev_btn_left = btn_left;
}
void gui_wm_handle_key(uint16_t key) {
gui_window_t* active = gui_wm_get_active_window();
if (active && active->handle_event) {
gui_event_t ev = {
.type = GUI_EVENT_KEY_DOWN,
.key = key
};
active->handle_event(active, &ev);
}
}
void gui_wm_render(void) {
// Render windows from bottom to top
for (int i = 0; i < g_num_windows; i++) {
int win_id = g_window_order[i];
gui_window_t* win = gui_wm_get_window(win_id);
if (!win || !win->visible || win->minimized) continue;
// Window Drop Shadow
gui_gfx_draw_shadow(win->x, win->y, win->width, win->height, 6);
// Window Outer Border
uint32_t border_col = win->active ? GUI_THEME_PRIMARY : GUI_THEME_BORDER;
gui_gfx_draw_rect(win->x, win->y, win->width, win->height, border_col);
// Titlebar Background Gradient
uint32_t top_bg = win->active ? 0xFF1E293B : 0xFF0F172A;
uint32_t bot_bg = win->active ? 0xFF0F172A : 0xFF0A0E1A;
gui_gfx_draw_gradient_v(win->x + 1, win->y + 1, win->width - 2, GUI_TITLEBAR_HEIGHT - 1, top_bg, bot_bg);
// Titlebar Separator
gui_gfx_draw_line(win->x, win->y + GUI_TITLEBAR_HEIGHT, win->x + win->width - 1, win->y + GUI_TITLEBAR_HEIGHT, border_col);
// Titlebar Window Title Text (Large sharp 8x16 font)
uint32_t title_fg = win->active ? GUI_THEME_TEXT_MAIN : GUI_THEME_TEXT_MUTED;
gui_gfx_draw_string_16_shadow(win->x + 8, win->y + 4, win->title, title_fg, GUI_COLOR_BLACK);
// Close Button [X]
int close_x = win->x + win->width - 20;
int close_y = win->y + 5;
gui_gfx_fill_rect(close_x, close_y, 14, 14, GUI_THEME_BTN_CLOSE);
gui_gfx_draw_rect(close_x, close_y, 14, 14, 0xFF991B1B);
gui_gfx_draw_line(close_x + 3, close_y + 3, close_x + 10, close_y + 10, GUI_COLOR_WHITE);
gui_gfx_draw_line(close_x + 10, close_y + 3, close_x + 3, close_y + 10, GUI_COLOR_WHITE);
// Client Area Background
gui_gfx_fill_rect(win->x + 1, win->y + GUI_TITLEBAR_HEIGHT + 1, win->width - 2, win->height - GUI_TITLEBAR_HEIGHT - 2, GUI_THEME_BG_SURFACE);
// Custom Window Paint Routine
if (win->paint) {
win->paint(win);
}
}
}