1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-28 10:27:36 +00:00

LibGUI+WindowServer: Notify Windows on input preemption

Previously Menus set themselves as active input solely to make
sure CaptureInput modals would close, but this is a functional
half-truth. Menus don't actually use the active input role; they
preempt normal Windows during event handling instead.

Now the active input window is notified on preemption and Menus
can remain outside the active input concept. This lets us make
more granular choices about modal behavior. For now, the only
thing clients care about is menu preemption on popup.

Fixes windows which close on changes to active input closing
on their own context menus.
This commit is contained in:
thankyouverycool 2022-09-07 07:49:00 -04:00 committed by Linus Groh
parent 6c35aac617
commit 463aff827e
13 changed files with 48 additions and 15 deletions

View file

@ -331,17 +331,14 @@ void MenuManager::open_menu(Menu& menu, bool as_current_menu)
void MenuManager::clear_current_menu()
{
Menu* previous_current_menu = m_current_menu;
m_current_menu = nullptr;
if (previous_current_menu) {
// When closing the last menu, restore the previous active input window
if (m_current_menu) {
auto& wm = WindowManager::the();
wm.restore_active_input_window(m_previous_input_window);
if (auto* window = wm.window_with_active_menu()) {
window->invalidate_menubar();
}
wm.set_window_with_active_menu(nullptr);
}
m_current_menu = nullptr;
}
void MenuManager::set_current_menu(Menu* menu)
@ -356,19 +353,17 @@ void MenuManager::set_current_menu(Menu* menu)
return;
}
Menu* previous_current_menu = m_current_menu;
m_current_menu = menu;
auto& wm = WindowManager::the();
if (!previous_current_menu) {
// When opening the first menu, store the current active input window
if (auto* active_input = wm.active_input_window())
m_previous_input_window = *active_input;
else
m_previous_input_window = nullptr;
if (auto* window = wm.active_input_window()) {
InputPreemptor preemptor { InputPreemptor::OtherMenu };
if (window->rect().contains(m_current_menu->unadjusted_position()))
preemptor = InputPreemptor::ContextMenu;
else if (!m_current_menu->rect_in_window_menubar().is_null())
preemptor = InputPreemptor::MenubarMenu;
wm.notify_input_preempted(*window, preemptor);
}
wm.set_active_input_window(m_current_menu->menu_window());
}
Menu* MenuManager::previous_menu(Menu* current)

View file

@ -58,7 +58,6 @@ private:
void refresh();
WeakPtr<Menu> m_current_menu;
WeakPtr<Window> m_previous_input_window;
Vector<WeakPtr<Menu>> m_open_menu_stack;
int m_theme_index { 0 };

View file

@ -20,6 +20,7 @@ endpoint WindowClient
window_activated(i32 window_id) =|
window_deactivated(i32 window_id) =|
window_state_changed(i32 window_id, bool minimized, bool maximized, bool occluded) =|
window_input_preempted(i32 window_id, i32 preemptor) =|
window_close_request(i32 window_id) =|
window_resized(i32 window_id, Gfx::IntRect new_rect) =|

View file

@ -642,6 +642,12 @@ void WindowManager::notify_progress_changed(Window& window)
tell_wms_window_state_changed(window);
}
void WindowManager::notify_input_preempted(Window& window, InputPreemptor preemptor)
{
if (window.client())
window.client()->async_window_input_preempted(window.window_id(), (i32)preemptor);
}
void WindowManager::pick_new_active_window(Window* previous_active)
{
Window* desktop = nullptr;

View file

@ -87,6 +87,7 @@ public:
void notify_occlusion_state_changed(Window&);
void notify_progress_changed(Window&);
void notify_modified_changed(Window&);
void notify_input_preempted(Window&, InputPreemptor = InputPreemptor::Other);
Gfx::IntRect tiled_window_rect(Window const&, WindowTileType tile_type = WindowTileType::Maximized, bool relative_to_window_screen = false) const;

View file

@ -24,4 +24,13 @@ enum class WindowMode {
_Count,
};
// InputPreemptors are Objects which take input precedence over the active input
// window without changing its activity state or joining its modal chain
enum class InputPreemptor {
ContextMenu = 0,
MenubarMenu,
OtherMenu,
Other,
};
}