From 011a5f57e1057977ad234331ec300681523ec6c2 Mon Sep 17 00:00:00 2001 From: Bananymous Date: Fri, 31 May 2024 03:02:58 +0300 Subject: [PATCH] WindowServer: Add title bars and clean up code --- userspace/WindowServer/Utils.h | 6 ++ userspace/WindowServer/Window.h | 62 +++++++++++++---- userspace/WindowServer/WindowServer.cpp | 91 +++++++++++++++++-------- userspace/WindowServer/WindowServer.h | 2 + userspace/WindowServer/main.cpp | 17 +++-- 5 files changed, 129 insertions(+), 49 deletions(-) diff --git a/userspace/WindowServer/Utils.h b/userspace/WindowServer/Utils.h index 32f8f7f7..6f673cbb 100644 --- a/userspace/WindowServer/Utils.h +++ b/userspace/WindowServer/Utils.h @@ -56,4 +56,10 @@ struct Rectangle .height = max_y - min_y, }; } + + bool operator==(const Rectangle& other) const + { + return x == other.x && y == other.y && width == other.width && height == other.height; + } + }; diff --git a/userspace/WindowServer/Window.h b/userspace/WindowServer/Window.h index 41d5d755..7250b175 100644 --- a/userspace/WindowServer/Window.h +++ b/userspace/WindowServer/Window.h @@ -13,14 +13,14 @@ public: void set_position(Position position) { - m_area.x = position.x; - m_area.y = position.y; + m_client_area.x = position.x; + m_client_area.y = position.y; } void set_size(Position size, uint32_t* fb_addr) { - m_area.width = size.x; - m_area.height = size.y; + m_client_area.width = size.x; + m_client_area.height = size.y; m_fb_addr = fb_addr; } @@ -29,17 +29,51 @@ public: int client_fd() const { return m_client_fd; } - int32_t x() const { return m_area.x; } - int32_t y() const { return m_area.y; } - uint32_t width() const { return m_area.width; } - uint32_t height() const { return m_area.height; } - Rectangle size() const { return { 0, 0, m_area.width, m_area.height }; } - const Rectangle& area() const { return m_area; } + int32_t client_x() const { return m_client_area.x; } + int32_t client_y() const { return m_client_area.y; } + int32_t client_width() const { return m_client_area.width; } + int32_t client_height() const { return m_client_area.height; } + Rectangle client_size() const { return { 0, 0, client_width(), client_height() }; } + Rectangle client_area() const { return m_client_area; } + + int32_t title_bar_x() const { return client_x(); } + int32_t title_bar_y() const { return client_y() - title_bar_height(); } + int32_t title_bar_width() const { return client_width(); } + int32_t title_bar_height() const { return m_title_bar_height; } + Rectangle title_bar_size() const { return { 0, 0, title_bar_width(), title_bar_height() }; } + Rectangle title_bar_area() const { return { title_bar_x(), title_bar_y(), title_bar_width(), title_bar_height() }; } + + int32_t full_x() const { return title_bar_x(); } + int32_t full_y() const { return title_bar_y(); } + int32_t full_width() const { return client_width(); } + int32_t full_height() const { return client_height() + title_bar_height(); } + Rectangle full_size() const { return { 0, 0, full_width(), full_height() }; } + Rectangle full_area() const { return { full_x(), full_y(), full_width(), full_height() }; } + const uint32_t* framebuffer() const { return m_fb_addr; } + uint32_t title_bar_pixel(int32_t abs_x, int32_t abs_y, Position cursor) const + { + ASSERT(title_bar_area().contains({ abs_x, abs_y })); + + Rectangle close_button = { + title_bar_x() + title_bar_width() - title_bar_height() + 1, + title_bar_y() + 1, + title_bar_height() - 2, + title_bar_height() - 2 + }; + + if (close_button.contains({ abs_x, abs_y })) + return close_button.contains(cursor) ? 0xFF0000 : 0xA00000; + + return 0xFFFFFF; + } + private: - const int m_client_fd { -1 }; - uint32_t* m_fb_addr { nullptr }; - Rectangle m_area { 0, 0, 0, 0 }; - bool m_deleted { false }; + static constexpr int32_t m_title_bar_height { 20 }; + + const int m_client_fd { -1 }; + uint32_t* m_fb_addr { nullptr }; + Rectangle m_client_area { 0, 0, 0, 0 }; + bool m_deleted { false }; }; diff --git a/userspace/WindowServer/WindowServer.cpp b/userspace/WindowServer/WindowServer.cpp index d944c0f8..a7cf2305 100644 --- a/userspace/WindowServer/WindowServer.cpp +++ b/userspace/WindowServer/WindowServer.cpp @@ -69,7 +69,7 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event) BAN::RefPtr target_window; for (size_t i = m_windows_ordered.size(); i > 0; i--) { - if (m_windows_ordered[i - 1]->area().contains(m_cursor)) + if (m_windows_ordered[i - 1]->full_area().contains(m_cursor)) { target_window = m_windows_ordered[i - 1]; break; @@ -82,28 +82,26 @@ void WindowServer::on_mouse_button(LibInput::MouseButtonEvent event) set_focused_window(target_window); - // Handle window moving when mod key is held - if (m_is_mod_key_held && event.pressed && event.button == LibInput::MouseButton::Left && !m_is_moving_window) + // Handle window moving when mod key is held or mouse press on title bar + if (event.pressed && event.button == LibInput::MouseButton::Left && !m_is_moving_window && (target_window->title_bar_area().contains(m_cursor) || m_is_mod_key_held)) m_is_moving_window = true; else if (m_is_moving_window && !event.pressed) m_is_moving_window = false; - else + else if (target_window->client_area().contains(m_cursor)) { // NOTE: we always have target window if code reaches here LibGUI::EventPacket packet; packet.type = LibGUI::EventPacket::Type::MouseButtonEvent; packet.mouse_button_event.button = event.button; packet.mouse_button_event.pressed = event.pressed; - packet.mouse_button_event.x = m_cursor.x - m_focused_window->x(); - packet.mouse_button_event.y = m_cursor.y - m_focused_window->y(); + packet.mouse_button_event.x = m_cursor.x - m_focused_window->client_x(); + packet.mouse_button_event.y = m_cursor.y - m_focused_window->client_y(); send(m_focused_window->client_fd(), &packet, sizeof(packet), 0); } } void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event) { - Rectangle old_cursor { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height }; - const int32_t new_x = BAN::Math::clamp(m_cursor.x + event.rel_x, 0, m_framebuffer.width); const int32_t new_y = BAN::Math::clamp(m_cursor.y - event.rel_y, 0, m_framebuffer.height); @@ -112,22 +110,32 @@ void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event) if (event.rel_x == 0 && event.rel_y == 0) return; + auto old_cursor = cursor_area(); m_cursor.x = new_x; m_cursor.y = new_y; + auto new_cursor = cursor_area(); + + // TODO: Really no need to loop over every window + for (auto& window : m_windows_ordered) + { + auto title_bar = window->title_bar_area(); + if (title_bar.get_overlap(old_cursor).has_value() || title_bar.get_overlap(new_cursor).has_value()) + invalidate(title_bar); + } - Rectangle new_cursor { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height }; invalidate(old_cursor.get_bounding_box(old_cursor)); invalidate(new_cursor.get_bounding_box(old_cursor)); if (m_is_moving_window) { - auto old_window = m_focused_window->area(); + auto old_window = m_focused_window->full_area(); m_focused_window->set_position({ - m_focused_window->x() + event.rel_x, - m_focused_window->y() + event.rel_y, + m_focused_window->client_x() + event.rel_x, + m_focused_window->client_y() + event.rel_y, }); + auto new_window = m_focused_window->full_area(); invalidate(old_window); - invalidate(m_focused_window->area()); + invalidate(new_window); return; } @@ -135,8 +143,8 @@ void WindowServer::on_mouse_move(LibInput::MouseMoveEvent event) { LibGUI::EventPacket packet; packet.type = LibGUI::EventPacket::Type::MouseMoveEvent; - packet.mouse_move_event.x = m_cursor.x - m_focused_window->x(); - packet.mouse_move_event.y = m_cursor.y - m_focused_window->y(); + packet.mouse_move_event.x = m_cursor.x - m_focused_window->client_x(); + packet.mouse_move_event.y = m_cursor.y - m_focused_window->client_y(); send(m_focused_window->client_fd(), &packet, sizeof(packet), 0); } } @@ -164,7 +172,7 @@ void WindowServer::set_focused_window(BAN::RefPtr window) m_focused_window = window; m_windows_ordered.remove(i - 1); MUST(m_windows_ordered.push_back(window)); - invalidate(window->area()); + invalidate(window->full_area()); break; } } @@ -184,23 +192,41 @@ void WindowServer::invalidate(Rectangle area) { auto& window = *pwindow; - auto overlap = window.area().get_overlap(area); - if (!overlap.has_value()) - continue; + // window title bar + if (auto overlap = window.title_bar_area().get_overlap(area); overlap.has_value()) + { + for (int32_t y_off = 0; y_off < overlap->height; y_off++) + { + for (int32_t x_off = 0; x_off < overlap->width; x_off++) + { + uint32_t pixel = window.title_bar_pixel( + overlap->x + x_off, + overlap->y + y_off, + m_cursor + ); + m_framebuffer.mmap[(overlap->y + y_off) * m_framebuffer.width + overlap->x + x_off] = pixel; + } + } + } - const int32_t src_x = overlap->x - window.x(); - const int32_t src_y = overlap->y - window.y(); - for (int32_t y_off = 0; y_off < overlap->height; y_off++) - memcpy( - &m_framebuffer.mmap[(overlap->y + y_off) * m_framebuffer.width + overlap->x], - &window.framebuffer()[(src_y + y_off) * window.width() + src_x], - overlap->width * 4 - ); + // window client area + if (auto overlap = window.client_area().get_overlap(area); overlap.has_value()) + { + const int32_t src_x = overlap->x - window.client_x(); + const int32_t src_y = overlap->y - window.client_y(); + for (int32_t y_off = 0; y_off < overlap->height; y_off++) + { + memcpy( + &m_framebuffer.mmap[(overlap->y + y_off) * m_framebuffer.width + overlap->x], + &window.framebuffer()[(src_y + y_off) * window.client_width() + src_x], + overlap->width * 4 + ); + } + } } - Rectangle cursor { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height }; - auto overlap = cursor.get_overlap(area); - if (overlap.has_value()) + auto cursor = cursor_area(); + if (auto overlap = cursor.get_overlap(area); overlap.has_value()) { for (int32_t dy = overlap->y - cursor.y; dy < overlap->height; dy++) { @@ -222,3 +248,8 @@ void WindowServer::invalidate(Rectangle area) mmap_start &= ~(uintptr_t)0xFFF; msync(reinterpret_cast(mmap_start), mmap_end - mmap_start, MS_SYNC); } + +Rectangle WindowServer::cursor_area() const +{ + return { m_cursor.x, m_cursor.y, s_cursor_width, s_cursor_height }; +} diff --git a/userspace/WindowServer/WindowServer.h b/userspace/WindowServer/WindowServer.h index e3b7b3f9..f7a21624 100644 --- a/userspace/WindowServer/WindowServer.h +++ b/userspace/WindowServer/WindowServer.h @@ -32,6 +32,8 @@ public: void set_focused_window(BAN::RefPtr window); void invalidate(Rectangle area); + Rectangle cursor_area() const; + private: Framebuffer& m_framebuffer; BAN::Vector> m_windows_ordered; diff --git a/userspace/WindowServer/main.cpp b/userspace/WindowServer/main.cpp index e6626a7a..a26eb729 100644 --- a/userspace/WindowServer/main.cpp +++ b/userspace/WindowServer/main.cpp @@ -228,9 +228,10 @@ int main() static_cast(packet.create.height) }, reinterpret_cast(smo_address)); window.set_position({ - static_cast(window.width() / 2), - static_cast(window.height() / 2) + static_cast((framebuffer.width - window.client_width()) / 2), + static_cast((framebuffer.height - window.client_height()) / 2) }); + window_server.invalidate(window.full_area()); break; } @@ -241,15 +242,21 @@ int main() dwarnln("Invalid Invalidate packet size"); break; } - if (packet.invalidate.x + packet.invalidate.width > window.width() || packet.invalidate.y + packet.invalidate.height > window.height()) + + if (packet.invalidate.width == 0 || packet.invalidate.height == 0) + break; + + const int32_t br_x = packet.invalidate.x + packet.invalidate.width - 1; + const int32_t br_y = packet.invalidate.y + packet.invalidate.height - 1; + if (!window.client_size().contains({ br_x, br_y })) { dwarnln("Invalid Invalidate packet parameters"); break; } window_server.invalidate({ - window.x() + static_cast(packet.invalidate.x), - window.y() + static_cast(packet.invalidate.y), + window.client_x() + static_cast(packet.invalidate.x), + window.client_y() + static_cast(packet.invalidate.y), static_cast(packet.invalidate.width), static_cast(packet.invalidate.height), });