FIX: Fixed framebuffer freeze upon screenshot

This commit is contained in:
boreddevnl 2026-04-01 23:05:52 +02:00
parent d7d97b5a97
commit 9634ebb086
6 changed files with 106 additions and 87 deletions

View file

@ -232,6 +232,16 @@ static uint32_t ramfs_allocate_cluster(void) {
return cluster; 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) { static bool check_desktop_limit(const char *normalized_path) {
if (desktop_file_limit < 0) return true; if (desktop_file_limit < 0) return true;
if (fs_strlen(normalized_path) > 9 && if (fs_strlen(normalized_path) > 9 &&
@ -245,10 +255,8 @@ static bool check_desktop_limit(const char *normalized_path) {
if (*p == '/') return true; if (*p == '/') return true;
p++; p++;
} }
FAT32_FileInfo *info = (FAT32_FileInfo*)kmalloc(256 * sizeof(FAT32_FileInfo));
if (!info) return true; int count = ramfs_count_files_in_dir("/Desktop");
int count = fat32_list_directory("/Desktop", info, 256);
kfree(info);
if (count >= desktop_file_limit) return false; if (count >= desktop_file_limit) return false;
} }
return true; return true;

View file

@ -9,16 +9,38 @@
#include "stb_image_write.h" #include "stb_image_write.h"
#include <string.h> #include <string.h>
#define GUI_CMD_GET_SCREEN_SIZE 17 #define GUI_CMD_GET_SCREEN_SIZE 50
#define GUI_CMD_GET_SCREENBUFFER 18 #define GUI_CMD_GET_SCREENBUFFER 51
#define GUI_CMD_SHOW_NOTIFICATION 19 #define GUI_CMD_SHOW_NOTIFICATION 52
#define GUI_CMD_GET_DATETIME 20 #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) { void png_write_func(void *context, void *data, int size) {
int fd = *(int*)context; (void)context;
sys_write_fs(fd, data, size); 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) { int main(int argc, char **argv) {
(void)argc; (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); syscall3(SYS_GUI, GUI_CMD_GET_SCREEN_SIZE, (uint64_t)&w, (uint64_t)&h);
if (w == 0 || h == 0 || w > 4096 || h > 4096) { 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; return 1;
} }
// 2. Allocate buffer for 0xAARRGGBB // 2. Allocate buffers
uint32_t *pixels = (uint32_t *)malloc(w * h * sizeof(uint32_t)); uint32_t *pixels = (uint32_t *)malloc(w * h * sizeof(uint32_t));
if (!pixels) { uint8_t *rgb_pixels = (uint8_t *)malloc(w * h * 3);
printf("Failed to allocate memory for %d x %d pixels\n", (int)w, (int)h); 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; return 1;
} }
// 3. Request screenbuffer // 3. Request screenbuffer
syscall2(SYS_GUI, GUI_CMD_GET_SCREENBUFFER, (uint64_t)pixels); syscall2(SYS_GUI, GUI_CMD_GET_SCREENBUFFER, (uint64_t)pixels);
// 4. Convert 0xAARRGGBB to RGB for stb_image_write // 4. Convert 0xAARRGGBB to RGB
uint8_t *rgb_pixels = (uint8_t *)malloc(w * h * 3);
if (!rgb_pixels) {
printf("Failed to allocate RGB buffer\n");
free(pixels);
return 1;
}
for (int y = 0; y < (int)h; y++) { for (int y = 0; y < (int)h; y++) {
for (int x = 0; x < (int)w; x++) { for (int x = 0; x < (int)w; x++) {
uint32_t px = pixels[y * 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}; uint64_t dt[6] = {0};
syscall2(SYS_GUI, GUI_CMD_GET_DATETIME, (uint64_t)dt); 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 int len = strlen(g_filename);
auto void append_num(int num, int digits); g_filename[len++] = '-'; g_filename[len] = '\0';
void append_num(int num, int digits) {
int len = 0; while (filename[len]) len++; append_num((int)dt[3], 2); // Hour
if (digits == 4) { append_num((int)dt[4], 2); // Min
filename[len++] = '0' + (num / 1000) % 10; append_num((int)dt[5], 2); // Sec
filename[len++] = '0' + (num / 100) % 10; 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); if (!res) {
append_num((int)dt[1], 2); syscall2(SYS_GUI, GUI_CMD_SHOW_NOTIFICATION, (uint64_t)"Failed to save screenshot");
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
} }
free(png_output_buf);
free(rgb_pixels); free(rgb_pixels);
free(pixels); free(pixels);
if (res) { return res ? 0 : 1;
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;
} }

View file

@ -374,7 +374,7 @@ static void cmd_init_config_defaults(void) {
shell_config.default_text_color = 0xFFFFFFFF; // White shell_config.default_text_color = 0xFFFFFFFF; // White
shell_config.bg_color = 0xFF1E1E1E; // Dark background shell_config.bg_color = 0xFF1E1E1E; // Dark background
shell_config.cursor_color = 0xFFFFFFFF; shell_config.cursor_color = 0xFFFFFFFF;
shell_config.show_drive = true; shell_config.show_drive = false;
shell_config.show_dir = true; shell_config.show_dir = true;
shell_config.dir_color = 0xFF569CD6; shell_config.dir_color = 0xFF569CD6;
shell_config.file_color = 0xFFFFFFFF; shell_config.file_color = 0xFFFFFFFF;

View file

@ -842,19 +842,22 @@ void graphics_flip_buffer(void) {
void graphics_copy_screenbuffer(uint32_t *dest) { void graphics_copy_screenbuffer(uint32_t *dest) {
if (!g_fb || !dest) return; if (!g_fb || !dest) return;
uint64_t rflags; extern uint64_t wm_lock_acquire(void);
asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); extern void wm_lock_release(uint64_t);
int sw = g_fb->width; uint64_t rflags = wm_lock_acquire();
int sh = g_fb->height;
// Copy the internal back object to the dest directly int sw = (int)g_fb->width;
int sh = (int)g_fb->height;
// Copy from the composition back buffer
for (int y = 0; y < sh; y++) { for (int y = 0; y < sh; y++) {
uint32_t *src_row = &g_back_buffer[y * sw]; uint32_t *src_row = &g_back_buffer[y * sw];
for (int x = 0; x < sw; x++) { for (int x = 0; x < sw; x++) {
dest[y * sw + x] = src_row[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) { void graphics_set_clipping(int x, int y, int w, int h) {

View file

@ -14,10 +14,11 @@
#define GUI_CMD_GET_STRING_WIDTH 8 #define GUI_CMD_GET_STRING_WIDTH 8
#define GUI_CMD_GET_FONT_HEIGHT 9 #define GUI_CMD_GET_FONT_HEIGHT 9
#define GUI_CMD_WINDOW_SET_RESIZABLE 14 #define GUI_CMD_WINDOW_SET_RESIZABLE 14
#define GUI_CMD_GET_SCREEN_SIZE 17 // Remapped Screenshot API Commands to avoid collisions (Originals 17, 18, 19 conflicted with magic numbers)
#define GUI_CMD_GET_SCREENBUFFER 18 #define GUI_CMD_GET_SCREEN_SIZE 50
#define GUI_CMD_SHOW_NOTIFICATION 19 #define GUI_CMD_GET_SCREENBUFFER 51
#define GUI_CMD_GET_DATETIME 20 #define GUI_CMD_SHOW_NOTIFICATION 52
#define GUI_CMD_GET_DATETIME 53
#define GUI_EVENT_NONE 0 #define GUI_EVENT_NONE 0
#define GUI_EVENT_PAINT 1 #define GUI_EVENT_PAINT 1

View file

@ -81,7 +81,7 @@ void (*wm_custom_paint_hook)(void) = NULL;
// Notification state // Notification state
static char notif_text[256] = {0}; static char notif_text[256] = {0};
static int notif_timer = 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; static bool notif_active = false;
extern bool ps2_ctrl_pressed; extern bool ps2_ctrl_pressed;
@ -1502,9 +1502,9 @@ void wm_paint(void) {
// Notification (dark mode) // Notification (dark mode)
if (notif_active) { if (notif_active) {
int nx = sw - 280 + notif_x_offset; int nx = sw - 400 + notif_x_offset;
int ny = 40; int ny = 40;
int nw = 260; int nw = 380;
int nh = 50; int nh = 50;
draw_rounded_rect_filled(nx, ny, nw, nh, 8, COLOR_DARK_PANEL); 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_text[i] = 0;
notif_timer = 180; // ~3 seconds at 60Hz notif_timer = 180; // ~3 seconds at 60Hz
notif_x_offset = 300; notif_x_offset = 420;
notif_active = true; notif_active = true;
force_redraw = true; force_redraw = true;
} }
@ -2811,19 +2811,19 @@ void wm_timer_tick(void) {
notif_timer--; notif_timer--;
// Slide in // Slide in
if (notif_timer > 165 && notif_x_offset > 0) { // First 15 ticks (1/4 sec) 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; if (notif_x_offset < 0) notif_x_offset = 0;
} }
// Slide out // Slide out
else if (notif_timer < 15 && notif_x_offset < 300) { // Last 15 ticks slide out else if (notif_timer < 15 && notif_x_offset < 420) { // Last 15 ticks slide out
notif_x_offset += 20; notif_x_offset += 28;
} }
} else { } else {
notif_active = false; notif_active = false;
} }
int sw = get_screen_width(); int sw = get_screen_width();
wm_mark_dirty(sw - 280, 40, 275, 60); wm_mark_dirty(sw - 420, 40, 415, 60);
} }
} }