Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions src/usr/wm/wm_logic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,10 @@ static void get_window_opaque_cover_rects(const Window &w, DirtyRect *out_rects,
return;
*out_count = 0;
if (w.transparent) {
out_rects[0] = window_client_bounds(w);
*out_count = 1;
// Transparent windows have no opaque coverage. Treating them as
// opaque causes the compositor to skip painting windows underneath
// (dock, menubar, and stacked windows behind them), which manifests
// as black or stale pixels showing through the transparent surface.
return;
}

Expand Down Expand Up @@ -384,7 +386,7 @@ static void get_window_opaque_cover_rects(const Window &w, DirtyRect *out_rects,
DirtyRect window_opaque_bounds(const Window &w)
{
if (w.transparent)
return window_client_bounds(w);
return {0, 0, 0, 0};
int side_inset = window_safe_side_inset();
int title_h = wm_title_bar_h();
int radius = gui_scaled_metric(12) - wm_frame_border();
Expand All @@ -401,6 +403,8 @@ DirtyRect window_opaque_bounds(const Window &w)

DirtyRect window_occlusion_bounds(const Window &w)
{
if (w.transparent)
return {0, 0, 0, 0};
return window_opaque_bounds(w);
}

Expand Down Expand Up @@ -2747,7 +2751,10 @@ void update_cursor_kind()
n_k = g_input.drag_edges == RESIZE_NONE ? GUI_CURSOR_MOVE : ck_edges(g_input.drag_edges);
else if (g_input.hover_resize_edges != RESIZE_NONE)
n_k = ck_edges(g_input.hover_resize_edges);
else if (g_input.hover_frame_index >= 2)
else if (g_input.hover_frame_index >= 2 && g_input.hover_button < 0)
// Only show the move cursor when hovering the title bar itself; over
// a chrome button the user expects an arrow cursor so the click
// affordance is unambiguous.
n_k = GUI_CURSOR_MOVE;
if (!g_input.pointer_down)
reset_window_snap_state();
Expand Down
7 changes: 6 additions & 1 deletion src/usr/wm/wm_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1716,6 +1716,11 @@ extern "C" int main(int argc, char **argv)
inter, g_display_copy_path, manip});

if (g_dirty_frame_ready && action == wm::PresentPolicyDecision::Submit) {
// Publish all backbuffer stores before the display engine can latch
// the present buffer. Without this fence, weakly-ordered cores or
// write-combining stores can cause partially composited frames to
// appear as tearing or sparkle on the screen.
asm volatile("sfence" ::: "memory");
uint32_t sub = present_frame(&g_presentbuffer, g_dirty_rects, clamp_dirty_rect_count(g_dirty_count),
frame_seq, g_frame_cursor_handle, g_frame_cursor_x, g_frame_cursor_y);
if (sub) {
Expand Down Expand Up @@ -1751,4 +1756,4 @@ extern "C" int main(int argc, char **argv)
reap_exited_children();
}
return 0;
}
}
46 changes: 37 additions & 9 deletions src/usr/wm/wm_render.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
#include "wm_core.h"

// Clipped wrapper around gui_fill_rounded_rect. When the requested rect is
// fully contained inside the dirty clip we draw the rounded shape, otherwise
// we fall back to a clipped axis-aligned fill so we never overdraw beyond the
// dirty region (which would corrupt neighbouring windows already composited
// into this frame).
static void gui_fill_rounded_rect_clipped(Surface *dst, int x, int y, int w, int h, int r, uint32_t color,
const DirtyRect &clip)
{
int ix, iy, iw, ih;
if (!gui_intersect_rect(x, y, w, h, clip.x, clip.y, clip.w, clip.h, &ix, &iy, &iw, &ih))
return;
if (rect_contains(clip, {x, y, w, h})) {
gui_fill_rounded_rect(dst, x, y, w, h, r, color);
} else {
gui_fill_rect(dst, ix, iy, iw, ih, color);
}
}

static void gui_draw_rounded_rect_clipped(Surface *dst, int x, int y, int w, int h, int r, uint32_t color,
const DirtyRect &clip)
{
int ix, iy, iw, ih;
if (!gui_intersect_rect(x, y, w, h, clip.x, clip.y, clip.w, clip.h, &ix, &iy, &iw, &ih))
return;
gui_draw_rounded_rect(dst, x, y, w, h, r, color);
}

static Surface g_icon_close = {};
static Surface g_icon_minimize = {};
static Surface g_icon_maximize = {};
Expand Down Expand Up @@ -676,19 +703,20 @@ static void draw_window_decoration_frame(Surface *dst, const Window &w, const Di

int shadow_offset = focused ? gui_scaled_metric(3) : gui_scaled_metric(2);
uint32_t shadow_color = focused ? 0x20000000u : 0x12000000u;
gui_fill_rounded_rect(dst, sx, sy + shadow_offset, sw, sh, radius + gui_scaled_metric(1), shadow_color);
gui_fill_rounded_rect_clipped(dst, sx, sy + shadow_offset, sw, sh, radius + gui_scaled_metric(1), shadow_color,
clip);

gui_fill_rounded_rect(dst, sx, sy, sw, sh, radius, outline_color);
gui_fill_rounded_rect_clipped(dst, sx, sy, sw, sh, radius, outline_color, clip);
if (sw > border * 2 && sh > border * 2) {
gui_fill_rounded_rect(dst, sx + border, sy + border, sw - border * 2, sh - border * 2, frame_radius,
frame_fill_color);
gui_fill_rounded_rect_clipped(dst, sx + border, sy + border, sw - border * 2, sh - border * 2, frame_radius,
frame_fill_color, clip);
}

if (sw > body_inset * 2 && sh > body_inset * 2) {
gui_fill_rounded_rect(dst, sx + body_inset, sy + body_inset, sw - body_inset * 2, sh - body_inset * 2,
body_radius, body_color);
gui_draw_rounded_rect(dst, sx + border, sy + border, sw - border * 2, sh - border * 2, frame_radius,
inner_stroke_color);
gui_fill_rounded_rect_clipped(dst, sx + body_inset, sy + body_inset, sw - body_inset * 2, sh - body_inset * 2,
body_radius, body_color, clip);
gui_draw_rounded_rect_clipped(dst, sx + border, sy + border, sw - border * 2, sh - border * 2, frame_radius,
inner_stroke_color, clip);
}

int title_fill_x = sx + border;
Expand Down Expand Up @@ -1139,4 +1167,4 @@ void draw_window_client_clipped(Surface *dst, const Window &w, const DirtyRect &
dst_ptr[x] = blend_coverage_rgb(dst_ptr[x], src_ptr[src_col], coverage);
}
}
}
}
Loading