fix: fix Screenshot fullscreen flickering
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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*/) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,25 +436,10 @@ 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
|
||||
(void)selection;
|
||||
(void)has_selection;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user