mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 05:18:12 +00:00
WindowServer: Expose window parent information and more modal improvements
* The parent information is necessary by the Taskbar to be able to determine a modal window's parent * Minimize and maximize modal window stacks together
This commit is contained in:
parent
2f731150a2
commit
bbdf0665fc
8 changed files with 113 additions and 43 deletions
|
@ -114,31 +114,40 @@ public:
|
||||||
|
|
||||||
class WMWindowStateChangedEvent : public WMEvent {
|
class WMWindowStateChangedEvent : public WMEvent {
|
||||||
public:
|
public:
|
||||||
WMWindowStateChangedEvent(int client_id, int window_id, const StringView& title, const Gfx::IntRect& rect, bool is_active, WindowType window_type, bool is_minimized, bool is_frameless, int progress)
|
WMWindowStateChangedEvent(int client_id, int window_id, int parent_client_id, int parent_window_id, const StringView& title, const Gfx::IntRect& rect, bool is_active, bool is_modal, WindowType window_type, bool is_minimized, bool is_frameless, int progress)
|
||||||
: WMEvent(Event::Type::WM_WindowStateChanged, client_id, window_id)
|
: WMEvent(Event::Type::WM_WindowStateChanged, client_id, window_id)
|
||||||
|
, m_parent_client_id(parent_client_id)
|
||||||
|
, m_parent_window_id(parent_window_id)
|
||||||
, m_title(title)
|
, m_title(title)
|
||||||
, m_rect(rect)
|
, m_rect(rect)
|
||||||
, m_window_type(window_type)
|
, m_window_type(window_type)
|
||||||
, m_active(is_active)
|
, m_active(is_active)
|
||||||
|
, m_modal(is_modal)
|
||||||
, m_minimized(is_minimized)
|
, m_minimized(is_minimized)
|
||||||
, m_frameless(is_frameless)
|
, m_frameless(is_frameless)
|
||||||
, m_progress(progress)
|
, m_progress(progress)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int parent_client_id() const { return m_parent_client_id; }
|
||||||
|
int parent_window_id() const { return m_parent_window_id; }
|
||||||
String title() const { return m_title; }
|
String title() const { return m_title; }
|
||||||
Gfx::IntRect rect() const { return m_rect; }
|
Gfx::IntRect rect() const { return m_rect; }
|
||||||
bool is_active() const { return m_active; }
|
bool is_active() const { return m_active; }
|
||||||
|
bool is_modal() const { return m_modal; }
|
||||||
WindowType window_type() const { return m_window_type; }
|
WindowType window_type() const { return m_window_type; }
|
||||||
bool is_minimized() const { return m_minimized; }
|
bool is_minimized() const { return m_minimized; }
|
||||||
bool is_frameless() const { return m_frameless; }
|
bool is_frameless() const { return m_frameless; }
|
||||||
int progress() const { return m_progress; }
|
int progress() const { return m_progress; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int m_parent_client_id;
|
||||||
|
int m_parent_window_id;
|
||||||
String m_title;
|
String m_title;
|
||||||
Gfx::IntRect m_rect;
|
Gfx::IntRect m_rect;
|
||||||
WindowType m_window_type;
|
WindowType m_window_type;
|
||||||
bool m_active;
|
bool m_active;
|
||||||
|
bool m_modal;
|
||||||
bool m_minimized;
|
bool m_minimized;
|
||||||
bool m_frameless;
|
bool m_frameless;
|
||||||
int m_progress;
|
int m_progress;
|
||||||
|
|
|
@ -273,7 +273,7 @@ void WindowServerConnection::handle(const Messages::WindowClient::MenuItemActiva
|
||||||
void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowStateChanged& message)
|
void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowStateChanged& message)
|
||||||
{
|
{
|
||||||
if (auto* window = Window::from_window_id(message.wm_id()))
|
if (auto* window = Window::from_window_id(message.wm_id()))
|
||||||
Core::EventLoop::current().post_event(*window, make<WMWindowStateChangedEvent>(message.client_id(), message.window_id(), message.title(), message.rect(), message.is_active(), static_cast<WindowType>(message.window_type()), message.is_minimized(), message.is_frameless(), message.progress()));
|
Core::EventLoop::current().post_event(*window, make<WMWindowStateChangedEvent>(message.client_id(), message.window_id(), message.parent_client_id(), message.parent_window_id(), message.title(), message.rect(), message.is_active(), message.is_modal(), static_cast<WindowType>(message.window_type()), message.is_minimized(), message.is_frameless(), message.progress()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowRectChanged& message)
|
void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowRectChanged& message)
|
||||||
|
|
|
@ -630,7 +630,7 @@ void ClientConnection::handle(const Messages::WindowServer::WM_SetActiveWindow&
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& window = *(*it).value;
|
auto& window = *(*it).value;
|
||||||
window.set_minimized(false);
|
WindowManager::the().minimize_windows(window, false);
|
||||||
WindowManager::the().move_to_front_and_make_active(window);
|
WindowManager::the().move_to_front_and_make_active(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,7 +647,11 @@ void ClientConnection::handle(const Messages::WindowServer::WM_PopupWindowMenu&
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& window = *(*it).value;
|
auto& window = *(*it).value;
|
||||||
window.popup_window_menu(message.screen_position(), WindowMenuDefaultAction::BasedOnWindowState);
|
if (auto* blocked_by_modal = window.is_blocked_by_modal_window()) {
|
||||||
|
blocked_by_modal->popup_window_menu(message.screen_position(), WindowMenuDefaultAction::BasedOnWindowState);
|
||||||
|
} else {
|
||||||
|
window.popup_window_menu(message.screen_position(), WindowMenuDefaultAction::BasedOnWindowState);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClientConnection::handle(const Messages::WindowServer::WM_StartWindowResize& request)
|
void ClientConnection::handle(const Messages::WindowServer::WM_StartWindowResize& request)
|
||||||
|
@ -681,7 +685,7 @@ void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowMinimize
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto& window = *(*it).value;
|
auto& window = *(*it).value;
|
||||||
window.set_minimized(message.minimized());
|
WindowManager::the().minimize_windows(window, message.minimized());
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnPtr<Messages::WindowServer::GreetResponse> ClientConnection::handle(const Messages::WindowServer::Greet&)
|
OwnPtr<Messages::WindowServer::GreetResponse> ClientConnection::handle(const Messages::WindowServer::Greet&)
|
||||||
|
|
|
@ -214,11 +214,10 @@ void Window::set_minimized(bool minimized)
|
||||||
return;
|
return;
|
||||||
if (minimized && !m_minimizable)
|
if (minimized && !m_minimizable)
|
||||||
return;
|
return;
|
||||||
if (is_blocked_by_modal_window())
|
|
||||||
return;
|
|
||||||
m_minimized = minimized;
|
m_minimized = minimized;
|
||||||
update_menu_item_text(PopupMenuItem::Minimize);
|
update_menu_item_text(PopupMenuItem::Minimize);
|
||||||
start_minimize_animation();
|
if (!is_blocked_by_modal_window())
|
||||||
|
start_minimize_animation();
|
||||||
if (!minimized)
|
if (!minimized)
|
||||||
request_update({ {}, size() });
|
request_update({ {}, size() });
|
||||||
invalidate();
|
invalidate();
|
||||||
|
@ -256,8 +255,6 @@ void Window::set_maximized(bool maximized)
|
||||||
return;
|
return;
|
||||||
if (maximized && !is_resizable())
|
if (maximized && !is_resizable())
|
||||||
return;
|
return;
|
||||||
if (is_blocked_by_modal_window())
|
|
||||||
return;
|
|
||||||
set_tiled(WindowTileType::None);
|
set_tiled(WindowTileType::None);
|
||||||
m_maximized = maximized;
|
m_maximized = maximized;
|
||||||
update_menu_item_text(PopupMenuItem::Maximize);
|
update_menu_item_text(PopupMenuItem::Maximize);
|
||||||
|
@ -446,14 +443,12 @@ void Window::ensure_window_menu()
|
||||||
m_window_menu->on_item_activation = [&](auto& item) {
|
m_window_menu->on_item_activation = [&](auto& item) {
|
||||||
switch (item.identifier()) {
|
switch (item.identifier()) {
|
||||||
case 1:
|
case 1:
|
||||||
set_minimized(!m_minimized);
|
WindowManager::the().minimize_windows(*this, !m_minimized);
|
||||||
if (!m_minimized)
|
if (!m_minimized)
|
||||||
WindowManager::the().move_to_front_and_make_active(*this);
|
WindowManager::the().move_to_front_and_make_active(*this);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
set_maximized(!m_maximized);
|
WindowManager::the().maximize_windows(*this, !m_maximized);
|
||||||
if (m_minimized)
|
|
||||||
set_minimized(false);
|
|
||||||
WindowManager::the().move_to_front_and_make_active(*this);
|
WindowManager::the().move_to_front_and_make_active(*this);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -613,6 +608,23 @@ bool Window::is_accessory_of(Window& window) const
|
||||||
return parent_window() == &window;
|
return parent_window() == &window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::modal_unparented()
|
||||||
|
{
|
||||||
|
m_modal = false;
|
||||||
|
WindowManager::the().notify_modal_unparented(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::is_modal() const
|
||||||
|
{
|
||||||
|
if (!m_modal)
|
||||||
|
return false;
|
||||||
|
if (!m_parent_window) {
|
||||||
|
const_cast<Window*>(this)->modal_unparented();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void Window::set_progress(int progress)
|
void Window::set_progress(int progress)
|
||||||
{
|
{
|
||||||
if (m_progress == progress)
|
if (m_progress == progress)
|
||||||
|
|
|
@ -145,7 +145,8 @@ public:
|
||||||
bool is_visible() const { return m_visible; }
|
bool is_visible() const { return m_visible; }
|
||||||
void set_visible(bool);
|
void set_visible(bool);
|
||||||
|
|
||||||
bool is_modal() const { return m_modal && m_parent_window; }
|
bool is_modal() const;
|
||||||
|
bool is_modal_dont_unparent() const { return m_modal && m_parent_window; }
|
||||||
|
|
||||||
Gfx::IntRect rect() const { return m_rect; }
|
Gfx::IntRect rect() const { return m_rect; }
|
||||||
void set_rect(const Gfx::IntRect&);
|
void set_rect(const Gfx::IntRect&);
|
||||||
|
@ -260,6 +261,7 @@ private:
|
||||||
void add_child_window(Window&);
|
void add_child_window(Window&);
|
||||||
void add_accessory_window(Window&);
|
void add_accessory_window(Window&);
|
||||||
void ensure_window_menu();
|
void ensure_window_menu();
|
||||||
|
void modal_unparented();
|
||||||
|
|
||||||
ClientConnection* m_client { nullptr };
|
ClientConnection* m_client { nullptr };
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ endpoint WindowClient = 4
|
||||||
ScreenRectChanged(Gfx::IntRect rect) =|
|
ScreenRectChanged(Gfx::IntRect rect) =|
|
||||||
|
|
||||||
WM_WindowRemoved(i32 wm_id, i32 client_id, i32 window_id) =|
|
WM_WindowRemoved(i32 wm_id, i32 client_id, i32 window_id) =|
|
||||||
WM_WindowStateChanged(i32 wm_id, i32 client_id, i32 window_id, bool is_active, bool is_minimized, bool is_frameless, i32 window_type, [UTF8] String title, Gfx::IntRect rect, i32 progress) =|
|
WM_WindowStateChanged(i32 wm_id, i32 client_id, i32 window_id, i32 parent_client_id, i32 parent_window_id, bool is_active, bool is_minimized, bool is_modal, bool is_frameless, i32 window_type, [UTF8] String title, Gfx::IntRect rect, i32 progress) =|
|
||||||
WM_WindowIconBitmapChanged(i32 wm_id, i32 client_id, i32 window_id, i32 icon_buffer_id, Gfx::IntSize icon_size) =|
|
WM_WindowIconBitmapChanged(i32 wm_id, i32 client_id, i32 window_id, i32 icon_buffer_id, Gfx::IntSize icon_size) =|
|
||||||
WM_WindowRectChanged(i32 wm_id, i32 client_id, i32 window_id, Gfx::IntRect rect) =|
|
WM_WindowRectChanged(i32 wm_id, i32 client_id, i32 window_id, Gfx::IntRect rect) =|
|
||||||
|
|
||||||
|
|
|
@ -220,31 +220,14 @@ void WindowManager::move_to_front_and_make_active(Window& window)
|
||||||
do_move_to_front(wnd, make_active, make_input);
|
do_move_to_front(wnd, make_active, make_input);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto* blocking_modal_window = window.is_blocked_by_modal_window();
|
// If a window that is currently blocked by a modal child is being
|
||||||
if (blocking_modal_window || window.is_modal()) {
|
// brought to the front, bring the entire stack of modal windows
|
||||||
// If a window that is currently blocked by a modal child is being
|
// to the front and activate the modal window. Also set the
|
||||||
// brought to the front, bring the entire stack of modal windows
|
// active input window to that same window (which would pull
|
||||||
// to the front and activate the modal window. Also set the
|
// active input from any accessory window)
|
||||||
// active input window to that same window (which would pull
|
for_each_window_in_modal_stack(window, [&](auto& w, bool is_stack_top) {
|
||||||
// active input from any accessory window)
|
move_window_to_front(w, is_stack_top, is_stack_top);
|
||||||
Vector<Window*> modal_stack;
|
});
|
||||||
auto* modal_stack_top = blocking_modal_window ? blocking_modal_window : &window;
|
|
||||||
for (auto* parent = modal_stack_top->parent_window(); parent; parent = parent->parent_window()) {
|
|
||||||
if (parent->is_blocked_by_modal_window() != blocking_modal_window)
|
|
||||||
break;
|
|
||||||
modal_stack.append(parent);
|
|
||||||
if (!parent->is_modal())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (!modal_stack.is_empty()) {
|
|
||||||
for (size_t i = modal_stack.size(); i > 0; i--) {
|
|
||||||
move_window_to_front(*modal_stack[i - 1], false, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
move_window_to_front(*modal_stack_top, true, true);
|
|
||||||
} else {
|
|
||||||
move_window_to_front(window, true, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::do_move_to_front(Window& window, bool make_active, bool make_input)
|
void WindowManager::do_move_to_front(Window& window, bool make_active, bool make_input)
|
||||||
|
@ -287,7 +270,7 @@ void WindowManager::remove_window(Window& window)
|
||||||
for_each_window_listening_to_wm_events([&window](Window& listener) {
|
for_each_window_listening_to_wm_events([&window](Window& listener) {
|
||||||
if (!(listener.wm_event_mask() & WMEventMask::WindowRemovals))
|
if (!(listener.wm_event_mask() & WMEventMask::WindowRemovals))
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
if (!window.is_internal())
|
if (!window.is_internal() && !window.is_modal())
|
||||||
listener.client()->post_message(Messages::WindowClient::WM_WindowRemoved(listener.window_id(), window.client_id(), window.window_id()));
|
listener.client()->post_message(Messages::WindowClient::WM_WindowRemoved(listener.window_id(), window.client_id(), window.window_id()));
|
||||||
return IterationDecision::Continue;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
@ -299,7 +282,8 @@ void WindowManager::tell_wm_listener_about_window(Window& listener, Window& wind
|
||||||
return;
|
return;
|
||||||
if (window.is_internal())
|
if (window.is_internal())
|
||||||
return;
|
return;
|
||||||
listener.client()->post_message(Messages::WindowClient::WM_WindowStateChanged(listener.window_id(), window.client_id(), window.window_id(), window.is_active(), window.is_minimized(), window.is_frameless(), (i32)window.type(), window.title(), window.rect(), window.progress()));
|
auto* parent = window.parent_window();
|
||||||
|
listener.client()->post_message(Messages::WindowClient::WM_WindowStateChanged(listener.window_id(), window.client_id(), window.window_id(), parent ? parent->client_id() : -1, parent ? parent->window_id() : -1, window.is_active(), window.is_minimized(), window.is_modal_dont_unparent(), window.is_frameless(), (i32)window.type(), window.title(), window.rect(), window.progress()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void WindowManager::tell_wm_listener_about_window_rect(Window& listener, Window& window)
|
void WindowManager::tell_wm_listener_about_window_rect(Window& listener, Window& window)
|
||||||
|
@ -366,6 +350,19 @@ void WindowManager::notify_title_changed(Window& window)
|
||||||
tell_wm_listeners_window_state_changed(window);
|
tell_wm_listeners_window_state_changed(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::notify_modal_unparented(Window& window)
|
||||||
|
{
|
||||||
|
if (window.type() != WindowType::Normal)
|
||||||
|
return;
|
||||||
|
#ifdef WINDOWMANAGER_DEBUG
|
||||||
|
dbg() << "[WM] Modal Window{" << &window << "} was unparented";
|
||||||
|
#endif
|
||||||
|
if (m_switcher.is_visible())
|
||||||
|
m_switcher.refresh();
|
||||||
|
|
||||||
|
tell_wm_listeners_window_state_changed(window);
|
||||||
|
}
|
||||||
|
|
||||||
void WindowManager::notify_rect_changed(Window& window, const Gfx::IntRect& old_rect, const Gfx::IntRect& new_rect)
|
void WindowManager::notify_rect_changed(Window& window, const Gfx::IntRect& old_rect, const Gfx::IntRect& new_rect)
|
||||||
{
|
{
|
||||||
UNUSED_PARAM(old_rect);
|
UNUSED_PARAM(old_rect);
|
||||||
|
@ -1405,4 +1402,20 @@ void WindowManager::did_popup_a_menu(Badge<Menu>)
|
||||||
m_active_input_tracking_window = nullptr;
|
m_active_input_tracking_window = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WindowManager::minimize_windows(Window& window, bool minimized)
|
||||||
|
{
|
||||||
|
for_each_window_in_modal_stack(window, [&](auto& w, bool) {
|
||||||
|
w.set_minimized(minimized);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void WindowManager::maximize_windows(Window& window, bool maximized)
|
||||||
|
{
|
||||||
|
for_each_window_in_modal_stack(window, [&](auto& w, bool) {
|
||||||
|
w.set_maximized(maximized);
|
||||||
|
if (w.is_minimized())
|
||||||
|
w.set_minimized(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,6 +88,7 @@ public:
|
||||||
void remove_window(Window&);
|
void remove_window(Window&);
|
||||||
|
|
||||||
void notify_title_changed(Window&);
|
void notify_title_changed(Window&);
|
||||||
|
void notify_modal_unparented(Window&);
|
||||||
void notify_rect_changed(Window&, const Gfx::IntRect& oldRect, const Gfx::IntRect& newRect);
|
void notify_rect_changed(Window&, const Gfx::IntRect& oldRect, const Gfx::IntRect& newRect);
|
||||||
void notify_minimization_state_changed(Window&);
|
void notify_minimization_state_changed(Window&);
|
||||||
void notify_opacity_changed(Window&);
|
void notify_opacity_changed(Window&);
|
||||||
|
@ -181,6 +182,35 @@ public:
|
||||||
void start_menu_doubleclick(Window& window, const MouseEvent& event);
|
void start_menu_doubleclick(Window& window, const MouseEvent& event);
|
||||||
bool is_menu_doubleclick(Window& window, const MouseEvent& event) const;
|
bool is_menu_doubleclick(Window& window, const MouseEvent& event) const;
|
||||||
|
|
||||||
|
void minimize_windows(Window&, bool);
|
||||||
|
void maximize_windows(Window&, bool);
|
||||||
|
|
||||||
|
template<typename Function>
|
||||||
|
void for_each_window_in_modal_stack(Window& window, Function f)
|
||||||
|
{
|
||||||
|
auto* blocking_modal_window = window.is_blocked_by_modal_window();
|
||||||
|
if (blocking_modal_window || window.is_modal()) {
|
||||||
|
Vector<Window*> modal_stack;
|
||||||
|
auto* modal_stack_top = blocking_modal_window ? blocking_modal_window : &window;
|
||||||
|
for (auto* parent = modal_stack_top->parent_window(); parent; parent = parent->parent_window()) {
|
||||||
|
if (parent->is_blocked_by_modal_window() != modal_stack_top)
|
||||||
|
break;
|
||||||
|
modal_stack.append(parent);
|
||||||
|
if (!parent->is_modal())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!modal_stack.is_empty()) {
|
||||||
|
for (size_t i = modal_stack.size(); i > 0; i--) {
|
||||||
|
f(*modal_stack[i - 1], false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f(*modal_stack_top, true);
|
||||||
|
} else {
|
||||||
|
// Not a modal window stack, just "iterate" over this window
|
||||||
|
f(window, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NonnullRefPtr<Cursor> get_cursor(const String& name);
|
NonnullRefPtr<Cursor> get_cursor(const String& name);
|
||||||
NonnullRefPtr<Cursor> get_cursor(const String& name, const Gfx::IntPoint& hotspot);
|
NonnullRefPtr<Cursor> get_cursor(const String& name, const Gfx::IntPoint& hotspot);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue