From 525f92cdf07d053c6bbc4c9d57cd7379843e3546 Mon Sep 17 00:00:00 2001 From: Daniel Hammer Date: Sun, 10 May 2026 12:50:23 +0200 Subject: [PATCH] fix: fix Screenshot fullscreen flickering --- kernel/src/Api/WinServer.cpp | 4 +- kernel/src/Ipc/Ipc.cpp | 40 +++++++++++++++ kernel/src/Ipc/Ipc.hpp | 1 + programs/src/screenshot/main.cpp | 88 ++++---------------------------- 4 files changed, 54 insertions(+), 79 deletions(-) diff --git a/kernel/src/Api/WinServer.cpp b/kernel/src/Api/WinServer.cpp index e805991..fde0109 100644 --- a/kernel/src/Api/WinServer.cpp +++ b/kernel/src/Api/WinServer.cpp @@ -99,7 +99,9 @@ namespace WinServer { WindowSlot& slot = g_slots[windowId]; if (!slot.used || slot.eventMailbox == nullptr) return -1; - int rc = Ipc::MailboxSend(slot.eventMailbox, 0, event, sizeof(*event)); + int rc = (event->type == 1) + ? Ipc::MailboxSendCoalescedMouse(slot.eventMailbox, 0, event, sizeof(*event)) + : Ipc::MailboxSend(slot.eventMailbox, 0, event, sizeof(*event)); return rc > 0 ? 0 : -1; } diff --git a/kernel/src/Ipc/Ipc.cpp b/kernel/src/Ipc/Ipc.cpp index a76ffeb..8d44d42 100644 --- a/kernel/src/Ipc/Ipc.cpp +++ b/kernel/src/Ipc/Ipc.cpp @@ -18,6 +18,7 @@ #include #include #include +#include namespace Ipc { @@ -851,6 +852,45 @@ namespace Ipc { return MailboxSendInternal(mailbox, -1, msgType, data, len, -1); } + int MailboxSendCoalescedMouse(Mailbox* mailbox, uint32_t msgType, const void* data, uint16_t len) { + if (mailbox == nullptr || data == nullptr) return -1; + if (len != sizeof(Montauk::WinEvent)) return MailboxSend(mailbox, msgType, data, len); + + const Montauk::WinEvent* incoming = (const Montauk::WinEvent*)data; + if (incoming->type != 1 || incoming->mouse.scroll != 0) + return MailboxSend(mailbox, msgType, data, len); + + bool incomingTransition = incoming->mouse.buttons != incoming->mouse.prev_buttons; + if (incomingTransition) + return MailboxSend(mailbox, msgType, data, len); + + mailbox->lock.Acquire(); + if (mailbox->receiverRefs == 0) { + mailbox->lock.Release(); + return -1; + } + + if (mailbox->count > 0) { + uint32_t idx = (mailbox->head + MaxMailboxMessages - 1) % MaxMailboxMessages; + MailboxMessage& latest = mailbox->messages[idx]; + if (latest.type == msgType && latest.size == len && !latest.hasAttachment) { + const Montauk::WinEvent* queued = (const Montauk::WinEvent*)latest.data; + bool queuedTransition = queued->type != 1 || + queued->mouse.scroll != 0 || + queued->mouse.buttons != queued->mouse.prev_buttons; + if (!queuedTransition) { + memcpy(latest.data, data, len); + mailbox->lock.Release(); + NotifyObjectChanged((Object*)mailbox); + return len; + } + } + } + mailbox->lock.Release(); + + return MailboxSend(mailbox, msgType, data, len); + } + static int MailboxRecvInternal(Mailbox* mailbox, int receiverSlot, uint32_t* msgType, void* data, uint16_t* inOutLen, int* outAttachHandle, bool /*nonBlocking*/) { diff --git a/kernel/src/Ipc/Ipc.hpp b/kernel/src/Ipc/Ipc.hpp index d6b5e8b..f225876 100644 --- a/kernel/src/Ipc/Ipc.hpp +++ b/kernel/src/Ipc/Ipc.hpp @@ -98,6 +98,7 @@ namespace Ipc { void RetainMailbox(Mailbox* mailbox, bool sender, bool receiver); void ReleaseMailbox(Mailbox* mailbox, bool sender, bool receiver); int MailboxSend(Mailbox* mailbox, uint32_t msgType, const void* data, uint16_t len); + int MailboxSendCoalescedMouse(Mailbox* mailbox, uint32_t msgType, const void* data, uint16_t len); int MailboxRecv(Mailbox* mailbox, uint32_t* msgType, void* data, uint16_t* inOutLen, bool nonBlocking); int MailboxSendHandle(int handle, uint32_t msgType, const void* data, uint16_t len, int attachHandle); int MailboxRecvHandle(int handle, uint32_t* msgType, void* data, uint16_t* inOutLen, int* outAttachHandle); diff --git a/programs/src/screenshot/main.cpp b/programs/src/screenshot/main.cpp index 9ae2de1..7edad3d 100644 --- a/programs/src/screenshot/main.cpp +++ b/programs/src/screenshot/main.cpp @@ -61,12 +61,6 @@ struct JpegBuffer { bool failed; }; -struct AreaRenderCache { - uint32_t* dimmed_pixels; - int width; - int height; -}; - static int g_win_w = INIT_W; static int g_win_h = INIT_H; static int g_mouse_x = -1; @@ -352,34 +346,6 @@ static uint32_t dim_pixel(uint32_t px) { return (px & 0xFF000000u) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; } -static void free_area_render_cache(AreaRenderCache* cache) { - if (!cache) return; - if (cache->dimmed_pixels) - montauk::mfree(cache->dimmed_pixels); - cache->dimmed_pixels = nullptr; - cache->width = 0; - cache->height = 0; -} - -static void build_area_render_cache(const ScreenBuffer& screen, AreaRenderCache* cache) { - if (!cache || !screen.pixels || screen.width <= 0 || screen.height <= 0) - return; - - uint64_t count = (uint64_t)screen.width * (uint64_t)screen.height; - uint64_t bytes = count * sizeof(uint32_t); - uint32_t* dimmed = (uint32_t*)montauk::malloc(bytes); - if (!dimmed) - return; - - for (uint64_t i = 0; i < count; i++) - dimmed[i] = dim_pixel(screen.pixels[i]); - - free_area_render_cache(cache); - cache->dimmed_pixels = dimmed; - cache->width = screen.width; - cache->height = screen.height; -} - // ============================================================================ // Area selection window // ============================================================================ @@ -462,8 +428,7 @@ static bool draw_fullscreen_preview(Canvas& c, const ScreenBuffer& screen, const Rect& preview, const Rect& selection, - bool has_selection, - const AreaRenderCache* cache) { + bool has_selection) { if (!screen.pixels || preview.x != 0 || preview.y != 0 || preview.w != c.w || preview.h != c.h || screen.width != c.w || screen.height != c.h) { @@ -471,24 +436,9 @@ static bool draw_fullscreen_preview(Canvas& c, } uint64_t bytes = (uint64_t)c.w * (uint64_t)c.h * sizeof(uint32_t); - Rect sel = clamp_rect_to_preview(selection, preview); - bool draw_dimmed = has_selection && !sel.empty() && - cache && cache->dimmed_pixels && - cache->width == screen.width && - cache->height == screen.height; - - if (draw_dimmed) - montauk::memcpy(c.pixels, cache->dimmed_pixels, bytes); - else - montauk::memcpy(c.pixels, screen.pixels, bytes); - - if (draw_dimmed) { - for (int y = 0; y < sel.h; y++) { - uint32_t* dst = c.pixels + (sel.y + y) * c.w + sel.x; - uint32_t* src = screen.pixels + (sel.y + y) * screen.width + sel.x; - montauk::memcpy(dst, src, (uint64_t)sel.w * sizeof(uint32_t)); - } - } + (void)selection; + (void)has_selection; + montauk::memcpy(c.pixels, screen.pixels, bytes); return true; } @@ -497,10 +447,9 @@ static void draw_scaled_preview(Canvas& c, const ScreenBuffer& screen, const Rect& preview, const Rect& selection, - bool has_selection, - const AreaRenderCache* cache) { + bool has_selection) { if (!screen.pixels || preview.empty()) return; - if (draw_fullscreen_preview(c, screen, preview, selection, has_selection, cache)) + if (draw_fullscreen_preview(c, screen, preview, selection, has_selection)) return; Rect sel = clamp_rect_to_preview(selection, preview); @@ -525,8 +474,7 @@ static void draw_scaled_preview(Canvas& c, static void draw_area_selector(Canvas& c, const ScreenBuffer& screen, - const AreaSelectorState& st, - const AreaRenderCache* cache) { + const AreaSelectorState& st) { mtk::Theme theme = app_theme(); if (!st.fullscreen) c.fill(theme.window_bg); @@ -534,7 +482,7 @@ static void draw_area_selector(Canvas& c, Rect preview = area_preview_rect(screen, st); if (!st.fullscreen) c.fill_rect(preview.x - 1, preview.y - 1, preview.w + 2, preview.h + 2, theme.border); - draw_scaled_preview(c, screen, preview, st.selection_view, st.has_selection || st.dragging, cache); + draw_scaled_preview(c, screen, preview, st.selection_view, st.has_selection || st.dragging); if ((st.has_selection || st.dragging) && !st.selection_view.empty()) { Rect sel = clamp_rect_to_preview(st.selection_view, preview); @@ -715,12 +663,9 @@ static bool run_area_selector(const ScreenBuffer& screen, Rect* out_area) { win.set_flags(Montauk::WIN_FLAG_FULLSCREEN); mtk::StandaloneHost host(&win); - AreaRenderCache cache = {}; Canvas canvas = host.canvas(); - draw_area_selector(canvas, screen, st, &cache); + draw_area_selector(canvas, screen, st); host.present(); - if (st.fullscreen) - build_area_render_cache(screen, &cache); bool accepted = false; while (true) { @@ -736,18 +681,6 @@ static bool run_area_selector(const ScreenBuffer& screen, Rect* out_area) { bool redraw = false; AreaEventResult result = handle_area_selector_event(win, screen, st, ev, &redraw); - for (int drain = 0; result == AREA_EVENT_CONTINUE && drain < 64; drain++) { - Montauk::WinEvent queued; - int qr = win.poll(&queued); - if (qr < 0) { - result = AREA_EVENT_CANCEL; - break; - } - if (qr == 0) - break; - result = handle_area_selector_event(win, screen, st, queued, &redraw); - } - if (result == AREA_EVENT_ACCEPT) { accepted = true; break; @@ -757,7 +690,7 @@ static bool run_area_selector(const ScreenBuffer& screen, Rect* out_area) { if (redraw) { canvas = host.canvas(); - draw_area_selector(canvas, screen, st, &cache); + draw_area_selector(canvas, screen, st); host.present(); } } @@ -770,7 +703,6 @@ static bool run_area_selector(const ScreenBuffer& screen, Rect* out_area) { } win.destroy(); - free_area_render_cache(&cache); return accepted; }