-
Notifications
You must be signed in to change notification settings - Fork 121
Show/Hide attached surfaces when entering/exiting from fullscreen #4664
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Show/Hide attached surfaces when entering/exiting from fullscreen #4664
Conversation
e76e32d to
4a67dd1
Compare
AlanGriffiths
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No tests?
src/miral/basic_window_manager.cpp
Outdated
| bool const was_fullscreen{info.state() == mir_window_state_fullscreen}; | ||
| if (was_fullscreen) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for a variable (especially with scope beyond the if statement).
But... does this code belong here anyway? I mean, if the focus shifts to another fullscreen window we need to undo this work.
Instead, when a window (or no window) gets focus we should be checking the state of the attached windows and acting accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I looked into it. This is the latest we can do this check. It was added specifically for the case where you have a fullscreen window, and you close it without exiting fullscreen first.
In that case, a few lines later, the info for this window will be erased before we reach the focus checking code, so we won't be able to move this code there.
mattkae
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An initial ask!
states They are attached! The previous state is constant for all of them!
Mir saw that the buffer is not mapped, but the client submitted a buffer with a size, so it sets its status to restored. `place_and_size_for_state` then sees that the attached client is not overlapping with the application zone. Which is correct because application zones shrink for attached surfaces with exclusion zones. It then tries to center the surface in the application zone, causing clients like waybar, ironbar, and gbar to appear in the middle of the screen when they try submitting a buffer while hidden under a fullscreen app.
…p to a fullscreen app
|
Something I've just realized is that I haven't taken into account cases where focus changes (or a surface is closed) with the closed surface and the newly focused surface on different outputs/display areas. So far I've assumed both are on the same display area. Another thing I should mention is that focus handling feels quite messy at the moment. For example, when we have two apps open. Let's call them A and B. If we close A, Context: mir/src/miral/basic_window_manager.cpp Lines 327 to 349 in 38d8e69
mir/src/miral/basic_window_manager.cpp Lines 578 to 581 in 38d8e69
We also call mir/src/miral/basic_window_manager.cpp Lines 385 to 402 in 38d8e69
Then that calls mir/src/miral/basic_window_manager.cpp Line 1703 in 38d8e69
Then we execute the rest of Edit: I just realized that I've worked on this alone for 120% of my time today. So there might be a solution to the mini-rant above that my neurons are just too fried to see right now. |
Should appease GCC
When there would be a layer shell surface with and a fullscreen surface on one output, and we click on empty space in the other output, this would cause the hidden layer shell surface to erroneously be restored.
its own private method
…al to its own private method
|
Bug: With two outputs, if we:
Edit: After thinking about it properly, no. waybar should not be automatically hidden. It will be hidden again if we focus terminal A, but it doesn't need to be hidden when focus is not on it. |
and window removal handling code
multiple outputs In that case, `current` was the attached surface on the other output, we later would return when seeing that it was not in the application layer, without restoring attached surfaces on the previous display area.
AlanGriffiths
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems messy.
I don't have a clear solution to offer, but trying to model a window state of "attached and hidden" as "hidden and in a list" introduces a lot of corner cases that might be avoided with another approach. (A separate "hidden" property or a new "attached and hidden" state.)
| hidden_attached_windows.push_back(window); | ||
| bwm.set_state(info, mir_window_state_hidden); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This mixing of logic across BasicWindowManager and DisplayArea seems inelegant.
Another way to divide the logic:
void miral::BasicWindowManager::DisplayArea::update_hidden_attached(std::function<bool(Window const& w) predicate)
{
// Copy as `predicate` may modify `attached_windows` and invalidate the iterator.
auto const attached_windows = this->attached_windows;
decltype(hidden_attached_windows) hidden_attached_windows;
for (auto& window : attached_windows)
{
if (predicate(window))
{
hidden_attached_windows.push_back(window);
}
}
this->hidden_attached_windows = std:move(hidden_attached_windows);
} current_display_area->update_hidden_attached([this](Window const& w)
{
auto& info = info_for(window);
if (info.depth_layer() != mir_depth_layer_above) return false;
set_state(info, mir_window_state_hidden);
return true;
});| } | ||
| } | ||
|
|
||
| void miral::BasicWindowManager::DisplayArea::hide_all_attached(BasicWindowManager& bwm) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name is wrong - only some attached are hidden.
| auto current = window; | ||
| while (current) | ||
| { | ||
| auto& info = bwm.info_for(current); | ||
| if (info.state() == mir_window_state_fullscreen) | ||
| return true; | ||
| current = info.parent(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a weirdly written for loop?
| if (!window) | ||
| return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Redundant check?
| rect.top_left.y = zone.top_left.y + 0.5 * std::max(DeltaY{}, zone.size.height - rect.size.height); | ||
| } | ||
|
|
||
| auto is_window_or_parent_fullscreen(miral::Window const& window, miral::BasicWindowManager& bwm) -> bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simpler as a BasicWindowManager member function?
| void miral::BasicWindowManager::DisplayArea::restore_all_attached(BasicWindowManager& bwm) | ||
| { | ||
| for (auto& window : hidden_attached_windows) | ||
| { | ||
| if(!window) | ||
| continue; | ||
|
|
||
| auto& info = bwm.info_for(window); | ||
| bwm.set_state(info, mir_window_state_attached); | ||
| } | ||
|
|
||
| hidden_attached_windows.clear(); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Name wrong:
- it is not all attached that are restored; and,
- "restored" is a window state distinct from "attached"
| // If a layer shell surface (waybar) tries to submit a buffer while | ||
| // its hidden (in favor of another fullscreen surface), don't try | ||
| // to modify its placement. | ||
| if (display_area_for(info)->is_hidden_attached(info)) | ||
| mods.state().consume(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems overbroad: it bans any transitions. E.g. a panel that decides to transition from "attached" to "restored" (and, maybe, change layer too).
Closes #3274
What's new?
BasicWindowManagerto hide/restore attached surfaces in the "above" layer when a surface is fullscreened, unfullscreened, and removed.How to test
Scenario 1: waybar on the above layer + fullscreen app
~/.config/waybar/config):Scenario 2: Multiple outputs
Scenario 3: Fullscreen app and OSK
ubuntu-frame-oskkate, open any text file. OSK should pop up.Preferably, we'd like the OSK to be visible when an app is fullscreened, but since it's placed in the "above" layer, and we have no way in the layer shell protocol to identify it, it will be broken for now.
Scenario 4: Waybar + Fullscreen app + non-fullscreen app
This follows scenario 1, with the following extra steps
Scenario 5: Waybar + Fullscreen app exits
Repeat scenario 1. Then close the app via a shortcut. If using a terminal, CTRL + D. Waybar should pop into view once more.
Scenario 5: Waybar + Fullscreen app with child surfaces
Media > Open Fileor Ctrl + o,Scenario 6:
Same as scenario 4, but instead of switching focus between the two apps, you exit the non-fullscreen app first.
Focus should switch to the fullscreen app, and waybar should remain hidden.
Checklist