summaryrefslogtreecommitdiff
path: root/Userland/Services
diff options
context:
space:
mode:
authorthankyouverycool <66646555+thankyouverycool@users.noreply.github.com>2022-09-07 07:49:00 -0400
committerLinus Groh <mail@linusgroh.de>2022-09-08 23:21:54 +0100
commit463aff827e4d47afacd6693a031e8e0d868affc8 (patch)
tree0361ffa3d77218561571f4794360d2037ec2f056 /Userland/Services
parent6c35aac617b60f76a2daf5dcb2ad558a162c175a (diff)
downloadserenity-463aff827e4d47afacd6693a031e8e0d868affc8.zip
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.
Diffstat (limited to 'Userland/Services')
-rw-r--r--Userland/Services/WindowServer/MenuManager.cpp23
-rw-r--r--Userland/Services/WindowServer/MenuManager.h1
-rw-r--r--Userland/Services/WindowServer/WindowClient.ipc1
-rw-r--r--Userland/Services/WindowServer/WindowManager.cpp6
-rw-r--r--Userland/Services/WindowServer/WindowManager.h1
-rw-r--r--Userland/Services/WindowServer/WindowMode.h9
6 files changed, 26 insertions, 15 deletions
diff --git a/Userland/Services/WindowServer/MenuManager.cpp b/Userland/Services/WindowServer/MenuManager.cpp
index 07d8cab2fe..ad0750c637 100644
--- a/Userland/Services/WindowServer/MenuManager.cpp
+++ b/Userland/Services/WindowServer/MenuManager.cpp
@@ -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)
diff --git a/Userland/Services/WindowServer/MenuManager.h b/Userland/Services/WindowServer/MenuManager.h
index 77d214c852..a770597f14 100644
--- a/Userland/Services/WindowServer/MenuManager.h
+++ b/Userland/Services/WindowServer/MenuManager.h
@@ -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 };
diff --git a/Userland/Services/WindowServer/WindowClient.ipc b/Userland/Services/WindowServer/WindowClient.ipc
index 7318931233..4688b052f9 100644
--- a/Userland/Services/WindowServer/WindowClient.ipc
+++ b/Userland/Services/WindowServer/WindowClient.ipc
@@ -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) =|
diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp
index eb07b9cb63..e89aa6dca6 100644
--- a/Userland/Services/WindowServer/WindowManager.cpp
+++ b/Userland/Services/WindowServer/WindowManager.cpp
@@ -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;
diff --git a/Userland/Services/WindowServer/WindowManager.h b/Userland/Services/WindowServer/WindowManager.h
index 93b3a8b402..632520cf6d 100644
--- a/Userland/Services/WindowServer/WindowManager.h
+++ b/Userland/Services/WindowServer/WindowManager.h
@@ -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;
diff --git a/Userland/Services/WindowServer/WindowMode.h b/Userland/Services/WindowServer/WindowMode.h
index c70e821337..3cb82ee1f8 100644
--- a/Userland/Services/WindowServer/WindowMode.h
+++ b/Userland/Services/WindowServer/WindowMode.h
@@ -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,
+};
+
}