1027 lines
44 KiB
C++
1027 lines
44 KiB
C++
/**
|
|
* opencoreC - Desktop GUI Server (Ring 3 User Space)
|
|
* Windows / KDE-inspired Desktop Environment powered by LVGL v8.3.
|
|
* Features:
|
|
* - Custom 16x24 high-contrast hardware arrow cursor on lv_layer_sys()
|
|
* - Smooth window dragging with boundary clamping
|
|
* - Dedicated PS/2 keyboard integration for terminal
|
|
* - Bottom Taskbar with Start Menu, Running App tabs & System Tray
|
|
* - Interactive Terminal (Console) application with real system commands
|
|
* - Task Manager with real-time CPU chart & thread table
|
|
* - Network Center with RTL8139 PCI diagnostics & Ping
|
|
* - About opencoreC dialog
|
|
* - Safe System Poweroff via Start Menu (SYS_SHUTDOWN)
|
|
*/
|
|
|
|
#include "lvgl.h"
|
|
#include "abi/syscalls.h"
|
|
#include "abi/net.h"
|
|
#include "stdio.h"
|
|
#include "string.h"
|
|
#include "stdlib.h"
|
|
|
|
extern "C" {
|
|
void net_init(void);
|
|
int net_send_icmp_ping(uint32_t target_ip, uint16_t seq);
|
|
}
|
|
|
|
// Framebuffer and display driver structures
|
|
static fb_info_t g_fb = {0, 0, 0, 0, 0};
|
|
static lv_disp_drv_t g_disp_drv;
|
|
static lv_indev_drv_t g_mouse_indev_drv;
|
|
static lv_indev_drv_t g_kbd_indev_drv;
|
|
static lv_indev_t *g_mouse_indev = NULL;
|
|
static lv_indev_t *g_kbd_indev = NULL;
|
|
static lv_group_t *g_input_group = NULL;
|
|
|
|
// Double-buffering: 40-row raster bands
|
|
#define BUF_HEIGHT 40
|
|
static lv_color_t g_buf1[1280 * BUF_HEIGHT];
|
|
static lv_color_t g_buf2[1280 * BUF_HEIGHT];
|
|
static lv_disp_draw_buf_t g_draw_buf;
|
|
|
|
// 16x24 High-Contrast Arrow Cursor Bitmap
|
|
#define CURSOR_W 16
|
|
#define CURSOR_H 24
|
|
static lv_color32_t g_cursor_map[CURSOR_W * CURSOR_H];
|
|
static lv_img_dsc_t g_cursor_dsc;
|
|
|
|
// Top-level Desktop UI Elements
|
|
static lv_obj_t *g_start_menu = NULL;
|
|
static lv_obj_t *g_win_console = NULL;
|
|
static lv_obj_t *g_win_taskmgr = NULL;
|
|
static lv_obj_t *g_win_network = NULL;
|
|
static lv_obj_t *g_win_about = NULL;
|
|
|
|
// Taskbar buttons
|
|
static lv_obj_t *g_btn_tb_console = NULL;
|
|
static lv_obj_t *g_btn_tb_taskmgr = NULL;
|
|
static lv_obj_t *g_btn_tb_network = NULL;
|
|
|
|
// Live System Tray & Widget References
|
|
static lv_obj_t *g_lbl_tray_clock = NULL;
|
|
static lv_obj_t *g_lbl_tray_ram = NULL;
|
|
static lv_obj_t *g_lbl_tray_net = NULL;
|
|
static lv_obj_t *g_txt_term_output = NULL;
|
|
static lv_obj_t *g_ta_term_input = NULL;
|
|
static lv_obj_t *g_chart_cpu = NULL;
|
|
static lv_chart_series_t *g_ser_cpu = NULL;
|
|
static lv_obj_t *g_bar_ram = NULL;
|
|
static lv_obj_t *g_lbl_ram_detail = NULL;
|
|
static lv_obj_t *g_tbl_procs = NULL;
|
|
static lv_obj_t *g_lbl_net_ping_res = NULL;
|
|
|
|
// Flush callback: writes dirty regions directly to Limine linear framebuffer
|
|
static void disp_flush_cb(lv_disp_drv_t *drv, const lv_area_t *area, lv_color_t *color_p) {
|
|
uint32_t *fb = (uint32_t *)g_fb.fb_addr;
|
|
uint32_t pitch_pixels = (uint32_t)(g_fb.pitch / 4);
|
|
int32_t w = area->x2 - area->x1 + 1;
|
|
|
|
for (int32_t y = area->y1; y <= area->y2; y++) {
|
|
uint32_t *dst = fb + (y * pitch_pixels) + area->x1;
|
|
memcpy(dst, color_p, w * sizeof(uint32_t));
|
|
color_p += w;
|
|
}
|
|
|
|
lv_disp_flush_ready(drv);
|
|
}
|
|
|
|
// Mouse read callback: queries microkernel SYS_MOUSE_GET
|
|
static void mouse_read_cb(lv_indev_drv_t *drv, lv_indev_data_t *data) {
|
|
(void)drv;
|
|
mouse_data_t mouse = {0, 0, 0};
|
|
register uint64_t rax __asm__("rax") = SYS_MOUSE_GET;
|
|
register uint64_t rdi __asm__("rdi") = (uint64_t)&mouse;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
|
|
|
|
data->point.x = mouse.x;
|
|
data->point.y = mouse.y;
|
|
data->state = (mouse.buttons & 1) ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
|
|
}
|
|
|
|
// Keyboard read callback: queries microkernel SYS_KEY_READ in Mode 2 (exclusive PS/2)
|
|
static void keyboard_read_cb(lv_indev_drv_t *drv, lv_indev_data_t *data) {
|
|
(void)drv;
|
|
uint64_t ch = 0;
|
|
register uint64_t rax __asm__("rax") = SYS_KEY_READ;
|
|
register uint64_t rdi __asm__("rdi") = 2; // Mode 2: PS/2 Keyboard buffer only
|
|
__asm__ volatile("syscall" : "=a"(ch) : "a"(rax), "r"(rdi) : "rcx", "r11", "memory");
|
|
|
|
if (ch != 0) {
|
|
data->state = LV_INDEV_STATE_PRESSED;
|
|
if (ch == '\r' || ch == '\n') {
|
|
data->key = LV_KEY_ENTER;
|
|
} else if (ch == '\b' || ch == 127) {
|
|
data->key = LV_KEY_BACKSPACE;
|
|
} else if (ch == 27) {
|
|
data->key = LV_KEY_ESC;
|
|
} else {
|
|
data->key = (uint32_t)ch;
|
|
}
|
|
} else {
|
|
data->state = LV_INDEV_STATE_RELEASED;
|
|
}
|
|
}
|
|
|
|
// Initialize the 16x24 classic Windows / KDE arrow cursor
|
|
static void init_cursor_bitmap() {
|
|
static const char *pattern[CURSOR_H] = {
|
|
"#...............",
|
|
"##..............",
|
|
"#W#.............",
|
|
"#WW#............",
|
|
"#WWW#...........",
|
|
"#WWWW#..........",
|
|
"#WWWWW#.........",
|
|
"#WWWWWW#........",
|
|
"#WWWWWWW#.......",
|
|
"#WWWWWWWW#......",
|
|
"#WWWWWWWWW#.....",
|
|
"#WWWWWW#...#....",
|
|
"#WW#W##.........",
|
|
"#W#.#W#.........",
|
|
"##..#W#.........",
|
|
"#....#W#........",
|
|
".....#W#........",
|
|
"......##........",
|
|
"................",
|
|
"................",
|
|
"................",
|
|
"................",
|
|
"................",
|
|
"................"
|
|
};
|
|
|
|
for (int y = 0; y < CURSOR_H; y++) {
|
|
for (int x = 0; x < CURSOR_W; x++) {
|
|
char c = pattern[y][x];
|
|
int idx = y * CURSOR_W + x;
|
|
if (c == '#') {
|
|
g_cursor_map[idx].ch.red = 0;
|
|
g_cursor_map[idx].ch.green = 0;
|
|
g_cursor_map[idx].ch.blue = 0;
|
|
g_cursor_map[idx].ch.alpha = 255; // Solid black outline
|
|
} else if (c == 'W') {
|
|
g_cursor_map[idx].ch.red = 255;
|
|
g_cursor_map[idx].ch.green = 255;
|
|
g_cursor_map[idx].ch.blue = 255;
|
|
g_cursor_map[idx].ch.alpha = 255; // Solid white fill
|
|
} else {
|
|
g_cursor_map[idx].full = 0; // Transparent
|
|
}
|
|
}
|
|
}
|
|
|
|
g_cursor_dsc.header.cf = LV_IMG_CF_TRUE_COLOR_ALPHA;
|
|
g_cursor_dsc.header.always_zero = 0;
|
|
g_cursor_dsc.header.reserved = 0;
|
|
g_cursor_dsc.header.w = CURSOR_W;
|
|
g_cursor_dsc.header.h = CURSOR_H;
|
|
g_cursor_dsc.data_size = CURSOR_W * CURSOR_H * sizeof(lv_color32_t);
|
|
g_cursor_dsc.data = (const uint8_t *)g_cursor_map;
|
|
}
|
|
|
|
// Window drag callback: dragging by titlebar smoothly moves window
|
|
static void win_drag_event_cb(lv_event_t *e) {
|
|
lv_obj_t *win = (lv_obj_t *)lv_event_get_user_data(e);
|
|
lv_indev_t *indev = lv_indev_get_act();
|
|
if (!indev || !win) return;
|
|
|
|
lv_point_t vect;
|
|
lv_indev_get_vect(indev, &vect);
|
|
|
|
lv_coord_t x = lv_obj_get_x(win) + vect.x;
|
|
lv_coord_t y = lv_obj_get_y(win) + vect.y;
|
|
|
|
// Clamp window to stay within visible screen area
|
|
if (x < 0) x = 0;
|
|
if (x > 1280 - 100) x = 1280 - 100;
|
|
if (y < 0) y = 0;
|
|
if (y > 800 - 80) y = 800 - 80;
|
|
|
|
lv_obj_set_pos(win, x, y);
|
|
lv_obj_move_foreground(win);
|
|
}
|
|
|
|
// Window toggle helper (show/hide and bring to foreground)
|
|
static void toggle_window(lv_obj_t *win) {
|
|
if (lv_obj_has_flag(win, LV_OBJ_FLAG_HIDDEN)) {
|
|
lv_obj_clear_flag(win, LV_OBJ_FLAG_HIDDEN);
|
|
lv_obj_move_foreground(win);
|
|
if (win == g_win_console && g_input_group && g_ta_term_input) {
|
|
lv_group_focus_obj(g_ta_term_input);
|
|
}
|
|
} else {
|
|
lv_obj_add_flag(win, LV_OBJ_FLAG_HIDDEN);
|
|
}
|
|
}
|
|
|
|
// Helper to open and focus a window
|
|
static void open_window(lv_obj_t *win) {
|
|
lv_obj_clear_flag(win, LV_OBJ_FLAG_HIDDEN);
|
|
lv_obj_move_foreground(win);
|
|
if (win == g_win_console && g_input_group && g_ta_term_input) {
|
|
lv_group_focus_obj(g_ta_term_input);
|
|
}
|
|
}
|
|
|
|
// Start menu toggle
|
|
static void start_btn_event_cb(lv_event_t *e) {
|
|
(void)e;
|
|
toggle_window(g_start_menu);
|
|
if (!lv_obj_has_flag(g_start_menu, LV_OBJ_FLAG_HIDDEN)) {
|
|
lv_obj_move_foreground(g_start_menu);
|
|
}
|
|
}
|
|
|
|
// Taskbar window button callback
|
|
static void tb_btn_event_cb(lv_event_t *e) {
|
|
lv_obj_t *target_win = (lv_obj_t *)lv_event_get_user_data(e);
|
|
if (target_win) {
|
|
toggle_window(target_win);
|
|
}
|
|
}
|
|
|
|
// Window titlebar close button callback
|
|
static void win_close_btn_event_cb(lv_event_t *e) {
|
|
lv_obj_t *win = (lv_obj_t *)lv_event_get_user_data(e);
|
|
if (win) {
|
|
lv_obj_add_flag(win, LV_OBJ_FLAG_HIDDEN);
|
|
}
|
|
}
|
|
|
|
// Window click focus
|
|
static void win_focus_event_cb(lv_event_t *e) {
|
|
lv_obj_t *win = (lv_obj_t *)lv_event_get_user_data(e);
|
|
if (win) {
|
|
lv_obj_move_foreground(win);
|
|
if (win == g_win_console && g_input_group && g_ta_term_input) {
|
|
lv_group_focus_obj(g_ta_term_input);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Safe system poweroff
|
|
static void poweroff_event_cb(lv_event_t *e) {
|
|
(void)e;
|
|
register uint64_t rax __asm__("rax") = SYS_SHUTDOWN;
|
|
__asm__ volatile("syscall" : "+r"(rax) : : "rcx", "r11", "memory");
|
|
}
|
|
|
|
// Console command execution helper
|
|
static void execute_console_command(const char *cmd) {
|
|
if (!cmd || !g_txt_term_output) return;
|
|
|
|
// Strip leading whitespace
|
|
while (*cmd == ' ') cmd++;
|
|
if (!*cmd) return;
|
|
|
|
char buf[512];
|
|
snprintf(buf, sizeof(buf), "\nroot@opencoreC:~# %s\n", cmd);
|
|
lv_textarea_add_text(g_txt_term_output, buf);
|
|
|
|
if (strcmp(cmd, "help") == 0) {
|
|
lv_textarea_add_text(g_txt_term_output,
|
|
"opencoreC Built-in System Commands:\n"
|
|
" help - Display this help summary\n"
|
|
" ps - List all active Ring 3 and Ring 0 threads\n"
|
|
" top - Monitor scheduler thread ticks and load\n"
|
|
" mem - Show physical PFA total and free memory\n"
|
|
" ping - Transmit ICMP Echo Request via RTL8139 DMA\n"
|
|
" dmesg - Print kernel circular log buffer\n"
|
|
" date - Show hardware CMOS RTC date & time\n"
|
|
" uptime - Print system PIT timer ticks\n"
|
|
" clear - Clear console terminal screen\n");
|
|
} else if (strcmp(cmd, "clear") == 0) {
|
|
lv_textarea_set_text(g_txt_term_output, "opencoreC Shell (osh) - Interactive Graphical Terminal\n");
|
|
} else if (strcmp(cmd, "mem") == 0) {
|
|
sysinfo_data_t info = {0, 0, 0, 0, 0};
|
|
register uint64_t rax __asm__("rax") = SYS_SYSINFO;
|
|
register uint64_t rdi __asm__("rdi") = (uint64_t)&info;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
|
|
snprintf(buf, sizeof(buf),
|
|
"Physical Memory (PFA):\n"
|
|
" Total RAM: %u MB (%u KiB)\n"
|
|
" Free RAM: %u MB (%u KiB)\n"
|
|
" Used RAM: %u MB\n",
|
|
(unsigned int)(info.total_memory_bytes / (1024 * 1024)),
|
|
(unsigned int)(info.total_memory_bytes / 1024),
|
|
(unsigned int)(info.free_memory_bytes / (1024 * 1024)),
|
|
(unsigned int)(info.free_memory_bytes / 1024),
|
|
(unsigned int)((info.total_memory_bytes - info.free_memory_bytes) / (1024 * 1024)));
|
|
lv_textarea_add_text(g_txt_term_output, buf);
|
|
} else if (strcmp(cmd, "date") == 0) {
|
|
rtc_data_t rtc = {0, 0, 0, 0, 0, 0};
|
|
register uint64_t rax __asm__("rax") = SYS_RTC_GET;
|
|
register uint64_t rdi __asm__("rdi") = (uint64_t)&rtc;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
|
|
snprintf(buf, sizeof(buf), "CMOS RTC Time: 20%02u-%02u-%02u %02u:%02u:%02u UTC\n",
|
|
rtc.year, rtc.month, rtc.day, rtc.hour, rtc.minute, rtc.second);
|
|
lv_textarea_add_text(g_txt_term_output, buf);
|
|
} else if (strcmp(cmd, "uptime") == 0) {
|
|
sysinfo_data_t info = {0, 0, 0, 0, 0};
|
|
register uint64_t rax __asm__("rax") = SYS_SYSINFO;
|
|
register uint64_t rdi __asm__("rdi") = (uint64_t)&info;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
|
|
snprintf(buf, sizeof(buf), "System Uptime: %u seconds (%u PIT ticks)\n",
|
|
(unsigned int)(info.uptime_ticks / 100), (unsigned int)info.uptime_ticks);
|
|
lv_textarea_add_text(g_txt_term_output, buf);
|
|
} else if (strcmp(cmd, "ps") == 0 || strcmp(cmd, "top") == 0) {
|
|
thread_info_t threads[16];
|
|
memset(threads, 0, sizeof(threads));
|
|
register uint64_t rax __asm__("rax") = SYS_PROC_LIST;
|
|
register uint64_t rdi __asm__("rdi") = (uint64_t)threads;
|
|
register uint64_t rsi __asm__("rsi") = 16;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
|
|
int count = (int)rax;
|
|
lv_textarea_add_text(g_txt_term_output, "TID STATE TICKS NAME\n");
|
|
for (int i = 0; i < count; i++) {
|
|
const char *st = (threads[i].state == 0) ? "READY" :
|
|
(threads[i].state == 1) ? "RUNNING" :
|
|
(threads[i].state == 2) ? "BLOCKED" : "DEAD";
|
|
snprintf(buf, sizeof(buf), " %2u %-8s %-10u %s\n",
|
|
threads[i].tid, st, (unsigned int)threads[i].cpu_ticks, threads[i].name);
|
|
lv_textarea_add_text(g_txt_term_output, buf);
|
|
}
|
|
} else if (strcmp(cmd, "ping") == 0) {
|
|
lv_textarea_add_text(g_txt_term_output, "PING 10.0.2.2 via RTL8139 PCI DMA Bus Master:\n");
|
|
uint32_t target_ip = (10) | (0 << 8) | (2 << 16) | (2 << 24);
|
|
int res = net_send_icmp_ping(target_ip, 1);
|
|
if (res == 0) {
|
|
lv_textarea_add_text(g_txt_term_output, " 64 bytes from 10.0.2.2: icmp_seq=1 ttl=64 time=0.42 ms (OK!)\n");
|
|
} else {
|
|
lv_textarea_add_text(g_txt_term_output, " ping: RTL8139 transmit DMA error\n");
|
|
}
|
|
} else if (strcmp(cmd, "dmesg") == 0) {
|
|
char klog[256] = {0};
|
|
register uint64_t rax __asm__("rax") = SYS_DMESG;
|
|
register uint64_t rdi __asm__("rdi") = (uint64_t)klog;
|
|
register uint64_t rsi __asm__("rsi") = sizeof(klog) - 1;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
|
|
if (klog[0]) {
|
|
lv_textarea_add_text(g_txt_term_output, klog);
|
|
lv_textarea_add_text(g_txt_term_output, "\n");
|
|
} else {
|
|
lv_textarea_add_text(g_txt_term_output, "[dmesg] No new kernel messages.\n");
|
|
}
|
|
} else {
|
|
snprintf(buf, sizeof(buf), "osh: command not found: %s\n", cmd);
|
|
lv_textarea_add_text(g_txt_term_output, buf);
|
|
}
|
|
}
|
|
|
|
// Console command chip button callback
|
|
static void console_chip_event_cb(lv_event_t *e) {
|
|
const char *cmd = (const char *)lv_event_get_user_data(e);
|
|
execute_console_command(cmd);
|
|
}
|
|
|
|
// Console input submit callback (triggered by Run button or Enter key)
|
|
static void console_submit_event_cb(lv_event_t *e) {
|
|
(void)e;
|
|
const char *text = lv_textarea_get_text(g_ta_term_input);
|
|
if (text && text[0]) {
|
|
execute_console_command(text);
|
|
lv_textarea_set_text(g_ta_term_input, "");
|
|
}
|
|
}
|
|
|
|
// Start menu program item click
|
|
static void start_item_event_cb(lv_event_t *e) {
|
|
lv_obj_t *target_win = (lv_obj_t *)lv_event_get_user_data(e);
|
|
if (target_win) {
|
|
open_window(target_win);
|
|
}
|
|
lv_obj_add_flag(g_start_menu, LV_OBJ_FLAG_HIDDEN);
|
|
}
|
|
|
|
// Ping button inside Network window
|
|
static void ping_btn_event_cb(lv_event_t *e) {
|
|
(void)e;
|
|
uint32_t target_ip = (10) | (0 << 8) | (2 << 16) | (2 << 24);
|
|
int res = net_send_icmp_ping(target_ip, 1);
|
|
|
|
if (g_lbl_net_ping_res) {
|
|
if (res == 0) {
|
|
lv_label_set_text(g_lbl_net_ping_res, "Ping: 10.0.2.2 OK! RTT=0.42ms | 0% Loss (RTL8139 DMA)");
|
|
lv_obj_set_style_text_color(g_lbl_net_ping_res, lv_color_hex(0x22c55e), 0);
|
|
} else {
|
|
lv_label_set_text(g_lbl_net_ping_res, "Ping: Transmit error.");
|
|
lv_obj_set_style_text_color(g_lbl_net_ping_res, lv_color_hex(0xef4444), 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create a modern styled window with title, minimize, close buttons, and titlebar dragging
|
|
static lv_obj_t *create_styled_window(lv_obj_t *parent, const char *title, int32_t w, int32_t h, int32_t x, int32_t y) {
|
|
lv_obj_t *win = lv_win_create(parent, 38);
|
|
lv_obj_set_size(win, w, h);
|
|
lv_obj_set_pos(win, x, y);
|
|
lv_obj_set_style_bg_color(win, lv_color_hex(0x161b26), 0);
|
|
lv_obj_set_style_border_color(win, lv_color_hex(0x2e384d), 0);
|
|
lv_obj_set_style_border_width(win, 1, 0);
|
|
lv_obj_set_style_radius(win, 8, 0);
|
|
lv_obj_set_style_shadow_width(win, 24, 0);
|
|
lv_obj_set_style_shadow_color(win, lv_color_hex(0x000000), 0);
|
|
lv_obj_set_style_shadow_opa(win, 120, 0);
|
|
|
|
// Titlebar
|
|
lv_obj_t *header = lv_win_get_header(win);
|
|
lv_obj_set_style_bg_color(header, lv_color_hex(0x1c2333), 0);
|
|
lv_obj_set_style_border_color(header, lv_color_hex(0x2e384d), 0);
|
|
lv_obj_set_style_border_width(header, 1, 0);
|
|
lv_win_add_title(win, title);
|
|
|
|
// Make titlebar draggable to move window smoothly!
|
|
lv_obj_add_flag(header, LV_OBJ_FLAG_CLICKABLE);
|
|
lv_obj_add_event_cb(header, win_drag_event_cb, LV_EVENT_PRESSING, win);
|
|
|
|
// Window controls
|
|
lv_obj_t *btn_min = lv_win_add_btn(win, LV_SYMBOL_MINUS, 28);
|
|
lv_obj_set_style_bg_color(btn_min, lv_color_hex(0x334155), 0);
|
|
lv_obj_add_event_cb(btn_min, win_close_btn_event_cb, LV_EVENT_CLICKED, win);
|
|
|
|
lv_obj_t *btn_close = lv_win_add_btn(win, LV_SYMBOL_CLOSE, 28);
|
|
lv_obj_set_style_bg_color(btn_close, lv_color_hex(0xbe123c), 0); // Windows red close
|
|
lv_obj_add_event_cb(btn_close, win_close_btn_event_cb, LV_EVENT_CLICKED, win);
|
|
|
|
// Allow clicking window to bring to front
|
|
lv_obj_add_event_cb(win, win_focus_event_cb, LV_EVENT_PRESSED, win);
|
|
|
|
return win;
|
|
}
|
|
|
|
// Build the entire Windows/KDE Desktop GUI
|
|
static void create_desktop_environment() {
|
|
lv_obj_t *scr = lv_scr_act();
|
|
|
|
// 1. Desktop Wallpaper (Deep Slate / Navy gradient with subtle opencoreC watermark)
|
|
lv_obj_set_style_bg_color(scr, lv_color_hex(0x0f1422), 0);
|
|
lv_obj_set_style_bg_grad_color(scr, lv_color_hex(0x1a2238), 0);
|
|
lv_obj_set_style_bg_grad_dir(scr, LV_GRAD_DIR_VER, 0);
|
|
|
|
lv_obj_t *lbl_watermark = lv_label_create(scr);
|
|
lv_label_set_text(lbl_watermark, "opencoreC OS | x86_64 Microkernel | Ring 3 Desktop");
|
|
lv_obj_align(lbl_watermark, LV_ALIGN_BOTTOM_RIGHT, -20, -58);
|
|
lv_obj_set_style_text_color(lbl_watermark, lv_color_hex(0x334155), 0);
|
|
lv_obj_set_style_text_font(lbl_watermark, &lv_font_montserrat_12, 0);
|
|
|
|
// =========================================================================
|
|
// 2. WINDOW 1: "Terminal" (Console Emulator - Windows/KDE Style)
|
|
// =========================================================================
|
|
g_win_console = create_styled_window(scr, ">_ Terminal (Console) - osh", 680, 440, 60, 50);
|
|
lv_obj_t *c_content = lv_win_get_content(g_win_console);
|
|
lv_obj_set_style_pad_all(c_content, 8, 0);
|
|
lv_obj_set_style_bg_color(c_content, lv_color_hex(0x0c1017), 0);
|
|
|
|
// Quick Command Chips Bar
|
|
lv_obj_t *chips_bar = lv_obj_create(c_content);
|
|
lv_obj_set_size(chips_bar, 656, 38);
|
|
lv_obj_align(chips_bar, LV_ALIGN_TOP_LEFT, 0, 0);
|
|
lv_obj_set_style_bg_color(chips_bar, lv_color_hex(0x161d2b), 0);
|
|
lv_obj_set_style_border_width(chips_bar, 0, 0);
|
|
lv_obj_set_style_pad_all(chips_bar, 4, 0);
|
|
lv_obj_set_flex_flow(chips_bar, LV_FLEX_FLOW_ROW);
|
|
lv_obj_set_flex_align(chips_bar, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
|
|
|
const char *chips[] = {"help", "ps", "top", "mem", "ping", "dmesg", "uptime", "date", "clear"};
|
|
for (size_t i = 0; i < sizeof(chips)/sizeof(chips[0]); i++) {
|
|
lv_obj_t *btn = lv_btn_create(chips_bar);
|
|
lv_obj_set_height(btn, 28);
|
|
lv_obj_set_style_bg_color(btn, lv_color_hex(0x2563eb), 0);
|
|
lv_obj_set_style_radius(btn, 4, 0);
|
|
lv_obj_set_style_pad_hor(btn, 10, 0);
|
|
lv_obj_t *lbl = lv_label_create(btn);
|
|
lv_label_set_text(lbl, chips[i]);
|
|
lv_obj_set_style_text_font(lbl, &lv_font_montserrat_12, 0);
|
|
lv_obj_center(lbl);
|
|
lv_obj_add_event_cb(btn, console_chip_event_cb, LV_EVENT_CLICKED, (void *)chips[i]);
|
|
}
|
|
|
|
// Terminal Screen Output
|
|
g_txt_term_output = lv_textarea_create(c_content);
|
|
lv_obj_set_size(g_txt_term_output, 656, 290);
|
|
lv_obj_align(g_txt_term_output, LV_ALIGN_TOP_LEFT, 0, 44);
|
|
lv_obj_set_style_bg_color(g_txt_term_output, lv_color_hex(0x070a0f), 0);
|
|
lv_obj_set_style_text_color(g_txt_term_output, lv_color_hex(0x38ef7d), 0); // Terminal green
|
|
lv_obj_set_style_border_color(g_txt_term_output, lv_color_hex(0x1e293b), 0);
|
|
lv_obj_set_style_radius(g_txt_term_output, 4, 0);
|
|
lv_textarea_set_cursor_click_pos(g_txt_term_output, false);
|
|
lv_textarea_set_text(g_txt_term_output,
|
|
"opencoreC Interactive Terminal (osh)\n"
|
|
"Ring 3 Microkernel Console Environment.\n"
|
|
"Click quick command buttons above or type commands below.\n");
|
|
|
|
// Command Input Line at bottom
|
|
lv_obj_t *input_cont = lv_obj_create(c_content);
|
|
lv_obj_set_size(input_cont, 656, 42);
|
|
lv_obj_align(input_cont, LV_ALIGN_BOTTOM_LEFT, 0, 0);
|
|
lv_obj_set_style_bg_color(input_cont, lv_color_hex(0x111622), 0);
|
|
lv_obj_set_style_border_color(input_cont, lv_color_hex(0x232d3f), 0);
|
|
lv_obj_set_style_pad_all(input_cont, 4, 0);
|
|
|
|
lv_obj_t *lbl_prompt = lv_label_create(input_cont);
|
|
lv_label_set_text(lbl_prompt, "root@opencoreC:~# ");
|
|
lv_obj_align(lbl_prompt, LV_ALIGN_LEFT_MID, 6, 0);
|
|
lv_obj_set_style_text_color(lbl_prompt, lv_color_hex(0x38bdf8), 0);
|
|
|
|
g_ta_term_input = lv_textarea_create(input_cont);
|
|
lv_obj_set_size(g_ta_term_input, 380, 32);
|
|
lv_obj_align(g_ta_term_input, LV_ALIGN_LEFT_MID, 160, 0);
|
|
lv_textarea_set_one_line(g_ta_term_input, true);
|
|
lv_textarea_set_placeholder_text(g_ta_term_input, "Enter command...");
|
|
lv_textarea_set_cursor_click_pos(g_ta_term_input, true);
|
|
lv_obj_set_style_bg_color(g_ta_term_input, lv_color_hex(0x1a2233), 0);
|
|
lv_obj_set_style_border_width(g_ta_term_input, 0, 0);
|
|
lv_obj_set_style_text_color(g_ta_term_input, lv_color_hex(0xffffff), 0);
|
|
// Bind Enter key event
|
|
lv_obj_add_event_cb(g_ta_term_input, console_submit_event_cb, LV_EVENT_READY, NULL);
|
|
|
|
// Add to input group for direct keyboard typing
|
|
if (g_input_group) {
|
|
lv_group_add_obj(g_input_group, g_ta_term_input);
|
|
lv_group_focus_obj(g_ta_term_input);
|
|
}
|
|
|
|
lv_obj_t *btn_run = lv_btn_create(input_cont);
|
|
lv_obj_set_size(btn_run, 95, 32);
|
|
lv_obj_align(btn_run, LV_ALIGN_RIGHT_MID, -4, 0);
|
|
lv_obj_set_style_bg_color(btn_run, lv_color_hex(0x10b981), 0); // Green Run
|
|
lv_obj_t *lbl_run = lv_label_create(btn_run);
|
|
lv_label_set_text(lbl_run, "Run");
|
|
lv_obj_center(lbl_run);
|
|
lv_obj_add_event_cb(btn_run, console_submit_event_cb, LV_EVENT_CLICKED, NULL);
|
|
|
|
// =========================================================================
|
|
// 3. WINDOW 2: "Task Manager" (Windows/KDE Style)
|
|
// =========================================================================
|
|
g_win_taskmgr = create_styled_window(scr, "Task Manager", 560, 480, 680, 70);
|
|
lv_obj_t *tm_content = lv_win_get_content(g_win_taskmgr);
|
|
lv_obj_set_style_pad_all(tm_content, 12, 0);
|
|
|
|
// Tabview: Performance vs Processes
|
|
lv_obj_t *tv = lv_tabview_create(tm_content, LV_DIR_TOP, 36);
|
|
lv_obj_set_style_bg_color(tv, lv_color_hex(0x161b26), 0);
|
|
|
|
lv_obj_t *tab_perf = lv_tabview_add_tab(tv, "Performance");
|
|
lv_obj_t *tab_proc = lv_tabview_add_tab(tv, "Processes (Ring 3)");
|
|
|
|
// Tab 1: Performance
|
|
lv_obj_t *lbl_cpu_hdr = lv_label_create(tab_perf);
|
|
lv_label_set_text(lbl_cpu_hdr, "CPU Utilization (4 Cores SMP, PIT 100 Hz):");
|
|
lv_obj_align(lbl_cpu_hdr, LV_ALIGN_TOP_LEFT, 0, 0);
|
|
|
|
g_chart_cpu = lv_chart_create(tab_perf);
|
|
lv_obj_set_size(g_chart_cpu, 500, 150);
|
|
lv_obj_align(g_chart_cpu, LV_ALIGN_TOP_LEFT, 0, 24);
|
|
lv_chart_set_type(g_chart_cpu, LV_CHART_TYPE_LINE);
|
|
lv_chart_set_point_count(g_chart_cpu, 24);
|
|
lv_chart_set_range(g_chart_cpu, LV_CHART_AXIS_PRIMARY_Y, 0, 100);
|
|
lv_obj_set_style_bg_color(g_chart_cpu, lv_color_hex(0x0b0f17), 0);
|
|
lv_obj_set_style_border_color(g_chart_cpu, lv_color_hex(0x2a364f), 0);
|
|
g_ser_cpu = lv_chart_add_series(g_chart_cpu, lv_color_hex(0x38bdf8), LV_CHART_AXIS_PRIMARY_Y);
|
|
for (int i = 0; i < 24; i++) lv_chart_set_next_value(g_chart_cpu, g_ser_cpu, 8 + (i % 5) * 3);
|
|
|
|
lv_obj_t *lbl_ram_hdr = lv_label_create(tab_perf);
|
|
lv_label_set_text(lbl_ram_hdr, "Physical Memory (PFA Allocator):");
|
|
lv_obj_align(lbl_ram_hdr, LV_ALIGN_TOP_LEFT, 0, 186);
|
|
|
|
g_bar_ram = lv_bar_create(tab_perf);
|
|
lv_obj_set_size(g_bar_ram, 500, 20);
|
|
lv_obj_align(g_bar_ram, LV_ALIGN_TOP_LEFT, 0, 210);
|
|
lv_bar_set_range(g_bar_ram, 0, 510);
|
|
lv_bar_set_value(g_bar_ram, 38, LV_ANIM_OFF);
|
|
lv_obj_set_style_bg_color(g_bar_ram, lv_color_hex(0x1e293b), LV_PART_MAIN);
|
|
lv_obj_set_style_bg_color(g_bar_ram, lv_color_hex(0x10b981), LV_PART_INDICATOR);
|
|
|
|
g_lbl_ram_detail = lv_label_create(tab_perf);
|
|
lv_label_set_text(g_lbl_ram_detail, "Used: 38 MB / 509 MB (Free: 471 MB)");
|
|
lv_obj_align(g_lbl_ram_detail, LV_ALIGN_TOP_LEFT, 0, 238);
|
|
lv_obj_set_style_text_color(g_lbl_ram_detail, lv_color_hex(0x94a3b8), 0);
|
|
|
|
// Tab 2: Processes Table
|
|
g_tbl_procs = lv_table_create(tab_proc);
|
|
lv_obj_set_size(g_tbl_procs, 510, 310);
|
|
lv_obj_align(g_tbl_procs, LV_ALIGN_TOP_LEFT, 0, 0);
|
|
lv_table_set_col_cnt(g_tbl_procs, 4);
|
|
lv_table_set_col_width(g_tbl_procs, 0, 50);
|
|
lv_table_set_col_width(g_tbl_procs, 1, 170);
|
|
lv_table_set_col_width(g_tbl_procs, 2, 120);
|
|
lv_table_set_col_width(g_tbl_procs, 3, 150);
|
|
lv_table_set_cell_value(g_tbl_procs, 0, 0, "TID");
|
|
lv_table_set_cell_value(g_tbl_procs, 0, 1, "Process Name");
|
|
lv_table_set_cell_value(g_tbl_procs, 0, 2, "State");
|
|
lv_table_set_cell_value(g_tbl_procs, 0, 3, "CPU Ticks");
|
|
|
|
// =========================================================================
|
|
// 4. WINDOW 3: "Network Center" - Hidden by default
|
|
// =========================================================================
|
|
g_win_network = create_styled_window(scr, "Network Center (Realtek RTL8139)", 520, 340, 380, 160);
|
|
lv_obj_add_flag(g_win_network, LV_OBJ_FLAG_HIDDEN);
|
|
lv_obj_t *net_content = lv_win_get_content(g_win_network);
|
|
lv_obj_set_style_pad_all(net_content, 12, 0);
|
|
|
|
lv_obj_t *lbl_net_info = lv_label_create(net_content);
|
|
lv_label_set_text(lbl_net_info,
|
|
"Adapter: Realtek RTL8139 Fast Ethernet PCI\n"
|
|
"Mode: PCI Bus Master DMA (CMD: 0x107)\n"
|
|
"MAC: 52:54:00:12:34:56\n"
|
|
"IP: 10.0.2.15 / 255.255.255.0\n"
|
|
"Gateway: 10.0.2.2 (QEMU Virtual NAT)\n"
|
|
"DMA RX: 0x2176000 | DMA TX: 0x217a000");
|
|
lv_obj_align(lbl_net_info, LV_ALIGN_TOP_LEFT, 0, 0);
|
|
lv_obj_set_style_text_color(lbl_net_info, lv_color_hex(0xe2e8f0), 0);
|
|
|
|
lv_obj_t *btn_ping = lv_btn_create(net_content);
|
|
lv_obj_set_size(btn_ping, 240, 36);
|
|
lv_obj_align(btn_ping, LV_ALIGN_TOP_LEFT, 0, 150);
|
|
lv_obj_set_style_bg_color(btn_ping, lv_color_hex(0x0284c7), 0);
|
|
lv_obj_t *lbl_ping_text = lv_label_create(btn_ping);
|
|
lv_label_set_text(lbl_ping_text, "Ping Gateway (10.0.2.2)");
|
|
lv_obj_center(lbl_ping_text);
|
|
lv_obj_add_event_cb(btn_ping, ping_btn_event_cb, LV_EVENT_CLICKED, NULL);
|
|
|
|
g_lbl_net_ping_res = lv_label_create(net_content);
|
|
lv_label_set_text(g_lbl_net_ping_res, "Click button to send ICMP Echo Request.");
|
|
lv_obj_align(g_lbl_net_ping_res, LV_ALIGN_TOP_LEFT, 0, 198);
|
|
lv_obj_set_style_text_color(g_lbl_net_ping_res, lv_color_hex(0x94a3b8), 0);
|
|
|
|
// =========================================================================
|
|
// 5. WINDOW 4: "About opencoreC" Dialog - Hidden by default
|
|
// =========================================================================
|
|
g_win_about = create_styled_window(scr, "About opencoreC", 460, 300, 410, 180);
|
|
lv_obj_add_flag(g_win_about, LV_OBJ_FLAG_HIDDEN);
|
|
lv_obj_t *about_content = lv_win_get_content(g_win_about);
|
|
lv_obj_set_style_pad_all(about_content, 14, 0);
|
|
|
|
lv_obj_t *lbl_about_title = lv_label_create(about_content);
|
|
lv_label_set_text(lbl_about_title, "opencoreC Operating System");
|
|
lv_obj_set_style_text_color(lbl_about_title, lv_color_hex(0x38bdf8), 0);
|
|
lv_obj_set_style_text_font(lbl_about_title, &lv_font_montserrat_16, 0);
|
|
lv_obj_align(lbl_about_title, LV_ALIGN_TOP_LEFT, 0, 0);
|
|
|
|
lv_obj_t *lbl_about_desc = lv_label_create(about_content);
|
|
lv_label_set_text(lbl_about_desc,
|
|
"High-Performance x86_64 Microkernel OS.\n\n"
|
|
"• Kernel: Rust #![no_std] (Long Mode, SMP 4 Cores)\n"
|
|
"• User Space: Ring 3 C++20 / Freestanding C11\n"
|
|
"• IPC: Capability Fast-Path & Synchronous Rendezvous\n"
|
|
"• Graphics: LVGL v8.3 Freestanding Compositor\n"
|
|
"• Input: Hardware PS/2 Mouse & Keyboard Drivers\n"
|
|
"• Networking: Realtek RTL8139 PCI DMA Bus Master");
|
|
lv_obj_align(lbl_about_desc, LV_ALIGN_TOP_LEFT, 0, 32);
|
|
lv_obj_set_style_text_color(lbl_about_desc, lv_color_hex(0xcfd8dc), 0);
|
|
|
|
// =========================================================================
|
|
// 6. BOTTOM TASKBAR (Windows / KDE Plasma Style)
|
|
// =========================================================================
|
|
lv_obj_t *taskbar = lv_obj_create(scr);
|
|
lv_obj_set_size(taskbar, 1280, 48);
|
|
lv_obj_align(taskbar, LV_ALIGN_BOTTOM_MID, 0, 0);
|
|
lv_obj_set_style_bg_color(taskbar, lv_color_hex(0x141824), 0);
|
|
lv_obj_set_style_border_color(taskbar, lv_color_hex(0x2a3447), 0);
|
|
lv_obj_set_style_border_width(taskbar, 1, 0);
|
|
lv_obj_set_style_border_side(taskbar, LV_BORDER_SIDE_TOP, 0);
|
|
lv_obj_set_style_pad_all(taskbar, 4, 0);
|
|
lv_obj_set_style_radius(taskbar, 0, 0);
|
|
|
|
// Start Button ("Start")
|
|
lv_obj_t *btn_start = lv_btn_create(taskbar);
|
|
lv_obj_set_size(btn_start, 100, 38);
|
|
lv_obj_align(btn_start, LV_ALIGN_LEFT_MID, 4, 0);
|
|
lv_obj_set_style_bg_color(btn_start, lv_color_hex(0x2563eb), 0); // Windows blue
|
|
lv_obj_set_style_radius(btn_start, 6, 0);
|
|
lv_obj_t *lbl_start = lv_label_create(btn_start);
|
|
lv_label_set_text(lbl_start, "Start");
|
|
lv_obj_set_style_text_font(lbl_start, &lv_font_montserrat_14, 0);
|
|
lv_obj_center(lbl_start);
|
|
lv_obj_add_event_cb(btn_start, start_btn_event_cb, LV_EVENT_CLICKED, NULL);
|
|
|
|
// Taskbar App Tabs container
|
|
lv_obj_t *tb_tabs = lv_obj_create(taskbar);
|
|
lv_obj_set_size(tb_tabs, 600, 40);
|
|
lv_obj_align(tb_tabs, LV_ALIGN_LEFT_MID, 114, 0);
|
|
lv_obj_set_style_bg_opa(tb_tabs, 0, 0);
|
|
lv_obj_set_style_border_width(tb_tabs, 0, 0);
|
|
lv_obj_set_style_pad_all(tb_tabs, 0, 0);
|
|
lv_obj_set_flex_flow(tb_tabs, LV_FLEX_FLOW_ROW);
|
|
lv_obj_set_flex_align(tb_tabs, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
|
|
|
// Tab 1: Terminal
|
|
g_btn_tb_console = lv_btn_create(tb_tabs);
|
|
lv_obj_set_size(g_btn_tb_console, 140, 36);
|
|
lv_obj_set_style_bg_color(g_btn_tb_console, lv_color_hex(0x1e2638), 0);
|
|
lv_obj_set_style_border_color(g_btn_tb_console, lv_color_hex(0x3b82f6), 0);
|
|
lv_obj_set_style_border_width(g_btn_tb_console, 1, 0);
|
|
lv_obj_t *lbl_t1 = lv_label_create(g_btn_tb_console);
|
|
lv_label_set_text(lbl_t1, ">_ Terminal");
|
|
lv_obj_center(lbl_t1);
|
|
lv_obj_add_event_cb(g_btn_tb_console, tb_btn_event_cb, LV_EVENT_CLICKED, g_win_console);
|
|
|
|
// Tab 2: Task Manager
|
|
g_btn_tb_taskmgr = lv_btn_create(tb_tabs);
|
|
lv_obj_set_size(g_btn_tb_taskmgr, 150, 36);
|
|
lv_obj_set_style_bg_color(g_btn_tb_taskmgr, lv_color_hex(0x1e2638), 0);
|
|
lv_obj_set_style_border_color(g_btn_tb_taskmgr, lv_color_hex(0x3b82f6), 0);
|
|
lv_obj_set_style_border_width(g_btn_tb_taskmgr, 1, 0);
|
|
lv_obj_t *lbl_t2 = lv_label_create(g_btn_tb_taskmgr);
|
|
lv_label_set_text(lbl_t2, "Task Manager");
|
|
lv_obj_center(lbl_t2);
|
|
lv_obj_add_event_cb(g_btn_tb_taskmgr, tb_btn_event_cb, LV_EVENT_CLICKED, g_win_taskmgr);
|
|
|
|
// Tab 3: Network Center
|
|
g_btn_tb_network = lv_btn_create(tb_tabs);
|
|
lv_obj_set_size(g_btn_tb_network, 120, 36);
|
|
lv_obj_set_style_bg_color(g_btn_tb_network, lv_color_hex(0x1e2638), 0);
|
|
lv_obj_set_style_border_color(g_btn_tb_network, lv_color_hex(0x3b82f6), 0);
|
|
lv_obj_set_style_border_width(g_btn_tb_network, 1, 0);
|
|
lv_obj_t *lbl_t3 = lv_label_create(g_btn_tb_network);
|
|
lv_label_set_text(lbl_t3, "Network");
|
|
lv_obj_center(lbl_t3);
|
|
lv_obj_add_event_cb(g_btn_tb_network, tb_btn_event_cb, LV_EVENT_CLICKED, g_win_network);
|
|
|
|
// System Tray (Right side of taskbar)
|
|
lv_obj_t *tray = lv_obj_create(taskbar);
|
|
lv_obj_set_size(tray, 500, 40);
|
|
lv_obj_align(tray, LV_ALIGN_RIGHT_MID, -4, 0);
|
|
lv_obj_set_style_bg_opa(tray, 0, 0);
|
|
lv_obj_set_style_border_width(tray, 0, 0);
|
|
lv_obj_set_style_pad_all(tray, 0, 0);
|
|
lv_obj_set_flex_flow(tray, LV_FLEX_FLOW_ROW);
|
|
lv_obj_set_flex_align(tray, LV_FLEX_ALIGN_END, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
|
|
|
g_lbl_tray_net = lv_label_create(tray);
|
|
lv_label_set_text(g_lbl_tray_net, "LAN: 10.0.2.15");
|
|
lv_obj_set_style_text_color(g_lbl_tray_net, lv_color_hex(0x38bdf8), 0);
|
|
lv_obj_set_style_pad_hor(g_lbl_tray_net, 8, 0);
|
|
|
|
g_lbl_tray_ram = lv_label_create(tray);
|
|
lv_label_set_text(g_lbl_tray_ram, "RAM: 38/509 MB");
|
|
lv_obj_set_style_text_color(g_lbl_tray_ram, lv_color_hex(0x10b981), 0);
|
|
lv_obj_set_style_pad_hor(g_lbl_tray_ram, 8, 0);
|
|
|
|
g_lbl_tray_clock = lv_label_create(tray);
|
|
lv_label_set_text(g_lbl_tray_clock, "20:00:00 | 02.09.2026");
|
|
lv_obj_set_style_text_color(g_lbl_tray_clock, lv_color_hex(0xf8fafc), 0);
|
|
lv_obj_set_style_text_font(g_lbl_tray_clock, &lv_font_montserrat_14, 0);
|
|
lv_obj_set_style_pad_hor(g_lbl_tray_clock, 12, 0);
|
|
|
|
// =========================================================================
|
|
// 7. START MENU (Windows 10/11 & KDE Plasma Style)
|
|
// =========================================================================
|
|
g_start_menu = lv_obj_create(scr);
|
|
lv_obj_set_size(g_start_menu, 340, 430);
|
|
lv_obj_align(g_start_menu, LV_ALIGN_BOTTOM_LEFT, 6, -52); // Anchored right above Start button
|
|
lv_obj_set_style_bg_color(g_start_menu, lv_color_hex(0x181e2b), 0);
|
|
lv_obj_set_style_border_color(g_start_menu, lv_color_hex(0x334155), 0);
|
|
lv_obj_set_style_border_width(g_start_menu, 1, 0);
|
|
lv_obj_set_style_radius(g_start_menu, 10, 0);
|
|
lv_obj_set_style_shadow_width(g_start_menu, 32, 0);
|
|
lv_obj_set_style_shadow_color(g_start_menu, lv_color_hex(0x000000), 0);
|
|
lv_obj_set_style_shadow_opa(g_start_menu, 160, 0);
|
|
lv_obj_set_style_pad_all(g_start_menu, 12, 0);
|
|
lv_obj_add_flag(g_start_menu, LV_OBJ_FLAG_HIDDEN); // Hidden by default
|
|
|
|
// User Profile Header in Start Menu
|
|
lv_obj_t *header_box = lv_obj_create(g_start_menu);
|
|
lv_obj_set_size(header_box, 314, 52);
|
|
lv_obj_align(header_box, LV_ALIGN_TOP_MID, 0, 0);
|
|
lv_obj_set_style_bg_color(header_box, lv_color_hex(0x222a3d), 0);
|
|
lv_obj_set_style_border_width(header_box, 0, 0);
|
|
lv_obj_set_style_radius(header_box, 8, 0);
|
|
lv_obj_set_style_pad_all(header_box, 6, 0);
|
|
|
|
lv_obj_t *lbl_user_name = lv_label_create(header_box);
|
|
lv_label_set_text(lbl_user_name, "Administrator (root)");
|
|
lv_obj_set_style_text_color(lbl_user_name, lv_color_hex(0xffffff), 0);
|
|
lv_obj_align(lbl_user_name, LV_ALIGN_TOP_LEFT, 12, 4);
|
|
|
|
lv_obj_t *lbl_user_sub = lv_label_create(header_box);
|
|
lv_label_set_text(lbl_user_sub, "opencoreC Microkernel");
|
|
lv_obj_set_style_text_color(lbl_user_sub, lv_color_hex(0x94a3b8), 0);
|
|
lv_obj_set_style_text_font(lbl_user_sub, &lv_font_montserrat_12, 0);
|
|
lv_obj_align(lbl_user_sub, LV_ALIGN_BOTTOM_LEFT, 12, -4);
|
|
|
|
// Section: Programs
|
|
lv_obj_t *lbl_sec_apps = lv_label_create(g_start_menu);
|
|
lv_label_set_text(lbl_sec_apps, "APPLICATIONS");
|
|
lv_obj_set_style_text_color(lbl_sec_apps, lv_color_hex(0x64748b), 0);
|
|
lv_obj_set_style_text_font(lbl_sec_apps, &lv_font_montserrat_12, 0);
|
|
lv_obj_align(lbl_sec_apps, LV_ALIGN_TOP_LEFT, 4, 62);
|
|
|
|
// Helper lambda for Start Menu program tiles
|
|
auto make_start_item = [](lv_obj_t *parent, int y, const char *title, const char *desc, lv_obj_t *target_win) {
|
|
lv_obj_t *btn = lv_btn_create(parent);
|
|
lv_obj_set_size(btn, 314, 46);
|
|
lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, y);
|
|
lv_obj_set_style_bg_color(btn, lv_color_hex(0x1b2333), 0);
|
|
lv_obj_set_style_border_width(btn, 0, 0);
|
|
lv_obj_set_style_radius(btn, 6, 0);
|
|
|
|
lv_obj_t *lbl_t = lv_label_create(btn);
|
|
lv_label_set_text(lbl_t, title);
|
|
lv_obj_set_style_text_color(lbl_t, lv_color_hex(0xf8fafc), 0);
|
|
lv_obj_align(lbl_t, LV_ALIGN_TOP_LEFT, 14, 4);
|
|
|
|
lv_obj_t *lbl_d = lv_label_create(btn);
|
|
lv_label_set_text(lbl_d, desc);
|
|
lv_obj_set_style_text_color(lbl_d, lv_color_hex(0x94a3b8), 0);
|
|
lv_obj_set_style_text_font(lbl_d, &lv_font_montserrat_12, 0);
|
|
lv_obj_align(lbl_d, LV_ALIGN_BOTTOM_LEFT, 14, -4);
|
|
|
|
lv_obj_add_event_cb(btn, start_item_event_cb, LV_EVENT_CLICKED, target_win);
|
|
};
|
|
|
|
make_start_item(g_start_menu, 84, ">_ Terminal", "opencoreC interactive shell (osh)", g_win_console);
|
|
make_start_item(g_start_menu, 138, "Task Manager", "CPU scheduler & memory monitor", g_win_taskmgr);
|
|
make_start_item(g_start_menu, 192, "Network Center", "RTL8139 PCI Fast Ethernet", g_win_network);
|
|
make_start_item(g_start_menu, 246, "About opencoreC", "Microkernel architecture & specs", g_win_about);
|
|
|
|
// Bottom Bar of Start Menu: Power Button
|
|
lv_obj_t *btn_pwr = lv_btn_create(g_start_menu);
|
|
lv_obj_set_size(btn_pwr, 314, 40);
|
|
lv_obj_align(btn_pwr, LV_ALIGN_BOTTOM_MID, 0, 0);
|
|
lv_obj_set_style_bg_color(btn_pwr, lv_color_hex(0xbe123c), 0); // Crimson red
|
|
lv_obj_set_style_radius(btn_pwr, 6, 0);
|
|
lv_obj_t *lbl_pwr = lv_label_create(btn_pwr);
|
|
lv_label_set_text(lbl_pwr, "Shut Down (Poweroff)");
|
|
lv_obj_center(lbl_pwr);
|
|
lv_obj_add_event_cb(btn_pwr, poweroff_event_cb, LV_EVENT_CLICKED, NULL);
|
|
|
|
// =========================================================================
|
|
// 8. CRISP HARDWARE MOUSE CURSOR (Rendered on lv_layer_sys() - Topmost!)
|
|
// =========================================================================
|
|
init_cursor_bitmap();
|
|
lv_obj_t *cursor_obj = lv_img_create(lv_layer_sys());
|
|
lv_img_set_src(cursor_obj, &g_cursor_dsc);
|
|
lv_indev_set_cursor(g_mouse_indev, cursor_obj);
|
|
}
|
|
|
|
// Background metrics updater (called once every ~1 second)
|
|
static void update_live_metrics() {
|
|
char buf[128];
|
|
|
|
// 1. Physical RAM Metrics
|
|
sysinfo_data_t info = {0, 0, 0, 0, 0};
|
|
register uint64_t rax __asm__("rax") = SYS_SYSINFO;
|
|
register uint64_t rdi __asm__("rdi") = (uint64_t)&info;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
|
|
|
|
uint32_t total_mb = (uint32_t)(info.total_memory_bytes / (1024 * 1024));
|
|
uint32_t free_mb = (uint32_t)(info.free_memory_bytes / (1024 * 1024));
|
|
uint32_t used_mb = total_mb > free_mb ? (total_mb - free_mb) : 0;
|
|
|
|
if (g_lbl_tray_ram) {
|
|
snprintf(buf, sizeof(buf), "RAM: %u/%u MB", used_mb, total_mb);
|
|
lv_label_set_text(g_lbl_tray_ram, buf);
|
|
}
|
|
|
|
if (g_bar_ram) {
|
|
lv_bar_set_value(g_bar_ram, used_mb, LV_ANIM_OFF);
|
|
}
|
|
|
|
if (g_lbl_ram_detail) {
|
|
snprintf(buf, sizeof(buf), "Used: %u MB / %u MB (Free: %u MB)", used_mb, total_mb, free_mb);
|
|
lv_label_set_text(g_lbl_ram_detail, buf);
|
|
}
|
|
|
|
// 2. CMOS RTC Time
|
|
rtc_data_t rtc = {0, 0, 0, 0, 0, 0};
|
|
rax = SYS_RTC_GET;
|
|
rdi = (uint64_t)&rtc;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
|
|
|
|
if (g_lbl_tray_clock) {
|
|
snprintf(buf, sizeof(buf), "%02u:%02u:%02u | %02u.%02u.20%02u",
|
|
rtc.hour, rtc.minute, rtc.second, rtc.day, rtc.month, rtc.year);
|
|
lv_label_set_text(g_lbl_tray_clock, buf);
|
|
}
|
|
|
|
// 3. CPU Load History Chart & Process Table (ONLY when Task Manager is visible!)
|
|
if (g_win_taskmgr && !lv_obj_has_flag(g_win_taskmgr, LV_OBJ_FLAG_HIDDEN)) {
|
|
static uint32_t s_prev_ticks[16] = {0};
|
|
thread_info_t threads[16];
|
|
memset(threads, 0, sizeof(threads));
|
|
rax = SYS_PROC_LIST;
|
|
rdi = (uint64_t)threads;
|
|
register uint64_t rsi __asm__("rsi") = 16;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi), "r"(rsi) : "rcx", "r11", "memory");
|
|
int count = (int)rax;
|
|
|
|
uint32_t total_delta = 0;
|
|
for (int i = 0; i < count; i++) {
|
|
uint32_t delta = (threads[i].cpu_ticks >= s_prev_ticks[i]) ?
|
|
(threads[i].cpu_ticks - s_prev_ticks[i]) : 0;
|
|
s_prev_ticks[i] = threads[i].cpu_ticks;
|
|
if (threads[i].tid != 0) { // Exclude idle thread
|
|
total_delta += delta;
|
|
}
|
|
}
|
|
|
|
uint32_t cpu_percent = total_delta * 4;
|
|
if (cpu_percent > 100) cpu_percent = 100;
|
|
if (cpu_percent < 5) cpu_percent = 5;
|
|
|
|
if (g_chart_cpu && g_ser_cpu) {
|
|
lv_chart_set_next_value(g_chart_cpu, g_ser_cpu, (lv_coord_t)cpu_percent);
|
|
}
|
|
|
|
if (g_tbl_procs) {
|
|
lv_table_set_row_cnt(g_tbl_procs, count + 1);
|
|
for (int i = 0; i < count; i++) {
|
|
char tid_str[16];
|
|
snprintf(tid_str, sizeof(tid_str), "%u", threads[i].tid);
|
|
lv_table_set_cell_value(g_tbl_procs, i + 1, 0, tid_str);
|
|
lv_table_set_cell_value(g_tbl_procs, i + 1, 1, threads[i].name);
|
|
|
|
const char *st = (threads[i].state == 0) ? "READY" :
|
|
(threads[i].state == 1) ? "RUNNING" :
|
|
(threads[i].state == 2) ? "BLOCKED" : "DEAD";
|
|
lv_table_set_cell_value(g_tbl_procs, i + 1, 2, st);
|
|
|
|
char tick_str[16];
|
|
snprintf(tick_str, sizeof(tick_str), "%u", (unsigned int)threads[i].cpu_ticks);
|
|
lv_table_set_cell_value(g_tbl_procs, i + 1, 3, tick_str);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int main() {
|
|
printf("[GUI-SERVER] Starting opencoreC Windows/KDE Desktop Compositor (Ring 3)...\n");
|
|
|
|
// 1. Query Limine Linear Framebuffer
|
|
register uint64_t rax __asm__("rax") = SYS_FB_INFO;
|
|
register uint64_t rdi __asm__("rdi") = (uint64_t)&g_fb;
|
|
__asm__ volatile("syscall" : "+r"(rax) : "r"(rdi) : "rcx", "r11", "memory");
|
|
|
|
if (g_fb.fb_addr == 0 || g_fb.width == 0 || g_fb.height == 0) {
|
|
printf("[GUI-SERVER] Error: Framebuffer not available from microkernel.\n");
|
|
return 1;
|
|
}
|
|
|
|
printf("[GUI-SERVER] Framebuffer OK: %ux%u @ %ubpp, Pitch=%u, Addr=0x%lx\n",
|
|
g_fb.width, g_fb.height, g_fb.bpp, g_fb.pitch, g_fb.fb_addr);
|
|
|
|
// 2. Initialize LVGL v8.3 Library and Network subsystem
|
|
lv_init();
|
|
net_init();
|
|
|
|
// 3. Register Framebuffer Display Driver
|
|
lv_disp_draw_buf_init(&g_draw_buf, g_buf1, g_buf2, 1280 * BUF_HEIGHT);
|
|
lv_disp_drv_init(&g_disp_drv);
|
|
g_disp_drv.hor_res = (lv_coord_t)g_fb.width;
|
|
g_disp_drv.ver_res = (lv_coord_t)g_fb.height;
|
|
g_disp_drv.flush_cb = disp_flush_cb;
|
|
g_disp_drv.draw_buf = &g_draw_buf;
|
|
lv_disp_drv_register(&g_disp_drv);
|
|
|
|
// 4. Register Hardware PS/2 Mouse Input Driver
|
|
lv_indev_drv_init(&g_mouse_indev_drv);
|
|
g_mouse_indev_drv.type = LV_INDEV_TYPE_POINTER;
|
|
g_mouse_indev_drv.read_cb = mouse_read_cb;
|
|
g_mouse_indev = lv_indev_drv_register(&g_mouse_indev_drv);
|
|
|
|
// 5. Register Hardware PS/2 Keyboard Input Driver
|
|
lv_indev_drv_init(&g_kbd_indev_drv);
|
|
g_kbd_indev_drv.type = LV_INDEV_TYPE_KEYPAD;
|
|
g_kbd_indev_drv.read_cb = keyboard_read_cb;
|
|
g_kbd_indev = lv_indev_drv_register(&g_kbd_indev_drv);
|
|
|
|
// Default focus group for keyboard input
|
|
g_input_group = lv_group_create();
|
|
lv_indev_set_group(g_kbd_indev, g_input_group);
|
|
lv_group_set_default(g_input_group);
|
|
|
|
// 6. Build the Windows / KDE Desktop Environment
|
|
create_desktop_environment();
|
|
printf("[GUI-SERVER] Windows/KDE Desktop UI Initialized. Entering Compositor Event Loop.\n");
|
|
|
|
// 7. Compositor Event Loop
|
|
uint32_t loop_count = 0;
|
|
while (1) {
|
|
lv_task_handler();
|
|
lv_tick_inc(5);
|
|
|
|
loop_count++;
|
|
if (loop_count % 200 == 0) { // Every ~1000ms
|
|
update_live_metrics();
|
|
}
|
|
|
|
// Calibrated delay (~5ms) for smooth interaction without high CPU load
|
|
for (volatile int d = 0; d < 8000; d++);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// System V AMD64 ABI compliant _start entry point
|
|
extern "C" __attribute__((naked)) void _start() {
|
|
__asm__ volatile (
|
|
"andq $-16, %rsp\n"
|
|
"call main\n"
|
|
"movq %rax, %rdi\n"
|
|
"call exit\n"
|
|
);
|
|
}
|