0

wayland: session-management: Implement window removal

This implements window removal in ozone/wayland as well as adds the
required plumbing code in //chrome and //components. As mentioned in the
linked crbug and the design notes [1], for the experimental prototocol
which ships currently in Mutter 47 and 48, supporting window removals at
browser startup was more challenging than it's supposed to be in the
final protocol. That's because xdg_session_v1.remove_toplevel [2] is not
present there, leading to the hackish dummy window based approach. All
in all, it should be ok for this stage (experimental).

[1] https://notes.nickdiego.dev/chromium/wayland-session-management
[2] https://wayland.app/protocols/wayland-protocols/18#xdg_session_v1:request:remove_toplevel

R=dljames, fangzhoug, orko@igalia.com

Fixed: 352081012
Test: Manually with chrome on Gnome 48.0.
Change-Id: Ic2eb3b7a0f8586939f45820093857da395fc9f62
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6435570
Reviewed-by: Darryl James <dljames@chromium.org>
Reviewed-by: Orko Garai <orko@igalia.com>
Reviewed-by: Kramer Ge <fangzhoug@chromium.org>
Commit-Queue: Nick Yamane <nickdiego@igalia.com>
Cr-Commit-Position: refs/heads/main@{#1444315}
This commit is contained in:
Nick Diego Yamane
2025-04-08 12:53:51 -07:00
committed by Chromium LUCI CQ
parent d4fd07c3f2
commit 04881257ed
19 changed files with 314 additions and 64 deletions

@ -319,17 +319,20 @@ static bool TabVisualIndexSortFunction(const std::unique_ptr<SessionTab>& t1,
}
// Does the following:
// . Deletes and removes any windows with no tabs. NOTE: constrained windows
// that have been dragged out are of type browser. As such, this preserves any
// dragged out constrained windows (aka popups that have been dragged out).
// . Deletes and removes any windows with no tabs and insert them into
// `discarded_window_ids`. NOTE: constrained windows that have been dragged
// out are of type browser. As such, this preserves any dragged out
// constrained windows (aka popups that have been dragged out).
// . Sorts the tabs in windows with valid tabs based on the tabs;
// visual order, and adds the valid windows to |valid_windows|.
void SortTabsBasedOnVisualOrderAndClear(
IdToSessionWindow* windows,
std::vector<std::unique_ptr<SessionWindow>>* valid_windows) {
std::vector<std::unique_ptr<SessionWindow>>* valid_windows,
std::set<SessionID>* discarded_window_ids) {
for (auto& window_pair : *windows) {
std::unique_ptr<SessionWindow> window = std::move(window_pair.second);
if (window->tabs.empty() || window->is_constrained) {
discarded_window_ids->insert(window->window_id);
continue;
} else {
// Valid window; sort the tabs and add it to the list of valid windows.
@ -454,7 +457,8 @@ void CreateTabsAndWindows(
GroupIdToSessionTabGroup* tab_groups,
IdToSessionWindow* windows,
SessionID* active_window_id,
std::string* platform_session_id) {
std::string* platform_session_id,
std::set<SessionID>* discarded_window_ids) {
// If the file is corrupt (command with wrong size, or unknown command), we
// still return true and attempt to restore what we we can.
DVLOG(1) << "CreateTabsAndWindows";
@ -526,11 +530,13 @@ void CreateTabsAndWindows(
DVLOG(1) << "Failed reading command " << command->id();
return;
}
if (command->id() == kCommandTabClosed)
tabs->erase(SessionID::FromSerializedValue(payload.id));
else
windows->erase(SessionID::FromSerializedValue(payload.id));
SessionID id = SessionID::FromSerializedValue(payload.id);
if (command->id() == kCommandTabClosed) {
tabs->erase(id);
} else {
windows->erase(id);
discarded_window_ids->insert(id);
}
break;
}
@ -1257,16 +1263,18 @@ void RestoreSessionFromCommands(
const std::vector<std::unique_ptr<SessionCommand>>& commands,
std::vector<std::unique_ptr<SessionWindow>>* valid_windows,
SessionID* active_window_id,
std::string* platform_session_id) {
std::string* platform_session_id,
std::set<SessionID>* discarded_window_ids) {
IdToSessionTab tabs;
GroupIdToSessionTabGroup tab_groups;
IdToSessionWindow windows;
DVLOG(1) << "RestoreSessionFromCommands " << commands.size();
CreateTabsAndWindows(commands, &tabs, &tab_groups, &windows, active_window_id,
platform_session_id);
platform_session_id, discarded_window_ids);
AddTabsToWindows(&tabs, &tab_groups, &windows);
SortTabsBasedOnVisualOrderAndClear(&windows, valid_windows);
SortTabsBasedOnVisualOrderAndClear(&windows, valid_windows,
discarded_window_ids);
UpdateSelectedTabIndex(valid_windows);
// After processing, all windows should have at least one tab, and each
// tab should have at least one navigation.

@ -126,14 +126,18 @@ SESSIONS_EXPORT bool ReplacePendingCommand(
SESSIONS_EXPORT bool IsClosingCommand(SessionCommand* command);
// Converts a list of commands into SessionWindows. On return any valid
// windows are added to |valid_windows|. |active_window_id| will be set with the
// windows are added to `valid_windows`. `active_window_id` will be set with the
// id of the last active window, but it's only valid when this id corresponds
// to the id of one of the windows in |valid_windows|.
// to the id of one of the windows in `valid_windows`. Discarded
// windows, eg: the ones with no tab or previously closed are inserted
// into `discarded_window_ids`. If present, `platform_session_id` is set with
// the window system level session id, on platforms that support it.
SESSIONS_EXPORT void RestoreSessionFromCommands(
const std::vector<std::unique_ptr<SessionCommand>>& commands,
std::vector<std::unique_ptr<SessionWindow>>* valid_windows,
SessionID* active_window_id,
std::string* platform_session_id);
std::string* platform_session_id,
std::set<SessionID>* discarded_window_ids);
} // namespace sessions