WindowServer: Implement fullscreen windows
If window size does not match framebuffer size, window data will be scaled to framebuffer using nearest sampling for best performance.
This commit is contained in:
parent
5e041e6e5a
commit
bda2c663da
|
@ -256,6 +256,15 @@ namespace LibGUI
|
||||||
return on_socket_error(__FUNCTION__);
|
return on_socket_error(__FUNCTION__);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::set_fullscreen(bool fullscreen)
|
||||||
|
{
|
||||||
|
WindowPacket::WindowSetFullscreen packet;
|
||||||
|
packet.fullscreen = fullscreen;
|
||||||
|
|
||||||
|
if (auto ret = packet.send_serialized(m_server_fd); ret.is_error())
|
||||||
|
return on_socket_error(__FUNCTION__);
|
||||||
|
}
|
||||||
|
|
||||||
void Window::set_position(int32_t x, int32_t y)
|
void Window::set_position(int32_t x, int32_t y)
|
||||||
{
|
{
|
||||||
WindowPacket::WindowSetPosition packet;
|
WindowPacket::WindowSetPosition packet;
|
||||||
|
|
|
@ -164,6 +164,7 @@ namespace LibGUI
|
||||||
WindowSetAttributes,
|
WindowSetAttributes,
|
||||||
WindowSetMouseCapture,
|
WindowSetMouseCapture,
|
||||||
WindowSetSize,
|
WindowSetSize,
|
||||||
|
WindowSetFullscreen,
|
||||||
|
|
||||||
DestroyWindowEvent,
|
DestroyWindowEvent,
|
||||||
CloseWindowEvent,
|
CloseWindowEvent,
|
||||||
|
@ -221,6 +222,11 @@ namespace LibGUI
|
||||||
uint32_t, height
|
uint32_t, height
|
||||||
);
|
);
|
||||||
|
|
||||||
|
DEFINE_PACKET(
|
||||||
|
WindowSetFullscreen,
|
||||||
|
bool, fullscreen
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace EventPacket
|
namespace EventPacket
|
||||||
|
|
|
@ -61,6 +61,7 @@ namespace LibGUI
|
||||||
void invalidate() { return invalidate(0, 0, width(), height()); }
|
void invalidate() { return invalidate(0, 0, width(), height()); }
|
||||||
|
|
||||||
void set_mouse_capture(bool captured);
|
void set_mouse_capture(bool captured);
|
||||||
|
void set_fullscreen(bool fullscreen);
|
||||||
|
|
||||||
void set_position(int32_t x, int32_t y);
|
void set_position(int32_t x, int32_t y);
|
||||||
|
|
||||||
|
|
|
@ -125,6 +125,9 @@ void WindowServer::on_window_invalidate(int fd, const LibGUI::WindowPacket::Wind
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
if (m_is_fullscreen_window && m_focused_window->client_fd() == fd)
|
||||||
|
return;
|
||||||
|
|
||||||
BAN::RefPtr<Window> target_window;
|
BAN::RefPtr<Window> target_window;
|
||||||
for (auto& window : m_client_windows)
|
for (auto& window : m_client_windows)
|
||||||
{
|
{
|
||||||
|
@ -259,6 +262,45 @@ void WindowServer::on_window_set_size(int fd, const LibGUI::WindowPacket::Window
|
||||||
invalidate(target_window->full_area().get_bounding_box(old_area));
|
invalidate(target_window->full_area().get_bounding_box(old_area));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowServer::on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::WindowSetFullscreen& packet)
|
||||||
|
{
|
||||||
|
if (m_is_fullscreen_window)
|
||||||
|
{
|
||||||
|
ASSERT(m_focused_window);
|
||||||
|
if (m_focused_window->client_fd() != fd)
|
||||||
|
dwarnln("client tried to set fullscreen window size while another window is already fullscreen");
|
||||||
|
else if (!packet.fullscreen)
|
||||||
|
{
|
||||||
|
m_is_fullscreen_window = false;
|
||||||
|
invalidate(m_framebuffer.area());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!packet.fullscreen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
BAN::RefPtr<Window> target_window;
|
||||||
|
for (auto& window : m_client_windows)
|
||||||
|
{
|
||||||
|
if (window->client_fd() != fd)
|
||||||
|
continue;
|
||||||
|
target_window = window;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!target_window)
|
||||||
|
{
|
||||||
|
dwarnln("client tried to set window size while not owning a window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_is_fullscreen_window = true;
|
||||||
|
set_focused_window(target_window);
|
||||||
|
target_window->set_position({ 0, 0 });
|
||||||
|
invalidate(m_framebuffer.area());
|
||||||
|
}
|
||||||
|
|
||||||
void WindowServer::on_key_event(LibInput::KeyEvent event)
|
void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||||
{
|
{
|
||||||
// Mod key is not passed to clients
|
// Mod key is not passed to clients
|
||||||
|
@ -301,7 +343,7 @@ void WindowServer::on_key_event(LibInput::KeyEvent event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle window bounce with F2
|
// Toggle window bounce with F2
|
||||||
if (event.pressed() && event.key == LibInput::Key::F2)
|
if (!m_is_fullscreen_window && event.pressed() && event.key == LibInput::Key::F2)
|
||||||
m_is_bouncing_window = !m_is_bouncing_window;
|
m_is_bouncing_window = !m_is_bouncing_window;
|
||||||
|
|
||||||
if (m_focused_window)
|
if (m_focused_window)
|
||||||
|
@ -376,6 +418,9 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_is_fullscreen_window)
|
||||||
|
m_is_moving_window = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
|
void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event)
|
||||||
|
@ -497,6 +542,47 @@ static uint32_t alpha_blend(uint32_t color_a, uint32_t color_b)
|
||||||
|
|
||||||
void WindowServer::invalidate(Rectangle area)
|
void WindowServer::invalidate(Rectangle area)
|
||||||
{
|
{
|
||||||
|
if (m_is_fullscreen_window)
|
||||||
|
{
|
||||||
|
ASSERT(m_focused_window);
|
||||||
|
|
||||||
|
auto focused_overlap = area.get_overlap(m_focused_window->client_area());
|
||||||
|
if (!focused_overlap.has_value())
|
||||||
|
return;
|
||||||
|
area = focused_overlap.release_value();
|
||||||
|
|
||||||
|
if (m_focused_window->client_area() == m_framebuffer.area())
|
||||||
|
{
|
||||||
|
for (int32_t y = area.y; y < area.y + area.height; y++)
|
||||||
|
for (int32_t x = area.x; x < area.x + area.width; x++)
|
||||||
|
m_framebuffer.mmap[y * m_framebuffer.width + x] = m_focused_window->framebuffer()[y * m_focused_window->client_width() + x];
|
||||||
|
mark_pending_sync(area);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const Rectangle dst_area {
|
||||||
|
.x = area.x * m_framebuffer.width / m_focused_window->client_width(),
|
||||||
|
.y = area.y * m_framebuffer.height / m_focused_window->client_height(),
|
||||||
|
.width = BAN::Math::div_round_up(area.width * m_framebuffer.width, m_focused_window->client_width()),
|
||||||
|
.height = BAN::Math::div_round_up(area.height * m_framebuffer.height, m_focused_window->client_height())
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int32_t dst_y = dst_area.y; dst_y < dst_area.y + dst_area.height; dst_y++)
|
||||||
|
{
|
||||||
|
for (int32_t dst_x = dst_area.x; dst_x < dst_area.x + dst_area.width; dst_x++)
|
||||||
|
{
|
||||||
|
const int32_t src_x = dst_x * m_focused_window->client_width() / m_framebuffer.width;
|
||||||
|
const int32_t src_y = dst_y * m_focused_window->client_height() / m_framebuffer.height;
|
||||||
|
m_framebuffer.mmap[dst_y * m_framebuffer.width + dst_x] = m_focused_window->framebuffer()[src_y * m_focused_window->client_width() + src_x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_pending_sync(dst_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto fb_overlap = area.get_overlap(m_framebuffer.area());
|
auto fb_overlap = area.get_overlap(m_framebuffer.area());
|
||||||
if (!fb_overlap.has_value())
|
if (!fb_overlap.has_value())
|
||||||
return;
|
return;
|
||||||
|
@ -713,6 +799,13 @@ void WindowServer::invalidate(Rectangle area)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mark_pending_sync(area);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowServer::mark_pending_sync(Rectangle area)
|
||||||
|
{
|
||||||
|
// FIXME: this marks too many pages
|
||||||
|
|
||||||
const uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
|
const uintptr_t mmap_start = reinterpret_cast<uintptr_t>(m_framebuffer.mmap) + area.y * m_framebuffer.width * 4;
|
||||||
const uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
|
const uintptr_t mmap_end = mmap_start + (area.height + 1) * m_framebuffer.width * 4;
|
||||||
|
|
||||||
|
@ -801,6 +894,12 @@ void WindowServer::remove_client_fd(int fd)
|
||||||
return;
|
return;
|
||||||
m_client_data.remove(it);
|
m_client_data.remove(it);
|
||||||
|
|
||||||
|
if (m_is_fullscreen_window && m_focused_window->client_fd() == fd)
|
||||||
|
{
|
||||||
|
m_is_fullscreen_window = false;
|
||||||
|
invalidate(m_framebuffer.area());
|
||||||
|
}
|
||||||
|
|
||||||
for (size_t i = 0; i < m_client_windows.size(); i++)
|
for (size_t i = 0; i < m_client_windows.size(); i++)
|
||||||
{
|
{
|
||||||
auto window = m_client_windows[i];
|
auto window = m_client_windows[i];
|
||||||
|
|
|
@ -36,6 +36,7 @@ public:
|
||||||
void on_window_set_attributes(int fd, const LibGUI::WindowPacket::WindowSetAttributes&);
|
void on_window_set_attributes(int fd, const LibGUI::WindowPacket::WindowSetAttributes&);
|
||||||
void on_window_set_mouse_capture(int fd, const LibGUI::WindowPacket::WindowSetMouseCapture&);
|
void on_window_set_mouse_capture(int fd, const LibGUI::WindowPacket::WindowSetMouseCapture&);
|
||||||
void on_window_set_size(int fd, const LibGUI::WindowPacket::WindowSetSize&);
|
void on_window_set_size(int fd, const LibGUI::WindowPacket::WindowSetSize&);
|
||||||
|
void on_window_set_fullscreen(int fd, const LibGUI::WindowPacket::WindowSetFullscreen&);
|
||||||
|
|
||||||
void on_key_event(LibInput::KeyEvent event);
|
void on_key_event(LibInput::KeyEvent event);
|
||||||
void on_mouse_button(LibInput::MouseButtonEvent event);
|
void on_mouse_button(LibInput::MouseButtonEvent event);
|
||||||
|
@ -55,6 +56,9 @@ public:
|
||||||
|
|
||||||
bool is_stopped() const { return m_is_stopped; }
|
bool is_stopped() const { return m_is_stopped; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void mark_pending_sync(Rectangle area);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Framebuffer& m_framebuffer;
|
Framebuffer& m_framebuffer;
|
||||||
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
|
BAN::Vector<BAN::RefPtr<Window>> m_client_windows;
|
||||||
|
@ -69,6 +73,7 @@ private:
|
||||||
|
|
||||||
bool m_is_mod_key_held { false };
|
bool m_is_mod_key_held { false };
|
||||||
bool m_is_moving_window { false };
|
bool m_is_moving_window { false };
|
||||||
|
bool m_is_fullscreen_window { false };
|
||||||
BAN::RefPtr<Window> m_focused_window;
|
BAN::RefPtr<Window> m_focused_window;
|
||||||
Position m_cursor;
|
Position m_cursor;
|
||||||
|
|
||||||
|
|
|
@ -371,6 +371,10 @@ int main()
|
||||||
if (auto ret = LibGUI::WindowPacket::WindowSetSize::deserialize(client_data.packet_buffer.span()); !ret.is_error())
|
if (auto ret = LibGUI::WindowPacket::WindowSetSize::deserialize(client_data.packet_buffer.span()); !ret.is_error())
|
||||||
window_server.on_window_set_size(fd, ret.release_value());
|
window_server.on_window_set_size(fd, ret.release_value());
|
||||||
break;
|
break;
|
||||||
|
case LibGUI::PacketType::WindowSetFullscreen:
|
||||||
|
if (auto ret = LibGUI::WindowPacket::WindowSetFullscreen::deserialize(client_data.packet_buffer.span()); !ret.is_error())
|
||||||
|
window_server.on_window_set_fullscreen(fd, ret.release_value());
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dprintln("unhandled packet type: {}", *reinterpret_cast<uint32_t*>(client_data.packet_buffer.data()));
|
dprintln("unhandled packet type: {}", *reinterpret_cast<uint32_t*>(client_data.packet_buffer.data()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue