mirror of
https://github.com/BoredDevNL/BoredOS.git
synced 2026-05-15 18:58:40 +00:00
OPT: Multithreaded WM rendering
This commit is contained in:
parent
e60f232812
commit
91b67bd8d5
7 changed files with 567 additions and 461 deletions
|
|
@ -9,17 +9,16 @@
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
#include "process.h"
|
#include "process.h"
|
||||||
|
#include "work_queue.h"
|
||||||
|
|
||||||
extern void serial_write(const char *str);
|
extern void serial_write(const char *str);
|
||||||
extern void serial_write_num(uint32_t n);
|
extern void serial_write_num(uint32_t n);
|
||||||
extern void serial_write_hex(uint64_t n);
|
extern void serial_write_hex(uint64_t n);
|
||||||
|
|
||||||
// --- Dynamically allocated per-CPU state ---
|
static cpu_state_t *cpu_states = NULL;
|
||||||
static cpu_state_t *cpu_states = NULL; // Array[cpu_count]
|
|
||||||
static uint32_t total_cpus = 0;
|
static uint32_t total_cpus = 0;
|
||||||
static uint32_t bsp_lapic_id = 0;
|
static uint32_t bsp_lapic_id = 0;
|
||||||
|
|
||||||
// Get LAPIC ID via CPUID leaf 0x01 (works on all x86_64)
|
|
||||||
static uint32_t read_lapic_id(void) {
|
static uint32_t read_lapic_id(void) {
|
||||||
uint32_t eax, ebx, ecx, edx;
|
uint32_t eax, ebx, ecx, edx;
|
||||||
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1));
|
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1));
|
||||||
|
|
@ -44,49 +43,37 @@ cpu_state_t *smp_get_cpu(uint32_t cpu_id) {
|
||||||
return &cpu_states[cpu_id];
|
return &cpu_states[cpu_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- AP Entry Point ---
|
|
||||||
// Called by Limine on each Application Processor.
|
|
||||||
// The limine_smp_info* is passed as a parameter.
|
|
||||||
static void ap_entry(struct limine_smp_info *info) {
|
static void ap_entry(struct limine_smp_info *info) {
|
||||||
// 1. Figure out which CPU we are
|
|
||||||
uint32_t my_id = (uint32_t)(info->extra_argument);
|
uint32_t my_id = (uint32_t)(info->extra_argument);
|
||||||
|
|
||||||
// 2. Enable FPU/SSE on this core (same as BSP does in platform_init)
|
|
||||||
uint64_t cr0;
|
uint64_t cr0;
|
||||||
asm volatile("mov %%cr0, %0" : "=r"(cr0));
|
asm volatile("mov %%cr0, %0" : "=r"(cr0));
|
||||||
cr0 &= ~(1ULL << 2); // Clear EM
|
cr0 &= ~(1ULL << 2);
|
||||||
cr0 |= (1ULL << 1); // Set MP
|
cr0 |= (1ULL << 1);
|
||||||
cr0 |= (1ULL << 5); // Set NE
|
cr0 |= (1ULL << 5);
|
||||||
asm volatile("mov %0, %%cr0" : : "r"(cr0));
|
asm volatile("mov %0, %%cr0" : : "r"(cr0));
|
||||||
|
|
||||||
uint64_t cr4;
|
uint64_t cr4;
|
||||||
asm volatile("mov %%cr4, %0" : "=r"(cr4));
|
asm volatile("mov %%cr4, %0" : "=r"(cr4));
|
||||||
cr4 |= (1ULL << 9); // OSFXSR
|
cr4 |= (1ULL << 9);
|
||||||
cr4 |= (1ULL << 10); // OSXMMEXCPT
|
cr4 |= (1ULL << 10);
|
||||||
asm volatile("mov %0, %%cr4" : : "r"(cr4));
|
asm volatile("mov %0, %%cr4" : : "r"(cr4));
|
||||||
asm volatile("fninit");
|
asm volatile("fninit");
|
||||||
|
|
||||||
// 3. Load the shared GDT and properly reload all segments (including CS=0x08)
|
|
||||||
extern struct gdt_ptr gdtr;
|
extern struct gdt_ptr gdtr;
|
||||||
extern void gdt_flush(uint64_t);
|
extern void gdt_flush(uint64_t);
|
||||||
gdt_flush((uint64_t)&gdtr);
|
gdt_flush((uint64_t)&gdtr);
|
||||||
|
|
||||||
// 4. Load per-CPU TSS
|
|
||||||
gdt_load_ap_tss(my_id);
|
gdt_load_ap_tss(my_id);
|
||||||
|
|
||||||
// 5. Load the shared IDT
|
|
||||||
extern void idt_load(void);
|
extern void idt_load(void);
|
||||||
idt_load();
|
idt_load();
|
||||||
|
|
||||||
// 6. Load the kernel page tables (same CR3 as BSP — shared kernel space)
|
|
||||||
uint64_t kernel_cr3 = paging_get_pml4_phys();
|
uint64_t kernel_cr3 = paging_get_pml4_phys();
|
||||||
asm volatile("mov %0, %%cr3" : : "r"(kernel_cr3));
|
asm volatile("mov %0, %%cr3" : : "r"(kernel_cr3));
|
||||||
|
|
||||||
// 7. Enable LAPIC on this core so it can receive IPIs
|
|
||||||
extern void lapic_enable(void);
|
extern void lapic_enable(void);
|
||||||
lapic_enable();
|
lapic_enable();
|
||||||
|
|
||||||
// 8. Mark ourselves as online
|
|
||||||
cpu_states[my_id].online = true;
|
cpu_states[my_id].online = true;
|
||||||
|
|
||||||
serial_write("[SMP] AP ");
|
serial_write("[SMP] AP ");
|
||||||
|
|
@ -95,25 +82,17 @@ static void ap_entry(struct limine_smp_info *info) {
|
||||||
serial_write_num(cpu_states[my_id].lapic_id);
|
serial_write_num(cpu_states[my_id].lapic_id);
|
||||||
serial_write(")\n");
|
serial_write(")\n");
|
||||||
|
|
||||||
// 9. Initialize the current_process pointer for this CPU
|
process_t *ap_idle = process_create(NULL, false);
|
||||||
// Create a dedicated idle task for this AP (PID 0 is reserved for the BSP)
|
|
||||||
process_t *ap_idle = process_create(NULL, false); // Idle process
|
|
||||||
ap_idle->cpu_affinity = my_id;
|
ap_idle->cpu_affinity = my_id;
|
||||||
process_set_current_for_cpu(my_id, ap_idle);
|
process_set_current_for_cpu(my_id, ap_idle);
|
||||||
|
|
||||||
// 10. Enable interrupts and enter idle halt loop.
|
|
||||||
// APs will be woken by scheduling IPIs from BSP (vector 0x41).
|
|
||||||
// The IPI handler does context switching for this CPU's processes.
|
|
||||||
asm volatile("sti");
|
asm volatile("sti");
|
||||||
|
|
||||||
// Idle loop — APs halt and wait for IPI
|
work_queue_drain_loop();
|
||||||
for (;;) { asm volatile("hlt"); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- SMP Initialization ---
|
// --- SMP Initialization ---
|
||||||
uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
||||||
if (!smp_resp || smp_resp->cpu_count <= 1) {
|
if (!smp_resp || smp_resp->cpu_count <= 1) {
|
||||||
// Single CPU system — just set up the BSP entry
|
|
||||||
total_cpus = 1;
|
total_cpus = 1;
|
||||||
cpu_states = (cpu_state_t *)kmalloc(sizeof(cpu_state_t));
|
cpu_states = (cpu_state_t *)kmalloc(sizeof(cpu_state_t));
|
||||||
if (!cpu_states) return 1;
|
if (!cpu_states) return 1;
|
||||||
|
|
@ -135,7 +114,6 @@ uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
||||||
serial_write_num(bsp_lapic_id);
|
serial_write_num(bsp_lapic_id);
|
||||||
serial_write("\n");
|
serial_write("\n");
|
||||||
|
|
||||||
// Allocate per-CPU state array
|
|
||||||
cpu_states = (cpu_state_t *)kmalloc(total_cpus * sizeof(cpu_state_t));
|
cpu_states = (cpu_state_t *)kmalloc(total_cpus * sizeof(cpu_state_t));
|
||||||
if (!cpu_states) {
|
if (!cpu_states) {
|
||||||
serial_write("[SMP] ERROR: Failed to allocate CPU state array!\n");
|
serial_write("[SMP] ERROR: Failed to allocate CPU state array!\n");
|
||||||
|
|
@ -145,10 +123,8 @@ uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
||||||
extern void mem_memset(void *, int, size_t);
|
extern void mem_memset(void *, int, size_t);
|
||||||
mem_memset(cpu_states, 0, total_cpus * sizeof(cpu_state_t));
|
mem_memset(cpu_states, 0, total_cpus * sizeof(cpu_state_t));
|
||||||
|
|
||||||
// Initialize per-CPU GDT/TSS entries for all CPUs
|
|
||||||
gdt_init_ap_tss(total_cpus);
|
gdt_init_ap_tss(total_cpus);
|
||||||
|
|
||||||
// Fill in CPU state and start APs
|
|
||||||
uint32_t bsp_index = 0;
|
uint32_t bsp_index = 0;
|
||||||
for (uint32_t i = 0; i < total_cpus; i++) {
|
for (uint32_t i = 0; i < total_cpus; i++) {
|
||||||
struct limine_smp_info *cpu = smp_resp->cpus[i];
|
struct limine_smp_info *cpu = smp_resp->cpus[i];
|
||||||
|
|
@ -156,7 +132,6 @@ uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
||||||
cpu_states[i].lapic_id = cpu->lapic_id;
|
cpu_states[i].lapic_id = cpu->lapic_id;
|
||||||
|
|
||||||
if (cpu->lapic_id == bsp_lapic_id) {
|
if (cpu->lapic_id == bsp_lapic_id) {
|
||||||
// This is the BSP — already running
|
|
||||||
cpu_states[i].online = true;
|
cpu_states[i].online = true;
|
||||||
bsp_index = i;
|
bsp_index = i;
|
||||||
serial_write("[SMP] BSP CPU ");
|
serial_write("[SMP] BSP CPU ");
|
||||||
|
|
@ -165,7 +140,6 @@ uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
||||||
serial_write_num(cpu->lapic_id);
|
serial_write_num(cpu->lapic_id);
|
||||||
serial_write(") online\n");
|
serial_write(") online\n");
|
||||||
} else {
|
} else {
|
||||||
// Allocate a kernel stack for this AP
|
|
||||||
void *ap_stack = kmalloc_aligned(65536, 65536);
|
void *ap_stack = kmalloc_aligned(65536, 65536);
|
||||||
if (!ap_stack) {
|
if (!ap_stack) {
|
||||||
serial_write("[SMP] ERROR: Failed to allocate AP stack!\n");
|
serial_write("[SMP] ERROR: Failed to allocate AP stack!\n");
|
||||||
|
|
@ -175,27 +149,18 @@ uint32_t smp_init(struct limine_smp_response *smp_resp) {
|
||||||
cpu_states[i].kernel_stack_alloc = ap_stack;
|
cpu_states[i].kernel_stack_alloc = ap_stack;
|
||||||
cpu_states[i].online = false;
|
cpu_states[i].online = false;
|
||||||
|
|
||||||
// Set extra_argument so the AP knows its index
|
|
||||||
cpu->extra_argument = i;
|
cpu->extra_argument = i;
|
||||||
|
|
||||||
// Tell Limine to start this AP. Limine sets up the AP's stack
|
|
||||||
// from extra_argument's stack, but we need the goto_address.
|
|
||||||
// Limine will jump to ap_entry with the AP's limine_smp_info*.
|
|
||||||
// Important: Limine creates a temporary stack for the AP, and the
|
|
||||||
// goto_address is where the AP starts executing.
|
|
||||||
|
|
||||||
serial_write("[SMP] Starting AP ");
|
serial_write("[SMP] Starting AP ");
|
||||||
serial_write_num(i);
|
serial_write_num(i);
|
||||||
serial_write(" (LAPIC ");
|
serial_write(" (LAPIC ");
|
||||||
serial_write_num(cpu->lapic_id);
|
serial_write_num(cpu->lapic_id);
|
||||||
serial_write(")...\n");
|
serial_write(")...\n");
|
||||||
|
|
||||||
// This atomic write triggers the AP to start executing at ap_entry
|
|
||||||
__atomic_store_n(&cpu->goto_address, ap_entry, __ATOMIC_SEQ_CST);
|
__atomic_store_n(&cpu->goto_address, ap_entry, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for all APs to come online (with timeout)
|
|
||||||
volatile uint32_t timeout = 10000000;
|
volatile uint32_t timeout = 10000000;
|
||||||
uint32_t online_count = 0;
|
uint32_t online_count = 0;
|
||||||
while (timeout-- > 0) {
|
while (timeout-- > 0) {
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
#include "wm.h"
|
#include "wm.h"
|
||||||
#include "fat32.h"
|
#include "fat32.h"
|
||||||
#include "paging.h"
|
#include "paging.h"
|
||||||
|
#include "work_queue.h"
|
||||||
|
#include "smp.h"
|
||||||
#include "platform.h"
|
#include "platform.h"
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
#include "pci.h"
|
#include "pci.h"
|
||||||
|
|
@ -630,9 +632,10 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
if (win->pixels) {
|
if (win->pixels) {
|
||||||
int rx = (int)params[0]; int ry = (int)params[1];
|
int rx = (int)params[0]; int ry = (int)params[1];
|
||||||
int rw = (int)params[2]; int rh = (int)params[3];
|
int rw = (int)params[2]; int rh = (int)params[3];
|
||||||
|
int src_w = rw;
|
||||||
int src_x_offset = 0;
|
int src_x_offset = 0;
|
||||||
int src_y_offset = 0;
|
int src_y_offset = 0;
|
||||||
|
|
||||||
if (rx < 0) { src_x_offset = -rx; rw += rx; rx = 0; }
|
if (rx < 0) { src_x_offset = -rx; rw += rx; rx = 0; }
|
||||||
if (ry < 0) { src_y_offset = -ry; rh += ry; ry = 0; }
|
if (ry < 0) { src_y_offset = -ry; rh += ry; ry = 0; }
|
||||||
if (rx + rw > win->w) rw = win->w - rx;
|
if (rx + rw > win->w) rw = win->w - rx;
|
||||||
|
|
@ -641,15 +644,13 @@ static uint64_t syscall_handler_inner(registers_t *regs) {
|
||||||
if (rw > 0 && rh > 0) {
|
if (rw > 0 && rh > 0) {
|
||||||
for (int y = 0; y < rh; y++) {
|
for (int y = 0; y < rh; y++) {
|
||||||
uint32_t *dest = &win->pixels[(ry + y) * win->w + rx];
|
uint32_t *dest = &win->pixels[(ry + y) * win->w + rx];
|
||||||
uint32_t *src = &image_data[(src_y_offset + y) * (int)params[2] + src_x_offset];
|
uint32_t *src = &image_data[(src_y_offset + y) * src_w + src_x_offset];
|
||||||
for (int x = 0; x < rw; x++) {
|
for (int x = 0; x < rw; x++) {
|
||||||
uint32_t s = src[x];
|
uint32_t s = src[x];
|
||||||
uint8_t alpha = (s >> 24) & 0xFF;
|
uint8_t alpha = (s >> 24) & 0xFF;
|
||||||
if (alpha == 0xFF) {
|
if (alpha == 0xFF) {
|
||||||
dest[x] = s;
|
dest[x] = s;
|
||||||
} else if (alpha == 0) {
|
} else if (alpha > 0) {
|
||||||
// Skip
|
|
||||||
} else {
|
|
||||||
uint32_t d = dest[x];
|
uint32_t d = dest[x];
|
||||||
uint32_t rb = ((s & 0xFF00FF) * alpha + (d & 0xFF00FF) * (255 - alpha)) >> 8;
|
uint32_t rb = ((s & 0xFF00FF) * alpha + (d & 0xFF00FF) * (255 - alpha)) >> 8;
|
||||||
uint32_t g = ((s & 0x00FF00) * alpha + (d & 0x00FF00) * (255 - alpha)) >> 8;
|
uint32_t g = ((s & 0x00FF00) * alpha + (d & 0x00FF00) * (255 - alpha)) >> 8;
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,9 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "stdlib.h"
|
#include "stdlib.h"
|
||||||
|
|
||||||
|
// External syscalls from libc
|
||||||
|
extern void sys_parallel_run(void (*fn)(void*), void **args, int count);
|
||||||
|
|
||||||
// =========
|
// =========
|
||||||
// Constants
|
// Constants
|
||||||
// =========
|
// =========
|
||||||
|
|
@ -464,6 +467,10 @@ static double surf_z2[GRID_3D][GRID_3D]; // Back root
|
||||||
static bool surf_v1[GRID_3D][GRID_3D];
|
static bool surf_v1[GRID_3D][GRID_3D];
|
||||||
static bool surf_v2[GRID_3D][GRID_3D];
|
static bool surf_v2[GRID_3D][GRID_3D];
|
||||||
|
|
||||||
|
// Screen-space vertex cache for parallel rasterization
|
||||||
|
static int surf_sx1[GRID_3D][GRID_3D], surf_sy1[GRID_3D][GRID_3D];
|
||||||
|
static int surf_sx2[GRID_3D][GRID_3D], surf_sy2[GRID_3D][GRID_3D];
|
||||||
|
|
||||||
static bool surface_needs_eval = true;
|
static bool surface_needs_eval = true;
|
||||||
|
|
||||||
// Cached trig values for performance
|
// Cached trig values for performance
|
||||||
|
|
@ -500,7 +507,9 @@ static widget_context_t wctx = { 0, gfx_draw_rect, gfx_draw_rr, gfx_draw_str, NU
|
||||||
// ================
|
// ================
|
||||||
static void gfb_clear(uint32_t c) {
|
static void gfb_clear(uint32_t c) {
|
||||||
int total = graph_w * graph_h;
|
int total = graph_w * graph_h;
|
||||||
for (int i = 0; i < total; i++) graph_fb[i] = c;
|
uint32_t *p = graph_fb;
|
||||||
|
// Simple but often faster for compilers to vectorize than raw loop
|
||||||
|
for (int i = 0; i < total; i++) p[i] = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gfb_pixel(int x, int y, uint32_t c) {
|
static void gfb_pixel(int x, int y, uint32_t c) {
|
||||||
|
|
@ -865,6 +874,7 @@ typedef struct {
|
||||||
int start_j, end_j;
|
int start_j, end_j;
|
||||||
double range;
|
double range;
|
||||||
double step;
|
double step;
|
||||||
|
double z_scale;
|
||||||
} eval_job_t;
|
} eval_job_t;
|
||||||
|
|
||||||
static void eval_3d_explicit_job(void *arg) {
|
static void eval_3d_explicit_job(void *arg) {
|
||||||
|
|
@ -923,73 +933,81 @@ static void eval_3d_implicit_job(void *arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parallel Projection Job
|
||||||
|
static void eval_3d_project_job(void *arg) {
|
||||||
|
eval_job_t *job = (eval_job_t *)arg;
|
||||||
|
for (int j = job->start_j; j < job->end_j; j++) {
|
||||||
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
|
if (surf_v1[j][i]) {
|
||||||
|
project_3d(surf_x[j][i], surf_z1[j][i] * job->z_scale, surf_y_3d[j][i], &surf_sx1[j][i], &surf_sy1[j][i]);
|
||||||
|
}
|
||||||
|
if (surf_v2[j][i]) {
|
||||||
|
project_3d(surf_x[j][i], surf_z2[j][i] * job->z_scale, surf_y_3d[j][i], &surf_sx2[j][i], &surf_sy2[j][i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int start_j, end_j;
|
||||||
|
double zmin, zmax;
|
||||||
|
} draw_job_t;
|
||||||
|
|
||||||
|
// Parallel Draw Job
|
||||||
|
static void render_3d_draw_job(void *arg) {
|
||||||
|
draw_job_t *job = (draw_job_t *)arg;
|
||||||
|
for (int j = job->start_j; j < job->end_j; j++) {
|
||||||
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
|
for (int s = 0; s < 2; s++) {
|
||||||
|
bool *v = (s == 0) ? surf_v1[j] : surf_v2[j];
|
||||||
|
int *sx_row = (s == 0) ? surf_sx1[j] : surf_sx2[j];
|
||||||
|
int *sy_row = (s == 0) ? surf_sy1[j] : surf_sy2[j];
|
||||||
|
double *z_row = (s == 0) ? surf_z1[j] : surf_z2[j];
|
||||||
|
|
||||||
|
if (!v[i]) continue;
|
||||||
|
|
||||||
|
int sx0 = sx_row[i], sy0 = sy_row[i];
|
||||||
|
uint32_t col = color_by_height(z_row[i], job->zmin, job->zmax);
|
||||||
|
|
||||||
|
if (i + 1 < GRID_3D) {
|
||||||
|
bool v_next = (s == 0) ? surf_v1[j][i+1] : surf_v2[j][i+1];
|
||||||
|
if (v_next) {
|
||||||
|
int *sx_next_row = (s == 0) ? surf_sx1[j] : surf_sx2[j];
|
||||||
|
int *sy_next_row = (s == 0) ? surf_sy1[j] : surf_sy2[j];
|
||||||
|
gfb_line(sx0, sy0, sx_next_row[i+1], sy_next_row[i+1], col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (j + 1 < GRID_3D) {
|
||||||
|
bool v_next = (s == 0) ? surf_v1[j+1][i] : surf_v2[j+1][i];
|
||||||
|
if (v_next) {
|
||||||
|
int *sx_next_row = (s == 0) ? surf_sx1[j+1] : surf_sx2[j+1];
|
||||||
|
int *sy_next_row = (s == 0) ? surf_sy1[j+1] : surf_sy2[j+1];
|
||||||
|
gfb_line(sx0, sy0, sx_next_row[i], sy_next_row[i], col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s == 0 && surf_v1[j][i] && surf_v2[j][i]) {
|
||||||
|
bool edge = false;
|
||||||
|
if (i+1 < GRID_3D && !surf_v1[j][i+1]) edge = true;
|
||||||
|
if (i-1 >= 0 && !surf_v1[j][i-1]) edge = true;
|
||||||
|
if (j+1 < GRID_3D && !surf_v1[j+1][i]) edge = true;
|
||||||
|
if (j-1 >= 0 && !surf_v1[j-1][i]) edge = true;
|
||||||
|
if (edge) {
|
||||||
|
gfb_line(sx0, sy0, surf_sx2[j][i], surf_sy2[j][i], col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void render_3d_explicit(void) {
|
static void render_3d_explicit(void) {
|
||||||
double step = range_3d * 2.0 / (GRID_3D - 1);
|
double step = range_3d * 2.0 / (GRID_3D - 1);
|
||||||
double zmin = 1e30, zmax = -1e30;
|
double zmin = 1e30, zmax = -1e30;
|
||||||
// why are you reading this lol
|
|
||||||
if (surface_needs_eval) {
|
|
||||||
int num_chunks = 4; // Parallelize into 4 chunks (matching typical core count)
|
|
||||||
eval_job_t jobs[4];
|
|
||||||
void *job_args[4];
|
|
||||||
int rows_per_chunk = GRID_3D / num_chunks;
|
|
||||||
|
|
||||||
for (int c = 0; c < num_chunks; c++) {
|
|
||||||
jobs[c].start_j = c * rows_per_chunk;
|
|
||||||
jobs[c].end_j = (c == num_chunks - 1) ? GRID_3D : (c + 1) * rows_per_chunk;
|
|
||||||
jobs[c].range = range_3d;
|
|
||||||
jobs[c].step = step;
|
|
||||||
job_args[c] = &jobs[c];
|
|
||||||
}
|
|
||||||
|
|
||||||
extern void sys_parallel_run(void (*fn)(void*), void **args, int count);
|
|
||||||
sys_parallel_run(eval_3d_explicit_job, job_args, num_chunks);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compute min/max for coloring based on what's visible
|
|
||||||
for (int j = 0; j < GRID_3D; j++) {
|
|
||||||
for (int i = 0; i < GRID_3D; i++) {
|
|
||||||
if (surf_v1[j][i]) {
|
|
||||||
if (surf_z1[j][i] < zmin) zmin = surf_z1[j][i];
|
|
||||||
if (surf_z1[j][i] > zmax) zmax = surf_z1[j][i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double z_scale = 1.0;
|
|
||||||
if (zmax > zmin && (zmax - zmin) > 0.001) {
|
|
||||||
// Auto-fit Z bounds to X/Y bounds to prevent vertical spikes in explicit graphing
|
|
||||||
z_scale = (range_3d * 2.0) / (zmax - zmin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Draw wireframe
|
|
||||||
for (int j = 0; j < GRID_3D; j++) {
|
|
||||||
for (int i = 0; i < GRID_3D; i++) {
|
|
||||||
if (!surf_v1[j][i]) continue;
|
|
||||||
int sx0, sy0;
|
|
||||||
project_3d(surf_x[j][i], surf_z1[j][i] * z_scale, surf_y_3d[j][i], &sx0, &sy0);
|
|
||||||
uint32_t col = color_by_height(surf_z1[j][i], zmin, zmax);
|
|
||||||
|
|
||||||
if (i + 1 < GRID_3D && surf_v1[j][i+1]) {
|
|
||||||
int sx1, sy1;
|
|
||||||
project_3d(surf_x[j][i+1], surf_z1[j][i+1] * z_scale, surf_y_3d[j][i+1], &sx1, &sy1);
|
|
||||||
gfb_line(sx0, sy0, sx1, sy1, col);
|
|
||||||
}
|
|
||||||
if (j + 1 < GRID_3D && surf_v1[j+1][i]) {
|
|
||||||
int sx1, sy1;
|
|
||||||
project_3d(surf_x[j+1][i], surf_z1[j+1][i] * z_scale, surf_y_3d[j+1][i], &sx1, &sy1);
|
|
||||||
gfb_line(sx0, sy0, sx1, sy1, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void render_3d_implicit(void) {
|
|
||||||
double step = range_3d * 2.0 / (GRID_3D - 1);
|
|
||||||
int z_steps = 100;
|
|
||||||
double z_step = range_3d * 2.0 / z_steps;
|
|
||||||
double zmin = 1e30, zmax = -1e30;
|
|
||||||
|
|
||||||
if (surface_needs_eval) {
|
if (surface_needs_eval) {
|
||||||
|
for (int j = 0; j < GRID_3D; j++) { for (int i = 0; i < GRID_3D; i++) { surf_v1[j][i] = false; surf_v2[j][i] = false; } }
|
||||||
|
|
||||||
int num_chunks = 4;
|
int num_chunks = 4;
|
||||||
eval_job_t jobs[4];
|
eval_job_t jobs[4];
|
||||||
void *job_args[4];
|
void *job_args[4];
|
||||||
|
|
@ -1003,10 +1021,99 @@ static void render_3d_implicit(void) {
|
||||||
job_args[c] = &jobs[c];
|
job_args[c] = &jobs[c];
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void sys_parallel_run(void (*fn)(void*), void **args, int count);
|
sys_parallel_run(eval_3d_explicit_job, job_args, num_chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute min/max for coloring
|
||||||
|
for (int j = 0; j < GRID_3D; j++) {
|
||||||
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
|
if (surf_v1[j][i]) {
|
||||||
|
if (surf_z1[j][i] < zmin) zmin = surf_z1[j][i];
|
||||||
|
if (surf_z1[j][i] > zmax) zmax = surf_z1[j][i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double z_scale = 1.0;
|
||||||
|
if (zmax > zmin && (zmax - zmin) > 0.001) {
|
||||||
|
z_scale = (range_3d * 2.0) / (zmax - zmin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass 2: Parallel Projection
|
||||||
|
{
|
||||||
|
int num_chunks = 4;
|
||||||
|
eval_job_t jobs[4];
|
||||||
|
void *job_args[4];
|
||||||
|
int rows_per_chunk = GRID_3D / num_chunks;
|
||||||
|
for (int c = 0; c < num_chunks; c++) {
|
||||||
|
jobs[c].start_j = c * rows_per_chunk;
|
||||||
|
jobs[c].end_j = (c == num_chunks - 1) ? GRID_3D : (c + 1) * rows_per_chunk;
|
||||||
|
jobs[c].range = range_3d;
|
||||||
|
jobs[c].step = step;
|
||||||
|
jobs[c].z_scale = z_scale;
|
||||||
|
job_args[c] = &jobs[c];
|
||||||
|
}
|
||||||
|
sys_parallel_run(eval_3d_project_job, job_args, num_chunks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass 3: Parallel Drawing
|
||||||
|
{
|
||||||
|
int num_chunks = 4;
|
||||||
|
draw_job_t jobs[4];
|
||||||
|
void *job_args[4];
|
||||||
|
int rows_per_chunk = GRID_3D / num_chunks;
|
||||||
|
for (int c = 0; c < num_chunks; c++) {
|
||||||
|
jobs[c].start_j = c * rows_per_chunk;
|
||||||
|
jobs[c].end_j = (c == num_chunks - 1) ? GRID_3D : (c + 1) * rows_per_chunk;
|
||||||
|
jobs[c].zmin = zmin;
|
||||||
|
jobs[c].zmax = zmax;
|
||||||
|
job_args[c] = &jobs[c];
|
||||||
|
}
|
||||||
|
sys_parallel_run(render_3d_draw_job, job_args, num_chunks);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void render_3d_implicit(void) {
|
||||||
|
double step = range_3d * 2.0 / (GRID_3D - 1);
|
||||||
|
int z_steps = 100;
|
||||||
|
double zmin = 1e30, zmax = -1e30;
|
||||||
|
|
||||||
|
if (surface_needs_eval) {
|
||||||
|
int num_chunks = 4;
|
||||||
|
eval_job_t jobs[4];
|
||||||
|
void *job_args[4];
|
||||||
|
for (int j = 0; j < GRID_3D; j++) { for (int i = 0; i < GRID_3D; i++) { surf_v1[j][i] = false; surf_v2[j][i] = false; } }
|
||||||
|
|
||||||
|
int rows_per_chunk = GRID_3D / num_chunks;
|
||||||
|
|
||||||
|
for (int c = 0; c < num_chunks; c++) {
|
||||||
|
jobs[c].start_j = c * rows_per_chunk;
|
||||||
|
jobs[c].end_j = (c == num_chunks - 1) ? GRID_3D : (c + 1) * rows_per_chunk;
|
||||||
|
jobs[c].range = range_3d;
|
||||||
|
jobs[c].step = step;
|
||||||
|
job_args[c] = &jobs[c];
|
||||||
|
}
|
||||||
|
|
||||||
sys_parallel_run(eval_3d_implicit_job, job_args, num_chunks);
|
sys_parallel_run(eval_3d_implicit_job, job_args, num_chunks);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Pass 2: Parallel Projection
|
||||||
|
{
|
||||||
|
int num_chunks = 4;
|
||||||
|
eval_job_t jobs[4];
|
||||||
|
void *job_args[4];
|
||||||
|
int rows_per_chunk = GRID_3D / num_chunks;
|
||||||
|
for (int c = 0; c < num_chunks; c++) {
|
||||||
|
jobs[c].start_j = c * rows_per_chunk;
|
||||||
|
jobs[c].end_j = (c == num_chunks - 1) ? GRID_3D : (c + 1) * rows_per_chunk;
|
||||||
|
jobs[c].range = range_3d;
|
||||||
|
jobs[c].step = step;
|
||||||
|
jobs[c].z_scale = 1.0;
|
||||||
|
job_args[c] = &jobs[c];
|
||||||
|
}
|
||||||
|
sys_parallel_run(eval_3d_project_job, job_args, num_chunks);
|
||||||
|
}
|
||||||
|
|
||||||
// Compute min/max for coloring based on what's visible
|
// Compute min/max for coloring based on what's visible
|
||||||
for (int j = 0; j < GRID_3D; j++) {
|
for (int j = 0; j < GRID_3D; j++) {
|
||||||
for (int i = 0; i < GRID_3D; i++) {
|
for (int i = 0; i < GRID_3D; i++) {
|
||||||
|
|
@ -1021,45 +1128,20 @@ static void render_3d_implicit(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw mesh for both surfaces
|
// Pass 3: Parallel Drawing
|
||||||
for (int j = 0; j < GRID_3D; j++) {
|
{
|
||||||
for (int i = 0; i < GRID_3D; i++) {
|
int num_chunks = 4;
|
||||||
for (int s = 0; s < 2; s++) {
|
draw_job_t jobs[4];
|
||||||
bool *v = (s == 0) ? surf_v1[j] : surf_v2[j];
|
void *job_args[4];
|
||||||
double *z = (s == 0) ? surf_z1[j] : surf_z2[j];
|
int rows_per_chunk = GRID_3D / num_chunks;
|
||||||
if (!v[i]) continue;
|
for (int c = 0; c < num_chunks; c++) {
|
||||||
int sx0, sy0;
|
jobs[c].start_j = c * rows_per_chunk;
|
||||||
project_3d(surf_x[j][i], z[i], surf_y_3d[j][i], &sx0, &sy0);
|
jobs[c].end_j = (c == num_chunks - 1) ? GRID_3D : (c + 1) * rows_per_chunk;
|
||||||
uint32_t col = color_by_height(z[i], zmin, zmax);
|
jobs[c].zmin = zmin;
|
||||||
|
jobs[c].zmax = zmax;
|
||||||
if (i+1 < GRID_3D && ((s == 0 && surf_v1[j][i+1]) || (s == 1 && surf_v2[j][i+1]))) {
|
job_args[c] = &jobs[c];
|
||||||
int sx1, sy1;
|
|
||||||
double *znext = (s == 0) ? surf_z1[j] : surf_z2[j];
|
|
||||||
project_3d(surf_x[j][i+1], znext[i+1], surf_y_3d[j][i+1], &sx1, &sy1);
|
|
||||||
gfb_line(sx0, sy0, sx1, sy1, col);
|
|
||||||
}
|
|
||||||
if (j+1 < GRID_3D && ((s == 0 && surf_v1[j+1][i]) || (s == 1 && surf_v2[j+1][i]))) {
|
|
||||||
int sx1, sy1;
|
|
||||||
double *znext = (s == 0) ? surf_z1[j+1] : surf_z2[j+1];
|
|
||||||
project_3d(surf_x[j+1][i], znext[i], surf_y_3d[j+1][i], &sx1, &sy1);
|
|
||||||
gfb_line(sx0, sy0, sx1, sy1, col);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stitch the front and back roots together at the boundary to close zigzag gaps
|
|
||||||
if (s == 0 && surf_v1[j][i] && surf_v2[j][i]) {
|
|
||||||
bool edge = false;
|
|
||||||
if (i+1 < GRID_3D && !surf_v1[j][i+1]) edge = true;
|
|
||||||
if (i-1 >= 0 && !surf_v1[j][i-1]) edge = true;
|
|
||||||
if (j+1 < GRID_3D && !surf_v1[j+1][i]) edge = true;
|
|
||||||
if (j-1 >= 0 && !surf_v1[j-1][i]) edge = true;
|
|
||||||
if (edge) {
|
|
||||||
int sx2, sy2;
|
|
||||||
project_3d(surf_x[j][i], surf_z2[j][i], surf_y_3d[j][i], &sx2, &sy2);
|
|
||||||
gfb_line(sx0, sy0, sx2, sy2, col);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
sys_parallel_run(render_3d_draw_job, job_args, num_chunks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -920,7 +920,7 @@ static void explorer_paint(Window *win) {
|
||||||
DirtyRect dirty = graphics_get_dirty_rect();
|
DirtyRect dirty = graphics_get_dirty_rect();
|
||||||
|
|
||||||
|
|
||||||
graphics_set_clipping(offset_x, offset_y, win->w - 8, win->h - 28);
|
graphics_push_clipping(offset_x, offset_y, win->w - 8, win->h - 28);
|
||||||
|
|
||||||
draw_rect(offset_x, offset_y, win->w - 8, win->h - 28, COLOR_DARK_BG);
|
draw_rect(offset_x, offset_y, win->w - 8, win->h - 28, COLOR_DARK_BG);
|
||||||
|
|
||||||
|
|
@ -984,7 +984,7 @@ static void explorer_paint(Window *win) {
|
||||||
|
|
||||||
int content_start_y = offset_y + 30;
|
int content_start_y = offset_y + 30;
|
||||||
|
|
||||||
graphics_set_clipping(win->x + 4, content_start_y, win->w - 8, win->h - 54 - 4);
|
graphics_push_clipping(win->x + 4, content_start_y, win->w - 8, win->h - 54 - 4);
|
||||||
|
|
||||||
for (int i = 0; i < state->item_count; i++) {
|
for (int i = 0; i < state->item_count; i++) {
|
||||||
int row = i / EXPLORER_COLS;
|
int row = i / EXPLORER_COLS;
|
||||||
|
|
@ -1010,11 +1010,8 @@ static void explorer_paint(Window *win) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (dirty.active) {
|
graphics_pop_clipping(); // Pop content clipping
|
||||||
graphics_set_clipping(dirty.x, dirty.y, dirty.w, dirty.h);
|
graphics_pop_clipping(); // Pop main window clipping
|
||||||
} else {
|
|
||||||
graphics_clear_clipping();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state->drive_menu_visible) {
|
if (state->drive_menu_visible) {
|
||||||
int menu_x = win->x + 4;
|
int menu_x = win->x + 4;
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,16 @@ static DirtyRect g_dirty = {0, 0, 0, 0, false};
|
||||||
#define MAX_FB_HEIGHT 2048
|
#define MAX_FB_HEIGHT 2048
|
||||||
static uint32_t g_back_buffer[MAX_FB_WIDTH * MAX_FB_HEIGHT] __attribute__((aligned(4096)));
|
static uint32_t g_back_buffer[MAX_FB_WIDTH * MAX_FB_HEIGHT] __attribute__((aligned(4096)));
|
||||||
|
|
||||||
static int g_clip_x = 0, g_clip_y = 0, g_clip_w = 0, g_clip_h = 0;
|
#define MAX_RENDER_CPUS 32
|
||||||
static bool g_clip_enabled = false;
|
#define CLIP_STACK_DEPTH 8
|
||||||
|
static int g_clip_stack_x[MAX_RENDER_CPUS][CLIP_STACK_DEPTH];
|
||||||
|
static int g_clip_stack_y[MAX_RENDER_CPUS][CLIP_STACK_DEPTH];
|
||||||
|
static int g_clip_stack_w[MAX_RENDER_CPUS][CLIP_STACK_DEPTH];
|
||||||
|
static int g_clip_stack_h[MAX_RENDER_CPUS][CLIP_STACK_DEPTH];
|
||||||
|
static int g_clip_stack_ptr[MAX_RENDER_CPUS] = {0};
|
||||||
|
static bool g_clip_enabled[MAX_RENDER_CPUS] = {false};
|
||||||
|
|
||||||
extern uint32_t smp_this_cpu_id(void);
|
extern uint32_t smp_this_cpu_id(void);
|
||||||
#define MAX_RENDER_CPUS 32
|
|
||||||
static uint32_t *g_render_target[MAX_RENDER_CPUS] = {0};
|
static uint32_t *g_render_target[MAX_RENDER_CPUS] = {0};
|
||||||
static int g_rt_width[MAX_RENDER_CPUS] = {0};
|
static int g_rt_width[MAX_RENDER_CPUS] = {0};
|
||||||
static int g_rt_height[MAX_RENDER_CPUS] = {0};
|
static int g_rt_height[MAX_RENDER_CPUS] = {0};
|
||||||
|
|
@ -198,9 +203,10 @@ void put_pixel(int x, int y, uint32_t color) {
|
||||||
if (!g_fb) return;
|
if (!g_fb) return;
|
||||||
if (x < 0 || x >= (int)g_fb->width || y < 0 || y >= (int)g_fb->height) return;
|
if (x < 0 || x >= (int)g_fb->width || y < 0 || y >= (int)g_fb->height) return;
|
||||||
|
|
||||||
if (g_clip_enabled) {
|
if (g_clip_enabled[cpu]) {
|
||||||
if (x < g_clip_x || x >= g_clip_x + g_clip_w ||
|
int ptr = g_clip_stack_ptr[cpu];
|
||||||
y < g_clip_y || y >= g_clip_y + g_clip_h) {
|
if (x < g_clip_stack_x[cpu][ptr] || x >= g_clip_stack_x[cpu][ptr] + g_clip_stack_w[cpu][ptr] ||
|
||||||
|
y < g_clip_stack_y[cpu][ptr] || y >= g_clip_stack_y[cpu][ptr] + g_clip_stack_h[cpu][ptr]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -247,11 +253,12 @@ void draw_rect(int x, int y, int w, int h, uint32_t color) {
|
||||||
|
|
||||||
if (!g_fb) return;
|
if (!g_fb) return;
|
||||||
|
|
||||||
if (g_clip_enabled) {
|
if (g_clip_enabled[cpu]) {
|
||||||
if (x1 < g_clip_x) x1 = g_clip_x;
|
int ptr = g_clip_stack_ptr[cpu];
|
||||||
if (y1 < g_clip_y) y1 = g_clip_y;
|
if (x1 < g_clip_stack_x[cpu][ptr]) x1 = g_clip_stack_x[cpu][ptr];
|
||||||
if (x2 > g_clip_x + g_clip_w) x2 = g_clip_x + g_clip_w;
|
if (y1 < g_clip_stack_y[cpu][ptr]) y1 = g_clip_stack_y[cpu][ptr];
|
||||||
if (y2 > g_clip_y + g_clip_h) y2 = g_clip_y + g_clip_h;
|
if (x2 > g_clip_stack_x[cpu][ptr] + g_clip_stack_w[cpu][ptr]) x2 = g_clip_stack_x[cpu][ptr] + g_clip_stack_w[cpu][ptr];
|
||||||
|
if (y2 > g_clip_stack_y[cpu][ptr] + g_clip_stack_h[cpu][ptr]) y2 = g_clip_stack_y[cpu][ptr] + g_clip_stack_h[cpu][ptr];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x1 < 0) x1 = 0;
|
if (x1 < 0) x1 = 0;
|
||||||
|
|
@ -409,16 +416,23 @@ void draw_rounded_rect_blurred(int x, int y, int w, int h, int radius, uint32_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int c = 0; c < w; c++) {
|
|
||||||
for (int r = 0; r < h; r++) {
|
for (int r = 0; r < h; r++) {
|
||||||
int g_y = y + r;
|
int g_y = y + r;
|
||||||
int g_x = x + c;
|
if (g_y < 0 || g_y >= sh) continue;
|
||||||
|
|
||||||
if (g_clip_enabled) {
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
if (g_x < g_clip_x || g_x >= g_clip_x + g_clip_w ||
|
if (g_clip_enabled[cpu]) {
|
||||||
g_y < g_clip_y || g_y >= g_clip_y + g_clip_h) {
|
int ptr = g_clip_stack_ptr[cpu];
|
||||||
continue;
|
if (g_y < g_clip_stack_y[cpu][ptr] || g_y >= g_clip_stack_y[cpu][ptr] + g_clip_stack_h[cpu][ptr]) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int c = 0; c < w; c++) {
|
||||||
|
int g_x = x + c;
|
||||||
|
if (g_x < 0 || g_x >= sw) continue;
|
||||||
|
|
||||||
|
if (g_clip_enabled[cpu]) {
|
||||||
|
int ptr = g_clip_stack_ptr[cpu];
|
||||||
|
if (g_x < g_clip_stack_x[cpu][ptr] || g_x >= g_clip_stack_x[cpu][ptr] + g_clip_stack_w[cpu][ptr]) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool in_corner = false;
|
bool in_corner = false;
|
||||||
|
|
@ -478,9 +492,10 @@ void draw_char(int x, int y, char c, uint32_t color) {
|
||||||
|
|
||||||
uint32_t cpu = smp_this_cpu_id();
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
bool has_rt = (cpu < MAX_RENDER_CPUS && g_render_target[cpu]);
|
bool has_rt = (cpu < MAX_RENDER_CPUS && g_render_target[cpu]);
|
||||||
if (g_clip_enabled && !has_rt) {
|
if (g_clip_enabled[cpu] && !has_rt) {
|
||||||
if (x + 8 <= g_clip_x || x >= g_clip_x + g_clip_w ||
|
int ptr = g_clip_stack_ptr[cpu];
|
||||||
y + 8 <= g_clip_y || y >= g_clip_y + g_clip_h) {
|
if (x + 8 <= g_clip_stack_x[cpu][ptr] || x >= g_clip_stack_x[cpu][ptr] + g_clip_stack_w[cpu][ptr] ||
|
||||||
|
y + 8 <= g_clip_stack_y[cpu][ptr] || y >= g_clip_stack_y[cpu][ptr] + g_clip_stack_h[cpu][ptr]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -502,9 +517,10 @@ void draw_char_bitmap(int x, int y, char c, uint32_t color) {
|
||||||
|
|
||||||
uint32_t cpu = smp_this_cpu_id();
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
bool has_rt = (cpu < MAX_RENDER_CPUS && g_render_target[cpu]);
|
bool has_rt = (cpu < MAX_RENDER_CPUS && g_render_target[cpu]);
|
||||||
if (g_clip_enabled && !has_rt) {
|
if (g_clip_enabled[cpu] && !has_rt) {
|
||||||
if (x + 8 <= g_clip_x || x >= g_clip_x + g_clip_w ||
|
int ptr = g_clip_stack_ptr[cpu];
|
||||||
y + 8 <= g_clip_y || y >= g_clip_y + g_clip_h) {
|
if (x + 8 <= g_clip_stack_x[cpu][ptr] || x >= g_clip_stack_x[cpu][ptr] + g_clip_stack_w[cpu][ptr] ||
|
||||||
|
y + 8 <= g_clip_stack_y[cpu][ptr] || y >= g_clip_stack_y[cpu][ptr] + g_clip_stack_h[cpu][ptr]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -640,9 +656,11 @@ void draw_desktop_background(void) {
|
||||||
if (g_use_image && g_bg_image) {
|
if (g_use_image && g_bg_image) {
|
||||||
// Draw wallpaper image (stretch/scale to screen)
|
// Draw wallpaper image (stretch/scale to screen)
|
||||||
int x1 = 0, y1 = 0, x2 = g_fb->width, y2 = g_fb->height;
|
int x1 = 0, y1 = 0, x2 = g_fb->width, y2 = g_fb->height;
|
||||||
if (g_clip_enabled) {
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
x1 = g_clip_x; y1 = g_clip_y;
|
if (g_clip_enabled[cpu]) {
|
||||||
x2 = g_clip_x + g_clip_w; y2 = g_clip_y + g_clip_h;
|
int ptr = g_clip_stack_ptr[cpu];
|
||||||
|
x1 = g_clip_stack_x[cpu][ptr]; y1 = g_clip_stack_y[cpu][ptr];
|
||||||
|
x2 = g_clip_stack_x[cpu][ptr] + g_clip_stack_w[cpu][ptr]; y2 = g_clip_stack_y[cpu][ptr] + g_clip_stack_h[cpu][ptr];
|
||||||
}
|
}
|
||||||
for (int y = y1; y < y2; y++) {
|
for (int y = y1; y < y2; y++) {
|
||||||
int src_y = y * g_bg_image_h / (int)g_fb->height;
|
int src_y = y * g_bg_image_h / (int)g_fb->height;
|
||||||
|
|
@ -657,9 +675,11 @@ void draw_desktop_background(void) {
|
||||||
} else if (g_use_pattern) {
|
} else if (g_use_pattern) {
|
||||||
// Optimized tiled pattern: only draw within the clipping/dirty rect
|
// Optimized tiled pattern: only draw within the clipping/dirty rect
|
||||||
int x1 = 0, y1 = 0, x2 = g_fb->width, y2 = g_fb->height;
|
int x1 = 0, y1 = 0, x2 = g_fb->width, y2 = g_fb->height;
|
||||||
if (g_clip_enabled) {
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
x1 = g_clip_x; y1 = g_clip_y;
|
if (g_clip_enabled[cpu]) {
|
||||||
x2 = g_clip_x + g_clip_w; y2 = g_clip_y + g_clip_h;
|
int ptr = g_clip_stack_ptr[cpu];
|
||||||
|
x1 = g_clip_stack_x[cpu][ptr]; y1 = g_clip_stack_y[cpu][ptr];
|
||||||
|
x2 = g_clip_stack_x[cpu][ptr] + g_clip_stack_w[cpu][ptr]; y2 = g_clip_stack_y[cpu][ptr] + g_clip_stack_h[cpu][ptr];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int y = y1; y < y2; y++) {
|
for (int y = y1; y < y2; y++) {
|
||||||
|
|
@ -889,33 +909,94 @@ void graphics_set_clipping(int x, int y, int w, int h) {
|
||||||
if (w < 0) w = 0;
|
if (w < 0) w = 0;
|
||||||
if (h < 0) h = 0;
|
if (h < 0) h = 0;
|
||||||
|
|
||||||
g_clip_x = x;
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
g_clip_y = y;
|
g_clip_stack_x[cpu][0] = x;
|
||||||
g_clip_w = w;
|
g_clip_stack_y[cpu][0] = y;
|
||||||
g_clip_h = h;
|
g_clip_stack_w[cpu][0] = w;
|
||||||
g_clip_enabled = true;
|
g_clip_stack_h[cpu][0] = h;
|
||||||
|
g_clip_stack_ptr[cpu] = 0; // Reset to base
|
||||||
|
g_clip_enabled[cpu] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphics_push_clipping(int x, int y, int w, int h) {
|
||||||
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
|
int cur_ptr = g_clip_stack_ptr[cpu];
|
||||||
|
if (cur_ptr + 1 >= CLIP_STACK_DEPTH) return; // Stack overflow
|
||||||
|
|
||||||
|
// Intersect with current top
|
||||||
|
int cx1 = g_clip_stack_x[cpu][cur_ptr];
|
||||||
|
int cy1 = g_clip_stack_y[cpu][cur_ptr];
|
||||||
|
int cx2 = cx1 + g_clip_stack_w[cpu][cur_ptr];
|
||||||
|
int cy2 = cy1 + g_clip_stack_h[cpu][cur_ptr];
|
||||||
|
|
||||||
|
int nx1 = x;
|
||||||
|
int ny1 = y;
|
||||||
|
int nx2 = x + w;
|
||||||
|
int ny2 = y + h;
|
||||||
|
|
||||||
|
if (nx1 < cx1) nx1 = cx1;
|
||||||
|
if (ny1 < cy1) ny1 = cy1;
|
||||||
|
if (nx2 > cx2) nx2 = cx2;
|
||||||
|
if (ny2 > cy2) ny2 = cy2;
|
||||||
|
|
||||||
|
int nw = nx2 - nx1;
|
||||||
|
int nh = ny2 - ny1;
|
||||||
|
if (nw < 0) nw = 0;
|
||||||
|
if (nh < 0) nh = 0;
|
||||||
|
|
||||||
|
g_clip_stack_ptr[cpu]++;
|
||||||
|
g_clip_stack_x[cpu][cur_ptr + 1] = nx1;
|
||||||
|
g_clip_stack_y[cpu][cur_ptr + 1] = ny1;
|
||||||
|
g_clip_stack_w[cpu][cur_ptr + 1] = nw;
|
||||||
|
g_clip_stack_h[cpu][cur_ptr + 1] = nh;
|
||||||
|
g_clip_enabled[cpu] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void graphics_pop_clipping(void) {
|
||||||
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
|
if (g_clip_stack_ptr[cpu] > 0) {
|
||||||
|
g_clip_stack_ptr[cpu]--;
|
||||||
|
} else {
|
||||||
|
g_clip_enabled[cpu] = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void graphics_clear_clipping(void) {
|
void graphics_clear_clipping(void) {
|
||||||
g_clip_enabled = false;
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
|
g_clip_stack_ptr[cpu] = 0;
|
||||||
|
g_clip_enabled[cpu] = false;
|
||||||
}
|
}
|
||||||
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) {
|
||||||
if (!g_fb || !src) return;
|
if (!g_fb || !src) return;
|
||||||
int sw = get_screen_width();
|
int sw = get_screen_width();
|
||||||
int sh = get_screen_height();
|
int sh = get_screen_height();
|
||||||
|
|
||||||
for (int y = 0; y < h; y++) {
|
uint32_t cpu = smp_this_cpu_id();
|
||||||
int vy = dst_y + y;
|
int cx1 = 0, cy1 = 0, cx2 = sw, cy2 = sh;
|
||||||
if (vy < 0 || vy >= sh) continue;
|
if (g_clip_enabled[cpu]) {
|
||||||
|
int ptr = g_clip_stack_ptr[cpu];
|
||||||
|
cx1 = g_clip_stack_x[cpu][ptr];
|
||||||
|
cy1 = g_clip_stack_y[cpu][ptr];
|
||||||
|
cx2 = cx1 + g_clip_stack_w[cpu][ptr];
|
||||||
|
cy2 = cy1 + g_clip_stack_h[cpu][ptr];
|
||||||
|
}
|
||||||
|
|
||||||
for (int x = 0; x < w; x++) {
|
int x1 = dst_x, y1 = dst_y, x2 = dst_x + w, y2 = dst_y + h;
|
||||||
int vx = dst_x + x;
|
if (x1 < cx1) x1 = cx1;
|
||||||
if (vx < 0 || vx >= sw) continue;
|
if (y1 < cy1) y1 = cy1;
|
||||||
|
if (x2 > cx2) x2 = cx2;
|
||||||
|
if (y2 > cy2) y2 = cy2;
|
||||||
|
|
||||||
uint32_t pcol = src[y * w + x];
|
if (x1 >= x2 || y1 >= y2) return;
|
||||||
|
|
||||||
|
for (int y = y1; y < y2; y++) {
|
||||||
|
uint32_t *dst_row = &g_back_buffer[y * sw + x1];
|
||||||
|
uint32_t *src_row = &src[(y - dst_y) * w + (x1 - dst_x)];
|
||||||
|
int len = x2 - x1;
|
||||||
|
for (int x = 0; x < len; x++) {
|
||||||
|
uint32_t pcol = src_row[x];
|
||||||
if ((pcol & 0xFF000000) != 0 || (pcol & 0xFFFFFF) != 0) {
|
if ((pcol & 0xFF000000) != 0 || (pcol & 0xFFFFFF) != 0) {
|
||||||
g_back_buffer[vy * sw + vx] = pcol;
|
dst_row[x] = pcol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,8 @@ void graphics_clear_back_buffer(uint32_t color);
|
||||||
|
|
||||||
// Clipping
|
// Clipping
|
||||||
void graphics_set_clipping(int x, int y, int w, int h);
|
void graphics_set_clipping(int x, int y, int w, int h);
|
||||||
|
void graphics_push_clipping(int x, int y, int w, int h);
|
||||||
|
void graphics_pop_clipping(void);
|
||||||
void graphics_clear_clipping(void);
|
void graphics_clear_clipping(void);
|
||||||
|
|
||||||
// Font access (requires font_manager.h for ttf_font_t)
|
// Font access (requires font_manager.h for ttf_font_t)
|
||||||
|
|
|
||||||
384
src/wm/wm.c
384
src/wm/wm.c
|
|
@ -17,6 +17,8 @@
|
||||||
#include "userland/stb_image.h"
|
#include "userland/stb_image.h"
|
||||||
#include "memory_manager.h"
|
#include "memory_manager.h"
|
||||||
#include "disk.h"
|
#include "disk.h"
|
||||||
|
#include "../sys/work_queue.h"
|
||||||
|
#include "../sys/smp.h"
|
||||||
|
|
||||||
|
|
||||||
// Hello developer,
|
// Hello developer,
|
||||||
|
|
@ -98,6 +100,14 @@ static int drag_offset_y = 0;
|
||||||
bool is_dragging_file = false;
|
bool is_dragging_file = false;
|
||||||
static char drag_file_path[FAT32_MAX_PATH];
|
static char drag_file_path[FAT32_MAX_PATH];
|
||||||
static int drag_icon_type = 0;
|
static int drag_icon_type = 0;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int y_start;
|
||||||
|
int y_end;
|
||||||
|
DirtyRect dirty;
|
||||||
|
volatile int *completion_counter;
|
||||||
|
int pass;
|
||||||
|
} wm_strip_job_t;
|
||||||
static int drag_start_x = 0;
|
static int drag_start_x = 0;
|
||||||
static int drag_start_y = 0;
|
static int drag_start_y = 0;
|
||||||
static int drag_icon_orig_x = 0;
|
static int drag_icon_orig_x = 0;
|
||||||
|
|
@ -111,10 +121,8 @@ static int window_count = 0;
|
||||||
// Redraw system
|
// Redraw system
|
||||||
static bool force_redraw = true;
|
static bool force_redraw = true;
|
||||||
static uint32_t timer_ticks = 0;
|
static uint32_t timer_ticks = 0;
|
||||||
static int desktop_refresh_timer = 0;
|
|
||||||
|
|
||||||
// Cursor state
|
// Cursor state
|
||||||
static bool cursor_visible = true;
|
|
||||||
static int last_cursor_x = 400;
|
static int last_cursor_x = 400;
|
||||||
static int last_cursor_y = 300;
|
static int last_cursor_y = 300;
|
||||||
|
|
||||||
|
|
@ -1110,27 +1118,6 @@ static void draw_dock_clock(int x, int y) {
|
||||||
draw_rect(cx, cy - 1, 10, 2, 0xFF333333);
|
draw_rect(cx, cy - 1, 10, 2, 0xFF333333);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_dock_editor(int x, int y) {
|
|
||||||
draw_rounded_rect_filled(x, y, 48, 48, 10, 0xFF0A1628);
|
|
||||||
draw_rounded_rect_filled(x + 1, y + 1, 46, 28, 9, 0xFF1565C0);
|
|
||||||
draw_rounded_rect_filled(x + 1, y + 24, 46, 23, 9, 0xFF0D47A1);
|
|
||||||
draw_rect(x + 5, y + 8, 9, 32, 0xFF1A237E);
|
|
||||||
draw_filled_circle(x + 10, y + 14, 2, 0xFF7986CB);
|
|
||||||
draw_filled_circle(x + 10, y + 22, 2, 0xFF7986CB);
|
|
||||||
draw_filled_circle(x + 10, y + 30, 2, 0xFF7986CB);
|
|
||||||
draw_rect(x + 15, y + 8, 28, 32, 0xFF1B2B3C);
|
|
||||||
draw_rect(x + 15, y + 8, 14, 5, 0xFF1B2B3C);
|
|
||||||
draw_rect(x + 15, y + 8, 14, 1, 0xFF569CD6);
|
|
||||||
draw_rect(x + 18, y + 13, 9, 2, 0xFF569CD6);
|
|
||||||
draw_rect(x + 29, y + 13, 8, 2, 0xFF4EC9B0);
|
|
||||||
draw_rect(x + 18, y + 18, 5, 2, 0xFFCE9178);
|
|
||||||
draw_rect(x + 25, y + 18, 7, 2, 0xFFCE9178);
|
|
||||||
draw_rect(x + 21, y + 23, 7, 2, 0xFF9CDCFE);
|
|
||||||
draw_rect(x + 30, y + 23, 5, 2, 0xFFD4D4D4);
|
|
||||||
draw_rect(x + 18, y + 28, 16, 2, 0xFF6A9955);
|
|
||||||
draw_rect(x + 18, y + 33, 10, 2, 0xFFD4D4D4);
|
|
||||||
draw_rect(x + 30, y + 33, 6, 2, 0xFF569CD6);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_window(Window *win) {
|
void draw_window(Window *win) {
|
||||||
if (!win->visible) return;
|
if (!win->visible) return;
|
||||||
|
|
@ -1240,6 +1227,7 @@ static void erase_cursor(int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Clock ---
|
// --- Clock ---
|
||||||
|
|
||||||
static uint8_t rtc_read(uint8_t reg) {
|
static uint8_t rtc_read(uint8_t reg) {
|
||||||
outb(0x70, reg);
|
outb(0x70, reg);
|
||||||
return inb(0x71);
|
return inb(0x71);
|
||||||
|
|
@ -1274,60 +1262,43 @@ static void draw_clock(int x, int y) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Main Paint Function ---
|
// --- Main Paint Function ---
|
||||||
void wm_paint(void) {
|
bool rect_contains(int x, int y, int w, int h, int px, int py) {
|
||||||
|
return px >= x && px < x + w && py >= y && py < y + h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Window *sorted_windows_cache[32];
|
||||||
|
static int sorted_window_count_cache = 0;
|
||||||
|
|
||||||
|
static void wm_paint_region(int y_start, int y_end, DirtyRect dirty, int pass) {
|
||||||
int sw = get_screen_width();
|
int sw = get_screen_width();
|
||||||
int sh = get_screen_height();
|
int sh = get_screen_height();
|
||||||
|
|
||||||
uint64_t rflags;
|
int cx = 0, cy = y_start, cw = sw, ch = y_end - y_start;
|
||||||
rflags = wm_lock_acquire();
|
|
||||||
|
|
||||||
wm_mark_dirty(last_cursor_x, last_cursor_y, 12, 12);
|
|
||||||
wm_mark_dirty(mx, my, 12, 12);
|
|
||||||
|
|
||||||
DirtyRect dirty = graphics_get_dirty_rect();
|
|
||||||
|
|
||||||
if (dirty.active) {
|
if (dirty.active) {
|
||||||
int d_h = 60;
|
if (cx < dirty.x) { cw -= (dirty.x - cx); cx = dirty.x; }
|
||||||
int d_y = sh - d_h - 6;
|
if (cy < dirty.y) { ch -= (dirty.y - cy); cy = dirty.y; }
|
||||||
int d_item_sz = 48;
|
if (cx + cw > dirty.x + dirty.w) cw = dirty.x + dirty.w - cx;
|
||||||
int d_space = 10;
|
if (cy + ch > dirty.y + dirty.h) ch = dirty.y + dirty.h - cy;
|
||||||
int d_tw = 10 * (d_item_sz + d_space);
|
|
||||||
int d_bg_x = (sw - d_tw) / 2 - 12;
|
|
||||||
int d_bg_w = d_tw + 24;
|
|
||||||
|
|
||||||
if (!(dirty.x >= d_bg_x + d_bg_w || dirty.x + dirty.w <= d_bg_x ||
|
|
||||||
dirty.y >= d_y + d_h || dirty.y + dirty.h <= d_y)) {
|
|
||||||
graphics_mark_dirty(d_bg_x - 10, d_y - 10, d_bg_w + 20, d_h + 20);
|
|
||||||
dirty = graphics_get_dirty_rect();
|
|
||||||
}
|
|
||||||
graphics_set_clipping(dirty.x, dirty.y, dirty.w, dirty.h);
|
|
||||||
} else {
|
|
||||||
graphics_clear_clipping();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. Desktop Background (respects wallpaper color/pattern)
|
if (cw <= 0 || ch <= 0) return;
|
||||||
|
|
||||||
|
graphics_set_clipping(cx, cy, cw, ch);
|
||||||
|
|
||||||
|
if (pass == 1) {
|
||||||
draw_desktop_background();
|
draw_desktop_background();
|
||||||
|
|
||||||
// Draw Desktop Icons
|
|
||||||
for (int i = 0; i < desktop_icon_count; i++) {
|
for (int i = 0; i < desktop_icon_count; i++) {
|
||||||
DesktopIcon *icon = &desktop_icons[i];
|
DesktopIcon *icon = &desktop_icons[i];
|
||||||
if (dirty.active) {
|
if (icon->y + 85 <= cy || icon->y >= cy + ch) continue;
|
||||||
if (icon->x + 80 <= dirty.x || icon->x >= dirty.x + dirty.w ||
|
if (dirty.active && (icon->x + 85 <= dirty.x || icon->x >= dirty.x + dirty.w)) continue;
|
||||||
icon->y + 80 <= dirty.y || icon->y >= dirty.y + dirty.h) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (icon->type == 1) draw_folder_icon(icon->x, icon->y, icon->name);
|
if (icon->type == 1) draw_folder_icon(icon->x, icon->y, icon->name);
|
||||||
else if (icon->type == 2) {
|
else if (icon->type == 2) {
|
||||||
// App icon - strip .shortcut for display
|
char label[64]; int len = 0;
|
||||||
char label[64];
|
|
||||||
int len = 0;
|
|
||||||
while(icon->name[len] && len < 63) { label[len] = icon->name[len]; len++; }
|
while(icon->name[len] && len < 63) { label[len] = icon->name[len]; len++; }
|
||||||
label[len] = 0;
|
label[len] = 0;
|
||||||
if (len > 9 && str_ends_with(label, ".shortcut")) {
|
if (len > 9 && str_ends_with(label, ".shortcut")) label[len-9] = 0;
|
||||||
label[len-9] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (str_starts_with(icon->name, "Notepad")) draw_notepad_icon(icon->x, icon->y, label);
|
if (str_starts_with(icon->name, "Notepad")) draw_notepad_icon(icon->x, icon->y, label);
|
||||||
else if (str_starts_with(icon->name, "Calculator")) draw_calculator_icon(icon->x, icon->y, label);
|
else if (str_starts_with(icon->name, "Calculator")) draw_calculator_icon(icon->x, icon->y, label);
|
||||||
else if (str_starts_with(icon->name, "Terminal")) draw_terminal_icon(icon->x, icon->y, label);
|
else if (str_starts_with(icon->name, "Terminal")) draw_terminal_icon(icon->x, icon->y, label);
|
||||||
|
|
@ -1343,8 +1314,7 @@ void wm_paint(void) {
|
||||||
if (str_ends_with(icon->name, ".elf")) draw_elf_icon(icon->x, icon->y, icon->name);
|
if (str_ends_with(icon->name, ".elf")) draw_elf_icon(icon->x, icon->y, icon->name);
|
||||||
else if (str_ends_with(icon->name, ".pnt")) draw_paint_icon(icon->x, icon->y, icon->name);
|
else if (str_ends_with(icon->name, ".pnt")) draw_paint_icon(icon->x, icon->y, icon->name);
|
||||||
else if (is_image_file(icon->name)) {
|
else if (is_image_file(icon->name)) {
|
||||||
char full_path[128] = "/Desktop/";
|
char full_path[128] = "/Desktop/"; int p=9; int n=0; while(icon->name[n] && p < 127) full_path[p++] = icon->name[n++]; full_path[p]=0;
|
||||||
int p=9; int n=0; while(icon->name[n] && p < 127) full_path[p++] = icon->name[n++]; full_path[p]=0;
|
|
||||||
draw_image_icon(icon->x, icon->y, full_path);
|
draw_image_icon(icon->x, icon->y, full_path);
|
||||||
draw_icon_label(icon->x, icon->y, icon->name);
|
draw_icon_label(icon->x, icon->y, icon->name);
|
||||||
}
|
}
|
||||||
|
|
@ -1353,196 +1323,202 @@ void wm_paint(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. Windows - sort by z-index and draw
|
for (int i = 0; i < sorted_window_count_cache; i++) {
|
||||||
int local_window_count = window_count;
|
Window *win = sorted_windows_cache[i];
|
||||||
Window *sorted_windows[32];
|
|
||||||
for (int i = 0; i < local_window_count; i++) {
|
|
||||||
sorted_windows[i] = all_windows[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < local_window_count - 1; i++) {
|
|
||||||
for (int j = 0; j < local_window_count - i - 1; j++) {
|
|
||||||
if (sorted_windows[j] && sorted_windows[j + 1] &&
|
|
||||||
sorted_windows[j]->z_index > sorted_windows[j + 1]->z_index) {
|
|
||||||
Window *temp = sorted_windows[j];
|
|
||||||
sorted_windows[j] = sorted_windows[j + 1];
|
|
||||||
sorted_windows[j + 1] = temp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < local_window_count; i++) {
|
|
||||||
Window *win = sorted_windows[i];
|
|
||||||
if (!win || !win->visible) continue;
|
if (!win || !win->visible) continue;
|
||||||
|
if (win->y + win->h <= cy || win->y >= cy + ch) continue;
|
||||||
if (dirty.active && !win->focused) {
|
if (dirty.active && !win->focused && (win->x + win->w <= dirty.x || win->x >= dirty.x + dirty.w)) continue;
|
||||||
if (win->x + win->w <= dirty.x || win->x >= dirty.x + dirty.w ||
|
|
||||||
win->y + win->h <= dirty.y || win->y >= dirty.y + dirty.h) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
draw_window(win);
|
draw_window(win);
|
||||||
}
|
}
|
||||||
|
} else if (pass == 2) {
|
||||||
|
if (0 < cy + ch && 30 > cy) {
|
||||||
draw_rect(0, 0, sw, 30, COLOR_TOPBAR_BG);
|
draw_rect(0, 0, sw, 30, COLOR_TOPBAR_BG);
|
||||||
draw_boredos_logo(8, 8, 1);
|
draw_boredos_logo(8, 8, 1);
|
||||||
draw_clock(sw - 80, 12);
|
draw_clock(sw - 80, 12);
|
||||||
|
}
|
||||||
|
|
||||||
if (start_menu_open) {
|
if (start_menu_open && 40 < cy + ch && 125 > cy) {
|
||||||
int menu_h = 85;
|
draw_rounded_rect_filled(8, 40, 160, 85, 8, COLOR_DARK_PANEL);
|
||||||
draw_rounded_rect_filled(8, 40, 160, menu_h, 8, COLOR_DARK_PANEL);
|
|
||||||
draw_string(20, 48, "About BoredOS", COLOR_DARK_TEXT);
|
draw_string(20, 48, "About BoredOS", COLOR_DARK_TEXT);
|
||||||
draw_string(20, 68, "Settings", COLOR_DARK_TEXT);
|
draw_string(20, 68, "Settings", COLOR_DARK_TEXT);
|
||||||
draw_string(20, 88, "Shutdown", COLOR_DARK_TEXT);
|
draw_string(20, 88, "Shutdown", COLOR_DARK_TEXT);
|
||||||
draw_string(20, 108, "Restart", COLOR_DARK_TEXT);
|
draw_string(20, 108, "Restart", COLOR_DARK_TEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int dock_h = 60;
|
int dock_h = 60, dock_y = sh - dock_h - 6;
|
||||||
int dock_y = sh - dock_h - 6;
|
if (dock_y < cy + ch && dock_y + dock_h > cy) {
|
||||||
int dock_item_size = 48;
|
int d_item_sz = 48, d_space = 10, d_total_w = 11 * (d_item_sz + d_space);
|
||||||
int dock_spacing = 10;
|
int d_bg_x = (sw - d_total_w) / 2 - 12, d_bg_w = d_total_w + 24;
|
||||||
int total_dock_width = 11 * (dock_item_size + dock_spacing);
|
draw_rounded_rect_blurred(d_bg_x, dock_y, d_bg_w, dock_h, 18, COLOR_DOCK_BG, 5, 140);
|
||||||
int dock_bg_x = (sw - total_dock_width) / 2 - 12;
|
int dx = (sw - d_total_w) / 2, dy = dock_y + 6;
|
||||||
int dock_bg_w = total_dock_width + 24;
|
draw_dock_files(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_settings(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_notepad(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_calculator(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_terminal(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_minesweeper(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_paint(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_browser(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_taskman(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_clock(dx, dy); dx += d_item_sz+d_space;
|
||||||
|
draw_dock_word(dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw blurred dock background with reduced radius and tint
|
|
||||||
draw_rounded_rect_blurred(dock_bg_x, dock_y, dock_bg_w, dock_h, 18, COLOR_DOCK_BG, 5, 140);
|
|
||||||
|
|
||||||
int dock_x = (sw - total_dock_width) / 2;
|
|
||||||
int dock_item_y = dock_y + 6;
|
|
||||||
|
|
||||||
draw_dock_files(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_settings(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_notepad(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_calculator(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_terminal(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_minesweeper(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_paint(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_browser(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_taskman(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_clock(dock_x, dock_item_y);
|
|
||||||
dock_x += dock_item_size + dock_spacing;
|
|
||||||
draw_dock_word(dock_x, dock_item_y);
|
|
||||||
|
|
||||||
// Desktop Context Menu (with rounded corners)
|
|
||||||
if (desktop_menu_visible) {
|
if (desktop_menu_visible) {
|
||||||
int menu_w = 140;
|
int d_mw = 140, d_mh = (desktop_menu_target_icon != -1) ? 125 : 75;
|
||||||
|
if (desktop_menu_y < cy + ch && desktop_menu_y + d_mh > cy) {
|
||||||
|
draw_rounded_rect_filled(desktop_menu_x, desktop_menu_y, d_mw, d_mh, 8, COLOR_DARK_PANEL);
|
||||||
int item_h = 25;
|
int item_h = 25;
|
||||||
int menu_h = (desktop_menu_target_icon != -1) ? 125 : 75;
|
|
||||||
|
|
||||||
draw_rounded_rect_filled(desktop_menu_x, desktop_menu_y, menu_w, menu_h, 8, COLOR_DARK_PANEL);
|
|
||||||
|
|
||||||
if (desktop_menu_target_icon != -1) {
|
if (desktop_menu_target_icon != -1) {
|
||||||
bool can_paste = explorer_clipboard_has_content();
|
bool cp = explorer_clipboard_has_content();
|
||||||
draw_string(desktop_menu_x + 10, desktop_menu_y + 5, "Cut", COLOR_WHITE);
|
draw_string(desktop_menu_x + 10, desktop_menu_y + 5, "Cut", COLOR_WHITE);
|
||||||
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h, "Copy", COLOR_WHITE);
|
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h, "Copy", COLOR_WHITE);
|
||||||
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h * 2, "Paste", can_paste ? COLOR_WHITE : COLOR_DKGRAY);
|
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h * 2, "Paste", cp ? COLOR_WHITE : COLOR_DKGRAY);
|
||||||
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h * 3, "Delete", COLOR_TRAFFIC_RED);
|
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h * 3, "Delete", COLOR_TRAFFIC_RED);
|
||||||
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h * 4, "Rename", COLOR_WHITE);
|
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h * 4, "Rename", COLOR_WHITE);
|
||||||
} else {
|
} else {
|
||||||
bool can_paste = explorer_clipboard_has_content();
|
bool cp = explorer_clipboard_has_content();
|
||||||
draw_string(desktop_menu_x + 10, desktop_menu_y + 5, "New File", COLOR_WHITE);
|
draw_string(desktop_menu_x + 10, desktop_menu_y + 5, "New File", COLOR_WHITE);
|
||||||
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h, "New Folder", COLOR_WHITE);
|
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h, "New Folder", COLOR_WHITE);
|
||||||
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h * 2, "Paste", can_paste ? COLOR_WHITE : COLOR_DKGRAY);
|
draw_string(desktop_menu_x + 10, desktop_menu_y + 5 + item_h * 2, "Paste", cp ? COLOR_WHITE : COLOR_DKGRAY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Desktop Dialogs (dark mode)
|
|
||||||
if (desktop_dialog_state != 0) {
|
if (desktop_dialog_state != 0) {
|
||||||
int dlg_w = 300; int dlg_h = 110;
|
int dlg_w = 300, dlg_h = 110, dg_x = (sw - dlg_w)/2, dg_y = (sh - dlg_h)/2;
|
||||||
int dlg_x = (sw - dlg_w) / 2;
|
if (dg_y < cy + ch && dg_y + dlg_h > cy) {
|
||||||
int dlg_y = (sh - dlg_h) / 2;
|
draw_rounded_rect_filled(dg_x, dg_y, dlg_w, dlg_h, 8, COLOR_DARK_PANEL);
|
||||||
|
const char *title = (desktop_dialog_state == 1) ? "Create New File" : (desktop_dialog_state == 2 ? "Create New Folder" : "Rename");
|
||||||
draw_rounded_rect_filled(dlg_x, dlg_y, dlg_w, dlg_h, 8, COLOR_DARK_PANEL);
|
const char *btn = (desktop_dialog_state == 0) ? "Rename" : "Create";
|
||||||
|
draw_string(dg_x + 10, dg_y + 10, title, COLOR_WHITE);
|
||||||
const char *title = "Rename";
|
draw_rounded_rect_filled(dg_x + 10, dg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
||||||
const char *btn_text = "Rename";
|
draw_string(dg_x + 15, dg_y + 40, desktop_dialog_input, COLOR_WHITE);
|
||||||
if (desktop_dialog_state == 1) { title = "Create New File"; btn_text = "Create"; }
|
char temp_sub[64]; int k; for (k=0; k<desktop_dialog_cursor&&desktop_dialog_input[k]; k++) temp_sub[k]=desktop_dialog_input[k]; temp_sub[k]=0;
|
||||||
else if (desktop_dialog_state == 2) { title = "Create New Folder"; btn_text = "Create"; }
|
draw_rect(dg_x + 15 + font_manager_get_string_width(graphics_get_current_ttf(), temp_sub), dg_y + 39, 2, 12, COLOR_WHITE);
|
||||||
|
draw_rounded_rect_filled(dg_x + 50, dg_y + 65, 80, 25, 4, COLOR_DARK_BORDER); draw_string(dg_x + 70, dg_y + 72, btn, COLOR_WHITE);
|
||||||
draw_string(dlg_x + 10, dlg_y + 10, title, COLOR_WHITE);
|
draw_rounded_rect_filled(dg_x + 170, dg_y + 65, 80, 25, 4, COLOR_DARK_BORDER); draw_string(dg_x + 185, dg_y + 72, "Cancel", COLOR_WHITE);
|
||||||
draw_rounded_rect_filled(dlg_x + 10, dlg_y + 35, 280, 20, 4, COLOR_DARK_BG);
|
}
|
||||||
draw_string(dlg_x + 15, dlg_y + 40, desktop_dialog_input, COLOR_WHITE);
|
|
||||||
// Cursor
|
|
||||||
char sub[64];
|
|
||||||
int k;
|
|
||||||
for (k = 0; k < desktop_dialog_cursor && desktop_dialog_input[k]; k++) sub[k] = desktop_dialog_input[k];
|
|
||||||
sub[k] = 0;
|
|
||||||
int cx = font_manager_get_string_width(graphics_get_current_ttf(), sub);
|
|
||||||
draw_rect(dlg_x + 15 + cx, dlg_y + 39, 2, 12, COLOR_WHITE);
|
|
||||||
|
|
||||||
draw_rounded_rect_filled(dlg_x + 50, dlg_y + 65, 80, 25, 4, COLOR_DARK_BORDER);
|
|
||||||
draw_string(dlg_x + 70, dlg_y + 72, btn_text, COLOR_WHITE);
|
|
||||||
|
|
||||||
draw_rounded_rect_filled(dlg_x + 170, dlg_y + 65, 80, 25, 4, COLOR_DARK_BORDER);
|
|
||||||
draw_string(dlg_x + 185, dlg_y + 72, "Cancel", COLOR_WHITE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message Box (dark mode)
|
|
||||||
if (msg_box_visible) {
|
if (msg_box_visible) {
|
||||||
int mw = 320;
|
int mw = 320, mh = 100, m_x = (sw - mw)/2, m_y = (sh - mh)/2;
|
||||||
int mh = 100;
|
if (m_y < cy + ch && m_y + mh > cy) {
|
||||||
int mx = (sw - mw) / 2;
|
draw_rounded_rect_filled(m_x, m_y, mw, mh, 8, COLOR_DARK_PANEL);
|
||||||
int my = (sh - mh) / 2;
|
draw_string(m_x + 15, m_y + 10, msg_box_title, COLOR_DARK_TEXT);
|
||||||
|
draw_string(m_x + 10, m_y + 40, msg_box_text, COLOR_DARK_TEXT);
|
||||||
draw_rounded_rect_filled(mx, my, mw, mh, 8, COLOR_DARK_PANEL);
|
draw_rounded_rect_filled(m_x + mw/2 - 30, m_y + 70, 60, 20, 4, COLOR_DARK_BORDER);
|
||||||
draw_string(mx + 15, my + 10, msg_box_title, COLOR_DARK_TEXT);
|
draw_string(m_x + mw/2 - 10, m_y + 75, "OK", COLOR_WHITE);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notification (dark mode)
|
|
||||||
if (notif_active) {
|
if (notif_active) {
|
||||||
int nx = sw - 400 + notif_x_offset;
|
int nx = sw - 400 + notif_x_offset, ny = 40, nw = 380, nh = 50;
|
||||||
int ny = 40;
|
if (ny < cy + ch && ny + nh > cy) {
|
||||||
int nw = 380;
|
|
||||||
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);
|
||||||
draw_string(nx + 15, ny + 10, "Screenshot", COLOR_DARK_TEXT);
|
draw_string(nx + 15, ny + 10, "Screenshot", COLOR_DARK_TEXT);
|
||||||
draw_string(nx + 15, ny + 30, notif_text, COLOR_DKGRAY);
|
draw_string(nx + 15, ny + 30, notif_text, COLOR_DKGRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom Overlay (VM Graphics)
|
|
||||||
if (wm_custom_paint_hook) {
|
|
||||||
wm_custom_paint_hook();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw Dragged Icon
|
if (wm_custom_paint_hook) wm_custom_paint_hook();
|
||||||
|
|
||||||
if (is_dragging_file) {
|
if (is_dragging_file) {
|
||||||
|
if (mx - 20 < cx + cw && mx + 20 > cx && my - 20 < cy + ch && my + 20 > cy) {
|
||||||
if (drag_icon_type == 1) draw_folder_icon(mx - 20, my - 20, "Moving...");
|
if (drag_icon_type == 1) draw_folder_icon(mx - 20, my - 20, "Moving...");
|
||||||
else if (drag_icon_type == 2) draw_icon(mx - 20, my - 20, "Moving...");
|
else if (drag_icon_type == 2) draw_icon(mx - 20, my - 20, "Moving...");
|
||||||
else draw_document_icon(mx - 20, my - 20, "Moving...");
|
else draw_document_icon(mx - 20, my - 20, "Moving...");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 7. Mouse cursor (draw last so it's on top)
|
static void wm_strip_worker_job(void *arg) {
|
||||||
|
wm_strip_job_t *job = (wm_strip_job_t *)arg;
|
||||||
|
wm_paint_region(job->y_start, job->y_end, job->dirty, job->pass);
|
||||||
|
__atomic_sub_fetch(job->completion_counter, 1, __ATOMIC_SEQ_CST);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wm_paint(void) {
|
||||||
|
int sw = get_screen_width();
|
||||||
|
int sh = get_screen_height();
|
||||||
|
uint64_t rflags;
|
||||||
|
rflags = wm_lock_acquire();
|
||||||
|
wm_mark_dirty(last_cursor_x, last_cursor_y, 12, 12);
|
||||||
|
wm_mark_dirty(mx, my, 12, 12);
|
||||||
|
|
||||||
|
DirtyRect dirty = graphics_get_dirty_rect();
|
||||||
|
if (dirty.active) {
|
||||||
|
int d_h = 60, d_y = sh - d_h - 6, d_total_w = 11 * (48 + 10);
|
||||||
|
int d_bg_x = (sw - d_total_w) / 2 - 12, d_bg_w = d_total_w + 24;
|
||||||
|
if (!(dirty.x >= d_bg_x + d_bg_w || dirty.x + dirty.w <= d_bg_x ||
|
||||||
|
dirty.y >= d_y + d_h || dirty.y + dirty.h <= d_y)) {
|
||||||
|
graphics_mark_dirty(d_bg_x - 10, d_y - 10, d_bg_w + 20, d_h + 20);
|
||||||
|
dirty = graphics_get_dirty_rect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sorted_window_count_cache = window_count;
|
||||||
|
if (sorted_window_count_cache > 32) sorted_window_count_cache = 32;
|
||||||
|
for (int i = 0; i < sorted_window_count_cache; i++) sorted_windows_cache[i] = all_windows[i];
|
||||||
|
for (int i = 0; i < sorted_window_count_cache - 1; i++) {
|
||||||
|
for (int j = 0; j < sorted_window_count_cache - i - 1; j++) {
|
||||||
|
if (sorted_windows_cache[j] && sorted_windows_cache[j+1] &&
|
||||||
|
sorted_windows_cache[j]->z_index > sorted_windows_cache[j+1]->z_index) {
|
||||||
|
Window *tmp = sorted_windows_cache[j];
|
||||||
|
sorted_windows_cache[j] = sorted_windows_cache[j+1];
|
||||||
|
sorted_windows_cache[j+1] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Memory barrier to ensure APs see the sorted window list correctly
|
||||||
|
asm volatile("" ::: "memory");
|
||||||
|
|
||||||
|
uint32_t cpu_count = smp_cpu_count();
|
||||||
|
if (cpu_count > 32) cpu_count = 32;
|
||||||
|
if (cpu_count < 1) cpu_count = 1;
|
||||||
|
|
||||||
|
volatile int completion_counter = (int)cpu_count;
|
||||||
|
wm_strip_job_t jobs[32];
|
||||||
|
int rows_per_strip = sh / cpu_count;
|
||||||
|
|
||||||
|
// PASS 1: BACKGROUND & WINDOWS
|
||||||
|
for (uint32_t i = 0; i < cpu_count; i++) {
|
||||||
|
jobs[i].y_start = i * rows_per_strip;
|
||||||
|
jobs[i].y_end = (i == cpu_count - 1) ? sh : (i + 1) * rows_per_strip;
|
||||||
|
jobs[i].dirty = dirty;
|
||||||
|
jobs[i].completion_counter = &completion_counter;
|
||||||
|
jobs[i].pass = 1;
|
||||||
|
if (i < cpu_count - 1) work_queue_submit(wm_strip_worker_job, &jobs[i]);
|
||||||
|
}
|
||||||
|
wm_paint_region(jobs[cpu_count-1].y_start, jobs[cpu_count-1].y_end, dirty, 1);
|
||||||
|
__atomic_sub_fetch(&completion_counter, 1, __ATOMIC_SEQ_CST);
|
||||||
|
while (completion_counter > 0) {
|
||||||
|
if (!work_queue_drain_one()) asm volatile("pause");
|
||||||
|
}
|
||||||
|
|
||||||
|
// PASS 2: UI OVERLAY (Dock, start menu, menus etc)
|
||||||
|
completion_counter = (int)cpu_count;
|
||||||
|
for (uint32_t i = 0; i < cpu_count; i++) {
|
||||||
|
jobs[i].pass = 2;
|
||||||
|
if (i < cpu_count - 1) work_queue_submit(wm_strip_worker_job, &jobs[i]);
|
||||||
|
}
|
||||||
|
wm_paint_region(jobs[cpu_count-1].y_start, jobs[cpu_count-1].y_end, dirty, 2);
|
||||||
|
__atomic_sub_fetch(&completion_counter, 1, __ATOMIC_SEQ_CST);
|
||||||
|
while (completion_counter > 0) {
|
||||||
|
if (!work_queue_drain_one()) asm volatile("pause");
|
||||||
|
}
|
||||||
|
|
||||||
|
graphics_clear_clipping();
|
||||||
draw_cursor(mx, my);
|
draw_cursor(mx, my);
|
||||||
last_cursor_x = mx;
|
last_cursor_x = mx;
|
||||||
last_cursor_y = my;
|
last_cursor_y = my;
|
||||||
|
|
||||||
// Flip the buffer - display the rendered frame atomically
|
|
||||||
graphics_flip_buffer();
|
graphics_flip_buffer();
|
||||||
graphics_clear_dirty_no_lock();
|
graphics_clear_dirty_no_lock();
|
||||||
|
|
||||||
// Restore IRQs
|
|
||||||
wm_lock_release(rflags);
|
wm_lock_release(rflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Input Handling ---
|
|
||||||
|
|
||||||
bool rect_contains(int x, int y, int w, int h, int px, int py) {
|
|
||||||
return px >= x && px < x + w && py >= y && py < y + h;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wm_bring_to_front_locked(Window *win) {
|
void wm_bring_to_front_locked(Window *win) {
|
||||||
for (int i = 0; i < window_count; i++) {
|
for (int i = 0; i < window_count; i++) {
|
||||||
all_windows[i]->focused = false;
|
all_windows[i]->focused = false;
|
||||||
|
|
@ -1725,7 +1701,8 @@ void wm_handle_click(int x, int y) {
|
||||||
if (desktop_snap_to_grid) {
|
if (desktop_snap_to_grid) {
|
||||||
int col = (desktop_icons[new_idx].x - 20 + 40) / 80;
|
int col = (desktop_icons[new_idx].x - 20 + 40) / 80;
|
||||||
int row = (desktop_icons[new_idx].y - 20 + 40) / 80;
|
int row = (desktop_icons[new_idx].y - 20 + 40) / 80;
|
||||||
if (col < 0) col = 0; if (row < 0) row = 0;
|
if (col < 0) col = 0;
|
||||||
|
if (row < 0) row = 0;
|
||||||
desktop_icons[new_idx].x = 20 + col * 80;
|
desktop_icons[new_idx].x = 20 + col * 80;
|
||||||
desktop_icons[new_idx].y = 20 + row * 80;
|
desktop_icons[new_idx].y = 20 + row * 80;
|
||||||
}
|
}
|
||||||
|
|
@ -2414,7 +2391,8 @@ static void wm_handle_mouse_internal(int dx, int dy, uint8_t buttons, int dz) {
|
||||||
if (desktop_snap_to_grid) {
|
if (desktop_snap_to_grid) {
|
||||||
int col = (desktop_icons[i].x - 20 + 40) / 80;
|
int col = (desktop_icons[i].x - 20 + 40) / 80;
|
||||||
int row = (desktop_icons[i].y - 20 + 40) / 80;
|
int row = (desktop_icons[i].y - 20 + 40) / 80;
|
||||||
if (col < 0) col = 0; if (row < 0) row = 0;
|
if (col < 0) col = 0;
|
||||||
|
if (row < 0) row = 0;
|
||||||
desktop_icons[i].x = 20 + col * 80;
|
desktop_icons[i].x = 20 + col * 80;
|
||||||
desktop_icons[i].y = 20 + row * 80;
|
desktop_icons[i].y = 20 + row * 80;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue