fix: fix Screenshot fullscreen flickering
This commit is contained in:
@@ -99,7 +99,9 @@ namespace WinServer {
|
|||||||
WindowSlot& slot = g_slots[windowId];
|
WindowSlot& slot = g_slots[windowId];
|
||||||
if (!slot.used || slot.eventMailbox == nullptr) return -1;
|
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;
|
return rc > 0 ? 0 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#include <Timekeeping/ApicTimer.hpp>
|
#include <Timekeeping/ApicTimer.hpp>
|
||||||
#include <Terminal/Terminal.hpp>
|
#include <Terminal/Terminal.hpp>
|
||||||
#include <Api/UserMemory.hpp>
|
#include <Api/UserMemory.hpp>
|
||||||
|
#include <Api/Syscall.hpp>
|
||||||
|
|
||||||
namespace Ipc {
|
namespace Ipc {
|
||||||
|
|
||||||
@@ -851,6 +852,45 @@ namespace Ipc {
|
|||||||
return MailboxSendInternal(mailbox, -1, msgType, data, len, -1);
|
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,
|
static int MailboxRecvInternal(Mailbox* mailbox, int receiverSlot, uint32_t* msgType,
|
||||||
void* data, uint16_t* inOutLen, int* outAttachHandle,
|
void* data, uint16_t* inOutLen, int* outAttachHandle,
|
||||||
bool /*nonBlocking*/) {
|
bool /*nonBlocking*/) {
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ namespace Ipc {
|
|||||||
void RetainMailbox(Mailbox* mailbox, bool sender, bool receiver);
|
void RetainMailbox(Mailbox* mailbox, bool sender, bool receiver);
|
||||||
void ReleaseMailbox(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 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 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 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);
|
int MailboxRecvHandle(int handle, uint32_t* msgType, void* data, uint16_t* inOutLen, int* outAttachHandle);
|
||||||
|
|||||||
@@ -61,12 +61,6 @@ struct JpegBuffer {
|
|||||||
bool failed;
|
bool failed;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AreaRenderCache {
|
|
||||||
uint32_t* dimmed_pixels;
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int g_win_w = INIT_W;
|
static int g_win_w = INIT_W;
|
||||||
static int g_win_h = INIT_H;
|
static int g_win_h = INIT_H;
|
||||||
static int g_mouse_x = -1;
|
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;
|
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
|
// Area selection window
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -462,8 +428,7 @@ static bool draw_fullscreen_preview(Canvas& c,
|
|||||||
const ScreenBuffer& screen,
|
const ScreenBuffer& screen,
|
||||||
const Rect& preview,
|
const Rect& preview,
|
||||||
const Rect& selection,
|
const Rect& selection,
|
||||||
bool has_selection,
|
bool has_selection) {
|
||||||
const AreaRenderCache* cache) {
|
|
||||||
if (!screen.pixels || preview.x != 0 || preview.y != 0 ||
|
if (!screen.pixels || preview.x != 0 || preview.y != 0 ||
|
||||||
preview.w != c.w || preview.h != c.h ||
|
preview.w != c.w || preview.h != c.h ||
|
||||||
screen.width != c.w || screen.height != 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);
|
uint64_t bytes = (uint64_t)c.w * (uint64_t)c.h * sizeof(uint32_t);
|
||||||
Rect sel = clamp_rect_to_preview(selection, preview);
|
(void)selection;
|
||||||
bool draw_dimmed = has_selection && !sel.empty() &&
|
(void)has_selection;
|
||||||
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);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -497,10 +447,9 @@ static void draw_scaled_preview(Canvas& c,
|
|||||||
const ScreenBuffer& screen,
|
const ScreenBuffer& screen,
|
||||||
const Rect& preview,
|
const Rect& preview,
|
||||||
const Rect& selection,
|
const Rect& selection,
|
||||||
bool has_selection,
|
bool has_selection) {
|
||||||
const AreaRenderCache* cache) {
|
|
||||||
if (!screen.pixels || preview.empty()) return;
|
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;
|
return;
|
||||||
|
|
||||||
Rect sel = clamp_rect_to_preview(selection, preview);
|
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,
|
static void draw_area_selector(Canvas& c,
|
||||||
const ScreenBuffer& screen,
|
const ScreenBuffer& screen,
|
||||||
const AreaSelectorState& st,
|
const AreaSelectorState& st) {
|
||||||
const AreaRenderCache* cache) {
|
|
||||||
mtk::Theme theme = app_theme();
|
mtk::Theme theme = app_theme();
|
||||||
if (!st.fullscreen)
|
if (!st.fullscreen)
|
||||||
c.fill(theme.window_bg);
|
c.fill(theme.window_bg);
|
||||||
@@ -534,7 +482,7 @@ static void draw_area_selector(Canvas& c,
|
|||||||
Rect preview = area_preview_rect(screen, st);
|
Rect preview = area_preview_rect(screen, st);
|
||||||
if (!st.fullscreen)
|
if (!st.fullscreen)
|
||||||
c.fill_rect(preview.x - 1, preview.y - 1, preview.w + 2, preview.h + 2, theme.border);
|
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()) {
|
if ((st.has_selection || st.dragging) && !st.selection_view.empty()) {
|
||||||
Rect sel = clamp_rect_to_preview(st.selection_view, preview);
|
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);
|
win.set_flags(Montauk::WIN_FLAG_FULLSCREEN);
|
||||||
|
|
||||||
mtk::StandaloneHost host(&win);
|
mtk::StandaloneHost host(&win);
|
||||||
AreaRenderCache cache = {};
|
|
||||||
Canvas canvas = host.canvas();
|
Canvas canvas = host.canvas();
|
||||||
draw_area_selector(canvas, screen, st, &cache);
|
draw_area_selector(canvas, screen, st);
|
||||||
host.present();
|
host.present();
|
||||||
if (st.fullscreen)
|
|
||||||
build_area_render_cache(screen, &cache);
|
|
||||||
|
|
||||||
bool accepted = false;
|
bool accepted = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -736,18 +681,6 @@ static bool run_area_selector(const ScreenBuffer& screen, Rect* out_area) {
|
|||||||
bool redraw = false;
|
bool redraw = false;
|
||||||
AreaEventResult result = handle_area_selector_event(win, screen, st, ev, &redraw);
|
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) {
|
if (result == AREA_EVENT_ACCEPT) {
|
||||||
accepted = true;
|
accepted = true;
|
||||||
break;
|
break;
|
||||||
@@ -757,7 +690,7 @@ static bool run_area_selector(const ScreenBuffer& screen, Rect* out_area) {
|
|||||||
|
|
||||||
if (redraw) {
|
if (redraw) {
|
||||||
canvas = host.canvas();
|
canvas = host.canvas();
|
||||||
draw_area_selector(canvas, screen, st, &cache);
|
draw_area_selector(canvas, screen, st);
|
||||||
host.present();
|
host.present();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -770,7 +703,6 @@ static bool run_area_selector(const ScreenBuffer& screen, Rect* out_area) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
win.destroy();
|
win.destroy();
|
||||||
free_area_render_cache(&cache);
|
|
||||||
return accepted;
|
return accepted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user