mirror of
https://github.com/RGBCube/serenity
synced 2025-07-28 06:27:45 +00:00
WindowServer: Add API to change virtual desktop settings
This also adds the ability to query how many virtual desktops are set up, and for the Taskbar to be notified when the active virtual desktop has changed.
This commit is contained in:
parent
584b144953
commit
7984c2836d
21 changed files with 383 additions and 64 deletions
|
@ -53,7 +53,8 @@ ClientConnection::ClientConnection(NonnullRefPtr<Core::LocalSocket> client_socke
|
|||
s_connections = new HashMap<int, NonnullRefPtr<ClientConnection>>;
|
||||
s_connections->set(client_id, *this);
|
||||
|
||||
async_fast_greet(Screen::rects(), Screen::main().index(), Gfx::current_system_theme_buffer(), Gfx::FontDatabase::default_font_query(), Gfx::FontDatabase::fixed_width_font_query());
|
||||
auto& wm = WindowManager::the();
|
||||
async_fast_greet(Screen::rects(), Screen::main().index(), wm.window_stack_rows(), wm.window_stack_columns(), Gfx::current_system_theme_buffer(), Gfx::FontDatabase::default_font_query(), Gfx::FontDatabase::fixed_width_font_query());
|
||||
}
|
||||
|
||||
ClientConnection::~ClientConnection()
|
||||
|
@ -84,9 +85,10 @@ void ClientConnection::die()
|
|||
});
|
||||
}
|
||||
|
||||
void ClientConnection::notify_about_new_screen_rects(Vector<Gfx::IntRect, 4> const& rects, size_t main_screen_index)
|
||||
void ClientConnection::notify_about_new_screen_rects()
|
||||
{
|
||||
async_screen_rects_changed(rects, main_screen_index);
|
||||
auto& wm = WindowManager::the();
|
||||
async_screen_rects_changed(Screen::rects(), Screen::main().index(), wm.window_stack_rows(), wm.window_stack_columns());
|
||||
}
|
||||
|
||||
void ClientConnection::create_menubar(i32 menubar_id)
|
||||
|
@ -323,6 +325,20 @@ Messages::WindowServer::SaveScreenLayoutResponse ClientConnection::save_screen_l
|
|||
return { success, move(error_msg) };
|
||||
}
|
||||
|
||||
Messages::WindowServer::ApplyVirtualDesktopSettingsResponse ClientConnection::apply_virtual_desktop_settings(u32 rows, u32 columns, bool save)
|
||||
{
|
||||
if (rows == 0 || columns == 0 || rows > WindowManager::max_window_stack_rows || columns > WindowManager::max_window_stack_columns)
|
||||
return { false };
|
||||
|
||||
return { WindowManager::the().apply_virtual_desktop_settings(rows, columns, save) };
|
||||
}
|
||||
|
||||
Messages::WindowServer::GetVirtualDesktopSettingsResponse ClientConnection::get_virtual_desktop_settings()
|
||||
{
|
||||
auto& wm = WindowManager::the();
|
||||
return { (unsigned)wm.window_stack_rows(), (unsigned)wm.window_stack_columns(), WindowManager::max_window_stack_rows, WindowManager::max_window_stack_columns };
|
||||
}
|
||||
|
||||
void ClientConnection::show_screen_numbers(bool show)
|
||||
{
|
||||
if (m_show_screen_number == show)
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
static ClientConnection* from_client_id(int client_id);
|
||||
static void for_each_client(Function<void(ClientConnection&)>);
|
||||
|
||||
void notify_about_new_screen_rects(const Vector<Gfx::IntRect, 4>&, size_t);
|
||||
void notify_about_new_screen_rects();
|
||||
void post_paint_message(Window&, bool ignore_occlusion = false);
|
||||
|
||||
Menu* find_menu_by_id(int menu_id)
|
||||
|
@ -130,6 +130,8 @@ private:
|
|||
virtual Messages::WindowServer::SetScreenLayoutResponse set_screen_layout(ScreenLayout const&, bool) override;
|
||||
virtual Messages::WindowServer::GetScreenLayoutResponse get_screen_layout() override;
|
||||
virtual Messages::WindowServer::SaveScreenLayoutResponse save_screen_layout() override;
|
||||
virtual Messages::WindowServer::ApplyVirtualDesktopSettingsResponse apply_virtual_desktop_settings(u32, u32, bool) override;
|
||||
virtual Messages::WindowServer::GetVirtualDesktopSettingsResponse get_virtual_desktop_settings() override;
|
||||
virtual void show_screen_numbers(bool) override;
|
||||
virtual void set_window_cursor(i32, i32) override;
|
||||
virtual void set_window_custom_cursor(i32, Gfx::ShareableBitmap const&) override;
|
||||
|
|
|
@ -1287,11 +1287,7 @@ void Compositor::update_animations(Screen& screen, Gfx::DisjointRectSet& flush_r
|
|||
|
||||
void Compositor::create_window_stack_switch_overlay(WindowStack& target_stack)
|
||||
{
|
||||
if (m_stack_switch_overlay_timer) {
|
||||
// Cancel any timer, we're going to delete the overlay
|
||||
m_stack_switch_overlay_timer->stop();
|
||||
m_stack_switch_overlay_timer = nullptr;
|
||||
}
|
||||
stop_window_stack_switch_overlay_timer();
|
||||
Screen::for_each([&](auto& screen) {
|
||||
auto& screen_data = m_screen_data[screen.index()];
|
||||
screen_data.m_window_stack_switch_overlay = nullptr; // delete it first
|
||||
|
@ -1301,20 +1297,45 @@ void Compositor::create_window_stack_switch_overlay(WindowStack& target_stack)
|
|||
});
|
||||
}
|
||||
|
||||
void Compositor::remove_window_stack_switch_overlays()
|
||||
{
|
||||
Screen::for_each([&](auto& screen) {
|
||||
auto& screen_data = m_screen_data[screen.index()];
|
||||
screen_data.m_window_stack_switch_overlay = nullptr;
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
void Compositor::stop_window_stack_switch_overlay_timer()
|
||||
{
|
||||
if (m_stack_switch_overlay_timer) {
|
||||
// Cancel any timer, we're going to delete the overlay
|
||||
m_stack_switch_overlay_timer->stop();
|
||||
m_stack_switch_overlay_timer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Compositor::start_window_stack_switch_overlay_timer()
|
||||
{
|
||||
if (m_stack_switch_overlay_timer) {
|
||||
m_stack_switch_overlay_timer->stop();
|
||||
m_stack_switch_overlay_timer = nullptr;
|
||||
}
|
||||
bool have_overlay = false;
|
||||
Screen::for_each([&](auto& screen) {
|
||||
auto& screen_data = m_screen_data[screen.index()];
|
||||
if (screen_data.m_window_stack_switch_overlay) {
|
||||
have_overlay = true;
|
||||
return IterationDecision::Break;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
if (!have_overlay)
|
||||
return;
|
||||
m_stack_switch_overlay_timer = Core::Timer::create_single_shot(
|
||||
500,
|
||||
[this] {
|
||||
Screen::for_each([&](auto& screen) {
|
||||
auto& screen_data = m_screen_data[screen.index()];
|
||||
screen_data.m_window_stack_switch_overlay = nullptr;
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
remove_window_stack_switch_overlays();
|
||||
},
|
||||
this);
|
||||
m_stack_switch_overlay_timer->start();
|
||||
|
@ -1349,7 +1370,26 @@ void Compositor::finish_window_stack_switch()
|
|||
start_window_stack_switch_overlay_timer();
|
||||
}
|
||||
|
||||
void Compositor::switch_to_window_stack(WindowStack& new_window_stack)
|
||||
void Compositor::set_current_window_stack_no_transition(WindowStack& new_window_stack)
|
||||
{
|
||||
if (m_transitioning_to_window_stack) {
|
||||
finish_window_stack_switch();
|
||||
VERIFY(!m_window_stack_transition_animation);
|
||||
VERIFY(!m_transitioning_to_window_stack);
|
||||
}
|
||||
if (m_current_window_stack == &new_window_stack)
|
||||
return;
|
||||
m_current_window_stack = &new_window_stack;
|
||||
invalidate_for_window_stack_merge_or_change();
|
||||
}
|
||||
|
||||
void Compositor::invalidate_for_window_stack_merge_or_change()
|
||||
{
|
||||
invalidate_occlusions();
|
||||
invalidate_screen();
|
||||
}
|
||||
|
||||
void Compositor::switch_to_window_stack(WindowStack& new_window_stack, bool show_overlay)
|
||||
{
|
||||
if (m_transitioning_to_window_stack) {
|
||||
if (m_transitioning_to_window_stack == &new_window_stack)
|
||||
|
@ -1363,8 +1403,13 @@ void Compositor::switch_to_window_stack(WindowStack& new_window_stack)
|
|||
|
||||
if (&new_window_stack == m_current_window_stack) {
|
||||
// So that the user knows which stack they're on, show the overlay briefly
|
||||
create_window_stack_switch_overlay(*m_current_window_stack);
|
||||
start_window_stack_switch_overlay_timer();
|
||||
if (show_overlay) {
|
||||
create_window_stack_switch_overlay(*m_current_window_stack);
|
||||
start_window_stack_switch_overlay_timer();
|
||||
} else {
|
||||
stop_window_stack_switch_overlay_timer();
|
||||
remove_window_stack_switch_overlays();
|
||||
}
|
||||
return;
|
||||
}
|
||||
VERIFY(!m_transitioning_to_window_stack);
|
||||
|
@ -1387,8 +1432,13 @@ void Compositor::switch_to_window_stack(WindowStack& new_window_stack)
|
|||
m_transitioning_to_window_stack->set_transition_offset({}, { -delta_x, -delta_y });
|
||||
m_current_window_stack->set_transition_offset({}, {});
|
||||
|
||||
create_window_stack_switch_overlay(*m_transitioning_to_window_stack);
|
||||
// We start the timer when the animation ends!
|
||||
if (show_overlay) {
|
||||
// We start the timer when the animation ends!
|
||||
create_window_stack_switch_overlay(*m_transitioning_to_window_stack);
|
||||
} else {
|
||||
stop_window_stack_switch_overlay_timer();
|
||||
remove_window_stack_switch_overlays();
|
||||
}
|
||||
|
||||
VERIFY(!m_window_stack_transition_animation);
|
||||
m_window_stack_transition_animation = Animation::create();
|
||||
|
|
|
@ -112,7 +112,9 @@ public:
|
|||
}
|
||||
|
||||
bool is_switching_window_stacks() const { return m_transitioning_to_window_stack != nullptr; }
|
||||
void switch_to_window_stack(WindowStack&);
|
||||
void switch_to_window_stack(WindowStack&, bool);
|
||||
void set_current_window_stack_no_transition(WindowStack&);
|
||||
void invalidate_for_window_stack_merge_or_change();
|
||||
|
||||
void did_construct_window_manager(Badge<WindowManager>);
|
||||
|
||||
|
@ -142,6 +144,8 @@ private:
|
|||
Gfx::IntPoint window_transition_offset(Window&);
|
||||
void update_animations(Screen&, Gfx::DisjointRectSet& flush_rects);
|
||||
void create_window_stack_switch_overlay(WindowStack&);
|
||||
void remove_window_stack_switch_overlays();
|
||||
void stop_window_stack_switch_overlay_timer();
|
||||
void start_window_stack_switch_overlay_timer();
|
||||
void finish_window_stack_switch();
|
||||
|
||||
|
@ -227,7 +231,6 @@ private:
|
|||
WindowStack* m_current_window_stack { nullptr };
|
||||
WindowStack* m_transitioning_to_window_stack { nullptr };
|
||||
RefPtr<Animation> m_window_stack_transition_animation;
|
||||
OwnPtr<WindowStackSwitchOverlay> m_stack_switch_overlay;
|
||||
RefPtr<Core::Timer> m_stack_switch_overlay_timer;
|
||||
|
||||
size_t m_show_screen_number_count { 0 };
|
||||
|
|
|
@ -1204,4 +1204,5 @@ String Window::computed_title() const
|
|||
return String::formatted("{} (Not responding)", title);
|
||||
return title;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ enum WMEventMask {
|
|||
WindowStateChanges = 1 << 1,
|
||||
WindowIconChanges = 1 << 2,
|
||||
WindowRemovals = 1 << 3,
|
||||
VirtualDesktopChanges = 1 << 4,
|
||||
};
|
||||
|
||||
enum class WindowTileType {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
endpoint WindowClient
|
||||
{
|
||||
fast_greet(Vector<Gfx::IntRect> screen_rects, u32 main_screen_index, Core::AnonymousBuffer theme_buffer, String default_font_query, String fixed_width_font_query) =|
|
||||
fast_greet(Vector<Gfx::IntRect> screen_rects, u32 main_screen_index, u32 virtual_desktop_rows, u32 virtual_desktop_columns, Core::AnonymousBuffer theme_buffer, String default_font_query, String fixed_width_font_query) =|
|
||||
|
||||
paint(i32 window_id, Gfx::IntSize window_size, Vector<Gfx::IntRect> rects) =|
|
||||
mouse_move(i32 window_id, Gfx::IntPoint mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta, bool is_drag, Vector<String> mime_types) =|
|
||||
|
@ -28,7 +28,7 @@ endpoint WindowClient
|
|||
menu_item_left(i32 menu_id, u32 identifier) =|
|
||||
menu_visibility_did_change(i32 menu_id, bool visible) =|
|
||||
|
||||
screen_rects_changed(Vector<Gfx::IntRect> rects, u32 main_screen_index) =|
|
||||
screen_rects_changed(Vector<Gfx::IntRect> rects, u32 main_screen_index, u32 virtual_desktop_rows, u32 virtual_desktop_columns) =|
|
||||
|
||||
set_wallpaper_finished(bool success) =|
|
||||
|
||||
|
|
|
@ -40,23 +40,13 @@ 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);
|
||||
}
|
||||
// If we haven't created any window stacks, at least create the stationary/main window stack
|
||||
auto row = adopt_own(*new RemoveReference<decltype(m_window_stacks[0])>());
|
||||
auto main_window_stack = adopt_own(*new WindowStack(0, 0));
|
||||
main_window_stack->set_stationary_window_stack(*main_window_stack);
|
||||
m_current_window_stack = main_window_stack.ptr();
|
||||
row->append(move(main_window_stack));
|
||||
m_window_stacks.append(move(row));
|
||||
}
|
||||
|
||||
reload_config();
|
||||
|
@ -78,6 +68,14 @@ void WindowManager::reload_config()
|
|||
{
|
||||
m_config = Core::ConfigFile::open("/etc/WindowServer.ini");
|
||||
|
||||
unsigned virtual_desktop_rows = (unsigned)m_config->read_num_entry("VirtualDesktop", "Rows", default_window_stack_rows);
|
||||
unsigned virtual_desktop_columns = (unsigned)m_config->read_num_entry("VirtualDesktop", "Columns", default_window_stack_columns);
|
||||
if (virtual_desktop_rows == 0 || virtual_desktop_columns == 0 || virtual_desktop_rows > max_window_stack_rows || virtual_desktop_columns > max_window_stack_columns) {
|
||||
virtual_desktop_rows = default_window_stack_rows;
|
||||
virtual_desktop_columns = default_window_stack_columns;
|
||||
}
|
||||
apply_virtual_desktop_settings(virtual_desktop_rows, virtual_desktop_columns, false);
|
||||
|
||||
m_double_click_speed = m_config->read_num_entry("Input", "DoubleClickSpeed", 250);
|
||||
|
||||
auto* current_cursor = Compositor::the().current_cursor();
|
||||
|
@ -139,9 +137,7 @@ bool WindowManager::set_screen_layout(ScreenLayout&& screen_layout, bool save, S
|
|||
|
||||
Compositor::the().screen_resolution_changed();
|
||||
|
||||
ClientConnection::for_each_client([&](ClientConnection& client) {
|
||||
client.notify_about_new_screen_rects(Screen::rects(), Screen::main().index());
|
||||
});
|
||||
tell_wms_screen_rects_changed();
|
||||
|
||||
for_each_window_stack([&](auto& window_stack) {
|
||||
window_stack.for_each_window([](Window& window) {
|
||||
|
@ -171,6 +167,113 @@ bool WindowManager::save_screen_layout(String& error_msg)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WindowManager::apply_virtual_desktop_settings(unsigned rows, unsigned columns, bool save)
|
||||
{
|
||||
VERIFY(rows != 0);
|
||||
VERIFY(rows <= max_window_stack_rows);
|
||||
VERIFY(columns != 0);
|
||||
VERIFY(columns <= max_window_stack_columns);
|
||||
|
||||
auto current_rows = window_stack_rows();
|
||||
auto current_columns = window_stack_columns();
|
||||
if (rows != current_rows || columns != current_columns) {
|
||||
auto& current_window_stack = this->current_window_stack();
|
||||
auto current_stack_row = current_window_stack.row();
|
||||
auto current_stack_column = current_window_stack.column();
|
||||
bool need_rerender = false;
|
||||
bool removing_current_stack = current_stack_row > rows - 1 || current_stack_column > columns - 1;
|
||||
auto new_current_row = min(current_stack_row, rows - 1);
|
||||
auto new_current_column = min(current_stack_column, columns - 1);
|
||||
|
||||
// Collect all windows that were moved. We can't tell the wms at this point because
|
||||
// the current window stack may not be valid anymore, until after the move is complete
|
||||
Vector<Window*, 32> windows_moved;
|
||||
|
||||
auto merge_window_stack = [&](WindowStack& from_stack, WindowStack& into_stack) {
|
||||
auto move_to = WindowStack::MoveAllWindowsTo::Back;
|
||||
|
||||
// TODO: Figure out a better algorithm. We basically always layer it on top, unless
|
||||
// it's either being moved to window stack we're viewing or that we will be viewing.
|
||||
// In that case we would want to make sure the window stack ends up on top (with no
|
||||
// change to the active window)
|
||||
bool moving_to_new_current_stack = into_stack.row() == new_current_row && into_stack.column() == new_current_column;
|
||||
if (moving_to_new_current_stack)
|
||||
move_to = WindowStack::MoveAllWindowsTo::Front;
|
||||
from_stack.move_all_windows(into_stack, windows_moved, move_to);
|
||||
};
|
||||
|
||||
// While we have too many rows, merge each row too many into the new bottom row
|
||||
while (current_rows > rows) {
|
||||
auto& row = m_window_stacks[rows];
|
||||
for (size_t column_index = 0; column_index < row.size(); column_index++) {
|
||||
merge_window_stack(row[column_index], m_window_stacks[rows - 1][column_index]);
|
||||
if (rows - 1 == current_stack_row && column_index == current_stack_column)
|
||||
need_rerender = true;
|
||||
}
|
||||
m_window_stacks.remove(rows);
|
||||
current_rows--;
|
||||
}
|
||||
// While we have too many columns, merge each column too many into the new right most column
|
||||
while (current_columns > columns) {
|
||||
for (size_t row_index = 0; row_index < current_rows; row_index++) {
|
||||
auto& row = m_window_stacks[row_index];
|
||||
merge_window_stack(row[columns], row[columns - 1]);
|
||||
if (row_index == current_stack_row && columns - 1 == current_stack_column)
|
||||
need_rerender = true;
|
||||
row.remove(columns);
|
||||
}
|
||||
current_columns--;
|
||||
}
|
||||
// Add more rows if necessary
|
||||
while (rows > current_rows) {
|
||||
auto row = adopt_own(*new RemoveReference<decltype(m_window_stacks[0])>());
|
||||
for (size_t column_index = 0; column_index < columns; column_index++) {
|
||||
auto window_stack = adopt_own(*new WindowStack(current_rows, column_index));
|
||||
window_stack->set_stationary_window_stack(m_window_stacks[0][0]);
|
||||
row->append(move(window_stack));
|
||||
}
|
||||
m_window_stacks.append(move(row));
|
||||
current_rows++;
|
||||
}
|
||||
// Add more columns if necessary
|
||||
while (columns > current_columns) {
|
||||
for (size_t row_index = 0; row_index < current_rows; row_index++) {
|
||||
auto& row = m_window_stacks[row_index];
|
||||
while (row.size() < columns) {
|
||||
auto window_stack = adopt_own(*new WindowStack(row_index, row.size()));
|
||||
window_stack->set_stationary_window_stack(m_window_stacks[0][0]);
|
||||
row.append(move(window_stack));
|
||||
}
|
||||
}
|
||||
current_columns++;
|
||||
}
|
||||
|
||||
if (removing_current_stack) {
|
||||
// If we're on a window stack that was removed, we need to move...
|
||||
m_current_window_stack = &m_window_stacks[new_current_row][new_current_column];
|
||||
Compositor::the().set_current_window_stack_no_transition(*m_current_window_stack);
|
||||
need_rerender = false; // The compositor already called invalidate_for_window_stack_merge_or_change for us
|
||||
}
|
||||
|
||||
for (auto* window_moved : windows_moved)
|
||||
WindowManager::the().tell_wms_window_state_changed(*window_moved);
|
||||
|
||||
tell_wms_screen_rects_changed(); // updates the available virtual desktops
|
||||
if (current_stack_row != new_current_row || current_stack_column != new_current_column)
|
||||
tell_wms_current_window_stack_changed();
|
||||
|
||||
if (need_rerender)
|
||||
Compositor::the().invalidate_for_window_stack_merge_or_change();
|
||||
}
|
||||
|
||||
if (save) {
|
||||
m_config->write_num_entry("VirtualDesktop", "Rows", window_stack_rows());
|
||||
m_config->write_num_entry("VirtualDesktop", "Columns", window_stack_columns());
|
||||
return m_config->sync();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void WindowManager::set_acceleration_factor(double factor)
|
||||
{
|
||||
ScreenInput::the().set_acceleration_factor(factor);
|
||||
|
@ -322,6 +425,8 @@ void WindowManager::greet_window_manager(WMClientConnection& conn)
|
|||
if (conn.window_id() < 0)
|
||||
return;
|
||||
|
||||
tell_wm_about_current_window_stack(conn);
|
||||
|
||||
for_each_window_stack([&](auto& window_stack) {
|
||||
window_stack.for_each_window([&](Window& other_window) {
|
||||
//if (conn.window_id() != other_window.window_id()) {
|
||||
|
@ -345,7 +450,12 @@ void WindowManager::tell_wm_about_window(WMClientConnection& conn, Window& windo
|
|||
if (window.is_internal())
|
||||
return;
|
||||
auto* parent = window.parent_window();
|
||||
conn.async_window_state_changed(conn.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.computed_title(), window.rect(), window.progress());
|
||||
auto* window_stack = ¤t_window_stack();
|
||||
if (!is_stationary_window_type(window.type())) {
|
||||
if (auto* stack = window.outer_stack())
|
||||
window_stack = stack;
|
||||
}
|
||||
conn.async_window_state_changed(conn.window_id(), window.client_id(), window.window_id(), parent ? parent->client_id() : -1, parent ? parent->window_id() : -1, window_stack->row(), window_stack->column(), window.is_active(), window.is_minimized(), window.is_modal_dont_unparent(), window.is_frameless(), (i32)window.type(), window.computed_title(), window.rect(), window.progress());
|
||||
}
|
||||
|
||||
void WindowManager::tell_wm_about_window_rect(WMClientConnection& conn, Window& window)
|
||||
|
@ -370,6 +480,16 @@ void WindowManager::tell_wm_about_window_icon(WMClientConnection& conn, Window&
|
|||
conn.async_window_icon_bitmap_changed(conn.window_id(), window.client_id(), window.window_id(), window.icon().to_shareable_bitmap());
|
||||
}
|
||||
|
||||
void WindowManager::tell_wm_about_current_window_stack(WMClientConnection& conn)
|
||||
{
|
||||
if (conn.window_id() < 0)
|
||||
return;
|
||||
if (!(conn.event_mask() & WMEventMask::VirtualDesktopChanges))
|
||||
return;
|
||||
auto& window_stack = current_window_stack();
|
||||
conn.async_virtual_desktop_changed(conn.window_id(), window_stack.row(), window_stack.column());
|
||||
}
|
||||
|
||||
void WindowManager::tell_wms_window_state_changed(Window& window)
|
||||
{
|
||||
for_each_window_manager([&](WMClientConnection& conn) {
|
||||
|
@ -394,6 +514,13 @@ void WindowManager::tell_wms_window_rect_changed(Window& window)
|
|||
});
|
||||
}
|
||||
|
||||
void WindowManager::tell_wms_screen_rects_changed()
|
||||
{
|
||||
ClientConnection::for_each_client([&](ClientConnection& client) {
|
||||
client.notify_about_new_screen_rects();
|
||||
});
|
||||
}
|
||||
|
||||
void WindowManager::tell_wms_applet_area_size_changed(Gfx::IntSize const& size)
|
||||
{
|
||||
for_each_window_manager([&](WMClientConnection& conn) {
|
||||
|
@ -427,6 +554,14 @@ void WindowManager::tell_wms_super_space_key_pressed()
|
|||
});
|
||||
}
|
||||
|
||||
void WindowManager::tell_wms_current_window_stack_changed()
|
||||
{
|
||||
for_each_window_manager([&](WMClientConnection& conn) {
|
||||
tell_wm_about_current_window_stack(conn);
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
static bool window_type_has_title(WindowType type)
|
||||
{
|
||||
return type == WindowType::Normal || type == WindowType::ToolWindow;
|
||||
|
@ -1283,7 +1418,7 @@ bool WindowManager::is_window_in_modal_stack(Window& window_in_modal_stack, Wind
|
|||
return result == IterationDecision::Break;
|
||||
}
|
||||
|
||||
void WindowManager::switch_to_window_stack(WindowStack& window_stack, Window* carry_window)
|
||||
void WindowManager::switch_to_window_stack(WindowStack& window_stack, Window* carry_window, bool show_overlay)
|
||||
{
|
||||
m_carry_window_to_new_stack.clear();
|
||||
m_switching_to_window_stack = &window_stack;
|
||||
|
@ -1334,7 +1469,7 @@ void WindowManager::switch_to_window_stack(WindowStack& window_stack, Window* ca
|
|||
m_current_window_stack = &window_stack;
|
||||
}
|
||||
|
||||
Compositor::the().switch_to_window_stack(window_stack);
|
||||
Compositor::the().switch_to_window_stack(window_stack, show_overlay);
|
||||
}
|
||||
|
||||
void WindowManager::did_switch_window_stack(Badge<Compositor>, WindowStack& previous_stack, WindowStack& new_stack)
|
||||
|
@ -1343,7 +1478,6 @@ void WindowManager::did_switch_window_stack(Badge<Compositor>, WindowStack& prev
|
|||
|
||||
// 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;
|
||||
|
@ -1352,8 +1486,10 @@ void WindowManager::did_switch_window_stack(Badge<Compositor>, WindowStack& prev
|
|||
// 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())
|
||||
if (auto* window = window_ref.ptr()) {
|
||||
window->set_moving_to_another_stack(false);
|
||||
tell_wms_window_state_changed(*window);
|
||||
}
|
||||
}
|
||||
m_carry_window_to_new_stack.clear();
|
||||
}
|
||||
|
@ -1378,6 +1514,8 @@ void WindowManager::did_switch_window_stack(Badge<Compositor>, WindowStack& prev
|
|||
pick_new_active_window(nullptr);
|
||||
|
||||
reevaluate_hovered_window();
|
||||
|
||||
tell_wms_current_window_stack_changed();
|
||||
}
|
||||
|
||||
void WindowManager::process_key_event(KeyEvent& event)
|
||||
|
|
|
@ -60,6 +60,13 @@ class WindowManager : public Core::Object {
|
|||
friend class WindowSwitcher;
|
||||
|
||||
public:
|
||||
static constexpr size_t default_window_stack_rows = 2;
|
||||
static constexpr size_t default_window_stack_columns = 2;
|
||||
static_assert(default_window_stack_rows >= 1);
|
||||
static_assert(default_window_stack_columns >= 1);
|
||||
static constexpr unsigned max_window_stack_rows = 16;
|
||||
static constexpr unsigned max_window_stack_columns = 16;
|
||||
|
||||
static WindowManager& the();
|
||||
|
||||
explicit WindowManager(Gfx::PaletteImpl const&);
|
||||
|
@ -173,9 +180,11 @@ public:
|
|||
void tell_wms_window_state_changed(Window&);
|
||||
void tell_wms_window_icon_changed(Window&);
|
||||
void tell_wms_window_rect_changed(Window&);
|
||||
void tell_wms_screen_rects_changed();
|
||||
void tell_wms_applet_area_size_changed(Gfx::IntSize const&);
|
||||
void tell_wms_super_key_pressed();
|
||||
void tell_wms_super_space_key_pressed();
|
||||
void tell_wms_current_window_stack_changed();
|
||||
|
||||
bool is_active_window_or_accessory(Window&) const;
|
||||
|
||||
|
@ -251,11 +260,13 @@ public:
|
|||
void reevaluate_hovered_window(Window* = nullptr);
|
||||
Window* hovered_window() const { return m_hovered_window.ptr(); }
|
||||
|
||||
void switch_to_window_stack(WindowStack&, Window* = nullptr);
|
||||
void switch_to_window_stack(WindowStack&, Window* = nullptr, bool show_overlay = true);
|
||||
|
||||
size_t window_stack_rows() const { return m_window_stacks.size(); }
|
||||
size_t window_stack_columns() const { return m_window_stacks[0].size(); }
|
||||
|
||||
bool apply_virtual_desktop_settings(unsigned rows, unsigned columns, bool save);
|
||||
|
||||
WindowStack& current_window_stack()
|
||||
{
|
||||
VERIFY(m_current_window_stack);
|
||||
|
@ -324,6 +335,7 @@ private:
|
|||
void tell_wm_about_window(WMClientConnection& conn, Window&);
|
||||
void tell_wm_about_window_icon(WMClientConnection& conn, Window&);
|
||||
void tell_wm_about_window_rect(WMClientConnection& conn, Window&);
|
||||
void tell_wm_about_current_window_stack(WMClientConnection&);
|
||||
bool pick_new_active_window(Window*);
|
||||
|
||||
void do_move_to_front(Window&, bool, bool);
|
||||
|
@ -350,7 +362,7 @@ private:
|
|||
RefPtr<MultiScaleBitmaps> m_overlay_rect_shadow;
|
||||
|
||||
// Setup 2 rows 1 column by default
|
||||
NonnullOwnPtrVector<NonnullOwnPtrVector<WindowStack, 3>, 2> m_window_stacks;
|
||||
NonnullOwnPtrVector<NonnullOwnPtrVector<WindowStack, default_window_stack_columns>, default_window_stack_rows> m_window_stacks;
|
||||
WindowStack* m_current_window_stack { nullptr };
|
||||
|
||||
struct DoubleClickInfo {
|
||||
|
|
|
@ -3,10 +3,11 @@
|
|||
endpoint WindowManagerClient
|
||||
{
|
||||
window_removed(i32 wm_id, i32 client_id, i32 window_id) =|
|
||||
window_state_changed(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, Optional<i32> progress) =|
|
||||
window_state_changed(i32 wm_id, i32 client_id, i32 window_id, i32 parent_client_id, i32 parent_window_id, u32 virtual_desktop_row, u32 virtual_desktop_column, bool is_active, bool is_minimized, bool is_modal, bool is_frameless, i32 window_type, [UTF8] String title, Gfx::IntRect rect, Optional<i32> progress) =|
|
||||
window_icon_bitmap_changed(i32 wm_id, i32 client_id, i32 window_id, Gfx::ShareableBitmap bitmap) =|
|
||||
window_rect_changed(i32 wm_id, i32 client_id, i32 window_id, Gfx::IntRect rect) =|
|
||||
applet_area_size_changed(i32 wm_id, Gfx::IntSize size) =|
|
||||
super_key_pressed(i32 wm_id) =|
|
||||
super_space_key_pressed(i32 wm_id) =|
|
||||
virtual_desktop_changed(i32 wm_id, u32 row, u32 column) =|
|
||||
}
|
||||
|
|
|
@ -102,6 +102,9 @@ endpoint WindowServer
|
|||
save_screen_layout() => (bool success, String error_msg)
|
||||
show_screen_numbers(bool show) =|
|
||||
|
||||
apply_virtual_desktop_settings(u32 rows, u32 columns, bool save) => (bool success)
|
||||
get_virtual_desktop_settings() => (u32 rows, u32 columns, u32 max_rows, u32 max_columns)
|
||||
|
||||
set_window_icon_bitmap(i32 window_id, Gfx::ShareableBitmap icon) =|
|
||||
|
||||
get_wallpaper() => (String path)
|
||||
|
|
|
@ -26,6 +26,13 @@ void WindowStack::add(Window& window)
|
|||
window.set_outer_stack({}, this);
|
||||
}
|
||||
|
||||
void WindowStack::add_to_back(Window& window)
|
||||
{
|
||||
VERIFY(window.outer_stack() == nullptr);
|
||||
m_windows.prepend(window);
|
||||
window.set_outer_stack({}, this);
|
||||
}
|
||||
|
||||
void WindowStack::remove(Window& window)
|
||||
{
|
||||
VERIFY(window.outer_stack() == this);
|
||||
|
@ -47,6 +54,27 @@ void WindowStack::move_to_front(Window& window)
|
|||
m_windows.append(window);
|
||||
}
|
||||
|
||||
void WindowStack::move_all_windows(WindowStack& new_window_stack, Vector<Window*, 32>& windows_moved, MoveAllWindowsTo move_to)
|
||||
{
|
||||
VERIFY(this != &new_window_stack);
|
||||
if (move_to == MoveAllWindowsTo::Front) {
|
||||
while (auto* window = m_windows.take_first()) {
|
||||
window->set_outer_stack({}, nullptr);
|
||||
new_window_stack.add(*window);
|
||||
windows_moved.append(window);
|
||||
}
|
||||
} else {
|
||||
while (auto* window = m_windows.take_last()) {
|
||||
window->set_outer_stack({}, nullptr);
|
||||
new_window_stack.add_to_back(*window);
|
||||
windows_moved.append(window);
|
||||
}
|
||||
}
|
||||
m_active_window = nullptr;
|
||||
m_active_input_window = nullptr;
|
||||
m_active_input_tracking_window = nullptr;
|
||||
}
|
||||
|
||||
Window* WindowStack::window_at(Gfx::IntPoint const& position, IncludeWindowFrame include_window_frame) const
|
||||
{
|
||||
auto result = hit_test(position);
|
||||
|
|
|
@ -19,9 +19,16 @@ public:
|
|||
|
||||
bool is_empty() const { return m_windows.is_empty(); }
|
||||
void add(Window&);
|
||||
void add_to_back(Window&);
|
||||
void remove(Window&);
|
||||
void move_to_front(Window&);
|
||||
|
||||
enum class MoveAllWindowsTo {
|
||||
Front,
|
||||
Back
|
||||
};
|
||||
void move_all_windows(WindowStack&, Vector<Window*, 32>&, MoveAllWindowsTo);
|
||||
|
||||
enum class IncludeWindowFrame {
|
||||
Yes,
|
||||
No,
|
||||
|
@ -38,6 +45,8 @@ public:
|
|||
|
||||
template<typename Callback>
|
||||
void for_each_window(Callback);
|
||||
template<typename Callback>
|
||||
IterationDecision for_each_window_from_back_to_front(Callback);
|
||||
|
||||
Window::List& windows() { return m_windows; }
|
||||
|
||||
|
@ -145,6 +154,17 @@ inline void WindowStack::for_each_window(Callback callback)
|
|||
}
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
inline IterationDecision WindowStack::for_each_window_from_back_to_front(Callback callback)
|
||||
{
|
||||
for (auto& window : m_windows) {
|
||||
IterationDecision decision = callback(window);
|
||||
if (decision != IterationDecision::Break)
|
||||
return decision;
|
||||
}
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
template<typename Callback>
|
||||
inline IterationDecision WindowStack::for_each_window_of_type_from_front_to_back(WindowType type, Callback callback, bool ignore_highlight)
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue