mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:17:45 +00:00
WindowServer: Add basic virtual desktop support
This creates a 2-dimensional array of WindowStack instances, one for each virtual desktop. The main desktop 0,0 is the main desktop, which is the desktop used for all stationary windows (e.g. taskbar, desktop). When adding windows to a desktop, stationary windows are always added to the main desktop. When composing the desktop, there are usually two WindowStacks involved. For stationary windows, the main desktop will be traversed, and for everything else the current virtual desktop will be iterated. Iteration is interweaved to preserve the correct order. During the transition animation, two WindowStacks will be iterated at the same time.
This commit is contained in:
parent
944e5cfb35
commit
584b144953
11 changed files with 900 additions and 213 deletions
|
@ -39,6 +39,26 @@ WindowManager::WindowManager(Gfx::PaletteImpl const& palette)
|
|||
{
|
||||
s_the = this;
|
||||
|
||||
{
|
||||
// Create the default window stacks
|
||||
auto row_count = m_window_stacks.capacity();
|
||||
VERIFY(row_count > 0);
|
||||
for (size_t row_index = 0; row_index < row_count; row_index++) {
|
||||
auto row = adopt_own(*new RemoveReference<decltype(m_window_stacks[0])>());
|
||||
auto column_count = row->capacity();
|
||||
VERIFY(column_count > 0);
|
||||
for (size_t column_index = 0; column_index < column_count; column_index++)
|
||||
row->append(adopt_own(*new WindowStack(row_index, column_index)));
|
||||
m_window_stacks.append(move(row));
|
||||
}
|
||||
|
||||
m_current_window_stack = &m_window_stacks[0][0];
|
||||
for (auto& row : m_window_stacks) {
|
||||
for (auto& stack : row)
|
||||
stack.set_stationary_window_stack(*m_current_window_stack);
|
||||
}
|
||||
}
|
||||
|
||||
reload_config();
|
||||
|
||||
Compositor::the().did_construct_window_manager({});
|
||||
|
@ -123,9 +143,12 @@ bool WindowManager::set_screen_layout(ScreenLayout&& screen_layout, bool save, S
|
|||
client.notify_about_new_screen_rects(Screen::rects(), Screen::main().index());
|
||||
});
|
||||
|
||||
m_window_stack.for_each_window([](Window& window) {
|
||||
window.screens().clear_with_capacity();
|
||||
window.recalculate_rect();
|
||||
for_each_window_stack([&](auto& window_stack) {
|
||||
window_stack.for_each_window([](Window& window) {
|
||||
window.screens().clear_with_capacity();
|
||||
window.recalculate_rect();
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
|
@ -178,11 +201,23 @@ int WindowManager::double_click_speed() const
|
|||
return m_double_click_speed;
|
||||
}
|
||||
|
||||
WindowStack& WindowManager::window_stack_for_window(Window& window)
|
||||
{
|
||||
if (is_stationary_window_type(window.type()))
|
||||
return m_window_stacks[0][0];
|
||||
if (auto* parent = window.parent_window(); parent && !is_stationary_window_type(parent->type())) {
|
||||
if (auto* parent_window_stack = parent->outer_stack())
|
||||
return *parent_window_stack;
|
||||
}
|
||||
return current_window_stack();
|
||||
}
|
||||
|
||||
void WindowManager::add_window(Window& window)
|
||||
{
|
||||
bool is_first_window = m_window_stack.is_empty();
|
||||
auto& window_stack = window_stack_for_window(window);
|
||||
bool is_first_window = window_stack.is_empty();
|
||||
|
||||
m_window_stack.add(window);
|
||||
window_stack.add(window);
|
||||
|
||||
if (window.is_fullscreen()) {
|
||||
auto& screen = Screen::main(); // TODO: support fullscreen windows on other screens!
|
||||
|
@ -235,7 +270,9 @@ void WindowManager::move_to_front_and_make_active(Window& window)
|
|||
|
||||
void WindowManager::do_move_to_front(Window& window, bool make_active, bool make_input)
|
||||
{
|
||||
m_window_stack.move_to_front(window);
|
||||
auto* window_stack = window.outer_stack();
|
||||
VERIFY(window_stack);
|
||||
window_stack->move_to_front(window);
|
||||
|
||||
if (make_active)
|
||||
set_active_window(&window, make_input);
|
||||
|
@ -256,11 +293,11 @@ void WindowManager::do_move_to_front(Window& window, bool make_active, bool make
|
|||
|
||||
void WindowManager::remove_window(Window& window)
|
||||
{
|
||||
|
||||
check_hide_geometry_overlay(window);
|
||||
m_window_stack.remove(window);
|
||||
auto* active = active_window();
|
||||
auto* active_input = active_input_window();
|
||||
if (auto* window_stack = window.outer_stack())
|
||||
window_stack->remove(window);
|
||||
if (active == &window || active_input == &window || (active && window.is_descendant_of(*active)) || (active_input && active_input != active && window.is_descendant_of(*active_input)))
|
||||
pick_new_active_window(&window);
|
||||
|
||||
|
@ -285,11 +322,14 @@ void WindowManager::greet_window_manager(WMClientConnection& conn)
|
|||
if (conn.window_id() < 0)
|
||||
return;
|
||||
|
||||
m_window_stack.for_each_window([&](Window& other_window) {
|
||||
//if (conn.window_id() != other_window.window_id()) {
|
||||
tell_wm_about_window(conn, other_window);
|
||||
tell_wm_about_window_icon(conn, other_window);
|
||||
//}
|
||||
for_each_window_stack([&](auto& window_stack) {
|
||||
window_stack.for_each_window([&](Window& other_window) {
|
||||
//if (conn.window_id() != other_window.window_id()) {
|
||||
tell_wm_about_window(conn, other_window);
|
||||
tell_wm_about_window_icon(conn, other_window);
|
||||
//}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
if (auto* applet_area_window = AppletManager::the().window())
|
||||
|
@ -473,7 +513,8 @@ bool WindowManager::pick_new_active_window(Window* previous_active)
|
|||
{
|
||||
bool new_window_picked = false;
|
||||
Window* first_candidate = nullptr;
|
||||
m_window_stack.for_each_visible_window_from_front_to_back([&](Window& candidate) {
|
||||
|
||||
for_each_visible_window_from_front_to_back([&](Window& candidate) {
|
||||
if (candidate.type() != WindowType::Normal && candidate.type() != WindowType::ToolWindow)
|
||||
return IterationDecision::Continue;
|
||||
if (candidate.is_destroyed())
|
||||
|
@ -555,7 +596,7 @@ void WindowManager::start_window_resize(Window& window, Gfx::IntPoint const& pos
|
|||
m_geometry_overlay = Compositor::the().create_overlay<WindowGeometryOverlay>(window);
|
||||
m_geometry_overlay->set_enabled(true);
|
||||
|
||||
m_active_input_tracking_window = nullptr;
|
||||
current_window_stack().set_active_input_tracking_window(nullptr);
|
||||
|
||||
window.invalidate(true, true);
|
||||
|
||||
|
@ -803,7 +844,7 @@ bool WindowManager::process_ongoing_drag(MouseEvent& event)
|
|||
m_dnd_overlay->cursor_moved();
|
||||
|
||||
// We didn't let go of the drag yet, see if we should send some drag move events..
|
||||
m_window_stack.for_each_visible_window_from_front_to_back([&](Window& window) {
|
||||
for_each_visible_window_from_front_to_back([&](Window& window) {
|
||||
if (!window.rect().contains(event.position()))
|
||||
return IterationDecision::Continue;
|
||||
event.set_drag(true);
|
||||
|
@ -816,7 +857,7 @@ bool WindowManager::process_ongoing_drag(MouseEvent& event)
|
|||
if (!(event.type() == Event::MouseUp && event.button() == MouseButton::Left))
|
||||
return true;
|
||||
|
||||
if (auto* window = m_window_stack.window_at(event.position())) {
|
||||
if (auto* window = current_window_stack().window_at(event.position())) {
|
||||
m_dnd_client->async_drag_accepted();
|
||||
if (window->client()) {
|
||||
auto translated_event = event.translated(-window->position());
|
||||
|
@ -971,7 +1012,9 @@ void WindowManager::deliver_mouse_event(Window& window, MouseEvent const& event,
|
|||
|
||||
bool WindowManager::process_ongoing_active_input_mouse_event(MouseEvent const& event)
|
||||
{
|
||||
if (!m_active_input_tracking_window)
|
||||
auto& window_stack = current_window_stack();
|
||||
auto* input_tracking_window = window_stack.active_input_tracking_window();
|
||||
if (!input_tracking_window)
|
||||
return false;
|
||||
|
||||
// At this point, we have delivered the start of an input sequence to a
|
||||
|
@ -980,11 +1023,10 @@ bool WindowManager::process_ongoing_active_input_mouse_event(MouseEvent const& e
|
|||
//
|
||||
// This prevents e.g. moving on one window out of the bounds starting
|
||||
// a move in that other unrelated window, and other silly shenanigans.
|
||||
deliver_mouse_event(*m_active_input_tracking_window, event, true);
|
||||
deliver_mouse_event(*input_tracking_window, event, true);
|
||||
|
||||
if (event.type() == Event::MouseUp && event.buttons() == 0) {
|
||||
m_active_input_tracking_window = nullptr;
|
||||
}
|
||||
if (event.type() == Event::MouseUp && event.buttons() == 0)
|
||||
window_stack.set_active_input_tracking_window(nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1049,7 +1091,7 @@ void WindowManager::process_mouse_event_for_window(HitTestResult& result, MouseE
|
|||
}
|
||||
|
||||
if (event.type() == Event::MouseDown)
|
||||
m_active_input_tracking_window = window;
|
||||
current_window_stack().set_active_input_tracking_window(&window);
|
||||
}
|
||||
|
||||
void WindowManager::process_mouse_event(MouseEvent& event)
|
||||
|
@ -1065,8 +1107,9 @@ void WindowManager::process_mouse_event(MouseEvent& event)
|
|||
// 2. Send the mouse event to all windows with global cursor tracking enabled.
|
||||
// The active input tracking window is excluded here because we're sending the event to it
|
||||
// in the next step.
|
||||
m_window_stack.for_each_visible_window_from_front_to_back([&](Window& window) {
|
||||
if (window.global_cursor_tracking() && &window != m_active_input_tracking_window)
|
||||
auto& window_stack = current_window_stack();
|
||||
for_each_visible_window_from_front_to_back([&](Window& window) {
|
||||
if (window.global_cursor_tracking() && &window != window_stack.active_input_tracking_window())
|
||||
deliver_mouse_event(window, event, false);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
@ -1112,7 +1155,7 @@ void WindowManager::process_mouse_event(MouseEvent& event)
|
|||
}
|
||||
|
||||
// 8. Hit test the window stack to see what's under the cursor.
|
||||
auto result = m_window_stack.hit_test(event.position());
|
||||
auto result = current_window_stack().hit_test(event.position());
|
||||
|
||||
if (!result.has_value()) {
|
||||
// No window is under the cursor.
|
||||
|
@ -1144,7 +1187,7 @@ void WindowManager::reevaluate_hovered_window(Window* updated_window)
|
|||
if (fullscreen_window->hit_test(cursor_location).has_value())
|
||||
hovered_window = fullscreen_window;
|
||||
} else {
|
||||
hovered_window = m_window_stack.window_at(cursor_location);
|
||||
hovered_window = current_window_stack().window_at(cursor_location);
|
||||
}
|
||||
|
||||
if (set_hovered_window(hovered_window)) {
|
||||
|
@ -1213,7 +1256,8 @@ void WindowManager::event(Core::Event& event)
|
|||
m_previous_event_was_super_keydown = false;
|
||||
|
||||
process_mouse_event(mouse_event);
|
||||
set_hovered_window(m_window_stack.window_at(mouse_event.position(), WindowStack::IncludeWindowFrame::No));
|
||||
// TODO: handle transitioning between two stacks
|
||||
set_hovered_window(current_window_stack().window_at(mouse_event.position(), WindowStack::IncludeWindowFrame::No));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1225,6 +1269,117 @@ void WindowManager::event(Core::Event& event)
|
|||
Core::Object::event(event);
|
||||
}
|
||||
|
||||
bool WindowManager::is_window_in_modal_stack(Window& window_in_modal_stack, Window& other_window)
|
||||
{
|
||||
auto result = for_each_window_in_modal_stack(window_in_modal_stack, [&](auto& window, auto) {
|
||||
if (&other_window == &window)
|
||||
return IterationDecision::Break;
|
||||
for (auto& accessory : window.accessory_windows()) {
|
||||
if (accessory.ptr() == &other_window)
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return result == IterationDecision::Break;
|
||||
}
|
||||
|
||||
void WindowManager::switch_to_window_stack(WindowStack& window_stack, Window* carry_window)
|
||||
{
|
||||
m_carry_window_to_new_stack.clear();
|
||||
m_switching_to_window_stack = &window_stack;
|
||||
if (carry_window && !is_stationary_window_type(carry_window->type()) && carry_window->outer_stack() != &window_stack) {
|
||||
auto& from_stack = *carry_window->outer_stack();
|
||||
|
||||
auto* blocking_modal = carry_window->blocking_modal_window();
|
||||
for_each_visible_window_from_back_to_front([&](Window& window) {
|
||||
if (is_stationary_window_type(window.type()))
|
||||
return IterationDecision::Continue;
|
||||
|
||||
if (window.outer_stack() != carry_window->outer_stack())
|
||||
return IterationDecision::Continue;
|
||||
if (&window == carry_window || ((carry_window->is_modal() || blocking_modal) && is_window_in_modal_stack(*carry_window, window)))
|
||||
m_carry_window_to_new_stack.append(window);
|
||||
return IterationDecision::Continue;
|
||||
},
|
||||
&from_stack);
|
||||
|
||||
auto* from_active_window = from_stack.active_window();
|
||||
auto* from_active_input_window = from_stack.active_input_window();
|
||||
bool did_carry_active_window = false;
|
||||
bool did_carry_active_input_window = false;
|
||||
for (auto& window : m_carry_window_to_new_stack) {
|
||||
if (window == from_active_window)
|
||||
did_carry_active_window = true;
|
||||
if (window == from_active_input_window)
|
||||
did_carry_active_input_window = true;
|
||||
window->set_moving_to_another_stack(true);
|
||||
VERIFY(window->outer_stack() == &from_stack);
|
||||
from_stack.remove(*window);
|
||||
window_stack.add(*window);
|
||||
}
|
||||
// Before we change to the new stack, find a new active window on the stack we're switching from
|
||||
if (did_carry_active_window || did_carry_active_input_window)
|
||||
pick_new_active_window(from_active_window);
|
||||
|
||||
// Now switch to the new stack
|
||||
m_current_window_stack = &window_stack;
|
||||
if (did_carry_active_window && from_active_window)
|
||||
set_active_window(from_active_window, from_active_input_window == from_active_window);
|
||||
if (did_carry_active_input_window && from_active_input_window && from_active_input_window != from_active_window)
|
||||
set_active_input_window(from_active_input_window);
|
||||
|
||||
// Because we moved windows between stacks we need to invalidate occlusions
|
||||
Compositor::the().invalidate_occlusions();
|
||||
} else {
|
||||
m_current_window_stack = &window_stack;
|
||||
}
|
||||
|
||||
Compositor::the().switch_to_window_stack(window_stack);
|
||||
}
|
||||
|
||||
void WindowManager::did_switch_window_stack(Badge<Compositor>, WindowStack& previous_stack, WindowStack& new_stack)
|
||||
{
|
||||
VERIFY(&previous_stack != &new_stack);
|
||||
|
||||
// We are being notified by the compositor, it should not be switching right now!
|
||||
VERIFY(!Compositor::the().is_switching_window_stacks());
|
||||
VERIFY(¤t_window_stack() == &new_stack);
|
||||
|
||||
if (m_switching_to_window_stack == &new_stack) {
|
||||
m_switching_to_window_stack = nullptr;
|
||||
if (!m_carry_window_to_new_stack.is_empty()) {
|
||||
// switched_to_stack may be different from the stack where the windows were
|
||||
// carried to when the user rapidly tries to switch stacks, so make sure to
|
||||
// only reset the moving flag if we arrived at our final destination
|
||||
for (auto& window_ref : m_carry_window_to_new_stack) {
|
||||
if (auto* window = window_ref.ptr())
|
||||
window->set_moving_to_another_stack(false);
|
||||
}
|
||||
m_carry_window_to_new_stack.clear();
|
||||
}
|
||||
}
|
||||
|
||||
auto* previous_stack_active_window = previous_stack.active_window();
|
||||
auto* previous_stack_active_input_window = previous_stack.active_input_window();
|
||||
auto* new_stack_active_window = new_stack.active_window();
|
||||
auto* new_stack_active_input_window = new_stack.active_input_window();
|
||||
if (previous_stack_active_input_window && previous_stack_active_input_window != new_stack_active_input_window)
|
||||
notify_previous_active_input_window(*previous_stack_active_input_window);
|
||||
if (new_stack_active_input_window && previous_stack_active_input_window != new_stack_active_input_window)
|
||||
notify_new_active_input_window(*new_stack_active_input_window);
|
||||
if (previous_stack_active_window != new_stack_active_window) {
|
||||
if (previous_stack_active_window && is_stationary_window_type(previous_stack_active_window->type()))
|
||||
notify_previous_active_window(*previous_stack_active_window);
|
||||
if (new_stack_active_window && is_stationary_window_type(new_stack_active_window->type()))
|
||||
notify_new_active_window(*new_stack_active_window);
|
||||
}
|
||||
|
||||
if (!new_stack_active_input_window)
|
||||
pick_new_active_window(nullptr);
|
||||
|
||||
reevaluate_hovered_window();
|
||||
}
|
||||
|
||||
void WindowManager::process_key_event(KeyEvent& event)
|
||||
{
|
||||
m_keyboard_modifiers = event.modifiers();
|
||||
|
@ -1258,7 +1413,7 @@ void WindowManager::process_key_event(KeyEvent& event)
|
|||
m_previous_event_was_super_keydown = true;
|
||||
} else if (m_previous_event_was_super_keydown) {
|
||||
m_previous_event_was_super_keydown = false;
|
||||
if (!m_dnd_client && !m_active_input_tracking_window && event.type() == Event::KeyUp && event.key() == Key_Super) {
|
||||
if (!m_dnd_client && !current_window_stack().active_input_tracking_window() && event.type() == Event::KeyUp && event.key() == Key_Super) {
|
||||
tell_wms_super_key_pressed();
|
||||
return;
|
||||
}
|
||||
|
@ -1281,59 +1436,110 @@ void WindowManager::process_key_event(KeyEvent& event)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!m_active_input_window)
|
||||
return;
|
||||
|
||||
if (event.type() == Event::KeyDown && event.modifiers() == Mod_Super && m_active_input_window->type() != WindowType::Desktop) {
|
||||
if (event.key() == Key_Down) {
|
||||
if (m_active_input_window->is_resizable() && m_active_input_window->is_maximized()) {
|
||||
maximize_windows(*m_active_input_window, false);
|
||||
return;
|
||||
if (event.type() == Event::KeyDown && (event.modifiers() == (Mod_Ctrl | Mod_Alt) || event.modifiers() == (Mod_Ctrl | Mod_Shift | Mod_Alt)) && (window_stack_columns() > 1 || window_stack_rows() > 1)) {
|
||||
auto& current_stack = current_window_stack();
|
||||
auto row = current_stack.row();
|
||||
auto column = current_stack.column();
|
||||
auto handle_window_stack_switch_key = [&]() {
|
||||
switch (event.key()) {
|
||||
case Key_Left:
|
||||
if (column == 0)
|
||||
return true;
|
||||
column--;
|
||||
return true;
|
||||
case Key_Right:
|
||||
if (column + 1 >= m_window_stacks[0].size())
|
||||
return true;
|
||||
column++;
|
||||
return true;
|
||||
case Key_Up:
|
||||
if (row == 0)
|
||||
return true;
|
||||
row--;
|
||||
return true;
|
||||
case Key_Down:
|
||||
if (row + 1 >= m_window_stacks.size())
|
||||
return true;
|
||||
row++;
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (m_active_input_window->is_minimizable())
|
||||
minimize_windows(*m_active_input_window, true);
|
||||
};
|
||||
if (handle_window_stack_switch_key()) {
|
||||
Window* carry_window = nullptr;
|
||||
auto& new_window_stack = m_window_stacks[row][column];
|
||||
if (&new_window_stack != ¤t_stack) {
|
||||
if (event.modifiers() == (Mod_Ctrl | Mod_Shift | Mod_Alt))
|
||||
carry_window = this->active_window();
|
||||
}
|
||||
// Call switch_to_window_stack even if we're not going to switch to another stack.
|
||||
// We'll show the window stack switch overlay briefly!
|
||||
switch_to_window_stack(new_window_stack, carry_window);
|
||||
return;
|
||||
}
|
||||
if (m_active_input_window->is_resizable()) {
|
||||
}
|
||||
|
||||
auto* active_input_window = current_window_stack().active_input_window();
|
||||
if (!active_input_window)
|
||||
return;
|
||||
|
||||
if (event.type() == Event::KeyDown && event.modifiers() == Mod_Super && active_input_window->type() != WindowType::Desktop) {
|
||||
if (event.key() == Key_Down) {
|
||||
if (active_input_window->is_resizable() && active_input_window->is_maximized()) {
|
||||
maximize_windows(*active_input_window, false);
|
||||
return;
|
||||
}
|
||||
if (active_input_window->is_minimizable())
|
||||
minimize_windows(*active_input_window, true);
|
||||
return;
|
||||
}
|
||||
if (active_input_window->is_resizable()) {
|
||||
if (event.key() == Key_Up) {
|
||||
maximize_windows(*m_active_input_window, !m_active_input_window->is_maximized());
|
||||
maximize_windows(*active_input_window, !active_input_window->is_maximized());
|
||||
return;
|
||||
}
|
||||
if (event.key() == Key_Left) {
|
||||
if (m_active_input_window->tiled() == WindowTileType::Left)
|
||||
if (active_input_window->tiled() == WindowTileType::Left)
|
||||
return;
|
||||
if (m_active_input_window->tiled() != WindowTileType::None) {
|
||||
m_active_input_window->set_untiled();
|
||||
if (active_input_window->tiled() != WindowTileType::None) {
|
||||
active_input_window->set_untiled();
|
||||
return;
|
||||
}
|
||||
if (m_active_input_window->is_maximized())
|
||||
maximize_windows(*m_active_input_window, false);
|
||||
m_active_input_window->set_tiled(nullptr, WindowTileType::Left);
|
||||
if (active_input_window->is_maximized())
|
||||
maximize_windows(*active_input_window, false);
|
||||
active_input_window->set_tiled(nullptr, WindowTileType::Left);
|
||||
return;
|
||||
}
|
||||
if (event.key() == Key_Right) {
|
||||
if (m_active_input_window->tiled() == WindowTileType::Right)
|
||||
if (active_input_window->tiled() == WindowTileType::Right)
|
||||
return;
|
||||
if (m_active_input_window->tiled() != WindowTileType::None) {
|
||||
m_active_input_window->set_untiled();
|
||||
if (active_input_window->tiled() != WindowTileType::None) {
|
||||
active_input_window->set_untiled();
|
||||
return;
|
||||
}
|
||||
if (m_active_input_window->is_maximized())
|
||||
maximize_windows(*m_active_input_window, false);
|
||||
m_active_input_window->set_tiled(nullptr, WindowTileType::Right);
|
||||
if (active_input_window->is_maximized())
|
||||
maximize_windows(*active_input_window, false);
|
||||
active_input_window->set_tiled(nullptr, WindowTileType::Right);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_active_input_window->dispatch_event(event);
|
||||
active_input_window->dispatch_event(event);
|
||||
}
|
||||
|
||||
void WindowManager::set_highlight_window(Window* new_highlight_window)
|
||||
{
|
||||
if (new_highlight_window == m_window_stack.highlight_window())
|
||||
// NOTE: The highlight window is global across all stacks. That's because we
|
||||
// can only have one and we want to be able to highlight it during transitions
|
||||
auto* previous_highlight_window = highlight_window();
|
||||
if (new_highlight_window == previous_highlight_window)
|
||||
return;
|
||||
auto* previous_highlight_window = m_window_stack.highlight_window();
|
||||
m_window_stack.set_highlight_window(new_highlight_window);
|
||||
if (!new_highlight_window)
|
||||
m_highlight_window = nullptr;
|
||||
else
|
||||
m_highlight_window = new_highlight_window->make_weak_ptr<Window>();
|
||||
|
||||
if (previous_highlight_window) {
|
||||
previous_highlight_window->invalidate(true, true);
|
||||
Compositor::the().invalidate_screen(previous_highlight_window->frame().render_rect());
|
||||
|
@ -1377,23 +1583,31 @@ void WindowManager::restore_active_input_window(Window* window)
|
|||
|
||||
Window* WindowManager::set_active_input_window(Window* window)
|
||||
{
|
||||
if (window == m_active_input_window)
|
||||
auto& window_stack = current_window_stack();
|
||||
auto* previous_input_window = window_stack.active_input_window();
|
||||
if (window == previous_input_window)
|
||||
return window;
|
||||
|
||||
Window* previous_input_window = m_active_input_window;
|
||||
if (previous_input_window)
|
||||
Core::EventLoop::current().post_event(*previous_input_window, make<Event>(Event::WindowInputLeft));
|
||||
notify_previous_active_input_window(*previous_input_window);
|
||||
|
||||
if (window) {
|
||||
m_active_input_window = *window;
|
||||
Core::EventLoop::current().post_event(*window, make<Event>(Event::WindowInputEntered));
|
||||
} else {
|
||||
m_active_input_window = nullptr;
|
||||
}
|
||||
window_stack.set_active_input_window(window);
|
||||
if (window)
|
||||
notify_new_active_input_window(*window);
|
||||
|
||||
return previous_input_window;
|
||||
}
|
||||
|
||||
void WindowManager::notify_new_active_input_window(Window& new_input_window)
|
||||
{
|
||||
Core::EventLoop::current().post_event(new_input_window, make<Event>(Event::WindowInputEntered));
|
||||
}
|
||||
|
||||
void WindowManager::notify_previous_active_input_window(Window& previous_input_window)
|
||||
{
|
||||
Core::EventLoop::current().post_event(previous_input_window, make<Event>(Event::WindowInputLeft));
|
||||
}
|
||||
|
||||
void WindowManager::set_active_window(Window* new_active_window, bool make_input)
|
||||
{
|
||||
if (new_active_window) {
|
||||
|
@ -1418,32 +1632,44 @@ void WindowManager::set_active_window(Window* new_active_window, bool make_input
|
|||
if (make_input)
|
||||
set_active_input_window(new_active_input_window);
|
||||
|
||||
if (new_active_window == m_window_stack.active_window())
|
||||
auto& window_stack = current_window_stack();
|
||||
if (new_active_window == window_stack.active_window())
|
||||
return;
|
||||
|
||||
if (auto* previously_active_window = m_window_stack.active_window()) {
|
||||
for (auto& child_window : previously_active_window->child_windows()) {
|
||||
if (child_window && child_window->type() == WindowType::Tooltip)
|
||||
child_window->request_close();
|
||||
}
|
||||
Core::EventLoop::current().post_event(*previously_active_window, make<Event>(Event::WindowDeactivated));
|
||||
previously_active_window->invalidate(true, true);
|
||||
m_window_stack.set_active_window(nullptr);
|
||||
m_active_input_tracking_window = nullptr;
|
||||
tell_wms_window_state_changed(*previously_active_window);
|
||||
if (auto* previously_active_window = window_stack.active_window()) {
|
||||
window_stack.set_active_window(nullptr);
|
||||
window_stack.set_active_input_tracking_window(nullptr);
|
||||
notify_previous_active_window(*previously_active_window);
|
||||
}
|
||||
|
||||
if (new_active_window) {
|
||||
m_window_stack.set_active_window(new_active_window);
|
||||
Core::EventLoop::current().post_event(*new_active_window, make<Event>(Event::WindowActivated));
|
||||
new_active_window->invalidate(true, true);
|
||||
tell_wms_window_state_changed(*new_active_window);
|
||||
window_stack.set_active_window(new_active_window);
|
||||
notify_new_active_window(*new_active_window);
|
||||
}
|
||||
|
||||
// Window shapes may have changed (e.g. shadows for inactive/active windows)
|
||||
Compositor::the().invalidate_occlusions();
|
||||
}
|
||||
|
||||
void WindowManager::notify_new_active_window(Window& new_active_window)
|
||||
{
|
||||
Core::EventLoop::current().post_event(new_active_window, make<Event>(Event::WindowActivated));
|
||||
new_active_window.invalidate(true, true);
|
||||
tell_wms_window_state_changed(new_active_window);
|
||||
}
|
||||
|
||||
void WindowManager::notify_previous_active_window(Window& previously_active_window)
|
||||
{
|
||||
for (auto& child_window : previously_active_window.child_windows()) {
|
||||
if (child_window && child_window->type() == WindowType::Tooltip)
|
||||
child_window->request_close();
|
||||
}
|
||||
Core::EventLoop::current().post_event(previously_active_window, make<Event>(Event::WindowDeactivated));
|
||||
previously_active_window.invalidate(true, true);
|
||||
|
||||
tell_wms_window_state_changed(previously_active_window);
|
||||
}
|
||||
|
||||
bool WindowManager::set_hovered_window(Window* window)
|
||||
{
|
||||
if (m_hovered_window == window)
|
||||
|
@ -1461,7 +1687,7 @@ bool WindowManager::set_hovered_window(Window* window)
|
|||
|
||||
ClientConnection const* WindowManager::active_client() const
|
||||
{
|
||||
if (auto* window = m_window_stack.active_window())
|
||||
if (auto* window = const_cast<WindowManager*>(this)->current_window_stack().active_window())
|
||||
return window->client();
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -1534,7 +1760,7 @@ Gfx::IntRect WindowManager::maximized_window_rect(Window const& window, bool rel
|
|||
|
||||
if (screen.is_main_screen()) {
|
||||
// Subtract taskbar window height if present
|
||||
const_cast<WindowManager*>(this)->m_window_stack.for_each_visible_window_of_type_from_back_to_front(WindowType::Taskbar, [&rect](Window& taskbar_window) {
|
||||
const_cast<WindowManager*>(this)->current_window_stack().for_each_visible_window_of_type_from_back_to_front(WindowType::Taskbar, [&rect](Window& taskbar_window) {
|
||||
rect.set_height(rect.height() - taskbar_window.height());
|
||||
return IterationDecision::Break;
|
||||
});
|
||||
|
@ -1558,7 +1784,7 @@ void WindowManager::start_dnd_drag(ClientConnection& client, String const& text,
|
|||
m_dnd_overlay->set_enabled(true);
|
||||
m_dnd_mime_data = mime_data;
|
||||
Compositor::the().invalidate_cursor();
|
||||
m_active_input_tracking_window = nullptr;
|
||||
current_window_stack().set_active_input_tracking_window(nullptr);
|
||||
}
|
||||
|
||||
void WindowManager::end_dnd_drag()
|
||||
|
@ -1574,8 +1800,11 @@ void WindowManager::invalidate_after_theme_or_font_change()
|
|||
{
|
||||
Compositor::the().set_background_color(m_config->read_entry("Background", "Color", palette().desktop_background().to_string()));
|
||||
WindowFrame::reload_config();
|
||||
m_window_stack.for_each_window([&](Window& window) {
|
||||
window.frame().theme_changed();
|
||||
for_each_window_stack([&](auto& window_stack) {
|
||||
window_stack.for_each_window([&](Window& window) {
|
||||
window.frame().theme_changed();
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
ClientConnection::for_each_client([&](ClientConnection& client) {
|
||||
|
@ -1604,10 +1833,11 @@ 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_tracking_window)
|
||||
auto* active_input_tracking_window = current_window_stack().active_input_tracking_window();
|
||||
if (!active_input_tracking_window)
|
||||
return;
|
||||
m_active_input_tracking_window->set_automatic_cursor_tracking_enabled(false);
|
||||
m_active_input_tracking_window = nullptr;
|
||||
active_input_tracking_window->set_automatic_cursor_tracking_enabled(false);
|
||||
active_input_tracking_window = nullptr;
|
||||
}
|
||||
|
||||
void WindowManager::minimize_windows(Window& window, bool minimized)
|
||||
|
@ -1638,7 +1868,7 @@ Gfx::IntPoint WindowManager::get_recommended_window_position(Gfx::IntPoint const
|
|||
int taskbar_height = 28;
|
||||
|
||||
Window const* overlap_window = nullptr;
|
||||
m_window_stack.for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, [&](Window& window) {
|
||||
current_window_stack().for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, [&](Window& window) {
|
||||
if (window.default_positioned() && (!overlap_window || overlap_window->window_id() < window.window_id())) {
|
||||
overlap_window = &window;
|
||||
}
|
||||
|
@ -1663,9 +1893,12 @@ Gfx::IntPoint WindowManager::get_recommended_window_position(Gfx::IntPoint const
|
|||
void WindowManager::reload_icon_bitmaps_after_scale_change()
|
||||
{
|
||||
reload_config();
|
||||
m_window_stack.for_each_window([&](Window& window) {
|
||||
auto& window_frame = window.frame();
|
||||
window_frame.theme_changed();
|
||||
for_each_window_stack([&](auto& window_stack) {
|
||||
window_stack.for_each_window([&](Window& window) {
|
||||
auto& window_frame = window.frame();
|
||||
window_frame.theme_changed();
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
@ -1679,4 +1912,10 @@ void WindowManager::set_window_with_active_menu(Window* window)
|
|||
else
|
||||
m_window_with_active_menu = nullptr;
|
||||
}
|
||||
|
||||
WindowStack& WindowManager::get_rendering_window_stacks(WindowStack*& transitioning_window_stack)
|
||||
{
|
||||
return Compositor::the().get_rendering_window_stacks(transitioning_window_stack);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue