Skip to content

Commit

Permalink
Fix minimized windows being focused when a focused window is closed (#…
Browse files Browse the repository at this point in the history
…3698)

Closes #3408
  • Loading branch information
mattkae authored Jan 21, 2025
2 parents 11c3234 + cc27301 commit 9fc7694
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 32 deletions.
15 changes: 15 additions & 0 deletions src/miral/application_selector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,10 @@ auto ApplicationSelector::advance(bool reverse, bool within_app) -> Window
is_active_ = true;
}

// If nothing is selected, start from the begining of the list.
if(!selected)
selected = *focus_list.begin();

// Attempt to focus the next application after the selected application.
auto it = find(selected);

Expand All @@ -231,7 +235,11 @@ auto ApplicationSelector::advance(bool reverse, bool within_app) -> Window
// This means that there is no other selectable window in the list but
// the currently selected one, so we don't need to select anything.
if (*it == selected)
{
if(!tools.info_for(selected).is_visible())
tools.select_active_window(selected);
return selected;
}

if (within_app)
{
Expand Down Expand Up @@ -279,7 +287,14 @@ auto ApplicationSelector::advance(bool reverse, bool within_app) -> Window

auto next_state_to_preserve = tools.info_for(next_window.value()).state();
tools.select_active_window(next_window.value());

// When using the application selector, the selection/raising of apps is
// more of a "preview" than actually selecting the application.
//
// So, apps should return to their previous state whenever we move on from
// them. Minimized apps should return to being minimized.
restore_state = next_state_to_preserve;

return next_window.value();
}

Expand Down
71 changes: 39 additions & 32 deletions src/miral/basic_window_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,22 +301,18 @@ void miral::BasicWindowManager::refocus(
// Try to activate to recently active window of any application in a shared workspace
{
miral::Window new_focus;
auto workspaces_containing_window_mut = workspaces_containing_window;
std::sort(workspaces_containing_window_mut.begin(), workspaces_containing_window_mut.end());

mru_active_windows.enumerate([&](miral::Window& window)
mru_active_windows.enumerate(
[&](miral::Window& other_window)
{
// select_active_window() calls set_focus_to() which updates mru_active_windows and changes window
auto const w = window;
if (!info_for(other_window).is_visible())
return true;

for (auto const& workspace : workspaces_containing(w))
{
for (auto const& ww : workspaces_containing_window)
{
if (ww == workspace)
{
return !(new_focus = select_active_window(w));
}
}
}
// select_active_window() calls set_focus_to() which updates mru_active_windows and changes window
if (window_workspaces_intersect(workspaces_containing_window_mut, other_window))
return !(new_focus = select_active_window(other_window));

return true;
});
Expand All @@ -327,22 +323,23 @@ void miral::BasicWindowManager::refocus(
if (can_activate_window_for_session(application))
return;

// Try to activate to recently active window of any application
// Try to activate the recently active window of any application
{
miral::Window new_focus;

mru_active_windows.enumerate([&](miral::Window& window)
{
// select_active_window() calls set_focus_to() which updates mru_active_windows and changes window
auto const w = window;
if(!info_for(w).is_visible()) return true;
return !(new_focus = select_active_window(w));
});

if (new_focus) return;
}

// Fallback to cycling through applications
focus_next_application();
// Can't focus anything else
focus_controller->set_focus_to(nullptr, nullptr);
}

void miral::BasicWindowManager::erase(miral::WindowInfo const& info)
Expand Down Expand Up @@ -1501,24 +1498,17 @@ void miral::BasicWindowManager::set_state(miral::WindowInfo& window_info, MirWin

if (window == active_window() || !active_window())
{
auto const workspaces_containing_window = workspaces_containing(window);
auto workspaces_containing_window = workspaces_containing(window);
std::sort(workspaces_containing_window.begin(), workspaces_containing_window.end());

// Try to activate to recently active window of any application
mru_active_windows.enumerate([&](Window& candidate)
{
if (candidate == window)
if (candidate == window || !info_for(candidate).is_visible())
return true;
auto const w = candidate;
for (auto const& workspace : workspaces_containing(w))
{
for (auto const& ww : workspaces_containing_window)
{
if (ww == workspace)
{
return !(select_active_window(w));
}
}
}

if(window_workspaces_intersect(workspaces_containing_window, candidate))
select_active_window(candidate);

return true;
});
Expand All @@ -1528,10 +1518,9 @@ void miral::BasicWindowManager::set_state(miral::WindowInfo& window_info, MirWin
if (window == active_window() || !active_window())
mru_active_windows.enumerate([&](Window& candidate)
{
if (candidate == window)
if (candidate == window || !info_for(candidate).is_visible())
return true;
auto const w = candidate;
return !(select_active_window(w));
return !(select_active_window(candidate));
});

if (window == active_window())
Expand Down Expand Up @@ -3001,3 +2990,21 @@ void miral::BasicWindowManager::move_cursor_to(mir::geometry::PointF point)
});
});
}

auto miral::BasicWindowManager::window_workspaces_intersect(std::vector<std::shared_ptr<Workspace>> const& w1_workspaces, Window const& w2) const -> bool
{
auto w2_workspaces = workspaces_containing(w2);
std::sort(w2_workspaces.begin(), w2_workspaces.end());

auto intersection = std::vector<std::shared_ptr<Workspace>>();

std::set_intersection(
w1_workspaces.begin(),
w1_workspaces.end(),
w2_workspaces.begin(),
w2_workspaces.end(),
std::back_inserter(intersection));

return !intersection.empty();
}

4 changes: 4 additions & 0 deletions src/miral/basic_window_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,10 @@ class BasicWindowManager : public virtual mir::shell::WindowManager,
void for_each_descendent_in(WindowInfo const& info, std::function<void(const Window&)> func);
/// Gathers windows provided WindowInfo
auto collect_windows(WindowInfo const& info) -> SurfaceSet;

// w1_workspaces must be sorted
auto window_workspaces_intersect(
std::vector<std::shared_ptr<Workspace>> const& w1_workspaces, Window const& w2) const -> bool;
};
}

Expand Down

0 comments on commit 9fc7694

Please sign in to comment.