mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-30 00:31:14 +00:00
WindowServer: Implement tile window overlay
This adds a tiling mode that will show a tile window overlay rather than immediately tiling a window, triggering window resizes.
This commit is contained in:
parent
035b0f9df6
commit
fe54a0ca27
Notes:
sideshowbarker
2024-07-16 21:30:48 +09:00
Author: https://github.com/tomuta Commit: https://github.com/SerenityOS/serenity/commit/fe54a0ca27 Pull-request: https://github.com/SerenityOS/serenity/pull/18175 Reviewed-by: https://github.com/gmta Reviewed-by: https://github.com/nico ✅ Reviewed-by: https://github.com/trflynn89
|
@ -121,6 +121,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
layout: @GUI::HorizontalBoxLayout {}
|
||||
|
||||
@GUI::Label {
|
||||
text: "Tile Window Behavior:"
|
||||
autosize: true
|
||||
}
|
||||
|
||||
@GUI::Layout::Spacer {}
|
||||
|
||||
@GUI::ComboBox {
|
||||
name: "tile_window_combobox"
|
||||
fixed_width: 130
|
||||
}
|
||||
}
|
||||
|
||||
@GUI::Widget {
|
||||
fixed_height: 4
|
||||
}
|
||||
|
|
|
@ -34,6 +34,13 @@ ErrorOr<void> EffectsSettingsWidget::setup_interface()
|
|||
set_modified(true);
|
||||
};
|
||||
|
||||
m_tile_window_combobox = find_descendant_of_type_named<ComboBox>("tile_window_combobox");
|
||||
m_tile_window_combobox->set_only_allow_values_from_model(true);
|
||||
m_tile_window_combobox->on_change = [this](auto&, auto&) {
|
||||
m_system_effects.set_tile_window(static_cast<WindowServer::TileWindow>(m_tile_window_combobox->selected_index()));
|
||||
set_modified(true);
|
||||
};
|
||||
|
||||
if (auto result = load_settings(); result.is_error()) {
|
||||
warnln("Failed to load [Effects] from WindowServer.ini");
|
||||
return {};
|
||||
|
@ -119,25 +126,36 @@ ErrorOr<void> EffectsSettingsWidget::load_settings()
|
|||
ws_config->read_bool_entry("Effects", "TooltipShadow", true),
|
||||
};
|
||||
auto geometry = WindowServer::ShowGeometryTools::string_to_enum(ws_config->read_entry("Effects", "ShowGeometry", "OnMoveAndResize"));
|
||||
m_system_effects = { effects, geometry };
|
||||
auto tile_window = WindowServer::TileWindowTools::string_to_enum(ws_config->read_entry("Effects", "TileWindow", "ShowTileOverlay"));
|
||||
m_system_effects = { effects, geometry, tile_window };
|
||||
|
||||
static constexpr Array list = {
|
||||
static constexpr Array geometry_list = {
|
||||
"On Move and Resize"sv,
|
||||
"On Move only"sv,
|
||||
"On Resize only"sv,
|
||||
"Never"sv
|
||||
};
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
TRY(m_geometry_list.try_append(TRY(String::from_utf8(list[i]))));
|
||||
for (size_t i = 0; i < geometry_list.size(); ++i)
|
||||
TRY(m_geometry_list.try_append(TRY(String::from_utf8(geometry_list[i]))));
|
||||
m_geometry_combobox->set_model(ItemListModel<String>::create(m_geometry_list));
|
||||
m_geometry_combobox->set_selected_index(to_underlying(m_system_effects.geometry()));
|
||||
|
||||
static constexpr Array tile_window_list = {
|
||||
"Tile immediately"sv,
|
||||
"Show tile overlay"sv,
|
||||
"Never"sv
|
||||
};
|
||||
for (size_t i = 0; i < tile_window_list.size(); ++i)
|
||||
TRY(m_tile_window_list.try_append(TRY(String::from_utf8(tile_window_list[i]))));
|
||||
m_tile_window_combobox->set_model(ItemListModel<String>::create(m_tile_window_list));
|
||||
m_tile_window_combobox->set_selected_index(static_cast<size_t>(m_system_effects.tile_window()));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void EffectsSettingsWidget::apply_settings()
|
||||
{
|
||||
ConnectionToWindowServer::the().async_set_system_effects(m_system_effects.effects(), to_underlying(m_system_effects.geometry()));
|
||||
ConnectionToWindowServer::the().async_set_system_effects(m_system_effects.effects(), to_underlying(m_system_effects.geometry()), to_underlying(m_system_effects.tile_window()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,7 +32,9 @@ private:
|
|||
|
||||
SystemEffects m_system_effects;
|
||||
Vector<String> m_geometry_list;
|
||||
Vector<String> m_tile_window_list;
|
||||
RefPtr<ComboBox> m_geometry_combobox;
|
||||
RefPtr<ComboBox> m_tile_window_combobox;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -980,9 +980,9 @@ Messages::WindowServer::SetSystemFontsResponse ConnectionFromClient::set_system_
|
|||
return !g_config->sync().is_error();
|
||||
}
|
||||
|
||||
void ConnectionFromClient::set_system_effects(Vector<bool> const& effects, u8 geometry)
|
||||
void ConnectionFromClient::set_system_effects(Vector<bool> const& effects, u8 geometry, u8 tile_window)
|
||||
{
|
||||
WindowManager::the().apply_system_effects(effects, static_cast<ShowGeometry>(geometry));
|
||||
WindowManager::the().apply_system_effects(effects, static_cast<ShowGeometry>(geometry), static_cast<TileWindow>(tile_window));
|
||||
ConnectionFromClient::for_each_client([&](auto& client) {
|
||||
client.async_update_system_effects(effects);
|
||||
});
|
||||
|
|
|
@ -160,7 +160,7 @@ private:
|
|||
virtual Messages::WindowServer::GetCursorHighlightColorResponse get_cursor_highlight_color() override;
|
||||
virtual Messages::WindowServer::GetCursorThemeResponse get_cursor_theme() override;
|
||||
virtual Messages::WindowServer::SetSystemFontsResponse set_system_fonts(DeprecatedString const&, DeprecatedString const&, DeprecatedString const&) override;
|
||||
virtual void set_system_effects(Vector<bool> const&, u8) override;
|
||||
virtual void set_system_effects(Vector<bool> const&, u8, u8) override;
|
||||
virtual void set_window_base_size_and_size_increment(i32, Gfx::IntSize, Gfx::IntSize) override;
|
||||
virtual void set_window_resize_aspect_ratio(i32, Optional<Gfx::IntSize> const&) override;
|
||||
virtual void enable_display_link() override;
|
||||
|
|
|
@ -351,4 +351,18 @@ WindowStackSwitchOverlay::WindowStackSwitchOverlay(Screen& screen, WindowStack&
|
|||
set_rect(calculate_frame_rect(Gfx::IntRect({}, m_content_size).inflated(2 * default_screen_rect_margin, 2 * default_screen_rect_margin)).centered_within(screen.rect()));
|
||||
}
|
||||
|
||||
TileWindowOverlay::TileWindowOverlay(Window& window, Gfx::IntRect const& tiled_frame_rect, Gfx::Palette&& palette)
|
||||
: m_window(window)
|
||||
, m_tiled_frame_rect(tiled_frame_rect)
|
||||
, m_palette(std::move(palette))
|
||||
{
|
||||
}
|
||||
|
||||
void TileWindowOverlay::render(Gfx::Painter& painter, Screen const&)
|
||||
{
|
||||
Gfx::IntRect paint_rect { {}, rect().size() };
|
||||
painter.fill_rect(paint_rect, m_palette.rubber_band_fill());
|
||||
painter.draw_rect(paint_rect, m_palette.rubber_band_border());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <AK/Vector.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibGfx/Painter.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
#include <WindowServer/MultiScaleBitmaps.h>
|
||||
#include <WindowServer/Screen.h>
|
||||
|
||||
|
@ -27,6 +28,7 @@ public:
|
|||
virtual ~Overlay();
|
||||
|
||||
enum class ZOrder {
|
||||
SnapWindow,
|
||||
WindowGeometry,
|
||||
Dnd,
|
||||
WindowStackSwitch,
|
||||
|
@ -192,4 +194,26 @@ private:
|
|||
int const m_target_column;
|
||||
};
|
||||
|
||||
class TileWindowOverlay : public Overlay {
|
||||
public:
|
||||
TileWindowOverlay(Window&, Gfx::IntRect const&, Gfx::Palette&&);
|
||||
|
||||
virtual ZOrder zorder() const override { return ZOrder::SnapWindow; }
|
||||
virtual void render(Gfx::Painter&, Screen const&) override;
|
||||
|
||||
void set_overlay_rect(Gfx::IntRect const& rect)
|
||||
{
|
||||
set_rect(rect);
|
||||
}
|
||||
|
||||
void set_tiled_frame_rect(Gfx::IntRect const& rect) { m_tiled_frame_rect = rect; }
|
||||
Gfx::IntRect const& tiled_frame_rect() const { return m_tiled_frame_rect; }
|
||||
bool is_window(Window& window) const { return &m_window == &window; }
|
||||
|
||||
private:
|
||||
Window& m_window;
|
||||
Gfx::IntRect m_tiled_frame_rect;
|
||||
Gfx::Palette m_palette;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
|
||||
namespace WindowServer {
|
||||
|
||||
enum class TileWindow : u8 {
|
||||
TileImmediately,
|
||||
ShowTileOverlay,
|
||||
Never
|
||||
};
|
||||
|
||||
enum class ShowGeometry : u8 {
|
||||
OnMoveAndResize,
|
||||
OnMoveOnly,
|
||||
|
@ -66,12 +72,42 @@ namespace ShowGeometryTools {
|
|||
|
||||
};
|
||||
|
||||
namespace TileWindowTools {
|
||||
|
||||
[[maybe_unused]] static StringView enum_to_string(TileWindow tile_window)
|
||||
{
|
||||
switch (tile_window) {
|
||||
case TileWindow::Never:
|
||||
return "Never"sv;
|
||||
case TileWindow::TileImmediately:
|
||||
return "TileImmediately"sv;
|
||||
case TileWindow::ShowTileOverlay:
|
||||
return "ShowTileOverlay"sv;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
[[maybe_unused]] static TileWindow string_to_enum(StringView tile_window)
|
||||
{
|
||||
if (tile_window == "Never"sv)
|
||||
return TileWindow::Never;
|
||||
else if (tile_window == "TileImmediately"sv)
|
||||
return TileWindow::TileImmediately;
|
||||
else if (tile_window == "ShowTileOverlay"sv)
|
||||
return TileWindow::ShowTileOverlay;
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class SystemEffects {
|
||||
public:
|
||||
SystemEffects() = default;
|
||||
SystemEffects(Vector<bool> effects, ShowGeometry show)
|
||||
SystemEffects(Vector<bool> effects, ShowGeometry show, TileWindow tile_window)
|
||||
: m_effects(effects)
|
||||
, m_geometry(show)
|
||||
, m_tile_window(tile_window)
|
||||
{
|
||||
}
|
||||
SystemEffects(Vector<bool> effects)
|
||||
|
@ -107,14 +143,18 @@ public:
|
|||
void set_geometry(ShowGeometry g) { m_geometry = g; }
|
||||
ShowGeometry geometry() const { return m_geometry; }
|
||||
|
||||
void set_tile_window(TileWindow tile_window) { m_tile_window = tile_window; }
|
||||
TileWindow tile_window() const { return m_tile_window; }
|
||||
|
||||
bool operator==(SystemEffects const& other) const
|
||||
{
|
||||
return m_effects == other.m_effects && m_geometry == other.m_geometry;
|
||||
return m_effects == other.m_effects && m_geometry == other.m_geometry && m_tile_window == other.m_tile_window;
|
||||
}
|
||||
|
||||
private:
|
||||
Vector<bool> m_effects;
|
||||
ShowGeometry m_geometry { ShowGeometry::Never };
|
||||
TileWindow m_tile_window { TileWindow::ShowTileOverlay };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -420,8 +420,8 @@ void Window::set_maximized(bool maximized)
|
|||
else
|
||||
set_rect(m_floating_rect);
|
||||
m_frame.did_set_maximized({}, maximized);
|
||||
Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect));
|
||||
Core::EventLoop::current().post_event(*this, make<MoveEvent>(m_rect));
|
||||
send_resize_event_to_client();
|
||||
send_move_event_to_client();
|
||||
set_default_positioned(false);
|
||||
|
||||
WindowManager::the().notify_minimization_state_changed(*this);
|
||||
|
@ -842,8 +842,8 @@ void Window::set_fullscreen(bool fullscreen)
|
|||
new_window_rect = m_saved_nonfullscreen_rect;
|
||||
}
|
||||
|
||||
Core::EventLoop::current().post_event(*this, make<ResizeEvent>(new_window_rect));
|
||||
Core::EventLoop::current().post_event(*this, make<MoveEvent>(new_window_rect));
|
||||
send_resize_event_to_client();
|
||||
send_move_event_to_client();
|
||||
set_rect(new_window_rect);
|
||||
}
|
||||
|
||||
|
@ -858,7 +858,7 @@ WindowTileType Window::tile_type_based_on_rect(Gfx::IntRect const& rect) const
|
|||
bool tiling_to_left = current_tile_type == WindowTileType::Left || current_tile_type == WindowTileType::TopLeft || current_tile_type == WindowTileType::BottomLeft;
|
||||
bool tiling_to_right = current_tile_type == WindowTileType::Right || current_tile_type == WindowTileType::TopRight || current_tile_type == WindowTileType::BottomRight;
|
||||
|
||||
auto ideal_tiled_rect = WindowManager::the().tiled_window_rect(*this, current_tile_type);
|
||||
auto ideal_tiled_rect = WindowManager::the().tiled_window_rect(*this, window_screen, current_tile_type);
|
||||
bool same_top = ideal_tiled_rect.top() == rect.top();
|
||||
bool same_left = ideal_tiled_rect.left() == rect.left();
|
||||
bool same_right = ideal_tiled_rect.right() == rect.right();
|
||||
|
@ -870,9 +870,9 @@ WindowTileType Window::tile_type_based_on_rect(Gfx::IntRect const& rect) const
|
|||
if (tiling_to_top && same_top && same_left && same_right)
|
||||
return WindowTileType::Top;
|
||||
else if ((tiling_to_top || tiling_to_left) && same_top && same_left)
|
||||
return rect.bottom() == WindowManager::the().tiled_window_rect(*this, WindowTileType::Bottom).bottom() ? WindowTileType::Left : WindowTileType::TopLeft;
|
||||
return rect.bottom() == WindowManager::the().tiled_window_rect(*this, window_screen, WindowTileType::Bottom).bottom() ? WindowTileType::Left : WindowTileType::TopLeft;
|
||||
else if ((tiling_to_top || tiling_to_right) && same_top && same_right)
|
||||
return rect.bottom() == WindowManager::the().tiled_window_rect(*this, WindowTileType::Bottom).bottom() ? WindowTileType::Right : WindowTileType::TopRight;
|
||||
return rect.bottom() == WindowManager::the().tiled_window_rect(*this, window_screen, WindowTileType::Bottom).bottom() ? WindowTileType::Right : WindowTileType::TopRight;
|
||||
else if (tiling_to_left && same_left && same_top && same_bottom)
|
||||
return WindowTileType::Left;
|
||||
else if (tiling_to_right && same_right && same_top && same_bottom)
|
||||
|
@ -880,9 +880,9 @@ WindowTileType Window::tile_type_based_on_rect(Gfx::IntRect const& rect) const
|
|||
else if (tiling_to_bottom && same_bottom && same_left && same_right)
|
||||
return WindowTileType::Bottom;
|
||||
else if ((tiling_to_bottom || tiling_to_left) && same_bottom && same_left)
|
||||
return rect.top() == WindowManager::the().tiled_window_rect(*this, WindowTileType::Left).top() ? WindowTileType::Left : WindowTileType::BottomLeft;
|
||||
return rect.top() == WindowManager::the().tiled_window_rect(*this, window_screen, WindowTileType::Left).top() ? WindowTileType::Left : WindowTileType::BottomLeft;
|
||||
else if ((tiling_to_bottom || tiling_to_right) && same_bottom && same_right)
|
||||
return rect.top() == WindowManager::the().tiled_window_rect(*this, WindowTileType::Right).top() ? WindowTileType::Right : WindowTileType::BottomRight;
|
||||
return rect.top() == WindowManager::the().tiled_window_rect(*this, window_screen, WindowTileType::Right).top() ? WindowTileType::Right : WindowTileType::BottomRight;
|
||||
}
|
||||
return tile_type;
|
||||
}
|
||||
|
@ -911,15 +911,11 @@ bool Window::set_untiled()
|
|||
VERIFY(!resize_aspect_ratio().has_value());
|
||||
|
||||
m_tile_type = WindowTileType::None;
|
||||
set_rect(m_floating_rect);
|
||||
|
||||
Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect));
|
||||
Core::EventLoop::current().post_event(*this, make<MoveEvent>(m_rect));
|
||||
|
||||
tile_type_changed();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Window::set_tiled(WindowTileType tile_type)
|
||||
void Window::set_tiled(WindowTileType tile_type, Optional<Screen const&> tile_on_screen)
|
||||
{
|
||||
VERIFY(tile_type != WindowTileType::None);
|
||||
|
||||
|
@ -933,9 +929,26 @@ void Window::set_tiled(WindowTileType tile_type)
|
|||
set_maximized(false);
|
||||
|
||||
m_tile_type = tile_type;
|
||||
tile_type_changed(tile_on_screen);
|
||||
}
|
||||
|
||||
set_rect(WindowManager::the().tiled_window_rect(*this, tile_type));
|
||||
void Window::tile_type_changed(Optional<Screen const&> tile_on_screen)
|
||||
{
|
||||
if (m_tile_type != WindowTileType::None)
|
||||
set_rect(WindowManager::the().tiled_window_rect(*this, tile_on_screen, m_tile_type));
|
||||
else
|
||||
set_rect(m_floating_rect);
|
||||
send_resize_event_to_client();
|
||||
send_move_event_to_client();
|
||||
}
|
||||
|
||||
void Window::send_resize_event_to_client()
|
||||
{
|
||||
Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect));
|
||||
}
|
||||
|
||||
void Window::send_move_event_to_client()
|
||||
{
|
||||
Core::EventLoop::current().post_event(*this, make<MoveEvent>(m_rect));
|
||||
}
|
||||
|
||||
|
@ -951,7 +964,7 @@ void Window::recalculate_rect()
|
|||
|
||||
bool send_event = true;
|
||||
if (is_tiled()) {
|
||||
set_rect(WindowManager::the().tiled_window_rect(*this, m_tile_type));
|
||||
set_rect(WindowManager::the().tiled_window_rect(*this, {}, m_tile_type));
|
||||
} else if (type() == WindowType::Desktop) {
|
||||
set_rect(WindowManager::the().arena_rect_for_type(Screen::main(), WindowType::Desktop));
|
||||
} else {
|
||||
|
@ -959,7 +972,7 @@ void Window::recalculate_rect()
|
|||
}
|
||||
|
||||
if (send_event) {
|
||||
Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect));
|
||||
send_resize_event_to_client();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ public:
|
|||
|
||||
WindowTileType tile_type() const { return m_tile_type; }
|
||||
bool is_tiled() const { return m_tile_type != WindowTileType::None; }
|
||||
void set_tiled(WindowTileType);
|
||||
void set_tiled(WindowTileType, Optional<Screen const&> = {});
|
||||
WindowTileType tile_type_based_on_rect(Gfx::IntRect const&) const;
|
||||
void check_untile_due_to_resize(Gfx::IntRect const&);
|
||||
bool set_untiled();
|
||||
|
@ -376,6 +376,9 @@ public:
|
|||
void remove_all_stealing() { m_stealable_by_client_ids.clear(); }
|
||||
bool is_stealable_by_client(i32 client_id) const { return m_stealable_by_client_ids.contains_slow(client_id); }
|
||||
|
||||
void send_resize_event_to_client();
|
||||
void send_move_event_to_client();
|
||||
|
||||
private:
|
||||
Window(ConnectionFromClient&, WindowType, WindowMode, int window_id, bool minimizable, bool closeable, bool frameless, bool resizable, bool fullscreen, Window* parent_window = nullptr);
|
||||
Window(Core::Object&, WindowType);
|
||||
|
@ -386,6 +389,7 @@ private:
|
|||
void add_child_window(Window&);
|
||||
void ensure_window_menu();
|
||||
void update_window_menu_items();
|
||||
void tile_type_changed(Optional<Screen const&> = {});
|
||||
ErrorOr<Optional<DeprecatedString>> compute_title_username(ConnectionFromClient* client);
|
||||
|
||||
ConnectionFromClient* m_client { nullptr };
|
||||
|
|
|
@ -60,7 +60,7 @@ static DeprecatedString s_last_menu_shadow_path;
|
|||
static DeprecatedString s_last_taskbar_shadow_path;
|
||||
static DeprecatedString s_last_tooltip_shadow_path;
|
||||
|
||||
static Gfx::IntRect frame_rect_for_window(Window& window, Gfx::IntRect const& rect)
|
||||
Gfx::IntRect WindowFrame::frame_rect_for_window(Window& window, Gfx::IntRect const& rect)
|
||||
{
|
||||
if (window.is_frameless())
|
||||
return rect;
|
||||
|
|
|
@ -43,6 +43,8 @@ public:
|
|||
};
|
||||
friend class RenderedCache;
|
||||
|
||||
static Gfx::IntRect frame_rect_for_window(Window&, Gfx::IntRect const&);
|
||||
|
||||
static void reload_config();
|
||||
|
||||
explicit WindowFrame(Window&);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <LibGfx/StylePainter.h>
|
||||
#include <LibGfx/SystemTheme.h>
|
||||
#include <Services/Taskbar/TaskbarWindow.h>
|
||||
#include <WindowServer/Animation.h>
|
||||
#include <WindowServer/AppletManager.h>
|
||||
#include <WindowServer/Button.h>
|
||||
#include <WindowServer/ConnectionFromClient.h>
|
||||
|
@ -335,8 +336,8 @@ void WindowManager::add_window(Window& window)
|
|||
|
||||
if (window.is_fullscreen()) {
|
||||
auto& screen = Screen::main(); // TODO: support fullscreen windows on other screens!
|
||||
Core::EventLoop::current().post_event(window, make<ResizeEvent>(screen.rect()));
|
||||
window.set_rect(screen.rect());
|
||||
window.send_resize_event_to_client();
|
||||
}
|
||||
|
||||
if (window.type() != WindowType::Desktop || is_first_window)
|
||||
|
@ -415,6 +416,9 @@ void WindowManager::remove_window(Window& window)
|
|||
conn.async_window_removed(conn.window_id(), window.client_id(), window.window_id());
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
if (m_tile_window_overlay && m_tile_window_overlay->is_window(window))
|
||||
stop_tile_window_animation();
|
||||
}
|
||||
|
||||
void WindowManager::greet_window_manager(WMConnectionFromClient& conn)
|
||||
|
@ -738,6 +742,44 @@ void WindowManager::start_window_resize(Window& window, MouseEvent const& event,
|
|||
start_window_resize(window, event.position(), event.button(), resize_direction);
|
||||
}
|
||||
|
||||
void WindowManager::start_tile_window_animation(Gfx::IntRect const& starting_rect)
|
||||
{
|
||||
m_tile_window_overlay_animation = Animation::create();
|
||||
m_tile_window_overlay_animation->set_duration(150);
|
||||
m_tile_window_overlay_animation->on_update = [this, starting_rect](float progress, Gfx::Painter&, Screen&, Gfx::DisjointIntRectSet&) {
|
||||
if (m_tile_window_overlay) {
|
||||
auto target_rect = starting_rect.interpolated_to(m_tile_window_overlay->tiled_frame_rect(), progress);
|
||||
m_tile_window_overlay->set_overlay_rect(target_rect);
|
||||
}
|
||||
};
|
||||
m_tile_window_overlay_animation->start();
|
||||
}
|
||||
|
||||
void WindowManager::stop_tile_window_animation()
|
||||
{
|
||||
m_tile_window_overlay = nullptr;
|
||||
m_tile_window_overlay_animation = nullptr;
|
||||
}
|
||||
|
||||
void WindowManager::show_tile_window_overlay(Window& window, Screen const& cursor_screen, WindowTileType tile_type)
|
||||
{
|
||||
m_move_window_suggested_tile = tile_type;
|
||||
if (tile_type != WindowTileType::None && (!m_tile_window_overlay || !m_tile_window_overlay->is_window(window))) {
|
||||
auto tiled_frame_rect = WindowFrame::frame_rect_for_window(window, tiled_window_rect(window, cursor_screen, tile_type));
|
||||
m_tile_window_overlay = Compositor::the().create_overlay<TileWindowOverlay>(window, tiled_frame_rect, palette());
|
||||
m_tile_window_overlay->set_enabled(true);
|
||||
start_tile_window_animation(window.frame().rect());
|
||||
} else if (tile_type == WindowTileType::None) {
|
||||
stop_tile_window_animation();
|
||||
} else {
|
||||
auto tiled_frame_rect = WindowFrame::frame_rect_for_window(window, tiled_window_rect(window, cursor_screen, tile_type));
|
||||
if (m_tile_window_overlay->tiled_frame_rect() != tiled_frame_rect) {
|
||||
m_tile_window_overlay->set_tiled_frame_rect(tiled_frame_rect);
|
||||
start_tile_window_animation(m_tile_window_overlay->rect());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowManager::process_ongoing_window_move(MouseEvent& event)
|
||||
{
|
||||
if (!m_move_window)
|
||||
|
@ -746,10 +788,21 @@ bool WindowManager::process_ongoing_window_move(MouseEvent& event)
|
|||
|
||||
dbgln_if(MOVE_DEBUG, "[WM] Finish moving Window({})", m_move_window);
|
||||
|
||||
if (!m_move_window->is_tiled())
|
||||
bool did_tile = false;
|
||||
if (m_move_window_suggested_tile != WindowTileType::None && m_system_effects.tile_window() == TileWindow::ShowTileOverlay) {
|
||||
auto& cursor_screen = Screen::closest_to_location(event.position());
|
||||
m_move_window->set_tiled(m_move_window_suggested_tile, cursor_screen);
|
||||
m_move_window_suggested_tile = WindowTileType::None;
|
||||
stop_tile_window_animation();
|
||||
did_tile = true;
|
||||
} else {
|
||||
did_tile = m_move_window->is_tiled();
|
||||
}
|
||||
|
||||
if (!did_tile)
|
||||
m_move_window->set_floating_rect(m_move_window->rect());
|
||||
|
||||
Core::EventLoop::current().post_event(*m_move_window, make<MoveEvent>(m_move_window->rect()));
|
||||
m_move_window->send_move_event_to_client();
|
||||
m_move_window->invalidate(true, true);
|
||||
if (m_move_window->is_resizable()) {
|
||||
process_event_for_doubleclick(*m_move_window, event);
|
||||
|
@ -788,30 +841,44 @@ bool WindowManager::process_ongoing_window_move(MouseEvent& event)
|
|||
}
|
||||
} else {
|
||||
bool is_resizable = m_move_window->is_resizable();
|
||||
auto tile_window = m_system_effects.tile_window();
|
||||
bool allow_tile = is_resizable && tile_window != TileWindow::Never;
|
||||
auto pixels_moved_from_start = event.position().pixels_moved(m_move_origin);
|
||||
|
||||
auto event_location_relative_to_screen = event.position().translated(-cursor_screen.rect().location());
|
||||
if (is_resizable && event_location_relative_to_screen.x() <= tiling_deadzone) {
|
||||
if (event_location_relative_to_screen.y() <= tiling_deadzone + desktop_relative_to_screen.top())
|
||||
m_move_window->set_tiled(WindowTileType::TopLeft);
|
||||
else if (event_location_relative_to_screen.y() >= desktop_relative_to_screen.height() - tiling_deadzone)
|
||||
m_move_window->set_tiled(WindowTileType::BottomLeft);
|
||||
else
|
||||
m_move_window->set_tiled(WindowTileType::Left);
|
||||
} else if (is_resizable && event_location_relative_to_screen.x() >= cursor_screen.width() - tiling_deadzone) {
|
||||
if (event_location_relative_to_screen.y() <= tiling_deadzone + desktop.top())
|
||||
m_move_window->set_tiled(WindowTileType::TopRight);
|
||||
else if (event_location_relative_to_screen.y() >= desktop_relative_to_screen.height() - tiling_deadzone)
|
||||
m_move_window->set_tiled(WindowTileType::BottomRight);
|
||||
else
|
||||
m_move_window->set_tiled(WindowTileType::Right);
|
||||
} else if (is_resizable && event_location_relative_to_screen.y() <= secondary_deadzone + desktop_relative_to_screen.top()) {
|
||||
m_move_window->set_tiled(WindowTileType::Top);
|
||||
} else if (is_resizable && event_location_relative_to_screen.y() >= desktop_relative_to_screen.bottom() - secondary_deadzone) {
|
||||
m_move_window->set_tiled(WindowTileType::Bottom);
|
||||
} else if (!m_move_window->is_tiled()) {
|
||||
Gfx::IntPoint pos = m_move_window_origin.translated(event.position() - m_move_origin);
|
||||
auto apply_window_tile = [&](WindowTileType tile_type) {
|
||||
if (tile_window == TileWindow::ShowTileOverlay) {
|
||||
show_tile_window_overlay(*m_move_window, cursor_screen, tile_type);
|
||||
} else if (tile_window == TileWindow::TileImmediately) {
|
||||
if (tile_type != WindowTileType::None) {
|
||||
m_move_window->set_tiled(tile_type, cursor_screen);
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto pos = m_move_window_origin.translated(event.position() - m_move_origin);
|
||||
m_move_window->set_position_without_repaint(pos);
|
||||
};
|
||||
|
||||
auto event_location_relative_to_screen = event.position().translated(-cursor_screen.rect().location());
|
||||
if (allow_tile && event_location_relative_to_screen.x() <= tiling_deadzone) {
|
||||
if (event_location_relative_to_screen.y() <= tiling_deadzone + desktop_relative_to_screen.top())
|
||||
apply_window_tile(WindowTileType::TopLeft);
|
||||
else if (event_location_relative_to_screen.y() >= desktop_relative_to_screen.height() - tiling_deadzone)
|
||||
apply_window_tile(WindowTileType::BottomLeft);
|
||||
else
|
||||
apply_window_tile(WindowTileType::Left);
|
||||
} else if (allow_tile && event_location_relative_to_screen.x() >= cursor_screen.width() - tiling_deadzone) {
|
||||
if (event_location_relative_to_screen.y() <= tiling_deadzone + desktop.top())
|
||||
apply_window_tile(WindowTileType::TopRight);
|
||||
else if (event_location_relative_to_screen.y() >= desktop_relative_to_screen.height() - tiling_deadzone)
|
||||
apply_window_tile(WindowTileType::BottomRight);
|
||||
else
|
||||
apply_window_tile(WindowTileType::Right);
|
||||
} else if (allow_tile && event_location_relative_to_screen.y() <= secondary_deadzone + desktop_relative_to_screen.top()) {
|
||||
apply_window_tile(WindowTileType::Top);
|
||||
} else if (allow_tile && event_location_relative_to_screen.y() >= desktop_relative_to_screen.bottom() - secondary_deadzone) {
|
||||
apply_window_tile(WindowTileType::Bottom);
|
||||
} else if (!m_move_window->is_tiled()) {
|
||||
apply_window_tile(WindowTileType::None);
|
||||
} else if (pixels_moved_from_start > 5) {
|
||||
Gfx::IntPoint adjusted_position = event.position().translated(-m_move_window_cursor_position);
|
||||
m_move_window->set_untiled();
|
||||
|
@ -824,7 +891,7 @@ bool WindowManager::process_ongoing_window_move(MouseEvent& event)
|
|||
m_geometry_overlay->window_rect_changed();
|
||||
}
|
||||
}
|
||||
Core::EventLoop::current().post_event(*m_move_window, make<MoveEvent>(m_move_window->rect()));
|
||||
m_move_window->send_move_event_to_client();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -875,7 +942,7 @@ bool WindowManager::process_ongoing_window_resize(MouseEvent const& event)
|
|||
if (!m_resize_window->is_tiled())
|
||||
m_resize_window->set_floating_rect(m_resize_window->rect());
|
||||
|
||||
Core::EventLoop::current().post_event(*m_resize_window, make<ResizeEvent>(m_resize_window->rect()));
|
||||
m_resize_window->send_resize_event_to_client();
|
||||
m_resize_window->invalidate(true, true);
|
||||
m_resize_window = nullptr;
|
||||
m_geometry_overlay = nullptr;
|
||||
|
@ -1013,7 +1080,7 @@ bool WindowManager::process_ongoing_window_resize(MouseEvent const& event)
|
|||
if (system_effects().geometry() == ShowGeometry::OnMoveAndResize || system_effects().geometry() == ShowGeometry::OnResizeOnly) {
|
||||
m_geometry_overlay->window_rect_changed();
|
||||
}
|
||||
Core::EventLoop::current().post_event(*m_resize_window, make<ResizeEvent>(new_rect));
|
||||
m_resize_window->send_resize_event_to_client();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1424,7 +1491,7 @@ void WindowManager::clear_resize_candidate()
|
|||
m_resize_candidate = nullptr;
|
||||
}
|
||||
|
||||
Gfx::IntRect WindowManager::desktop_rect(Screen& screen) const
|
||||
Gfx::IntRect WindowManager::desktop_rect(Screen const& screen) const
|
||||
{
|
||||
if (active_fullscreen_window())
|
||||
return Screen::main().rect(); // TODO: we should support fullscreen windows on any screen
|
||||
|
@ -1965,11 +2032,11 @@ ResizeDirection WindowManager::resize_direction_of_window(Window const& window)
|
|||
return m_resize_direction;
|
||||
}
|
||||
|
||||
Gfx::IntRect WindowManager::tiled_window_rect(Window const& window, WindowTileType tile_type, bool relative_to_window_screen) const
|
||||
Gfx::IntRect WindowManager::tiled_window_rect(Window const& window, Optional<Screen const&> cursor_screen, WindowTileType tile_type) const
|
||||
{
|
||||
VERIFY(tile_type != WindowTileType::None);
|
||||
|
||||
auto& screen = Screen::closest_to_rect(window.frame().rect());
|
||||
auto const& screen = cursor_screen.has_value() ? cursor_screen.value() : Screen::closest_to_rect(window.frame().rect());
|
||||
auto rect = desktop_rect(screen);
|
||||
|
||||
if (tile_type == WindowTileType::Maximized) {
|
||||
|
@ -2022,9 +2089,6 @@ Gfx::IntRect WindowManager::tiled_window_rect(Window const& window, WindowTileTy
|
|||
rect.set_y(rect.y() + window_rect.y() - window_frame_rect.y());
|
||||
rect.set_height(rect.height() - window_frame_rect.height() + window_rect.height());
|
||||
}
|
||||
|
||||
if (relative_to_window_screen)
|
||||
rect.translate_by(-screen.rect().location());
|
||||
return rect;
|
||||
}
|
||||
|
||||
|
@ -2312,12 +2376,12 @@ void WindowManager::set_cursor_highlight_color(Gfx::Color color)
|
|||
sync_config_to_disk();
|
||||
}
|
||||
|
||||
void WindowManager::apply_system_effects(Vector<bool> effects, ShowGeometry geometry)
|
||||
void WindowManager::apply_system_effects(Vector<bool> effects, ShowGeometry geometry, TileWindow tile_window)
|
||||
{
|
||||
if (m_system_effects == SystemEffects { effects, geometry })
|
||||
if (m_system_effects == SystemEffects { effects, geometry, tile_window })
|
||||
return;
|
||||
|
||||
m_system_effects = { effects, geometry };
|
||||
m_system_effects = { effects, geometry, tile_window };
|
||||
g_config->write_bool_entry("Effects", "AnimateMenus", m_system_effects.animate_menus());
|
||||
g_config->write_bool_entry("Effects", "FlashMenus", m_system_effects.flash_menus());
|
||||
g_config->write_bool_entry("Effects", "AnimateWindows", m_system_effects.animate_windows());
|
||||
|
@ -2329,6 +2393,7 @@ void WindowManager::apply_system_effects(Vector<bool> effects, ShowGeometry geom
|
|||
g_config->write_bool_entry("Effects", "WindowShadow", m_system_effects.window_shadow());
|
||||
g_config->write_bool_entry("Effects", "TooltipShadow", m_system_effects.tooltip_shadow());
|
||||
g_config->write_entry("Effects", "ShowGeometry", ShowGeometryTools::enum_to_string(geometry));
|
||||
g_config->write_entry("Effects", "TileWindow", TileWindowTools::enum_to_string(tile_window));
|
||||
sync_config_to_disk();
|
||||
}
|
||||
|
||||
|
@ -2347,7 +2412,8 @@ void WindowManager::load_system_effects()
|
|||
g_config->read_bool_entry("Effects", "TooltipShadow", true)
|
||||
};
|
||||
ShowGeometry geometry = ShowGeometryTools::string_to_enum(g_config->read_entry("Effects", "ShowGeometry", "OnMoveAndResize"));
|
||||
m_system_effects = { effects, geometry };
|
||||
TileWindow tile_window = TileWindowTools::string_to_enum(g_config->read_entry("Effects", "TileWindow", "ShowTileOverlay"));
|
||||
m_system_effects = { effects, geometry, tile_window };
|
||||
|
||||
ConnectionFromClient::for_each_client([&](auto& client) {
|
||||
client.async_update_system_effects(effects);
|
||||
|
|
|
@ -43,6 +43,7 @@ class WindowSwitcher;
|
|||
class Button;
|
||||
class DndOverlay;
|
||||
class WindowGeometryOverlay;
|
||||
class TileWindowOverlay;
|
||||
|
||||
class WindowManager : public Core::Object {
|
||||
C_OBJECT(WindowManager)
|
||||
|
@ -79,7 +80,7 @@ public:
|
|||
void notify_progress_changed(Window&);
|
||||
void notify_modified_changed(Window&);
|
||||
|
||||
Gfx::IntRect tiled_window_rect(Window const&, WindowTileType tile_type = WindowTileType::Maximized, bool relative_to_window_screen = false) const;
|
||||
Gfx::IntRect tiled_window_rect(Window const&, Optional<Screen const&> = {}, WindowTileType tile_type = WindowTileType::Maximized) const;
|
||||
|
||||
ConnectionFromClient const* dnd_client() const { return m_dnd_client.ptr(); }
|
||||
Core::MimeData const& dnd_mime_data() const { return *m_dnd_mime_data; }
|
||||
|
@ -115,7 +116,7 @@ public:
|
|||
|
||||
void move_to_front_and_make_active(Window&);
|
||||
|
||||
Gfx::IntRect desktop_rect(Screen&) const;
|
||||
Gfx::IntRect desktop_rect(Screen const&) const;
|
||||
Gfx::IntRect arena_rect_for_type(Screen&, WindowType) const;
|
||||
|
||||
Cursor const& active_cursor() const;
|
||||
|
@ -328,7 +329,7 @@ public:
|
|||
bool is_cursor_highlight_enabled() const { return m_cursor_highlight_radius > 0 && m_cursor_highlight_enabled; }
|
||||
|
||||
void load_system_effects();
|
||||
void apply_system_effects(Vector<bool>, ShowGeometry);
|
||||
void apply_system_effects(Vector<bool>, ShowGeometry, TileWindow);
|
||||
SystemEffects& system_effects() { return m_system_effects; }
|
||||
|
||||
RefPtr<KeymapSwitcher> keymap_switcher() { return m_keymap_switcher; }
|
||||
|
@ -339,6 +340,9 @@ public:
|
|||
|
||||
u8 last_processed_buttons() { return m_last_processed_buttons; }
|
||||
|
||||
void start_tile_window_animation(Gfx::IntRect const&);
|
||||
void stop_tile_window_animation();
|
||||
|
||||
private:
|
||||
explicit WindowManager(Gfx::PaletteImpl&);
|
||||
|
||||
|
@ -433,6 +437,8 @@ private:
|
|||
|
||||
Gfx::IntPoint to_floating_cursor_position(Gfx::IntPoint) const;
|
||||
|
||||
void show_tile_window_overlay(Window&, Screen const&, WindowTileType);
|
||||
|
||||
DoubleClickInfo m_double_click_info;
|
||||
int m_double_click_speed { 0 };
|
||||
int m_max_distance_for_double_click { 4 };
|
||||
|
@ -448,7 +454,10 @@ private:
|
|||
WeakPtr<Window> m_automatic_cursor_tracking_window;
|
||||
|
||||
OwnPtr<WindowGeometryOverlay> m_geometry_overlay;
|
||||
OwnPtr<TileWindowOverlay> m_tile_window_overlay;
|
||||
RefPtr<Animation> m_tile_window_overlay_animation;
|
||||
WeakPtr<Window> m_move_window;
|
||||
WindowTileType m_move_window_suggested_tile { WindowTileType::None };
|
||||
Gfx::IntPoint m_move_origin;
|
||||
Gfx::IntPoint m_move_window_origin;
|
||||
Gfx::IntPoint m_move_window_cursor_position;
|
||||
|
|
|
@ -152,7 +152,7 @@ endpoint WindowServer
|
|||
get_cursor_highlight_color() => (Gfx::Color color)
|
||||
|
||||
set_system_fonts(DeprecatedString default_font_query, DeprecatedString fixed_width_font_query, DeprecatedString window_title_font_query) => (bool success)
|
||||
set_system_effects(Vector<bool> effects, u8 geometry) =|
|
||||
set_system_effects(Vector<bool> effects, u8 geometry, u8 tile_window) =|
|
||||
|
||||
set_window_base_size_and_size_increment(i32 window_id, Gfx::IntSize base_size, Gfx::IntSize size_increment) =|
|
||||
set_window_resize_aspect_ratio(i32 window_id, Optional<Gfx::IntSize> resize_aspect_ratio) =|
|
||||
|
|
Loading…
Reference in a new issue