mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-10 13:00:29 +03:00
WindowServer: Un-tile window if resizing warrants it
Since being tiled means we restrict rendering a window to the screen it is on (so that we don't "bleed" into an adjacent screen), we need to untile it if the window either can't fit into the screen, or it is detached from the screen edges.
This commit is contained in:
parent
d3fc8652c7
commit
091628202f
Notes:
sideshowbarker
2024-07-18 11:26:25 +09:00
Author: https://github.com/tomuta Commit: https://github.com/SerenityOS/serenity/commit/091628202f1 Pull-request: https://github.com/SerenityOS/serenity/pull/8271
@ -15,6 +15,7 @@
|
|||||||
#include "WindowManager.h"
|
#include "WindowManager.h"
|
||||||
#include <AK/Badge.h>
|
#include <AK/Badge.h>
|
||||||
#include <AK/CharacterTypes.h>
|
#include <AK/CharacterTypes.h>
|
||||||
|
#include <AK/Debug.h>
|
||||||
#include <WindowServer/WindowClientEndpoint.h>
|
#include <WindowServer/WindowClientEndpoint.h>
|
||||||
|
|
||||||
namespace WindowServer {
|
namespace WindowServer {
|
||||||
@ -851,53 +852,130 @@ Gfx::IntRect Window::tiled_rect(Screen* target_screen, WindowTileType tiled) con
|
|||||||
screen.width() / 2 - frame_width,
|
screen.width() / 2 - frame_width,
|
||||||
max_height)
|
max_height)
|
||||||
.translated(screen_location);
|
.translated(screen_location);
|
||||||
case WindowTileType::Right:
|
case WindowTileType::Right: {
|
||||||
return Gfx::IntRect(screen.width() / 2 + frame_width,
|
Gfx::IntPoint location {
|
||||||
menu_height,
|
screen.width() / 2 + frame_width,
|
||||||
screen.width() / 2 - frame_width,
|
menu_height
|
||||||
max_height)
|
};
|
||||||
|
return Gfx::IntRect(
|
||||||
|
location,
|
||||||
|
{ screen.width() - location.x(), max_height })
|
||||||
.translated(screen_location);
|
.translated(screen_location);
|
||||||
|
}
|
||||||
case WindowTileType::Top:
|
case WindowTileType::Top:
|
||||||
return Gfx::IntRect(0,
|
return Gfx::IntRect(0,
|
||||||
menu_height,
|
menu_height,
|
||||||
screen.width(),
|
screen.width(),
|
||||||
(max_height - titlebar_height) / 2 - frame_width)
|
(max_height - titlebar_height) / 2 - frame_width)
|
||||||
.translated(screen_location);
|
.translated(screen_location);
|
||||||
case WindowTileType::Bottom:
|
case WindowTileType::Bottom: {
|
||||||
return Gfx::IntRect(0,
|
Gfx::IntPoint location {
|
||||||
menu_height + (titlebar_height + max_height) / 2 + frame_width,
|
0,
|
||||||
screen.width(),
|
menu_height + (titlebar_height + max_height) / 2 + frame_width
|
||||||
(max_height - titlebar_height) / 2 - frame_width)
|
};
|
||||||
|
return Gfx::IntRect(
|
||||||
|
location,
|
||||||
|
{ screen.width(), screen.height() - location.y() })
|
||||||
.translated(screen_location);
|
.translated(screen_location);
|
||||||
|
}
|
||||||
case WindowTileType::TopLeft:
|
case WindowTileType::TopLeft:
|
||||||
return Gfx::IntRect(0,
|
return Gfx::IntRect(0,
|
||||||
menu_height,
|
menu_height,
|
||||||
screen.width() / 2 - frame_width,
|
screen.width() / 2 - frame_width,
|
||||||
(max_height - titlebar_height) / 2 - frame_width)
|
(max_height - titlebar_height) / 2 - frame_width)
|
||||||
.translated(screen_location);
|
.translated(screen_location);
|
||||||
case WindowTileType::TopRight:
|
case WindowTileType::TopRight: {
|
||||||
return Gfx::IntRect(screen.width() / 2 + frame_width,
|
Gfx::IntPoint location {
|
||||||
menu_height,
|
screen.width() / 2 + frame_width,
|
||||||
screen.width() / 2 - frame_width,
|
menu_height
|
||||||
(max_height - titlebar_height) / 2 - frame_width)
|
};
|
||||||
|
return Gfx::IntRect(
|
||||||
|
location,
|
||||||
|
{ screen.width() - location.x(), (max_height - titlebar_height) / 2 - frame_width })
|
||||||
.translated(screen_location);
|
.translated(screen_location);
|
||||||
case WindowTileType::BottomLeft:
|
}
|
||||||
return Gfx::IntRect(0,
|
case WindowTileType::BottomLeft: {
|
||||||
menu_height + (titlebar_height + max_height) / 2 + frame_width,
|
Gfx::IntPoint location {
|
||||||
screen.width() / 2 - frame_width,
|
0,
|
||||||
(max_height - titlebar_height) / 2 - frame_width)
|
menu_height + (titlebar_height + max_height) / 2 + frame_width
|
||||||
|
};
|
||||||
|
return Gfx::IntRect(
|
||||||
|
location,
|
||||||
|
{ screen.width() / 2 - frame_width, screen.height() - location.y() })
|
||||||
.translated(screen_location);
|
.translated(screen_location);
|
||||||
case WindowTileType::BottomRight:
|
}
|
||||||
return Gfx::IntRect(screen.width() / 2 + frame_width,
|
case WindowTileType::BottomRight: {
|
||||||
menu_height + (titlebar_height + max_height) / 2 + frame_width,
|
Gfx::IntPoint location {
|
||||||
screen.width() / 2 - frame_width,
|
screen.width() / 2 + frame_width,
|
||||||
(max_height - titlebar_height) / 2 - frame_width)
|
menu_height + (titlebar_height + max_height) / 2 + frame_width
|
||||||
|
};
|
||||||
|
return Gfx::IntRect(
|
||||||
|
location,
|
||||||
|
{ screen.width() - location.x(), screen.height() - location.y() })
|
||||||
.translated(screen_location);
|
.translated(screen_location);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WindowTileType Window::tile_type_based_on_rect(Gfx::IntRect const& rect) const
|
||||||
|
{
|
||||||
|
auto& window_screen = Screen::closest_to_rect(this->rect()); // based on currently used rect
|
||||||
|
auto tile_type = WindowTileType::None;
|
||||||
|
if (window_screen.rect().contains(rect)) {
|
||||||
|
auto current_tiled = tiled();
|
||||||
|
bool tiling_to_top = current_tiled == WindowTileType::Top || current_tiled == WindowTileType::TopLeft || current_tiled == WindowTileType::TopRight;
|
||||||
|
bool tiling_to_bottom = current_tiled == WindowTileType::Bottom || current_tiled == WindowTileType::BottomLeft || current_tiled == WindowTileType::BottomRight;
|
||||||
|
bool tiling_to_left = current_tiled == WindowTileType::Left || current_tiled == WindowTileType::TopLeft || current_tiled == WindowTileType::BottomLeft;
|
||||||
|
bool tiling_to_right = current_tiled == WindowTileType::Right || current_tiled == WindowTileType::TopRight || current_tiled == WindowTileType::BottomRight;
|
||||||
|
|
||||||
|
auto ideal_tiled_rect = tiled_rect(&window_screen, current_tiled);
|
||||||
|
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();
|
||||||
|
bool same_bottom = ideal_tiled_rect.bottom() == rect.bottom();
|
||||||
|
|
||||||
|
// Try to find the most suitable tile type. For example, if a window is currently tiled to the BottomRight and
|
||||||
|
// the window is resized upwards as to where it perfectly touches the screen's top border, then the more suitable
|
||||||
|
// tile type would be Right, as three sides are lined up perfectly.
|
||||||
|
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() == tiled_rect(&window_screen, WindowTileType::Bottom).bottom() ? WindowTileType::Left : WindowTileType::TopLeft;
|
||||||
|
else if ((tiling_to_top || tiling_to_right) && same_top && same_right)
|
||||||
|
return rect.bottom() == tiled_rect(&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)
|
||||||
|
return WindowTileType::Right;
|
||||||
|
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() == tiled_rect(&window_screen, WindowTileType::Left).top() ? WindowTileType::Left : WindowTileType::BottomLeft;
|
||||||
|
else if ((tiling_to_bottom || tiling_to_right) && same_bottom && same_right)
|
||||||
|
return rect.top() == tiled_rect(&window_screen, WindowTileType::Right).top() ? WindowTileType::Right : WindowTileType::BottomRight;
|
||||||
|
}
|
||||||
|
return tile_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::check_untile_due_to_resize(Gfx::IntRect const& new_rect)
|
||||||
|
{
|
||||||
|
auto new_tile_type = tile_type_based_on_rect(new_rect);
|
||||||
|
if constexpr (RESIZE_DEBUG) {
|
||||||
|
if (new_tile_type == WindowTileType::None) {
|
||||||
|
auto current_rect = rect();
|
||||||
|
auto& window_screen = Screen::closest_to_rect(current_rect);
|
||||||
|
if (!(window_screen.rect().contains(new_rect)))
|
||||||
|
dbgln("Untiling because new rect {} does not fit into screen #{} rect {}", new_rect, window_screen.index(), window_screen.rect());
|
||||||
|
else
|
||||||
|
dbgln("Untiling because new rect {} does not touch screen #{} rect {}", new_rect, window_screen.index(), window_screen.rect());
|
||||||
|
} else if (new_tile_type != m_tiled)
|
||||||
|
dbgln("Changing tile type from {} to {}", (int)m_tiled, (int)new_tile_type);
|
||||||
|
}
|
||||||
|
m_tiled = new_tile_type;
|
||||||
|
}
|
||||||
|
|
||||||
bool Window::set_untiled(Optional<Gfx::IntPoint> fixed_point)
|
bool Window::set_untiled(Optional<Gfx::IntPoint> fixed_point)
|
||||||
{
|
{
|
||||||
if (m_tiled == WindowTileType::None)
|
if (m_tiled == WindowTileType::None)
|
||||||
|
@ -100,6 +100,8 @@ public:
|
|||||||
|
|
||||||
WindowTileType tiled() const { return m_tiled; }
|
WindowTileType tiled() const { return m_tiled; }
|
||||||
void set_tiled(Screen*, WindowTileType);
|
void set_tiled(Screen*, WindowTileType);
|
||||||
|
WindowTileType tile_type_based_on_rect(Gfx::IntRect const&) const;
|
||||||
|
void check_untile_due_to_resize(Gfx::IntRect const&);
|
||||||
bool set_untiled(Optional<Gfx::IntPoint> fixed_point = {});
|
bool set_untiled(Optional<Gfx::IntPoint> fixed_point = {});
|
||||||
|
|
||||||
bool is_occluded() const { return m_occluded; }
|
bool is_occluded() const { return m_occluded; }
|
||||||
|
@ -715,6 +715,7 @@ bool WindowManager::process_ongoing_window_resize(MouseEvent const& event)
|
|||||||
// First, size the new rect.
|
// First, size the new rect.
|
||||||
new_rect.set_width(new_rect.width() + change_w);
|
new_rect.set_width(new_rect.width() + change_w);
|
||||||
new_rect.set_height(new_rect.height() + change_h);
|
new_rect.set_height(new_rect.height() + change_h);
|
||||||
|
|
||||||
m_resize_window->apply_minimum_size(new_rect);
|
m_resize_window->apply_minimum_size(new_rect);
|
||||||
|
|
||||||
if (!m_resize_window->size_increment().is_null()) {
|
if (!m_resize_window->size_increment().is_null()) {
|
||||||
@ -762,6 +763,14 @@ bool WindowManager::process_ongoing_window_resize(MouseEvent const& event)
|
|||||||
if (m_resize_window->rect() == new_rect)
|
if (m_resize_window->rect() == new_rect)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (m_resize_window->tiled() != WindowTileType::None) {
|
||||||
|
// Check if we should be un-tiling the window. This should happen when one side touching
|
||||||
|
// the screen border changes. We need to un-tile because while it is tiled, rendering is
|
||||||
|
// constrained to the screen where it's tiled on, and if one of these sides move we should
|
||||||
|
// no longer constrain rendering to that screen. Changing the sides not touching a screen
|
||||||
|
// border however is fine as long as the screen contains the entire window.
|
||||||
|
m_resize_window->check_untile_due_to_resize(new_rect);
|
||||||
|
}
|
||||||
dbgln_if(RESIZE_DEBUG, "[WM] Resizing, original: {}, now: {}", m_resize_window_original_rect, new_rect);
|
dbgln_if(RESIZE_DEBUG, "[WM] Resizing, original: {}, now: {}", m_resize_window_original_rect, new_rect);
|
||||||
|
|
||||||
m_resize_window->set_rect(new_rect);
|
m_resize_window->set_rect(new_rect);
|
||||||
|
Loading…
Reference in New Issue
Block a user