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
Notes:
sideshowbarker
2024-07-19 04:48:19 +09:00
Author: https://github.com/tomuta Commit: https://github.com/SerenityOS/serenity/commit/ec3737510da Pull-request: https://github.com/SerenityOS/serenity/pull/2805
16 changed files with 216 additions and 59 deletions
|
@ -99,8 +99,17 @@ ComboBox::ComboBox()
|
|||
open();
|
||||
};
|
||||
|
||||
m_list_window = add<Window>();
|
||||
m_list_window = add<Window>(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);
|
||||
|
|
|
@ -57,6 +57,8 @@ public:
|
|||
WindowLeft,
|
||||
WindowBecameInactive,
|
||||
WindowBecameActive,
|
||||
WindowInputEntered,
|
||||
WindowInputLeft,
|
||||
FocusIn,
|
||||
FocusOut,
|
||||
WindowCloseRequest,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -98,6 +98,7 @@ public:
|
|||
};
|
||||
|
||||
Function<CloseRequestDecision()> on_close_request;
|
||||
Function<void(bool is_active_input)> on_active_input_change;
|
||||
Function<void(const bool is_active)> 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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -106,6 +106,18 @@ void WindowServerConnection::handle(const Messages::WindowClient::WindowDeactiva
|
|||
Core::EventLoop::current().post_event(*window, make<Event>(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>(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>(Event::WindowInputLeft));
|
||||
}
|
||||
|
||||
void WindowServerConnection::handle(const Messages::WindowClient::WindowCloseRequest& message)
|
||||
{
|
||||
if (auto* window = Window::from_window_id(message.window_id()))
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -434,22 +434,18 @@ Window* ClientConnection::window_from_id(i32 window_id)
|
|||
|
||||
OwnPtr<Messages::WindowServer::CreateWindowResponse> 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()) {
|
||||
|
|
|
@ -50,6 +50,8 @@ public:
|
|||
KeyUp,
|
||||
WindowActivated,
|
||||
WindowDeactivated,
|
||||
WindowInputEntered,
|
||||
WindowInputLeft,
|
||||
WindowCloseRequest,
|
||||
WindowResized,
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -76,7 +76,7 @@ class Window final : public Core::Object
|
|||
, public InlineLinkedListNode<Window> {
|
||||
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<WeakPtr<Window>>& child_windows() { return m_child_windows; }
|
||||
const Vector<WeakPtr<Window>>& child_windows() const { return m_child_windows; }
|
||||
|
||||
Vector<WeakPtr<Window>>& accessory_windows() { return m_accessory_windows; }
|
||||
const Vector<WeakPtr<Window>>& 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<Window> m_parent_window;
|
||||
Vector<WeakPtr<Window>> m_child_windows;
|
||||
Vector<WeakPtr<Window>> 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 };
|
||||
|
|
|
@ -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) =|
|
||||
|
|
|
@ -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() };
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Cursor> m_arrow_cursor;
|
||||
RefPtr<Cursor> m_hand_cursor;
|
||||
|
@ -262,6 +266,7 @@ private:
|
|||
WeakPtr<Window> m_hovered_window;
|
||||
WeakPtr<Window> m_highlight_window;
|
||||
WeakPtr<Window> m_active_input_window;
|
||||
WeakPtr<Window> m_active_input_tracking_window;
|
||||
|
||||
WeakPtr<Window> m_move_window;
|
||||
Gfx::IntPoint m_move_origin;
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue