fix: fix Screenshot fullscreen flickering

This commit is contained in:
2026-05-10 12:50:23 +02:00
parent 72e4fa080a
commit 525f92cdf0
4 changed files with 54 additions and 79 deletions
+3 -1
View File
@@ -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;
}
+40
View File
@@ -18,6 +18,7 @@
#include <Timekeeping/ApicTimer.hpp>
#include <Terminal/Terminal.hpp>
#include <Api/UserMemory.hpp>
#include <Api/Syscall.hpp>
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*/) {
+1
View File
@@ -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);
+10 -78
View File
@@ -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;
}