mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 10:48:38 +00:00
screenshot util
This commit is contained in:
parent
dbaff43c6f
commit
071f8339bf
20 changed files with 1992 additions and 21 deletions
BIN
boredos.iso
BIN
boredos.iso
Binary file not shown.
BIN
build/cmd.o
BIN
build/cmd.o
Binary file not shown.
BIN
build/explorer.o
BIN
build/explorer.o
Binary file not shown.
BIN
build/fat32.o
BIN
build/fat32.o
Binary file not shown.
BIN
build/graphics.o
BIN
build/graphics.o
Binary file not shown.
BIN
build/ps2.o
BIN
build/ps2.o
Binary file not shown.
BIN
disk.img
BIN
disk.img
Binary file not shown.
|
|
@ -818,6 +818,7 @@ static int realfs_write(FAT32_FileHandle *handle, const void *buffer, int size)
|
||||||
uint32_t old_val = *(uint32_t*)&fat_buf[fat_offset];
|
uint32_t old_val = *(uint32_t*)&fat_buf[fat_offset];
|
||||||
*(uint32_t*)&fat_buf[fat_offset] = (old_val & 0xF0000000) | 0x0FFFFFF8; // EOF
|
*(uint32_t*)&fat_buf[fat_offset] = (old_val & 0xF0000000) | 0x0FFFFFF8; // EOF
|
||||||
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
|
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
|
||||||
|
if (vol->cached_fat_sector == fat_sector) vol->cached_fat_sector = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
if (fat_buf) kfree(fat_buf);
|
if (fat_buf) kfree(fat_buf);
|
||||||
|
|
||||||
|
|
@ -894,6 +895,7 @@ static int realfs_write(FAT32_FileHandle *handle, const void *buffer, int size)
|
||||||
uint32_t old_val = *(uint32_t*)&fat_buf[fat_offset];
|
uint32_t old_val = *(uint32_t*)&fat_buf[fat_offset];
|
||||||
*(uint32_t*)&fat_buf[fat_offset] = (old_val & 0xF0000000) | (new_cluster & 0x0FFFFFFF);
|
*(uint32_t*)&fat_buf[fat_offset] = (old_val & 0xF0000000) | (new_cluster & 0x0FFFFFFF);
|
||||||
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
|
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
|
||||||
|
if (vol->cached_fat_sector == fat_sector) vol->cached_fat_sector = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
if (fat_buf) kfree(fat_buf);
|
if (fat_buf) kfree(fat_buf);
|
||||||
|
|
||||||
|
|
@ -905,6 +907,7 @@ static int realfs_write(FAT32_FileHandle *handle, const void *buffer, int size)
|
||||||
uint32_t old_val = *(uint32_t*)&fat_buf[fat_offset];
|
uint32_t old_val = *(uint32_t*)&fat_buf[fat_offset];
|
||||||
*(uint32_t*)&fat_buf[fat_offset] = (old_val & 0xF0000000) | 0x0FFFFFF8; // EOF
|
*(uint32_t*)&fat_buf[fat_offset] = (old_val & 0xF0000000) | 0x0FFFFFF8; // EOF
|
||||||
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
|
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
|
||||||
|
if (vol->cached_fat_sector == fat_sector) vol->cached_fat_sector = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
if (fat_buf) kfree(fat_buf);
|
if (fat_buf) kfree(fat_buf);
|
||||||
|
|
||||||
|
|
@ -1074,6 +1077,7 @@ static bool realfs_delete(char drive, const char *path) {
|
||||||
if (vol->disk->read_sector(vol->disk, fat_sector, fat_buf) == 0) {
|
if (vol->disk->read_sector(vol->disk, fat_sector, fat_buf) == 0) {
|
||||||
*(uint32_t*)&fat_buf[fat_offset] = 0; // Free
|
*(uint32_t*)&fat_buf[fat_offset] = 0; // Free
|
||||||
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
|
vol->disk->write_sector(vol->disk, fat_sector, fat_buf);
|
||||||
|
if (vol->cached_fat_sector == fat_sector) vol->cached_fat_sector = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
kfree(fat_buf);
|
kfree(fat_buf);
|
||||||
|
|
||||||
|
|
@ -1449,6 +1453,7 @@ static bool realfs_mkdir(char drive, const char *path) {
|
||||||
uint32_t old_val = *(uint32_t*)§_buf[fat_offset];
|
uint32_t old_val = *(uint32_t*)§_buf[fat_offset];
|
||||||
*(uint32_t*)§_buf[fat_offset] = (old_val & 0xF0000000) | (expanded & 0x0FFFFFFF);
|
*(uint32_t*)§_buf[fat_offset] = (old_val & 0xF0000000) | (expanded & 0x0FFFFFFF);
|
||||||
vol->disk->write_sector(vol->disk, fat_sector, sect_buf);
|
vol->disk->write_sector(vol->disk, fat_sector, sect_buf);
|
||||||
|
if (vol->cached_fat_sector == fat_sector) vol->cached_fat_sector = 0xFFFFFFFF;
|
||||||
}
|
}
|
||||||
// Zero out new cluster
|
// Zero out new cluster
|
||||||
for(uint32_t k=0; k<cluster_size; k++) dir_cluster_buf[k] = 0;
|
for(uint32_t k=0; k<cluster_size; k++) dir_cluster_buf[k] = 0;
|
||||||
|
|
|
||||||
|
|
@ -583,6 +583,24 @@ 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;
|
||||||
|
|
||||||
|
// Copy the internal back object to the dest directly
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
void graphics_set_clipping(int x, int y, int w, int h) {
|
void graphics_set_clipping(int x, int y, int w, int h) {
|
||||||
if (x < 0) { w += x; x = 0; }
|
if (x < 0) { w += x; x = 0; }
|
||||||
if (y < 0) { h += y; y = 0; }
|
if (y < 0) { h += y; y = 0; }
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ void graphics_set_bg_pattern(const uint32_t *pattern); // 128x128 pattern
|
||||||
void graphics_set_bg_image(uint32_t *pixels, int w, int h); // Full-screen wallpaper image
|
void graphics_set_bg_image(uint32_t *pixels, int w, int h); // Full-screen wallpaper image
|
||||||
void graphics_set_render_target(uint32_t *buffer, int w, int h);
|
void graphics_set_render_target(uint32_t *buffer, int w, int h);
|
||||||
void graphics_blit_buffer(uint32_t *src, int dst_x, int dst_y, int w, int h);
|
void graphics_blit_buffer(uint32_t *src, int dst_x, int dst_y, int w, int h);
|
||||||
|
void graphics_copy_screenbuffer(uint32_t *dest);
|
||||||
|
|
||||||
|
|
||||||
void draw_boredos_logo(int x, int y, int scale);
|
void draw_boredos_logo(int x, int y, int scale);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,10 @@
|
||||||
#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
|
||||||
|
#define GUI_CMD_GET_SCREENBUFFER 18
|
||||||
|
#define GUI_CMD_SHOW_NOTIFICATION 19
|
||||||
|
#define GUI_CMD_GET_DATETIME 20
|
||||||
|
|
||||||
#define GUI_EVENT_NONE 0
|
#define GUI_EVENT_NONE 0
|
||||||
#define GUI_EVENT_PAINT 1
|
#define GUI_EVENT_PAINT 1
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ uint64_t timer_handler(registers_t *regs) {
|
||||||
|
|
||||||
// --- Keyboard ---
|
// --- Keyboard ---
|
||||||
static bool shift_pressed = false;
|
static bool shift_pressed = false;
|
||||||
static bool ctrl_pressed = false;
|
bool ps2_ctrl_pressed = false;
|
||||||
static bool extended_scancode = false;
|
static bool extended_scancode = false;
|
||||||
|
|
||||||
static char scancode_map[128] = {
|
static char scancode_map[128] = {
|
||||||
|
|
@ -54,14 +54,14 @@ uint64_t keyboard_handler(registers_t *regs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scancode == 0x1D) {
|
if (scancode == 0x1D) {
|
||||||
ctrl_pressed = true;
|
ps2_ctrl_pressed = true;
|
||||||
extended_scancode = false; // Reset if Ctrl is pressed (prevents E0 1D bug)
|
extended_scancode = false; // Reset if Ctrl is pressed (prevents E0 1D bug)
|
||||||
} else if (scancode == 0x9D) {
|
} else if (scancode == 0x9D) {
|
||||||
ctrl_pressed = false;
|
ps2_ctrl_pressed = false;
|
||||||
extended_scancode = false;
|
extended_scancode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctrl_pressed && scancode == 0x2E) {
|
if (ps2_ctrl_pressed && scancode == 0x2E) {
|
||||||
extern process_t* process_get_current(void);
|
extern process_t* process_get_current(void);
|
||||||
process_t* proc = process_get_current();
|
process_t* proc = process_get_current();
|
||||||
if (proc && proc->is_user && proc->is_terminal_proc && proc->ui_window) {
|
if (proc && proc->is_user && proc->is_terminal_proc && proc->ui_window) {
|
||||||
|
|
|
||||||
|
|
@ -680,6 +680,51 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (cmd == GUI_CMD_GET_SCREEN_SIZE) {
|
||||||
|
uint64_t *out_w = (uint64_t *)arg2;
|
||||||
|
uint64_t *out_h = (uint64_t *)arg3;
|
||||||
|
if (out_w && out_h) {
|
||||||
|
extern int get_screen_width(void);
|
||||||
|
extern int get_screen_height(void);
|
||||||
|
*out_w = (uint64_t)get_screen_width();
|
||||||
|
*out_h = (uint64_t)get_screen_height();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else if (cmd == GUI_CMD_GET_SCREENBUFFER) {
|
||||||
|
uint32_t *dest = (uint32_t *)arg2;
|
||||||
|
if (dest) {
|
||||||
|
extern void graphics_copy_screenbuffer(uint32_t *dest);
|
||||||
|
graphics_copy_screenbuffer(dest);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else if (cmd == GUI_CMD_SHOW_NOTIFICATION) {
|
||||||
|
const char *user_msg = (const char *)arg2;
|
||||||
|
if (user_msg) {
|
||||||
|
char kernel_msg[256];
|
||||||
|
int i = 0;
|
||||||
|
while (i < 255 && user_msg[i]) {
|
||||||
|
kernel_msg[i] = user_msg[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
kernel_msg[i] = 0;
|
||||||
|
extern void wm_show_notification(const char *msg);
|
||||||
|
wm_show_notification(kernel_msg);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
} else if (cmd == GUI_CMD_GET_DATETIME) {
|
||||||
|
uint64_t *out_arr = (uint64_t *)arg2;
|
||||||
|
if (out_arr) {
|
||||||
|
extern void rtc_get_datetime(int *year, int *month, int *day, int *hour, int *minute, int *second);
|
||||||
|
int y, m, d, h, min, s;
|
||||||
|
rtc_get_datetime(&y, &m, &d, &h, &min, &s);
|
||||||
|
out_arr[0] = y;
|
||||||
|
out_arr[1] = m;
|
||||||
|
out_arr[2] = d;
|
||||||
|
out_arr[3] = h;
|
||||||
|
out_arr[4] = min;
|
||||||
|
out_arr[5] = s;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (syscall_num == SYS_FS) {
|
} else if (syscall_num == SYS_FS) {
|
||||||
int cmd = (int)arg1;
|
int cmd = (int)arg1;
|
||||||
|
|
@ -1090,9 +1135,6 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
mem += (processes[i].heap_end - processes[i].heap_start);
|
mem += (processes[i].heap_end - processes[i].heap_start);
|
||||||
|
|
||||||
if (processes[i].pid == 0) {
|
if (processes[i].pid == 0) {
|
||||||
// For kernel, we can report a more realistic figure if we want,
|
|
||||||
// but 32KB is specifically its stack. Let's keep it but maybe
|
|
||||||
// add a note in documentation.
|
|
||||||
mem = 32768;
|
mem = 32768;
|
||||||
} else {
|
} else {
|
||||||
if (processes[i].is_user) mem += 262144; // User stack
|
if (processes[i].is_user) mem += 262144; // User stack
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ CC = x86_64-elf-gcc
|
||||||
AS = nasm
|
AS = nasm
|
||||||
LD = x86_64-elf-ld
|
LD = x86_64-elf-ld
|
||||||
|
|
||||||
CFLAGS = -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone -Ilibc
|
CFLAGS = -Wall -Wextra -std=gnu11 -ffreestanding -O2 -fno-stack-protector -fno-stack-check -fno-lto -fno-pie -m64 -march=x86-64 -mno-red-zone -Ilibc
|
||||||
LDFLAGS = -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start
|
LDFLAGS = -m elf_x86_64 -nostdlib -static -no-pie -Ttext=0x40000000 --no-dynamic-linker -z text -z max-page-size=0x1000 -e _start
|
||||||
|
|
||||||
BIN_DIR = bin
|
BIN_DIR = bin
|
||||||
|
|
@ -45,6 +45,9 @@ $(BIN_DIR)/settings.elf: $(LIBC_OBJS) $(BIN_DIR)/settings.o $(BIN_DIR)/stb_image
|
||||||
$(BIN_DIR)/browser.elf: $(LIBC_OBJS) $(BIN_DIR)/browser.o $(BIN_DIR)/stb_image.o
|
$(BIN_DIR)/browser.elf: $(LIBC_OBJS) $(BIN_DIR)/browser.o $(BIN_DIR)/stb_image.o
|
||||||
$(LD) $(LDFLAGS) $^ -o $@
|
$(LD) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
|
$(BIN_DIR)/screenshot.elf: $(LIBC_OBJS) $(BIN_DIR)/screenshot.o $(BIN_DIR)/stb_image.o
|
||||||
|
$(LD) $(LDFLAGS) $^ -o $@
|
||||||
|
|
||||||
$(BIN_DIR)/%.o: doom/%.c
|
$(BIN_DIR)/%.o: doom/%.c
|
||||||
$(CC) $(CFLAGS) -Wno-error -Idoom -c $< -o $@
|
$(CC) $(CFLAGS) -Wno-error -Idoom -c $< -o $@
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,17 +185,7 @@ void _exit(int status) {
|
||||||
exit(status);
|
exit(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* memmove(void *dest, const void *src, size_t n) {
|
|
||||||
unsigned char *d = dest;
|
|
||||||
const unsigned char *s = src;
|
|
||||||
if (d < s) {
|
|
||||||
while (n--) *d++ = *s++;
|
|
||||||
} else {
|
|
||||||
d += n; s += n;
|
|
||||||
while (n--) *--d = *--s;
|
|
||||||
}
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
int fflush(FILE *stream) { return 0; }
|
int fflush(FILE *stream) { return 0; }
|
||||||
int abs(int x) { return x < 0 ? -x : x; }
|
int abs(int x) { return x < 0 ? -x : x; }
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,30 @@ void *memcpy(void *dest, const void *src, size_t n) {
|
||||||
return dest;
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *memmove(void *dest, const void *src, size_t n) {
|
||||||
|
unsigned char *d = (unsigned char *)dest;
|
||||||
|
const unsigned char *s = (const unsigned char *)src;
|
||||||
|
if (d < s) {
|
||||||
|
while (n--) *d++ = *s++;
|
||||||
|
} else {
|
||||||
|
d += n;
|
||||||
|
s += n;
|
||||||
|
while (n--) *--d = *--s;
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
int memcmp(const void *s1, const void *s2, size_t n) {
|
||||||
|
const unsigned char *p1 = (const unsigned char *)s1;
|
||||||
|
const unsigned char *p2 = (const unsigned char *)s2;
|
||||||
|
while (n--) {
|
||||||
|
if (*p1 != *p2) return *p1 - *p2;
|
||||||
|
p1++;
|
||||||
|
p2++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
// String functions
|
// String functions
|
||||||
size_t strlen(const char *s) {
|
size_t strlen(const char *s) {
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
#ifndef BOREDOS_LIBC_STRING_H
|
#ifndef BOREDOS_LIBC_STRING_H
|
||||||
#define BOREDOS_LIBC_STRING_H
|
#define BOREDOS_LIBC_STRING_H
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *memmove(void *dest, const void *src, size_t n);
|
||||||
|
int memcmp(const void *s1, const void *s2, size_t n);
|
||||||
|
void *memcpy(void *dest, const void *src, size_t n);
|
||||||
|
void *memset(void *s, int c, size_t n);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
122
src/kernel/userland/screenshot.c
Normal file
122
src/kernel/userland/screenshot.c
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "stdlib.h"
|
||||||
|
#include "libui.h"
|
||||||
|
#include "syscall_user.h"
|
||||||
|
|
||||||
|
#define STBI_WRITE_NO_STDIO
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#include "stb_image_write.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
void png_write_func(void *context, void *data, int size) {
|
||||||
|
int fd = *(int*)context;
|
||||||
|
sys_write_fs(fd, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
(void)argc;
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
// 1. Get screen size
|
||||||
|
uint64_t w = 0, h = 0;
|
||||||
|
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
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < (int)h; y++) {
|
||||||
|
for (int x = 0; x < (int)w; x++) {
|
||||||
|
uint32_t px = pixels[y * w + x];
|
||||||
|
int idx = (y * w + x) * 3;
|
||||||
|
rgb_pixels[idx + 0] = (px >> 16) & 0xFF; // R
|
||||||
|
rgb_pixels[idx + 1] = (px >> 8) & 0xFF; // G
|
||||||
|
rgb_pixels[idx + 2] = (px) & 0xFF; // B
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Get Datetime for filename
|
||||||
|
uint64_t dt[6] = {0};
|
||||||
|
syscall2(SYS_GUI, GUI_CMD_GET_DATETIME, (uint64_t)dt);
|
||||||
|
|
||||||
|
char filename[128] = "A:/Desktop/screenshot-";
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
1699
src/kernel/userland/stb_image_write.h
Normal file
1699
src/kernel/userland/stb_image_write.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -66,6 +66,13 @@ static char msg_box_text[64];
|
||||||
// Hook definition
|
// Hook definition
|
||||||
void (*wm_custom_paint_hook)(void) = NULL;
|
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 bool notif_active = false;
|
||||||
|
extern bool ps2_ctrl_pressed;
|
||||||
|
|
||||||
// Dragging State
|
// Dragging State
|
||||||
static bool is_dragging = false;
|
static bool is_dragging = false;
|
||||||
static bool is_resizing = false;
|
static bool is_resizing = false;
|
||||||
|
|
@ -1411,7 +1418,18 @@ void wm_paint(void) {
|
||||||
draw_string(mx + 15, my + 10, msg_box_title, COLOR_DARK_TEXT);
|
draw_string(mx + 15, my + 10, msg_box_title, COLOR_DARK_TEXT);
|
||||||
draw_string(mx + 10, my + 40, msg_box_text, COLOR_DARK_TEXT);
|
draw_string(mx + 10, my + 40, msg_box_text, COLOR_DARK_TEXT);
|
||||||
draw_rounded_rect_filled(mx + mw/2 - 30, my + 70, 60, 20, 4, COLOR_DARK_BORDER);
|
draw_rounded_rect_filled(mx + mw/2 - 30, my + 70, 60, 20, 4, COLOR_DARK_BORDER);
|
||||||
draw_string(mx + mw/2 - 18, my + 75, "OK", COLOR_DARK_TEXT);
|
}
|
||||||
|
|
||||||
|
// Notification (dark mode)
|
||||||
|
if (notif_active) {
|
||||||
|
int nx = sw - 280 + notif_x_offset;
|
||||||
|
int ny = 40;
|
||||||
|
int nw = 260;
|
||||||
|
int nh = 50;
|
||||||
|
|
||||||
|
draw_rounded_rect_filled(nx, ny, nw, nh, 8, COLOR_DARK_PANEL);
|
||||||
|
draw_string(nx + 15, ny + 10, "Screenshot", COLOR_DARK_TEXT);
|
||||||
|
draw_string(nx + 15, ny + 30, notif_text, COLOR_DKGRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom Overlay (VM Graphics)
|
// Custom Overlay (VM Graphics)
|
||||||
|
|
@ -2492,6 +2510,7 @@ static void wm_dispatch_key(char c, bool pressed) {
|
||||||
|
|
||||||
if (!target) return;
|
if (!target) return;
|
||||||
|
|
||||||
|
|
||||||
if (target->handle_key) {
|
if (target->handle_key) {
|
||||||
target->handle_key(target, c, pressed);
|
target->handle_key(target, c, pressed);
|
||||||
}
|
}
|
||||||
|
|
@ -2500,7 +2519,26 @@ static void wm_dispatch_key(char c, bool pressed) {
|
||||||
wm_mark_dirty(target->x, target->y, target->w, target->h);
|
wm_mark_dirty(target->x, target->y, target->w, target->h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wm_show_notification(const char *msg) {
|
||||||
|
int i = 0;
|
||||||
|
while (msg[i] && i < 255) {
|
||||||
|
notif_text[i] = msg[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
notif_text[i] = 0;
|
||||||
|
|
||||||
|
notif_timer = 180; // ~3 seconds at 60Hz
|
||||||
|
notif_x_offset = 300;
|
||||||
|
notif_active = true;
|
||||||
|
force_redraw = true;
|
||||||
|
}
|
||||||
|
|
||||||
void wm_handle_key(char c, bool pressed) {
|
void wm_handle_key(char c, bool pressed) {
|
||||||
|
if (pressed && c == 'p' && ps2_ctrl_pressed) {
|
||||||
|
process_create_elf("/bin/screenshot.elf", NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int next = (key_head + 1) % INPUT_QUEUE_SIZE;
|
int next = (key_head + 1) % INPUT_QUEUE_SIZE;
|
||||||
if (next != key_tail) {
|
if (next != key_tail) {
|
||||||
key_queue[key_head].c = c;
|
key_queue[key_head].c = c;
|
||||||
|
|
@ -2607,6 +2645,26 @@ void wm_timer_tick(void) {
|
||||||
wm_mark_dirty(sw - 110, 6, 110, 24);
|
wm_mark_dirty(sw - 110, 6, 110, 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (notif_active) {
|
||||||
|
if (notif_timer > 0) {
|
||||||
|
notif_timer--;
|
||||||
|
// Slide in
|
||||||
|
if (notif_timer > 165 && notif_x_offset > 0) { // First 15 ticks (1/4 sec) slide in
|
||||||
|
notif_x_offset -= 20;
|
||||||
|
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 {
|
||||||
|
notif_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sw = get_screen_width();
|
||||||
|
wm_mark_dirty(sw - 280, 40, 275, 60);
|
||||||
|
}
|
||||||
|
|
||||||
if (force_redraw) {
|
if (force_redraw) {
|
||||||
graphics_mark_screen_dirty();
|
graphics_mark_screen_dirty();
|
||||||
force_redraw = false;
|
force_redraw = false;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue