From ec3737510daf0f77d4932228b8d4bc4551c64e94 Mon Sep 17 00:00:00 2001 From: Tom Date: Tue, 14 Jul 2020 19:17:00 -0600 Subject: [PATCH] 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. --- Libraries/LibGUI/ComboBox.cpp | 11 +- Libraries/LibGUI/Event.h | 2 + Libraries/LibGUI/Widget.cpp | 9 +- Libraries/LibGUI/Window.cpp | 12 ++ Libraries/LibGUI/Window.h | 7 + Libraries/LibGUI/WindowServerConnection.cpp | 12 ++ Libraries/LibGUI/WindowServerConnection.h | 2 + Services/WindowServer/ClientConnection.cpp | 14 +- Services/WindowServer/Event.h | 2 + Services/WindowServer/Window.cpp | 28 +++- Services/WindowServer/Window.h | 12 +- Services/WindowServer/WindowClient.ipc | 2 + Services/WindowServer/WindowFrame.cpp | 2 +- Services/WindowServer/WindowManager.cpp | 150 ++++++++++++++------ Services/WindowServer/WindowManager.h | 9 +- Services/WindowServer/WindowServer.ipc | 1 + 16 files changed, 216 insertions(+), 59 deletions(-) diff --git a/Libraries/LibGUI/ComboBox.cpp b/Libraries/LibGUI/ComboBox.cpp index ae6a236edb..9b1abf63b3 100644 --- a/Libraries/LibGUI/ComboBox.cpp +++ b/Libraries/LibGUI/ComboBox.cpp @@ -99,8 +99,17 @@ ComboBox::ComboBox() open(); }; - m_list_window = add(); + m_list_window = add(window()); m_list_window->set_frameless(true); + m_list_window->set_accessory(true); + + m_list_window->on_active_input_change = [this](bool is_active_input) { + if (!is_active_input) { + m_open_button->set_enabled(true); + close(); + } + }; + m_list_window->on_activity_change = [this](const bool is_active) { if (!is_active) { m_open_button->set_enabled(false); diff --git a/Libraries/LibGUI/Event.h b/Libraries/LibGUI/Event.h index 298e8872a6..1fe9205892 100644 --- a/Libraries/LibGUI/Event.h +++ b/Libraries/LibGUI/Event.h @@ -57,6 +57,8 @@ public: WindowLeft, WindowBecameInactive, WindowBecameActive, + WindowInputEntered, + WindowInputLeft, FocusIn, FocusOut, WindowCloseRequest, diff --git a/Libraries/LibGUI/Widget.cpp b/Libraries/LibGUI/Widget.cpp index f64d1df5b2..5d1a123887 100644 --- a/Libraries/LibGUI/Widget.cpp +++ b/Libraries/LibGUI/Widget.cpp @@ -502,9 +502,12 @@ bool Widget::is_focused() const auto* win = window(); if (!win) return false; - if (!win->is_active()) - return false; - return win->focused_widget() == this; + // Accessory windows are not active despite being the active + // input window. So we can have focus if either we're the active + // input window or we're the active window + if (win->is_active_input() || win->is_active()) + return win->focused_widget() == this; + return false; } void Widget::set_focus(bool focus) diff --git a/Libraries/LibGUI/Window.cpp b/Libraries/LibGUI/Window.cpp index b5c024e0c3..b9a1c9e5cc 100644 --- a/Libraries/LibGUI/Window.cpp +++ b/Libraries/LibGUI/Window.cpp @@ -101,6 +101,7 @@ void Window::show() m_resizable, m_fullscreen, m_frameless, + m_accessory, m_opacity_when_windowless, m_base_size, m_size_increment, @@ -338,6 +339,17 @@ void Window::event(Core::Event& event) return; } + if (event.type() == Event::WindowInputEntered || event.type() == Event::WindowInputLeft) { + m_is_active_input = event.type() == Event::WindowInputEntered; + if (on_active_input_change) + on_active_input_change(m_is_active_input); + if (m_main_widget) + m_main_widget->dispatch_event(event, this); + if (m_focused_widget) + m_focused_widget->update(); + return; + } + if (event.type() == Event::WindowCloseRequest) { if (on_close_request) { if (on_close_request() == Window::CloseRequestDecision::StayOpen) diff --git a/Libraries/LibGUI/Window.h b/Libraries/LibGUI/Window.h index 1e75fec470..2b505b6b02 100644 --- a/Libraries/LibGUI/Window.h +++ b/Libraries/LibGUI/Window.h @@ -98,6 +98,7 @@ public: }; Function on_close_request; + Function on_active_input_change; Function on_activity_change; int x() const { return rect().x(); } @@ -122,6 +123,10 @@ public: bool is_visible() const; bool is_active() const { return m_is_active; } + bool is_active_input() const { return m_is_active_input; } + + bool is_accessory() const { return m_accessory; } + void set_accessory(bool accessory) { m_accessory = accessory; } void show(); void hide(); @@ -232,6 +237,7 @@ private: WindowType m_window_type { WindowType::Normal }; StandardCursor m_override_cursor { StandardCursor::None }; bool m_is_active { false }; + bool m_is_active_input { false }; bool m_has_alpha_channel { false }; bool m_double_buffering_enabled { true }; bool m_modal { false }; @@ -242,6 +248,7 @@ private: bool m_layout_pending { false }; bool m_visible_for_timer_purposes { true }; bool m_visible { false }; + bool m_accessory { false }; }; } diff --git a/Libraries/LibGUI/WindowServerConnection.cpp b/Libraries/LibGUI/WindowServerConnection.cpp index 5301186680..1f29afe18a 100644 --- a/Libraries/LibGUI/WindowServerConnection.cpp +++ b/Libraries/LibGUI/WindowServerConnection.cpp @@ -106,6 +106,18 @@ void WindowServerConnection::handle(const Messages::WindowClient::WindowDeactiva Core::EventLoop::current().post_event(*window, make(Event::WindowBecameInactive)); } +void WindowServerConnection::handle(const Messages::WindowClient::WindowInputEntered& message) +{ + if (auto* window = Window::from_window_id(message.window_id())) + Core::EventLoop::current().post_event(*window, make(Event::WindowInputEntered)); +} + +void WindowServerConnection::handle(const Messages::WindowClient::WindowInputLeft& message) +{ + if (auto* window = Window::from_window_id(message.window_id())) + Core::EventLoop::current().post_event(*window, make(Event::WindowInputLeft)); +} + void WindowServerConnection::handle(const Messages::WindowClient::WindowCloseRequest& message) { if (auto* window = Window::from_window_id(message.window_id())) diff --git a/Libraries/LibGUI/WindowServerConnection.h b/Libraries/LibGUI/WindowServerConnection.h index 9f8dda6e4e..49850e3839 100644 --- a/Libraries/LibGUI/WindowServerConnection.h +++ b/Libraries/LibGUI/WindowServerConnection.h @@ -59,6 +59,8 @@ private: virtual void handle(const Messages::WindowClient::KeyUp&) override; virtual void handle(const Messages::WindowClient::WindowActivated&) override; virtual void handle(const Messages::WindowClient::WindowDeactivated&) override; + virtual void handle(const Messages::WindowClient::WindowInputEntered&) override; + virtual void handle(const Messages::WindowClient::WindowInputLeft&) override; virtual void handle(const Messages::WindowClient::WindowCloseRequest&) override; virtual void handle(const Messages::WindowClient::WindowResized&) override; virtual void handle(const Messages::WindowClient::MenuItemActivated&) override; diff --git a/Services/WindowServer/ClientConnection.cpp b/Services/WindowServer/ClientConnection.cpp index d62d92a930..9089ece782 100644 --- a/Services/WindowServer/ClientConnection.cpp +++ b/Services/WindowServer/ClientConnection.cpp @@ -434,22 +434,18 @@ Window* ClientConnection::window_from_id(i32 window_id) OwnPtr ClientConnection::handle(const Messages::WindowServer::CreateWindow& message) { - int window_id = m_next_window_id++; - auto window = Window::construct(*this, (WindowType)message.type(), window_id, message.modal(), message.minimizable(), message.frameless(), message.resizable(), message.fullscreen()); - + Window* parent_window = nullptr; if (message.parent_window_id()) { - auto* parent_window = window_from_id(message.parent_window_id()); + parent_window = window_from_id(message.parent_window_id()); if (!parent_window) { did_misbehave("CreateWindow with bad parent_window_id"); return nullptr; } - if (parent_window->window_id() == window_id) { - did_misbehave("CreateWindow trying to make a window with itself as parent"); - return nullptr; - } - window->set_parent_window(*parent_window); } + int window_id = m_next_window_id++; + auto window = Window::construct(*this, (WindowType)message.type(), window_id, message.modal(), message.minimizable(), message.frameless(), message.resizable(), message.fullscreen(), message.accessory(), parent_window); + window->set_has_alpha_channel(message.has_alpha_channel()); window->set_title(message.title()); if (!message.fullscreen()) { diff --git a/Services/WindowServer/Event.h b/Services/WindowServer/Event.h index fb29fb4d4e..550c8275e9 100644 --- a/Services/WindowServer/Event.h +++ b/Services/WindowServer/Event.h @@ -50,6 +50,8 @@ public: KeyUp, WindowActivated, WindowDeactivated, + WindowInputEntered, + WindowInputLeft, WindowCloseRequest, WindowResized, }; diff --git a/Services/WindowServer/Window.cpp b/Services/WindowServer/Window.cpp index 8f16da8d93..08fc0f80f2 100644 --- a/Services/WindowServer/Window.cpp +++ b/Services/WindowServer/Window.cpp @@ -91,7 +91,7 @@ Window::Window(Core::Object& parent, WindowType type) WindowManager::the().add_window(*this); } -Window::Window(ClientConnection& client, WindowType window_type, int window_id, bool modal, bool minimizable, bool frameless, bool resizable, bool fullscreen) +Window::Window(ClientConnection& client, WindowType window_type, int window_id, bool modal, bool minimizable, bool frameless, bool resizable, bool fullscreen, bool accessory, Window* parent_window) : Core::Object(&client) , m_client(&client) , m_type(window_type) @@ -100,6 +100,7 @@ Window::Window(ClientConnection& client, WindowType window_type, int window_id, , m_frameless(frameless) , m_resizable(resizable) , m_fullscreen(fullscreen) + , m_accessory(accessory) , m_window_id(window_id) , m_client_id(client.client_id()) , m_icon(default_window_icon()) @@ -111,6 +112,8 @@ Window::Window(ClientConnection& client, WindowType window_type, int window_id, m_listens_to_wm_events = true; } + if (parent_window) + set_parent_window(*parent_window); WindowManager::the().add_window(*this); } @@ -321,6 +324,12 @@ void Window::event(Core::Event& event) case Event::WindowDeactivated: m_client->post_message(Messages::WindowClient::WindowDeactivated(m_window_id)); break; + case Event::WindowInputEntered: + m_client->post_message(Messages::WindowClient::WindowInputEntered(m_window_id)); + break; + case Event::WindowInputLeft: + m_client->post_message(Messages::WindowClient::WindowInputLeft(m_window_id)); + break; case Event::WindowCloseRequest: m_client->post_message(Messages::WindowClient::WindowCloseRequest(m_window_id)); break; @@ -566,11 +575,26 @@ void Window::add_child_window(Window& child_window) m_child_windows.append(child_window.make_weak_ptr()); } +void Window::add_accessory_window(Window& accessory_window) +{ + m_accessory_windows.append(accessory_window.make_weak_ptr()); +} + void Window::set_parent_window(Window& parent_window) { ASSERT(!m_parent_window); m_parent_window = parent_window.make_weak_ptr(); - parent_window.add_child_window(*this); + if (m_accessory) + parent_window.add_accessory_window(*this); + else + parent_window.add_child_window(*this); +} + +bool Window::is_accessory_of(Window& window) const +{ + if (!is_accessory()) + return false; + return parent_window() == &window; } void Window::set_progress(int progress) diff --git a/Services/WindowServer/Window.h b/Services/WindowServer/Window.h index fec098aaf6..b5384b5227 100644 --- a/Services/WindowServer/Window.h +++ b/Services/WindowServer/Window.h @@ -76,7 +76,7 @@ class Window final : public Core::Object , public InlineLinkedListNode { C_OBJECT(Window) public: - Window(ClientConnection&, WindowType, int window_id, bool modal, bool minimizable, bool frameless, bool resizable, bool fullscreen); + Window(ClientConnection&, WindowType, int window_id, bool modal, bool minimizable, bool frameless, bool resizable, bool fullscreen, bool accessory, Window* parent_window = nullptr); Window(Core::Object&, WindowType); virtual ~Window() override; @@ -240,6 +240,13 @@ public: Vector>& child_windows() { return m_child_windows; } const Vector>& child_windows() const { return m_child_windows; } + Vector>& accessory_windows() { return m_accessory_windows; } + const Vector>& accessory_windows() const { return m_accessory_windows; } + + void set_accessory(bool accessory) { m_accessory = accessory; } + bool is_accessory() const { return m_accessory; } + bool is_accessory_of(Window&) const; + void set_frameless(bool frameless) { m_frameless = frameless; } bool is_frameless() const { return m_frameless; } @@ -251,12 +258,14 @@ private: void update_menu_item_text(PopupMenuItem item); void update_menu_item_enabled(PopupMenuItem item); void add_child_window(Window&); + void add_accessory_window(Window&); void ensure_window_menu(); ClientConnection* m_client { nullptr }; WeakPtr m_parent_window; Vector> m_child_windows; + Vector> m_accessory_windows; String m_title; Gfx::IntRect m_rect; @@ -275,6 +284,7 @@ private: bool m_minimized { false }; bool m_maximized { false }; bool m_fullscreen { false }; + bool m_accessory { false }; WindowTileType m_tiled { WindowTileType::None }; Gfx::IntRect m_untiled_rect; bool m_occluded { false }; diff --git a/Services/WindowServer/WindowClient.ipc b/Services/WindowServer/WindowClient.ipc index ed0308c79c..53d8dc2747 100644 --- a/Services/WindowServer/WindowClient.ipc +++ b/Services/WindowServer/WindowClient.ipc @@ -8,6 +8,8 @@ endpoint WindowClient = 4 MouseWheel(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =| WindowEntered(i32 window_id) =| WindowLeft(i32 window_id) =| + WindowInputEntered(i32 window_id) =| + WindowInputLeft(i32 window_id) =| KeyDown(i32 window_id, u32 code_point, u32 key, u32 modifiers, u32 scancode) =| KeyUp(i32 window_id, u32 code_point, u32 key, u32 modifiers, u32 scancode) =| WindowActivated(i32 window_id) =| diff --git a/Services/WindowServer/WindowFrame.cpp b/Services/WindowServer/WindowFrame.cpp index 7e1d9fa589..cce040fd87 100644 --- a/Services/WindowServer/WindowFrame.cpp +++ b/Services/WindowServer/WindowFrame.cpp @@ -189,7 +189,7 @@ WindowFrame::FrameColors WindowFrame::compute_frame_colors() const return { palette.highlight_window_title(), palette.highlight_window_border1(), palette.highlight_window_border2() }; if (&m_window == wm.m_move_window) return { palette.moving_window_title(), palette.moving_window_border1(), palette.moving_window_border2() }; - if (&m_window == wm.m_active_window) + if (wm.is_active_window_or_accessory(m_window)) return { palette.active_window_title(), palette.active_window_border1(), palette.active_window_border2() }; return { palette.inactive_window_title(), palette.inactive_window_border1(), palette.inactive_window_border2() }; } diff --git a/Services/WindowServer/WindowManager.cpp b/Services/WindowServer/WindowManager.cpp index 9addfd4a23..06f218930b 100644 --- a/Services/WindowServer/WindowManager.cpp +++ b/Services/WindowServer/WindowManager.cpp @@ -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::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::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::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) { // 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; } } diff --git a/Services/WindowServer/WindowManager.h b/Services/WindowServer/WindowManager.h index 640a719349..89250941c5 100644 --- a/Services/WindowServer/WindowManager.h +++ b/Services/WindowServer/WindowManager.h @@ -145,7 +145,7 @@ public: bool set_resolution(int width, int height); Gfx::IntSize resolution() const; - void set_active_window(Window*); + void set_active_window(Window*, bool make_input = true); void set_hovered_button(Button*); const Button* cursor_tracking_button() const { return m_cursor_tracking_button.ptr(); } @@ -159,6 +159,8 @@ public: void tell_wm_listeners_window_icon_changed(Window&); void tell_wm_listeners_window_rect_changed(Window&); + bool is_active_window_or_accessory(Window&) const; + void start_window_resize(Window&, const Gfx::IntPoint&, MouseButton); void start_window_resize(Window&, const MouseEvent&); @@ -205,7 +207,9 @@ private: void tell_wm_listener_about_window(Window& listener, Window&); void tell_wm_listener_about_window_icon(Window& listener, Window&); void tell_wm_listener_about_window_rect(Window& listener, Window&); - void pick_new_active_window(); + void pick_new_active_window(Window&); + + void do_move_to_front(Window&, bool, bool); RefPtr m_arrow_cursor; RefPtr m_hand_cursor; @@ -262,6 +266,7 @@ private: WeakPtr m_hovered_window; WeakPtr m_highlight_window; WeakPtr m_active_input_window; + WeakPtr m_active_input_tracking_window; WeakPtr m_move_window; Gfx::IntPoint m_move_origin; diff --git a/Services/WindowServer/WindowServer.ipc b/Services/WindowServer/WindowServer.ipc index 8fb0b93318..a0b34bf9ee 100644 --- a/Services/WindowServer/WindowServer.ipc +++ b/Services/WindowServer/WindowServer.ipc @@ -38,6 +38,7 @@ endpoint WindowServer = 2 bool resizable, bool fullscreen, bool frameless, + bool accessory, float opacity, Gfx::IntSize base_size, Gfx::IntSize size_increment,