mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 12:48:10 +00:00
WindowServer: Add accessory windows
Accessory windows are windows that, when activated, will activate their parent and bring all other accessory windows of that parent to the front of the window stack. Accessory windows can only be active input windows. The accessory window's parent is always the active window regardless of whether it is also the active input window. In order to route input correctly, input is now sent to the active input window, which can be any accessory window or their parent, or any regular window.
This commit is contained in:
parent
396291b356
commit
ec3737510d
16 changed files with 216 additions and 59 deletions
|
@ -208,6 +208,27 @@ void WindowManager::move_to_front_and_make_active(Window& window)
|
|||
if (window.is_blocked_by_modal_window())
|
||||
return;
|
||||
|
||||
bool make_active = true;
|
||||
if (window.is_accessory()) {
|
||||
if (auto* parent = window.parent_window()) {
|
||||
do_move_to_front(*parent, true, false);
|
||||
make_active = false;
|
||||
|
||||
for (auto& accessory_window : parent->accessory_windows()) {
|
||||
if (accessory_window && accessory_window.ptr() != &window)
|
||||
do_move_to_front(*accessory_window, false, false);
|
||||
}
|
||||
} else {
|
||||
// If accessory window was unparented, convert to a regular window
|
||||
window.set_accessory(false);
|
||||
}
|
||||
}
|
||||
|
||||
do_move_to_front(window, make_active, true);
|
||||
}
|
||||
|
||||
void WindowManager::do_move_to_front(Window& window, bool make_active, bool make_input)
|
||||
{
|
||||
if (m_windows_in_order.tail() != &window)
|
||||
window.invalidate();
|
||||
m_windows_in_order.remove(&window);
|
||||
|
@ -215,17 +236,20 @@ void WindowManager::move_to_front_and_make_active(Window& window)
|
|||
|
||||
Compositor::the().recompute_occlusions();
|
||||
|
||||
set_active_window(&window);
|
||||
if (make_active)
|
||||
set_active_window(&window, make_input);
|
||||
|
||||
if (m_switcher.is_visible()) {
|
||||
m_switcher.refresh();
|
||||
m_switcher.select_window(window);
|
||||
set_highlight_window(&window);
|
||||
if (!window.is_accessory()) {
|
||||
m_switcher.select_window(window);
|
||||
set_highlight_window(&window);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& child_window : window.child_windows()) {
|
||||
if (child_window)
|
||||
move_to_front_and_make_active(*child_window);
|
||||
do_move_to_front(*child_window, make_active, make_input);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,7 +258,7 @@ void WindowManager::remove_window(Window& window)
|
|||
window.invalidate();
|
||||
m_windows_in_order.remove(&window);
|
||||
if (window.is_active())
|
||||
pick_new_active_window();
|
||||
pick_new_active_window(window);
|
||||
if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher)
|
||||
m_switcher.refresh();
|
||||
|
||||
|
@ -352,7 +376,7 @@ void WindowManager::notify_minimization_state_changed(Window& window)
|
|||
window.client()->post_message(Messages::WindowClient::WindowStateChanged(window.window_id(), window.is_minimized(), window.is_occluded()));
|
||||
|
||||
if (window.is_active() && window.is_minimized())
|
||||
pick_new_active_window();
|
||||
pick_new_active_window(window);
|
||||
}
|
||||
|
||||
void WindowManager::notify_occlusion_state_changed(Window& window)
|
||||
|
@ -366,12 +390,14 @@ void WindowManager::notify_progress_changed(Window& window)
|
|||
tell_wm_listeners_window_state_changed(window);
|
||||
}
|
||||
|
||||
void WindowManager::pick_new_active_window()
|
||||
void WindowManager::pick_new_active_window(Window& previous_active)
|
||||
{
|
||||
bool new_window_picked = false;
|
||||
for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, [&](Window& candidate) {
|
||||
set_active_window(&candidate);
|
||||
new_window_picked = true;
|
||||
if (!candidate.is_accessory_of(previous_active)) {
|
||||
set_active_window(&candidate);
|
||||
new_window_picked = true;
|
||||
}
|
||||
return IterationDecision::Break;
|
||||
});
|
||||
if (!new_window_picked)
|
||||
|
@ -846,20 +872,20 @@ void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_wind
|
|||
|
||||
Window* event_window_with_frame = nullptr;
|
||||
|
||||
if (m_active_input_window) {
|
||||
if (m_active_input_tracking_window) {
|
||||
// At this point, we have delivered the start of an input sequence to a
|
||||
// client application. We must keep delivering to that client
|
||||
// application until the input sequence is done.
|
||||
//
|
||||
// This prevents e.g. moving on one window out of the bounds starting
|
||||
// a move in that other unrelated window, and other silly shenanigans.
|
||||
if (!windows_who_received_mouse_event_due_to_cursor_tracking.contains(m_active_input_window)) {
|
||||
auto translated_event = event.translated(-m_active_input_window->position());
|
||||
deliver_mouse_event(*m_active_input_window, translated_event);
|
||||
windows_who_received_mouse_event_due_to_cursor_tracking.set(m_active_input_window.ptr());
|
||||
if (!windows_who_received_mouse_event_due_to_cursor_tracking.contains(m_active_input_tracking_window)) {
|
||||
auto translated_event = event.translated(-m_active_input_tracking_window->position());
|
||||
deliver_mouse_event(*m_active_input_tracking_window, translated_event);
|
||||
windows_who_received_mouse_event_due_to_cursor_tracking.set(m_active_input_tracking_window.ptr());
|
||||
}
|
||||
if (event.type() == Event::MouseUp && event.buttons() == 0) {
|
||||
m_active_input_window = nullptr;
|
||||
m_active_input_tracking_window = nullptr;
|
||||
}
|
||||
|
||||
for_each_visible_window_from_front_to_back([&](auto& window) {
|
||||
|
@ -915,7 +941,7 @@ void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_wind
|
|||
auto translated_event = event.translated(-window.position());
|
||||
deliver_mouse_event(window, translated_event);
|
||||
if (event.type() == Event::MouseDown) {
|
||||
m_active_input_window = window.make_weak_ptr();
|
||||
m_active_input_tracking_window = window.make_weak_ptr();
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -1004,45 +1030,45 @@ void WindowManager::event(Core::Event& event)
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_active_window) {
|
||||
if (m_active_input_window) {
|
||||
if (key_event.type() == Event::KeyDown && key_event.modifiers() == Mod_Logo) {
|
||||
if (key_event.key() == Key_Down) {
|
||||
if (m_active_window->is_resizable() && m_active_window->is_maximized()) {
|
||||
m_active_window->set_maximized(false);
|
||||
if (m_active_input_window->is_resizable() && m_active_input_window->is_maximized()) {
|
||||
m_active_input_window->set_maximized(false);
|
||||
return;
|
||||
}
|
||||
if (m_active_window->is_minimizable())
|
||||
m_active_window->set_minimized(true);
|
||||
if (m_active_input_window->is_minimizable())
|
||||
m_active_input_window->set_minimized(true);
|
||||
return;
|
||||
}
|
||||
if (m_active_window->is_resizable()) {
|
||||
if (m_active_input_window->is_resizable()) {
|
||||
if (key_event.key() == Key_Up) {
|
||||
m_active_window->set_maximized(!m_active_window->is_maximized());
|
||||
m_active_input_window->set_maximized(!m_active_input_window->is_maximized());
|
||||
return;
|
||||
}
|
||||
if (key_event.key() == Key_Left) {
|
||||
if (m_active_window->tiled() != WindowTileType::None) {
|
||||
m_active_window->set_tiled(WindowTileType::None);
|
||||
if (m_active_input_window->tiled() != WindowTileType::None) {
|
||||
m_active_input_window->set_tiled(WindowTileType::None);
|
||||
return;
|
||||
}
|
||||
if (m_active_window->is_maximized())
|
||||
m_active_window->set_maximized(false);
|
||||
m_active_window->set_tiled(WindowTileType::Left);
|
||||
if (m_active_input_window->is_maximized())
|
||||
m_active_input_window->set_maximized(false);
|
||||
m_active_input_window->set_tiled(WindowTileType::Left);
|
||||
return;
|
||||
}
|
||||
if (key_event.key() == Key_Right) {
|
||||
if (m_active_window->tiled() != WindowTileType::None) {
|
||||
m_active_window->set_tiled(WindowTileType::None);
|
||||
if (m_active_input_window->tiled() != WindowTileType::None) {
|
||||
m_active_input_window->set_tiled(WindowTileType::None);
|
||||
return;
|
||||
}
|
||||
if (m_active_window->is_maximized())
|
||||
m_active_window->set_maximized(false);
|
||||
m_active_window->set_tiled(WindowTileType::Right);
|
||||
if (m_active_input_window->is_maximized())
|
||||
m_active_input_window->set_maximized(false);
|
||||
m_active_input_window->set_tiled(WindowTileType::Right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_active_window->dispatch_event(event);
|
||||
m_active_input_window->dispatch_event(event);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -1061,12 +1087,30 @@ void WindowManager::set_highlight_window(Window* window)
|
|||
m_highlight_window->invalidate();
|
||||
}
|
||||
|
||||
bool WindowManager::is_active_window_or_accessory(Window& window) const
|
||||
{
|
||||
if (m_active_window == &window)
|
||||
return true;
|
||||
|
||||
if (!window.is_accessory())
|
||||
return false;
|
||||
|
||||
auto* parent = window.parent_window();
|
||||
if (!parent) {
|
||||
// If accessory window was unparented, convert to a regular window
|
||||
window.set_accessory(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
return m_active_window == parent;
|
||||
}
|
||||
|
||||
static bool window_type_can_become_active(WindowType type)
|
||||
{
|
||||
return type == WindowType::Normal || type == WindowType::Desktop;
|
||||
}
|
||||
|
||||
void WindowManager::set_active_window(Window* window)
|
||||
void WindowManager::set_active_window(Window* window, bool make_input)
|
||||
{
|
||||
if (window && window->is_blocked_by_modal_window())
|
||||
return;
|
||||
|
@ -1074,6 +1118,32 @@ void WindowManager::set_active_window(Window* window)
|
|||
if (window && !window_type_can_become_active(window->type()))
|
||||
return;
|
||||
|
||||
if (make_input) {
|
||||
auto* new_active_input_window = window;
|
||||
if (window && window->is_accessory()) {
|
||||
if (auto* parent = window->parent_window()) {
|
||||
// The parent of an accessory window is always the active
|
||||
// window, but input is routed to the accessory window
|
||||
window = parent;
|
||||
} else {
|
||||
// If accessory window was unparented, convert to a regular window
|
||||
window->set_accessory(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (new_active_input_window != m_active_input_window) {
|
||||
if (m_active_input_window)
|
||||
Core::EventLoop::current().post_event(*m_active_input_window, make<Event>(Event::WindowInputLeft));
|
||||
|
||||
if (new_active_input_window) {
|
||||
m_active_input_window = new_active_input_window->make_weak_ptr();
|
||||
Core::EventLoop::current().post_event(*new_active_input_window, make<Event>(Event::WindowInputEntered));
|
||||
} else {
|
||||
m_active_input_window = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (window == m_active_window)
|
||||
return;
|
||||
|
||||
|
@ -1087,7 +1157,7 @@ void WindowManager::set_active_window(Window* window)
|
|||
Core::EventLoop::current().post_event(*previously_active_window, make<Event>(Event::WindowDeactivated));
|
||||
previously_active_window->invalidate();
|
||||
m_active_window = nullptr;
|
||||
m_active_input_window = nullptr;
|
||||
m_active_input_tracking_window = nullptr;
|
||||
tell_wm_listeners_window_state_changed(*previously_active_window);
|
||||
}
|
||||
|
||||
|
@ -1236,7 +1306,7 @@ void WindowManager::start_dnd_drag(ClientConnection& client, const String& text,
|
|||
m_dnd_data_type = data_type;
|
||||
m_dnd_data = data;
|
||||
Compositor::the().invalidate_cursor();
|
||||
m_active_input_window = nullptr;
|
||||
m_active_input_tracking_window = nullptr;
|
||||
}
|
||||
|
||||
void WindowManager::end_dnd_drag()
|
||||
|
@ -1288,10 +1358,10 @@ bool WindowManager::update_theme(String theme_path, String theme_name)
|
|||
void WindowManager::did_popup_a_menu(Badge<Menu>)
|
||||
{
|
||||
// Clear any ongoing input gesture
|
||||
if (!m_active_input_window)
|
||||
if (!m_active_input_tracking_window)
|
||||
return;
|
||||
m_active_input_window->set_automatic_cursor_tracking_enabled(false);
|
||||
m_active_input_window = nullptr;
|
||||
m_active_input_tracking_window->set_automatic_cursor_tracking_enabled(false);
|
||||
m_active_input_tracking_window = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue