mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 10:07:44 +00:00
WindowServer: Remove misbehavior conditions for modals
This was too restrictive and there are already UI elements that rely on this behavior. Now Blocking modals will preempt interaction with all windows in their modal chain except those descending from them. Fixes crashing in FilePicker when permission is denied.
This commit is contained in:
parent
b2b68a7551
commit
1dd9086e1a
5 changed files with 14 additions and 18 deletions
|
@ -576,10 +576,6 @@ void ConnectionFromClient::create_window(i32 window_id, Gfx::IntRect const& rect
|
||||||
did_misbehave("CreateWindow with bad parent_window_id");
|
did_misbehave("CreateWindow with bad parent_window_id");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((parent_window->is_blocking() && mode != (i32)WindowMode::CaptureInput) || parent_window->is_capturing_input()) {
|
|
||||||
did_misbehave("CreateWindow with forbidden parent mode");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type < 0 || type >= (i32)WindowType::_Count) {
|
if (type < 0 || type >= (i32)WindowType::_Count) {
|
||||||
|
|
|
@ -442,7 +442,7 @@ void Window::event(Core::Event& event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blocking_modal_window() && !is_capturing_input()) {
|
if (blocking_modal_window()) {
|
||||||
// We still want to handle the WindowDeactivated event below when a new modal is
|
// We still want to handle the WindowDeactivated event below when a new modal is
|
||||||
// created to notify its parent window, despite it being "blocked by modal window".
|
// created to notify its parent window, despite it being "blocked by modal window".
|
||||||
if (event.type() != Event::WindowDeactivated)
|
if (event.type() != Event::WindowDeactivated)
|
||||||
|
@ -660,6 +660,8 @@ bool Window::is_active() const
|
||||||
Window* Window::blocking_modal_window()
|
Window* Window::blocking_modal_window()
|
||||||
{
|
{
|
||||||
auto maybe_blocker = WindowManager::the().for_each_window_in_modal_chain(*this, [&](auto& window) {
|
auto maybe_blocker = WindowManager::the().for_each_window_in_modal_chain(*this, [&](auto& window) {
|
||||||
|
if (is_descendant_of(window))
|
||||||
|
return IterationDecision::Continue;
|
||||||
if (window.is_blocking() && this != &window)
|
if (window.is_blocking() && this != &window)
|
||||||
return IterationDecision::Break;
|
return IterationDecision::Break;
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
|
|
|
@ -348,8 +348,7 @@ void WindowManager::move_to_front_and_make_active(Window& window)
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto* blocker = window.blocking_modal_window();
|
if (auto* blocker = window.blocking_modal_window()) {
|
||||||
if (blocker && !window.is_capturing_input()) {
|
|
||||||
blocker->window_stack().move_to_front(*blocker);
|
blocker->window_stack().move_to_front(*blocker);
|
||||||
set_active_window(blocker, true);
|
set_active_window(blocker, true);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1230,7 +1229,7 @@ void WindowManager::process_mouse_event_for_window(HitTestResult& result, MouseE
|
||||||
|
|
||||||
// First check if we should initiate a move or resize (Super+LMB or Super+RMB).
|
// First check if we should initiate a move or resize (Super+LMB or Super+RMB).
|
||||||
// In those cases, the event is swallowed by the window manager.
|
// In those cases, the event is swallowed by the window manager.
|
||||||
if ((!blocking_modal_window || window.is_capturing_input()) && window.is_movable()) {
|
if (!blocking_modal_window && window.is_movable()) {
|
||||||
if (!window.is_fullscreen() && m_keyboard_modifiers == Mod_Super && event.type() == Event::MouseDown && event.button() == MouseButton::Primary) {
|
if (!window.is_fullscreen() && m_keyboard_modifiers == Mod_Super && event.type() == Event::MouseDown && event.button() == MouseButton::Primary) {
|
||||||
start_window_move(window, event);
|
start_window_move(window, event);
|
||||||
return;
|
return;
|
||||||
|
@ -1248,7 +1247,7 @@ void WindowManager::process_mouse_event_for_window(HitTestResult& result, MouseE
|
||||||
set_active_window(&window);
|
set_active_window(&window);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (blocking_modal_window && !window.is_capturing_input()) {
|
if (blocking_modal_window) {
|
||||||
if (event.type() == Event::Type::MouseDown) {
|
if (event.type() == Event::Type::MouseDown) {
|
||||||
// We're clicking on something that's blocked by a modal window.
|
// We're clicking on something that's blocked by a modal window.
|
||||||
// Flash the modal window to let the user know about it.
|
// Flash the modal window to let the user know about it.
|
||||||
|
@ -1835,8 +1834,7 @@ void WindowManager::notify_previous_active_input_window(Window& previous_input_w
|
||||||
void WindowManager::set_active_window(Window* new_active_window, bool make_input)
|
void WindowManager::set_active_window(Window* new_active_window, bool make_input)
|
||||||
{
|
{
|
||||||
if (new_active_window) {
|
if (new_active_window) {
|
||||||
auto* blocker = new_active_window->blocking_modal_window();
|
if (auto* blocker = new_active_window->blocking_modal_window()) {
|
||||||
if (blocker && !new_active_window->is_capturing_input()) {
|
|
||||||
VERIFY(blocker->is_modal());
|
VERIFY(blocker->is_modal());
|
||||||
VERIFY(blocker != new_active_window);
|
VERIFY(blocker != new_active_window);
|
||||||
new_active_window = blocker;
|
new_active_window = blocker;
|
||||||
|
|
|
@ -241,24 +241,24 @@ public:
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
Window* for_each_window_in_modal_chain(Window& window, Callback callback)
|
Window* for_each_window_in_modal_chain(Window& window, Callback callback)
|
||||||
{
|
{
|
||||||
Window* maybe_break = nullptr;
|
|
||||||
Function<Window*(Window&)> recurse = [&](Window& w) -> Window* {
|
Function<Window*(Window&)> recurse = [&](Window& w) -> Window* {
|
||||||
if (!w.is_modal()) {
|
if (!w.is_modal()) {
|
||||||
auto decision = callback(w);
|
auto decision = callback(w);
|
||||||
if (decision == IterationDecision::Break)
|
if (decision == IterationDecision::Break)
|
||||||
return maybe_break = &w;
|
return &w;
|
||||||
}
|
}
|
||||||
for (auto& child : w.child_windows()) {
|
for (auto& child : w.child_windows()) {
|
||||||
if (!child || child->is_destroyed() || !child->is_modal())
|
if (!child || child->is_destroyed() || !child->is_modal())
|
||||||
continue;
|
continue;
|
||||||
auto decision = callback(*child);
|
auto decision = callback(*child);
|
||||||
|
if (auto* result = recurse(*child))
|
||||||
|
return result;
|
||||||
if (decision == IterationDecision::Break)
|
if (decision == IterationDecision::Break)
|
||||||
return maybe_break = child;
|
return child;
|
||||||
recurse(*child);
|
|
||||||
}
|
}
|
||||||
return maybe_break;
|
return nullptr;
|
||||||
};
|
};
|
||||||
if (auto* modeless = window.modeless_ancestor(); modeless)
|
if (auto* modeless = window.modeless_ancestor())
|
||||||
return recurse(*modeless);
|
return recurse(*modeless);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ namespace WindowServer {
|
||||||
// - Passive: Joins the modal chain but has no modal effect (default mode for child windows)
|
// - Passive: Joins the modal chain but has no modal effect (default mode for child windows)
|
||||||
// - RenderAbove: Renders above its parent
|
// - RenderAbove: Renders above its parent
|
||||||
// - CaptureInput: Captures input from its parent
|
// - CaptureInput: Captures input from its parent
|
||||||
// - Blocking: Preempts all interaction with its modal chain
|
// - Blocking: Preempts all interaction with its modal chain excepting descendants (default mode for Dialogs)
|
||||||
enum class WindowMode {
|
enum class WindowMode {
|
||||||
Modeless = 0,
|
Modeless = 0,
|
||||||
Passive,
|
Passive,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue