diff options
-rw-r--r-- | Userland/Libraries/LibGUI/Window.cpp | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/WindowType.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/ClassicWindowTheme.cpp | 56 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/ClassicWindowTheme.h | 3 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/WindowTheme.h | 4 | ||||
-rw-r--r-- | Userland/Services/WindowServer/ClientConnection.cpp | 2 | ||||
-rw-r--r-- | Userland/Services/WindowServer/Window.h | 4 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowFrame.cpp | 37 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowFrame.h | 2 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowManager.cpp | 22 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowManager.h | 4 | ||||
-rw-r--r-- | Userland/Services/WindowServer/WindowType.h | 3 |
12 files changed, 105 insertions, 37 deletions
diff --git a/Userland/Libraries/LibGUI/Window.cpp b/Userland/Libraries/LibGUI/Window.cpp index 5ddc73b1a5..7ba7de901d 100644 --- a/Userland/Libraries/LibGUI/Window.cpp +++ b/Userland/Libraries/LibGUI/Window.cpp @@ -299,7 +299,7 @@ void Window::set_window_type(WindowType window_type) if (!m_minimum_size_modified) { // Apply minimum size defaults. - if (m_window_type == WindowType::Normal) + if (m_window_type == WindowType::Normal || m_window_type == WindowType::ToolWindow) m_minimum_size_when_windowless = { 50, 50 }; else m_minimum_size_when_windowless = { 1, 1 }; diff --git a/Userland/Libraries/LibGUI/WindowType.h b/Userland/Libraries/LibGUI/WindowType.h index b3b2638aba..a7fae0987b 100644 --- a/Userland/Libraries/LibGUI/WindowType.h +++ b/Userland/Libraries/LibGUI/WindowType.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -40,6 +40,7 @@ enum class WindowType { MenuApplet, Notification, Desktop, + ToolWindow, }; } diff --git a/Userland/Libraries/LibGfx/ClassicWindowTheme.cpp b/Userland/Libraries/LibGfx/ClassicWindowTheme.cpp index 7b51828c68..2fd3cb3f72 100644 --- a/Userland/Libraries/LibGfx/ClassicWindowTheme.cpp +++ b/Userland/Libraries/LibGfx/ClassicWindowTheme.cpp @@ -26,7 +26,6 @@ #include <LibGfx/Bitmap.h> #include <LibGfx/ClassicWindowTheme.h> -#include <LibGfx/Font.h> #include <LibGfx/FontDatabase.h> #include <LibGfx/Painter.h> #include <LibGfx/Palette.h> @@ -44,6 +43,9 @@ ClassicWindowTheme::~ClassicWindowTheme() Gfx::IntRect ClassicWindowTheme::title_bar_icon_rect(WindowType window_type, const IntRect& window_rect, const Palette& palette) const { + if (window_type == WindowType::ToolWindow) + return {}; + auto titlebar_rect = title_bar_rect(window_type, window_rect, palette); Gfx::IntRect icon_rect { titlebar_rect.x() + 2, @@ -61,9 +63,9 @@ Gfx::IntRect ClassicWindowTheme::title_bar_text_rect(WindowType window_type, con auto titlebar_rect = title_bar_rect(window_type, window_rect, palette); auto titlebar_icon_rect = title_bar_icon_rect(window_type, window_rect, palette); return { - titlebar_rect.x() + 3 + titlebar_icon_rect.width() + 2, + titlebar_rect.x() + 3 + (titlebar_icon_rect.is_empty() ? 0 : titlebar_icon_rect.width() + 2), titlebar_rect.y(), - titlebar_rect.width() - 5 - titlebar_icon_rect.width() - 2, + titlebar_rect.width() - 5 - (titlebar_icon_rect.is_empty() ? 0 : titlebar_icon_rect.width() - 2), titlebar_rect.height() }; } @@ -110,10 +112,41 @@ void ClassicWindowTheme::paint_normal_frame(Painter& painter, WindowState window painter.blit(titlebar_icon_rect.location(), icon, icon.rect()); } +void ClassicWindowTheme::paint_tool_window_frame(Painter& painter, WindowState window_state, const IntRect& window_rect, const StringView& title_text, const Palette& palette, const IntRect& leftmost_button_rect) const +{ + auto frame_rect = frame_rect_for_window(WindowType::ToolWindow, window_rect, palette); + frame_rect.set_location({ 0, 0 }); + Gfx::StylePainter::paint_window_frame(painter, frame_rect, palette); + + auto& title_font = FontDatabase::default_bold_font(); + + auto titlebar_rect = title_bar_rect(WindowType::ToolWindow, window_rect, palette); + auto titlebar_inner_rect = title_bar_text_rect(WindowType::ToolWindow, window_rect, palette); + auto titlebar_title_rect = titlebar_inner_rect; + titlebar_title_rect.set_width(FontDatabase::default_bold_font().width(title_text)); + + auto [title_color, border_color, border_color2, stripes_color, shadow_color] = compute_frame_colors(window_state, palette); + + painter.draw_line(titlebar_rect.bottom_left().translated(0, 1), titlebar_rect.bottom_right().translated(0, 1), palette.button()); + painter.draw_line(titlebar_rect.bottom_left().translated(0, 2), titlebar_rect.bottom_right().translated(0, 2), palette.button()); + + painter.fill_rect_with_gradient(titlebar_rect, border_color, border_color2); + + int stripe_right = leftmost_button_rect.left() - 3; + + auto clipped_title_rect = titlebar_title_rect; + clipped_title_rect.set_width(stripe_right - clipped_title_rect.x()); + if (!clipped_title_rect.is_empty()) { + painter.draw_text(clipped_title_rect.translated(1, 2), title_text, title_font, Gfx::TextAlignment::CenterLeft, shadow_color, Gfx::TextElision::Right); + // FIXME: The translated(0, 1) wouldn't be necessary if we could center text based on its baseline. + painter.draw_text(clipped_title_rect.translated(0, 1), title_text, title_font, Gfx::TextAlignment::CenterLeft, title_color, Gfx::TextElision::Right); + } +} + IntRect ClassicWindowTheme::title_bar_rect(WindowType window_type, const IntRect& window_rect, const Palette& palette) const { auto& title_font = FontDatabase::default_bold_font(); - auto window_titlebar_height = title_bar_height(palette); + auto window_titlebar_height = title_bar_height(window_type, palette); // FIXME: The top of the titlebar doesn't get redrawn properly if this padding is different int total_vertical_padding = title_font.glyph_height() - 1; @@ -160,10 +193,11 @@ void ClassicWindowTheme::paint_notification_frame(Painter& painter, const IntRec IntRect ClassicWindowTheme::frame_rect_for_window(WindowType window_type, const IntRect& window_rect, const Gfx::Palette& palette) const { - auto window_titlebar_height = title_bar_height(palette); + auto window_titlebar_height = title_bar_height(window_type, palette); switch (window_type) { case WindowType::Normal: + case WindowType::ToolWindow: return { window_rect.x() - 4, window_rect.y() - window_titlebar_height - 6, @@ -210,10 +244,18 @@ Vector<IntRect> ClassicWindowTheme::layout_buttons(WindowType window_type, const return button_rects; } -int ClassicWindowTheme::title_bar_height(const Palette& palette) const +int ClassicWindowTheme::title_bar_height(WindowType window_type, const Palette& palette) const { auto& title_font = FontDatabase::default_bold_font(); - return max(palette.window_title_height(), title_font.glyph_height() + 8); + switch (window_type) { + case WindowType::Normal: + case WindowType::Notification: + return max(palette.window_title_height(), title_font.glyph_height() + 8); + case WindowType::ToolWindow: + return max(palette.window_title_height() - 4, title_font.glyph_height() + 4); + default: + return 0; + } } } diff --git a/Userland/Libraries/LibGfx/ClassicWindowTheme.h b/Userland/Libraries/LibGfx/ClassicWindowTheme.h index b0f2c86136..ae5b633e1d 100644 --- a/Userland/Libraries/LibGfx/ClassicWindowTheme.h +++ b/Userland/Libraries/LibGfx/ClassicWindowTheme.h @@ -37,9 +37,10 @@ public: virtual ~ClassicWindowTheme() override; virtual void paint_normal_frame(Painter&, WindowState, const IntRect& window_rect, const StringView& title, const Bitmap& icon, const Palette&, const IntRect& leftmost_button_rect) const override; + virtual void paint_tool_window_frame(Painter&, WindowState, const IntRect& window_rect, const StringView& title, const Palette&, const IntRect& leftmost_button_rect) const override; virtual void paint_notification_frame(Painter&, const IntRect& window_rect, const Palette&, const IntRect& close_button_rect) const override; - virtual int title_bar_height(const Palette&) const override; + virtual int title_bar_height(WindowType, const Palette&) const override; virtual IntRect title_bar_rect(WindowType, const IntRect& window_rect, const Palette&) const override; virtual IntRect title_bar_icon_rect(WindowType, const IntRect& window_rect, const Palette&) const override; virtual IntRect title_bar_text_rect(WindowType, const IntRect& window_rect, const Palette&) const override; diff --git a/Userland/Libraries/LibGfx/WindowTheme.h b/Userland/Libraries/LibGfx/WindowTheme.h index 7a18a0b422..2231187feb 100644 --- a/Userland/Libraries/LibGfx/WindowTheme.h +++ b/Userland/Libraries/LibGfx/WindowTheme.h @@ -35,6 +35,7 @@ class WindowTheme { public: enum class WindowType { Normal, + ToolWindow, Notification, Other, }; @@ -51,9 +52,10 @@ public: static WindowTheme& current(); virtual void paint_normal_frame(Painter&, WindowState, const IntRect& window_rect, const StringView& title, const Bitmap& icon, const Palette&, const IntRect& leftmost_button_rect) const = 0; + virtual void paint_tool_window_frame(Painter&, WindowState, const IntRect& window_rect, const StringView& title, const Palette&, const IntRect& leftmost_button_rect) const = 0; virtual void paint_notification_frame(Painter&, const IntRect& window_rect, const Palette&, const IntRect& close_button_rect) const = 0; - virtual int title_bar_height(const Palette&) const = 0; + virtual int title_bar_height(WindowType, const Palette&) const = 0; virtual IntRect title_bar_rect(WindowType, const IntRect& window_rect, const Palette&) const = 0; virtual IntRect title_bar_icon_rect(WindowType, const IntRect& window_rect, const Palette&) const = 0; virtual IntRect title_bar_text_rect(WindowType, const IntRect& window_rect, const Palette&) const = 0; diff --git a/Userland/Services/WindowServer/ClientConnection.cpp b/Userland/Services/WindowServer/ClientConnection.cpp index 3778213805..40f199b6a8 100644 --- a/Userland/Services/WindowServer/ClientConnection.cpp +++ b/Userland/Services/WindowServer/ClientConnection.cpp @@ -492,7 +492,7 @@ OwnPtr<Messages::WindowServer::CreateWindowResponse> ClientConnection::handle(co window->set_title(message.title()); if (!message.fullscreen()) { auto rect = message.rect(); - if (message.auto_position() && window->type() == WindowType::Normal) { + if (message.auto_position() && window->is_movable()) { rect = { WindowManager::the().get_recommended_window_position({ 100, 100 }), message.rect().size() }; window->set_default_positioned(true); } diff --git a/Userland/Services/WindowServer/Window.h b/Userland/Services/WindowServer/Window.h index cf36a38df0..5ed3aed27e 100644 --- a/Userland/Services/WindowServer/Window.h +++ b/Userland/Services/WindowServer/Window.h @@ -97,7 +97,7 @@ public: bool is_minimized() const { return m_minimized; } void set_minimized(bool); - bool is_minimizable() const { return m_minimizable; } + bool is_minimizable() const { return m_type == WindowType::Normal && m_minimizable; } void set_minimizable(bool); bool is_resizable() const { return m_resizable && !m_fullscreen; } @@ -120,7 +120,7 @@ public: bool is_movable() const { - return m_type == WindowType::Normal; + return m_type == WindowType::Normal || m_type == WindowType::ToolWindow; } WindowFrame& frame() { return m_frame; } diff --git a/Userland/Services/WindowServer/WindowFrame.cpp b/Userland/Services/WindowServer/WindowFrame.cpp index 85de106ee2..19231b52de 100644 --- a/Userland/Services/WindowServer/WindowFrame.cpp +++ b/Userland/Services/WindowServer/WindowFrame.cpp @@ -45,6 +45,8 @@ static Gfx::WindowTheme::WindowType to_theme_window_type(WindowType type) switch (type) { case WindowType::Normal: return Gfx::WindowTheme::WindowType::Normal; + case WindowType::ToolWindow: + return Gfx::WindowTheme::WindowType::ToolWindow; case WindowType::Notification: return Gfx::WindowTheme::WindowType::Notification; default: @@ -271,22 +273,25 @@ void WindowFrame::paint_notification_frame(Gfx::Painter& painter) Gfx::WindowTheme::current().paint_notification_frame(painter, m_window.rect(), palette, m_buttons.last().relative_rect()); } -void WindowFrame::paint_normal_frame(Gfx::Painter& painter) +String WindowFrame::compute_title_text() const +{ + if (m_window.client() && m_window.client()->is_unresponsive()) + return String::formatted("{} (Not responding)", m_window.title()); + return m_window.title(); +} + +void WindowFrame::paint_tool_window_frame(Gfx::Painter& painter) { auto palette = WindowManager::the().palette(); - auto& window = m_window; - String title_text; - if (window.client() && window.client()->is_unresponsive()) { - StringBuilder builder; - builder.append(window.title()); - builder.append(" (Not responding)"); - title_text = builder.to_string(); - } else { - title_text = window.title(); - } + auto leftmost_button_rect = m_buttons.is_empty() ? Gfx::IntRect() : m_buttons.last().relative_rect(); + Gfx::WindowTheme::current().paint_tool_window_frame(painter, window_state_for_theme(), m_window.rect(), compute_title_text(), palette, leftmost_button_rect); +} +void WindowFrame::paint_normal_frame(Gfx::Painter& painter) +{ + auto palette = WindowManager::the().palette(); auto leftmost_button_rect = m_buttons.is_empty() ? Gfx::IntRect() : m_buttons.last().relative_rect(); - Gfx::WindowTheme::current().paint_normal_frame(painter, window_state_for_theme(), m_window.rect(), title_text, m_window.icon(), palette, leftmost_button_rect); + Gfx::WindowTheme::current().paint_normal_frame(painter, window_state_for_theme(), m_window.rect(), compute_title_text(), m_window.icon(), palette, leftmost_button_rect); } void WindowFrame::paint(Gfx::Painter& painter, const Gfx::IntRect& rect) @@ -341,6 +346,8 @@ void WindowFrame::render(Gfx::Painter& painter) paint_notification_frame(painter); else if (m_window.type() == WindowType::Normal) paint_normal_frame(painter); + else if (m_window.type() == WindowType::ToolWindow) + paint_tool_window_frame(painter); else return; @@ -574,10 +581,10 @@ void WindowFrame::on_mouse_event(const MouseEvent& event) ASSERT(!m_window.is_fullscreen()); auto& wm = WindowManager::the(); - if (m_window.type() != WindowType::Normal && m_window.type() != WindowType::Notification) + if (m_window.type() != WindowType::Normal && m_window.type() != WindowType::ToolWindow && m_window.type() != WindowType::Notification) return; - if (m_window.type() == WindowType::Normal) { + if (m_window.type() == WindowType::Normal || m_window.type() == WindowType::ToolWindow) { if (event.type() == Event::MouseDown) wm.move_to_front_and_make_active(m_window); @@ -632,7 +639,7 @@ void WindowFrame::on_mouse_event(const MouseEvent& event) return button.on_mouse_event(event.translated(-button.relative_rect().location())); } if (event.type() == Event::MouseDown) { - if (m_window.type() == WindowType::Normal && event.button() == MouseButton::Right) { + if ((m_window.type() == WindowType::Normal || m_window.type() == WindowType::ToolWindow) && event.button() == MouseButton::Right) { auto default_action = m_window.is_maximized() ? WindowMenuDefaultAction::Restore : WindowMenuDefaultAction::Maximize; m_window.popup_window_menu(event.position().translated(rect().location()), default_action); return; diff --git a/Userland/Services/WindowServer/WindowFrame.h b/Userland/Services/WindowServer/WindowFrame.h index b03b58d955..9ca67bf5ab 100644 --- a/Userland/Services/WindowServer/WindowFrame.h +++ b/Userland/Services/WindowServer/WindowFrame.h @@ -96,12 +96,14 @@ private: void paint_simple_rect_shadow(Gfx::Painter&, const Gfx::IntRect&, const Gfx::Bitmap&) const; void paint_notification_frame(Gfx::Painter&); void paint_normal_frame(Gfx::Painter&); + void paint_tool_window_frame(Gfx::Painter&); Gfx::Bitmap* window_shadow() const; bool frame_has_alpha() const; Gfx::IntRect inflated_for_shadow(const Gfx::IntRect&) const; Gfx::Bitmap* inflate_for_shadow(Gfx::IntRect&, Gfx::IntPoint&) const; Gfx::WindowTheme::WindowState window_state_for_theme() const; + String compute_title_text() const; Window& m_window; NonnullOwnPtrVector<Button> m_buttons; diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index 19f2a7ef70..2551ebfcfb 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -340,9 +340,14 @@ void WindowManager::tell_wm_listeners_window_rect_changed(Window& window) }); } +static bool window_type_has_title(WindowType type) +{ + return type == WindowType::Normal || type == WindowType::ToolWindow; +} + void WindowManager::notify_title_changed(Window& window) { - if (window.type() != WindowType::Normal) + if (!window_type_has_title(window.type())) return; dbgln_if(WINDOWMANAGER_DEBUG, "[WM] Window({}) title set to '{}'", &window, window.title()); @@ -412,7 +417,9 @@ bool WindowManager::pick_new_active_window(Window* previous_active) { bool new_window_picked = false; Window* first_candidate = nullptr; - for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, [&](Window& candidate) { + for_each_visible_window_from_front_to_back([&](Window& candidate) { + if (candidate.type() != WindowType::Normal && candidate.type() == WindowType::ToolWindow) + return IterationDecision::Continue; if (candidate.is_destroyed()) return IterationDecision::Continue; if (previous_active != first_candidate) @@ -984,7 +991,7 @@ void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_wind if (auto* blocking_modal_window = window.blocking_modal_window()) blocking_modal_window->frame().start_flash_animation(); - if (window.type() == WindowType::Normal) + if (window.type() == WindowType::Normal || window.type() == WindowType::ToolWindow) move_to_front_and_make_active(window); else if (window.type() == WindowType::Desktop) set_active_window(&window); @@ -1068,6 +1075,7 @@ Gfx::IntRect WindowManager::arena_rect_for_type(WindowType type) const switch (type) { case WindowType::Desktop: case WindowType::Normal: + case WindowType::ToolWindow: return desktop_rect(); case WindowType::Menu: case WindowType::WindowSwitcher: @@ -1218,7 +1226,7 @@ bool WindowManager::is_active_window_or_accessory(Window& window) const static bool window_type_can_become_active(WindowType type) { - return type == WindowType::Normal || type == WindowType::Desktop; + return type == WindowType::Normal || type == WindowType::ToolWindow || type == WindowType::Desktop; } void WindowManager::restore_active_input_window(Window* window) @@ -1507,7 +1515,7 @@ void WindowManager::maximize_windows(Window& window, bool maximized) Gfx::IntPoint WindowManager::get_recommended_window_position(const Gfx::IntPoint& desired) { // FIXME: Find a better source for the width and height to shift by. - Gfx::IntPoint shift(8, Gfx::WindowTheme::current().title_bar_height(palette()) + 10); + Gfx::IntPoint shift(8, Gfx::WindowTheme::current().title_bar_height(Gfx::WindowTheme::WindowType::Normal, palette()) + 10); // FIXME: Find a better source for this. int taskbar_height = 28; @@ -1526,7 +1534,7 @@ Gfx::IntPoint WindowManager::get_recommended_window_position(const Gfx::IntPoint point = overlap_window->position() + shift; point = { point.x() % Screen::the().width(), (point.y() >= (Screen::the().height() - taskbar_height)) - ? menubar_height + Gfx::WindowTheme::current().title_bar_height(palette()) + ? menubar_height + Gfx::WindowTheme::current().title_bar_height(Gfx::WindowTheme::WindowType::Normal, palette()) : point.y() }; } else { point = desired; diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h index 84673fd0f5..52f2e530c6 100644 --- a/Userland/Services/WindowServer/WindowManager.h +++ b/Userland/Services/WindowServer/WindowManager.h @@ -389,6 +389,8 @@ IterationDecision WindowManager::for_each_visible_window_from_back_to_front(Call return IterationDecision::Break; if (for_each_visible_window_of_type_from_back_to_front(WindowType::Normal, callback) == IterationDecision::Break) return IterationDecision::Break; + if (for_each_visible_window_of_type_from_back_to_front(WindowType::ToolWindow, callback) == IterationDecision::Break) + return IterationDecision::Break; if (for_each_visible_window_of_type_from_back_to_front(WindowType::Taskbar, callback) == IterationDecision::Break) return IterationDecision::Break; if (for_each_visible_window_of_type_from_back_to_front(WindowType::Notification, callback) == IterationDecision::Break) @@ -440,6 +442,8 @@ IterationDecision WindowManager::for_each_visible_window_from_front_to_back(Call return IterationDecision::Break; if (for_each_visible_window_of_type_from_front_to_back(WindowType::Taskbar, callback) == IterationDecision::Break) return IterationDecision::Break; + if (for_each_visible_window_of_type_from_front_to_back(WindowType::ToolWindow, callback) == IterationDecision::Break) + return IterationDecision::Break; if (for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, callback) == IterationDecision::Break) return IterationDecision::Break; return for_each_visible_window_of_type_from_front_to_back(WindowType::Desktop, callback); diff --git a/Userland/Services/WindowServer/WindowType.h b/Userland/Services/WindowServer/WindowType.h index a3c53007a1..214aad9338 100644 --- a/Userland/Services/WindowServer/WindowType.h +++ b/Userland/Services/WindowServer/WindowType.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> + * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,4 +38,5 @@ enum class WindowType { MenuApplet, Notification, Desktop, + ToolWindow, }; |