From 9634ebb08660b3bdb2d246bd5619b85defa4baa0 Mon Sep 17 00:00:00 2001 From: boreddevnl Date: Wed, 1 Apr 2026 23:05:52 +0200 Subject: [PATCH] FIX: Fixed framebuffer freeze upon screenshot --- src/fs/fat32.c | 16 +++- src/userland/gui/screenshot.c | 135 ++++++++++++++++++---------------- src/wm/cmd.c | 2 +- src/wm/graphics.c | 15 ++-- src/wm/gui_ipc.h | 9 ++- src/wm/wm.c | 16 ++-- 6 files changed, 106 insertions(+), 87 deletions(-) diff --git a/src/fs/fat32.c b/src/fs/fat32.c index 4d2ae85..3440c69 100644 --- a/src/fs/fat32.c +++ b/src/fs/fat32.c @@ -232,6 +232,16 @@ static uint32_t ramfs_allocate_cluster(void) { return cluster; } +static int ramfs_count_files_in_dir(const char *normalized_path) { + int count = 0; + for (int i = 0; i < MAX_FILES; i++) { + if (files[i].used && fs_strcmp(files[i].parent_path, normalized_path) == 0) { + count++; + } + } + return count; +} + static bool check_desktop_limit(const char *normalized_path) { if (desktop_file_limit < 0) return true; if (fs_strlen(normalized_path) > 9 && @@ -245,10 +255,8 @@ static bool check_desktop_limit(const char *normalized_path) { if (*p == '/') return true; p++; } - FAT32_FileInfo *info = (FAT32_FileInfo*)kmalloc(256 * sizeof(FAT32_FileInfo)); - if (!info) return true; - int count = fat32_list_directory("/Desktop", info, 256); - kfree(info); + + int count = ramfs_count_files_in_dir("/Desktop"); if (count >= desktop_file_limit) return false; } return true; diff --git a/src/userland/gui/screenshot.c b/src/userland/gui/screenshot.c index e46d5e3..cc01537 100644 --- a/src/userland/gui/screenshot.c +++ b/src/userland/gui/screenshot.c @@ -9,16 +9,38 @@ #include "stb_image_write.h" #include -#define GUI_CMD_GET_SCREEN_SIZE 17 -#define GUI_CMD_GET_SCREENBUFFER 18 -#define GUI_CMD_SHOW_NOTIFICATION 19 -#define GUI_CMD_GET_DATETIME 20 +#define GUI_CMD_GET_SCREEN_SIZE 50 +#define GUI_CMD_GET_SCREENBUFFER 51 +#define GUI_CMD_SHOW_NOTIFICATION 52 +#define GUI_CMD_GET_DATETIME 53 + +#define PNG_WRITE_BUF_SIZE (8 * 1024 * 1024) // 8MB buffer to hold entire PNG +static uint8_t *png_output_buf = NULL; +static int png_output_idx = 0; void png_write_func(void *context, void *data, int size) { - int fd = *(int*)context; - sys_write_fs(fd, data, size); + (void)context; + if (!png_output_buf) return; + + if (png_output_idx + size < PNG_WRITE_BUF_SIZE) { + memcpy(png_output_buf + png_output_idx, data, size); + png_output_idx += size; + } } +// Global filename for helper functions +static char g_filename[128]; + +void append_num(int num, int digits) { + int len = 0; while (g_filename[len]) len++; + if (digits == 4) { + g_filename[len++] = '0' + (num / 1000) % 10; + g_filename[len++] = '0' + (num / 100) % 10; + } + g_filename[len++] = '0' + (num / 10) % 10; + g_filename[len++] = '0' + (num % 10); + g_filename[len] = '\0'; +} int main(int argc, char **argv) { (void)argc; @@ -29,28 +51,25 @@ int main(int argc, char **argv) { syscall3(SYS_GUI, GUI_CMD_GET_SCREEN_SIZE, (uint64_t)&w, (uint64_t)&h); if (w == 0 || h == 0 || w > 4096 || h > 4096) { - printf("Failed to get screen size %d x %d\n", (int)w, (int)h); return 1; } - // 2. Allocate buffer for 0xAARRGGBB + // 2. Allocate buffers uint32_t *pixels = (uint32_t *)malloc(w * h * sizeof(uint32_t)); - if (!pixels) { - printf("Failed to allocate memory for %d x %d pixels\n", (int)w, (int)h); + uint8_t *rgb_pixels = (uint8_t *)malloc(w * h * 3); + png_output_buf = (uint8_t *)malloc(PNG_WRITE_BUF_SIZE); + + if (!pixels || !rgb_pixels || !png_output_buf) { + if (pixels) free(pixels); + if (rgb_pixels) free(rgb_pixels); + if (png_output_buf) free(png_output_buf); return 1; } // 3. Request screenbuffer syscall2(SYS_GUI, GUI_CMD_GET_SCREENBUFFER, (uint64_t)pixels); - // 4. Convert 0xAARRGGBB to RGB for stb_image_write - uint8_t *rgb_pixels = (uint8_t *)malloc(w * h * 3); - if (!rgb_pixels) { - printf("Failed to allocate RGB buffer\n"); - free(pixels); - return 1; - } - + // 4. Convert 0xAARRGGBB to RGB for (int y = 0; y < (int)h; y++) { for (int x = 0; x < (int)w; x++) { uint32_t px = pixels[y * w + x]; @@ -61,62 +80,50 @@ int main(int argc, char **argv) { } } - // 5. Get Datetime for filename + // 5. Get Datetime and construct filename uint64_t dt[6] = {0}; syscall2(SYS_GUI, GUI_CMD_GET_DATETIME, (uint64_t)dt); - char filename[128] = "A:/Desktop/screenshot-"; + strcpy(g_filename, "/Desktop/screenshot-"); + append_num((int)dt[0], 4); // Year + append_num((int)dt[1], 2); // Month + append_num((int)dt[2], 2); // Day - // Quick helper to append 4-digit and 2-digit numbers - auto void append_num(int num, int digits); - void append_num(int num, int digits) { - int len = 0; while (filename[len]) len++; - if (digits == 4) { - filename[len++] = '0' + (num / 1000) % 10; - filename[len++] = '0' + (num / 100) % 10; + int len = strlen(g_filename); + g_filename[len++] = '-'; g_filename[len] = '\0'; + + append_num((int)dt[3], 2); // Hour + append_num((int)dt[4], 2); // Min + append_num((int)dt[5], 2); // Sec + strcat(g_filename, ".png"); + + // 6. Generate PNG in memory + png_output_idx = 0; + int res = stbi_write_png_to_func(png_write_func, NULL, (int)w, (int)h, 3, rgb_pixels, (int)w * 3); + + // 7. Perform a SINGLE write to the filesystem + if (res && png_output_idx > 0) { + int fd = sys_open(g_filename, "w"); + if (fd >= 0) { + sys_write_fs(fd, png_output_buf, png_output_idx); + sys_close(fd); + + // Show notification + char notif[256] = "Saved "; + strcat(notif, g_filename + 9); // Skip "/Desktop/" + syscall2(SYS_GUI, GUI_CMD_SHOW_NOTIFICATION, (uint64_t)notif); + } else { + res = 0; } - filename[len++] = '0' + (num / 10) % 10; - filename[len++] = '0' + (num % 10); - filename[len] = '\0'; } - append_num((int)dt[0], 4); - append_num((int)dt[1], 2); - append_num((int)dt[2], 2); - int len = 0; while (filename[len]) len++; - filename[len++] = '-'; filename[len] = '\0'; - append_num((int)dt[3], 2); - append_num((int)dt[4], 2); - append_num((int)dt[5], 2); - len = 0; while (filename[len]) len++; - filename[len++] = '.'; filename[len++] = 'p'; filename[len++] = 'n'; filename[len++] = 'g'; filename[len] = '\0'; - - // 6. Write to PNG - int fd = sys_open(filename, "w"); // Open file - int res = 0; - if (fd >= 0) { - res = stbi_write_png_to_func(png_write_func, &fd, (int)w, (int)h, 3, rgb_pixels, (int)w * 3); - sys_close(fd); // Close file + if (!res) { + syscall2(SYS_GUI, GUI_CMD_SHOW_NOTIFICATION, (uint64_t)"Failed to save screenshot"); } + free(png_output_buf); free(rgb_pixels); free(pixels); - if (res) { - char notif[256] = "Saved "; - int nlen = 6; - int flen = 0; - while (filename[11 + flen]) { - notif[nlen + flen] = filename[11 + flen]; - flen++; - } - notif[nlen + flen] = '\0'; - - syscall2(SYS_GUI, GUI_CMD_SHOW_NOTIFICATION, (uint64_t)notif); - } else { - syscall2(SYS_GUI, GUI_CMD_SHOW_NOTIFICATION, (uint64_t)"Failed to save screenshot"); - return 1; - } - - return 0; + return res ? 0 : 1; } diff --git a/src/wm/cmd.c b/src/wm/cmd.c index dd350c8..63c4da6 100644 --- a/src/wm/cmd.c +++ b/src/wm/cmd.c @@ -374,7 +374,7 @@ static void cmd_init_config_defaults(void) { shell_config.default_text_color = 0xFFFFFFFF; // White shell_config.bg_color = 0xFF1E1E1E; // Dark background shell_config.cursor_color = 0xFFFFFFFF; - shell_config.show_drive = true; + shell_config.show_drive = false; shell_config.show_dir = true; shell_config.dir_color = 0xFF569CD6; shell_config.file_color = 0xFFFFFFFF; diff --git a/src/wm/graphics.c b/src/wm/graphics.c index df1adf3..c586ec2 100644 --- a/src/wm/graphics.c +++ b/src/wm/graphics.c @@ -842,19 +842,22 @@ void graphics_flip_buffer(void) { void graphics_copy_screenbuffer(uint32_t *dest) { if (!g_fb || !dest) return; - uint64_t rflags; - asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); - int sw = g_fb->width; - int sh = g_fb->height; + extern uint64_t wm_lock_acquire(void); + extern void wm_lock_release(uint64_t); + uint64_t rflags = wm_lock_acquire(); + + int sw = (int)g_fb->width; + int sh = (int)g_fb->height; - // Copy the internal back object to the dest directly + // Copy from the composition back buffer for (int y = 0; y < sh; y++) { uint32_t *src_row = &g_back_buffer[y * sw]; for (int x = 0; x < sw; x++) { dest[y * sw + x] = src_row[x]; } } - asm volatile("push %0; popfq" : : "r"(rflags)); + + wm_lock_release(rflags); } void graphics_set_clipping(int x, int y, int w, int h) { diff --git a/src/wm/gui_ipc.h b/src/wm/gui_ipc.h index cc4b2ca..4e3c1f3 100644 --- a/src/wm/gui_ipc.h +++ b/src/wm/gui_ipc.h @@ -14,10 +14,11 @@ #define GUI_CMD_GET_STRING_WIDTH 8 #define GUI_CMD_GET_FONT_HEIGHT 9 #define GUI_CMD_WINDOW_SET_RESIZABLE 14 -#define GUI_CMD_GET_SCREEN_SIZE 17 -#define GUI_CMD_GET_SCREENBUFFER 18 -#define GUI_CMD_SHOW_NOTIFICATION 19 -#define GUI_CMD_GET_DATETIME 20 +// Remapped Screenshot API Commands to avoid collisions (Originals 17, 18, 19 conflicted with magic numbers) +#define GUI_CMD_GET_SCREEN_SIZE 50 +#define GUI_CMD_GET_SCREENBUFFER 51 +#define GUI_CMD_SHOW_NOTIFICATION 52 +#define GUI_CMD_GET_DATETIME 53 #define GUI_EVENT_NONE 0 #define GUI_EVENT_PAINT 1 diff --git a/src/wm/wm.c b/src/wm/wm.c index 6ee3b97..bcb282f 100644 --- a/src/wm/wm.c +++ b/src/wm/wm.c @@ -81,7 +81,7 @@ void (*wm_custom_paint_hook)(void) = NULL; // Notification state static char notif_text[256] = {0}; static int notif_timer = 0; -static int notif_x_offset = 300; // Starts offscreen +static int notif_x_offset = 420; // Starts offscreen static bool notif_active = false; extern bool ps2_ctrl_pressed; @@ -1502,9 +1502,9 @@ void wm_paint(void) { // Notification (dark mode) if (notif_active) { - int nx = sw - 280 + notif_x_offset; + int nx = sw - 400 + notif_x_offset; int ny = 40; - int nw = 260; + int nw = 380; int nh = 50; draw_rounded_rect_filled(nx, ny, nw, nh, 8, COLOR_DARK_PANEL); @@ -2679,7 +2679,7 @@ void wm_show_notification(const char *msg) { notif_text[i] = 0; notif_timer = 180; // ~3 seconds at 60Hz - notif_x_offset = 300; + notif_x_offset = 420; notif_active = true; force_redraw = true; } @@ -2811,19 +2811,19 @@ void wm_timer_tick(void) { notif_timer--; // Slide in if (notif_timer > 165 && notif_x_offset > 0) { // First 15 ticks (1/4 sec) slide in - notif_x_offset -= 20; + notif_x_offset -= 28; // Slightly faster slide for larger distance if (notif_x_offset < 0) notif_x_offset = 0; } // Slide out - else if (notif_timer < 15 && notif_x_offset < 300) { // Last 15 ticks slide out - notif_x_offset += 20; + else if (notif_timer < 15 && notif_x_offset < 420) { // Last 15 ticks slide out + notif_x_offset += 28; } } else { notif_active = false; } int sw = get_screen_width(); - wm_mark_dirty(sw - 280, 40, 275, 60); + wm_mark_dirty(sw - 420, 40, 415, 60); } }