WindowServer: Fix invalidation for fullscreen windows

This commit is contained in:
2026-06-26 23:03:25 +03:00
parent ac333c9677
commit 924576cf0d

View File

@@ -135,17 +135,50 @@ void WindowServer::on_window_invalidate(int fd, const LibGUI::WindowPacket::Wind
if (!target_window->get_attributes().shown) if (!target_window->get_attributes().shown)
return; return;
const auto client_area = target_window->client_area(); BAN::Optional<Rectangle> damaged_area;
const Rectangle damaged_area { if (m_state == State::Fullscreen)
{
if (target_window->client_width() == m_framebuffer.width && target_window->client_height() == m_framebuffer.height)
{
damaged_area = Rectangle {
.min_x = static_cast<int32_t>(packet.x),
.min_y = static_cast<int32_t>(packet.y),
.max_x = static_cast<int32_t>(packet.x + packet.width),
.max_y = static_cast<int32_t>(packet.y + packet.height),
};
}
else
{
const float scale = BAN::Math::min(
static_cast<float>(m_framebuffer.width) / m_focused_window->client_width(),
static_cast<float>(m_framebuffer.height) / m_focused_window->client_height()
);
const float offset_x = (m_framebuffer.width - m_focused_window->client_width() * scale) / 2.0f;
const float offset_y = (m_framebuffer.height - m_focused_window->client_height() * scale) / 2.0f;
damaged_area = Rectangle {
.min_x = static_cast<int32_t>(BAN::Math::floor(packet.x * scale + offset_x)),
.min_y = static_cast<int32_t>(BAN::Math::floor(packet.y * scale + offset_y)),
.max_x = static_cast<int32_t>(BAN::Math::ceil((packet.x + packet.width) * scale + offset_x)),
.max_y = static_cast<int32_t>(BAN::Math::ceil((packet.y + packet.height) * scale + offset_y)),
};
}
}
else
{
const auto client_area = target_window->client_area();
damaged_area = client_area.get_overlap({
.min_x = client_area.min_x + static_cast<int32_t>(packet.x), .min_x = client_area.min_x + static_cast<int32_t>(packet.x),
.min_y = client_area.min_y + static_cast<int32_t>(packet.y), .min_y = client_area.min_y + static_cast<int32_t>(packet.y),
.max_x = client_area.min_x + static_cast<int32_t>(packet.x + packet.width), .max_x = client_area.min_x + static_cast<int32_t>(packet.x + packet.width),
.max_y = client_area.min_y + static_cast<int32_t>(packet.y + packet.height), .max_y = client_area.min_y + static_cast<int32_t>(packet.y + packet.height),
}; });
}
if (auto opt_overlap = damaged_area.get_overlap(client_area); opt_overlap.has_value()) if (damaged_area.has_value())
add_damaged_area(opt_overlap.release_value()); add_damaged_area(damaged_area.release_value());
} }
void WindowServer::on_window_set_position(int fd, const LibGUI::WindowPacket::WindowSetPosition& packet) void WindowServer::on_window_set_position(int fd, const LibGUI::WindowPacket::WindowSetPosition& packet)
@@ -197,7 +230,6 @@ void WindowServer::on_window_set_attributes(int fd, const LibGUI::WindowPacket::
{ {
if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height())) if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height()))
return; return;
move_window(m_focused_window, m_non_full_screen_rect.min_x, m_non_full_screen_rect.min_y);
} }
m_focused_window = nullptr; m_focused_window = nullptr;
@@ -321,7 +353,6 @@ void WindowServer::on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::
{ {
if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height())) if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height()))
return; return;
move_window(m_focused_window, m_non_full_screen_rect.min_x, m_non_full_screen_rect.min_y);
} }
const LibGUI::EventPacket::WindowFullscreenEvent event_packet { .event = { const LibGUI::EventPacket::WindowFullscreenEvent event_packet { .event = {
@@ -355,7 +386,6 @@ void WindowServer::on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::
const auto old_area = target_window->client_area(); const auto old_area = target_window->client_area();
if (!resize_window(target_window, m_framebuffer.width, m_framebuffer.height)) if (!resize_window(target_window, m_framebuffer.width, m_framebuffer.height))
return; return;
move_window(target_window, 0, 0);
m_non_full_screen_rect = old_area; m_non_full_screen_rect = old_area;
} }
@@ -521,7 +551,6 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
{ {
if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height())) if (!resize_window(m_focused_window, m_non_full_screen_rect.width(), m_non_full_screen_rect.height()))
return; return;
move_window(m_focused_window, m_non_full_screen_rect.min_x, m_non_full_screen_rect.min_y);
} }
m_state = State::Normal; m_state = State::Normal;
} }
@@ -532,7 +561,6 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
const auto old_area = m_focused_window->client_area(); const auto old_area = m_focused_window->client_area();
if (!resize_window(m_focused_window, m_framebuffer.width, m_framebuffer.height)) if (!resize_window(m_focused_window, m_framebuffer.width, m_framebuffer.height))
return; return;
move_window(m_focused_window, 0, 0);
m_non_full_screen_rect = old_area; m_non_full_screen_rect = old_area;
} }
m_state = State::Fullscreen; m_state = State::Fullscreen;
@@ -941,6 +969,8 @@ static void alpha_blend4(const uint32_t color_a[4], const uint32_t color_b[4], u
void WindowServer::invalidate(Rectangle area) void WindowServer::invalidate(Rectangle area)
{ {
ASSERT(area.get_bounding_box(m_framebuffer.area()) == m_framebuffer.area());
const Window::Cursor* window_cursor = nullptr; const Window::Cursor* window_cursor = nullptr;
if (auto window = this->find_hovered_window(); window && window->has_cursor()) if (auto window = this->find_hovered_window(); window && window->has_cursor())
window_cursor = &window->cursor(); window_cursor = &window->cursor();
@@ -969,26 +999,10 @@ void WindowServer::invalidate(Rectangle area)
if (m_state == State::Fullscreen) if (m_state == State::Fullscreen)
{ {
ASSERT(m_focused_window); ASSERT(m_focused_window);
area.min_x -= m_focused_window->client_x();
area.max_x -= m_focused_window->client_x();
area.min_y -= m_focused_window->client_y();
area.max_y -= m_focused_window->client_y();
const Rectangle client_area {
.min_x = 0,
.min_y = 0,
.max_x = m_focused_window->client_width(),
.max_y = m_focused_window->client_height(),
};
auto focused_overlap = area.get_overlap(client_area);
if (!focused_overlap.has_value())
return;
area = focused_overlap.release_value();
const bool should_alpha_blend = m_focused_window->get_attributes().alpha_channel; const bool should_alpha_blend = m_focused_window->get_attributes().alpha_channel;
if (client_area == m_framebuffer.area()) if (m_focused_window->client_width() == m_framebuffer.width && m_focused_window->client_height() == m_framebuffer.height)
{ {
const uint32_t* client_ptr = m_focused_window->framebuffer(); const uint32_t* client_ptr = m_focused_window->framebuffer();
const size_t client_width = m_focused_window->client_width(); const size_t client_width = m_focused_window->client_width();
@@ -1032,28 +1046,38 @@ void WindowServer::invalidate(Rectangle area)
} }
else else
{ {
auto opt_dst_area = Rectangle { const float scale = BAN::Math::min(
.min_x = area.min_x * m_framebuffer.width / m_focused_window->client_width(), static_cast<float>(m_framebuffer.width) / m_focused_window->client_width(),
.min_y = area.min_y * m_framebuffer.height / m_focused_window->client_height(), static_cast<float>(m_framebuffer.height) / m_focused_window->client_height()
.max_x = BAN::Math::div_round_up(area.max_x * m_framebuffer.width, m_focused_window->client_width()), );
.max_y = BAN::Math::div_round_up(area.max_y * m_framebuffer.height, m_focused_window->client_height())
}.get_overlap(m_framebuffer.area());
if (!opt_dst_area.has_value())
return;
const auto dst_area = opt_dst_area.release_value(); const float offset_x = (m_framebuffer.width - m_focused_window->client_width() * scale) / 2.0f;
for (int32_t dst_y = dst_area.min_y; dst_y < dst_area.max_y; dst_y++) const float offset_y = (m_framebuffer.height - m_focused_window->client_height() * scale) / 2.0f;
const Rectangle window_area {
.min_x = 0,
.min_y = 0,
.max_x = m_focused_window->client_width(),
.max_y = m_focused_window->client_height(),
};
const float inv_scale = 1.0f / scale;
for (int32_t dst_y = area.min_y; dst_y < area.max_y; dst_y++)
{ {
for (int32_t dst_x = dst_area.min_x; dst_x < dst_area.max_x; dst_x++) for (int32_t dst_x = area.min_x; dst_x < area.max_x; dst_x++)
{ {
const int32_t src_x = BAN::Math::clamp<int32_t>(dst_x * m_focused_window->client_width() / m_framebuffer.width, 0, m_focused_window->client_width()); const int32_t src_x = (dst_x - offset_x) * inv_scale;
const int32_t src_y = BAN::Math::clamp<int32_t>(dst_y * m_focused_window->client_height() / m_framebuffer.height, 0, m_focused_window->client_height()); const int32_t src_y = (dst_y - offset_y) * inv_scale;
if (!window_area.contains({ .x = src_x, .y = src_y }))
{
m_framebuffer.mmap[dst_y * m_framebuffer.width + dst_x] = 0x000000;
continue;
}
const uint32_t src_pixel = m_focused_window->framebuffer()[src_y * m_focused_window->client_width() + src_x]; const uint32_t src_pixel = m_focused_window->framebuffer()[src_y * m_focused_window->client_width() + src_x];
const uint32_t bg_pixel = m_background_image[dst_y * m_framebuffer.width + dst_x]; m_framebuffer.mmap[dst_y * m_framebuffer.width + dst_x] = should_alpha_blend
? alpha_blend(src_pixel, m_background_image[dst_y * m_framebuffer.width + dst_x])
uint32_t& dst_pixel = m_framebuffer.mmap[dst_y * m_framebuffer.width + dst_x]; : src_pixel;
dst_pixel = should_alpha_blend ? alpha_blend(src_pixel, bg_pixel) : src_pixel;
} }
} }
} }
@@ -1094,11 +1118,6 @@ void WindowServer::invalidate(Rectangle area)
return; return;
} }
auto fb_overlap = area.get_overlap(m_framebuffer.area());
if (!fb_overlap.has_value())
return;
area = fb_overlap.release_value();
for (int32_t y = area.min_y; y < area.max_y; y++) for (int32_t y = area.min_y; y < area.max_y; y++)
{ {
memcpy( memcpy(