Skip to content
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

Implement floating #2027

Merged
merged 34 commits into from Jun 1, 2018
Merged

Implement floating #2027

merged 34 commits into from Jun 1, 2018

Conversation

RyanDwyer
Copy link
Member

This implements basic floating features. You can float views, unfloat views, make them sticky and unsticky, and click to focus/unfocus them. You cannot move or resize them.

I was going to make it so you can float C_CONTAINERs in this PR, but there were some issues and I wanted to get this in front of everyone for review, so I blocked off that functionality. There's still bits in the code where it handles C_CONTAINERs being floated though.

This PR has a known issue with floating xdg_shell views when using multiple outputs. If floating the view on the left output, I'm experiencing a flickering copy of the container at the same output-local position on the right output. This does not happen for xwayland views. I can't see what I'm doing wrong, so if someone can assist me with that then that would be appreciated.

I went with the approach of having a sway_workspace->floating property, but I made it a struct sway_container * rather than a list_t. Using a container makes it easier to pass to functions that expect to be given a container. This floating container is created at workspace creation, destroyed at workspace destruction, and is immune to reaping. The type of this container is C_CONTAINER and the layout is irrelevant and never used.

Each view implementation has a new wants_floating function, which allows the implementation to inspect the view and determine if it should be floating or not. There's a basic/terrible implementation for xwayland already done, but there needs to be some discussion on how to do this properly. Perhaps wlroots should expose its own list of window types so we don't have to use the xcb library. At the moment I'm using magic numbers, but this is a temporary solution.

Test plan:

  • Use as daily driver
  • Float and unfloat things
  • Make things sticky and unsticky
  • Use multiple outputs

My preference is to implement the move/resize commands and floating C_CONTAINERs as separate PRs.

title_texture = con->title_unfocused;
marks_texture = view->marks_unfocused;
}
render_titlebar(soutput, damage, con, con->x, con->y, con->width,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be a check against the border style here. If you have a floating view with opacity set below 1.0 and border pixel or border none, the title bar is visible since it is being rendered underneath the view.

@@ -76,6 +75,14 @@ struct sway_container {
enum sway_container_layout layout;
enum sway_container_layout prev_layout;

// Allow the container to be automatically removed if it's empty. True by
// default, false for the magic floating container that each workspace has.
bool reapable;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, why don't you keep the L_FLOATING for the floating container?

bool reapable;

// Saves us from searching the list of children/floating in the parent
bool is_floating;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is_floating is trivially implemented with a function

@RedSoxFan
Copy link
Member

I found a couple more issues:

  1. If you fullscreen enable a floating view and then fullscreen disable it, the position and geometry are not restored and the view remains to cover the entire output.
  2. When you focus a sticky view, whatever workspace the view was made sticky on is switched to

@@ -32,7 +32,9 @@ struct sway_view_impl {
void (*configure)(struct sway_view *view, double ox, double oy, int width,
int height);
void (*set_activated)(struct sway_view *view, bool activated);
void (*set_maximized)(struct sway_view *view, bool maximized);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be renamed set_tiled (see #1988).

@@ -22,8 +22,6 @@ static const char *layout_to_str(enum sway_container_layout layout) {
return "L_STACKED";
case L_TABBED:
return "L_TABBED";
case L_FLOATING:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be added back?

// coordinates into output-local coordinates. This needs to happen for all
// children of the floating container too.
struct sway_container *output = container_parent(con, C_OUTPUT);
container_translate(con, -output->x, -output->y);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm really not a fan of this. Find another way.

Copy link
Member Author

@RyanDwyer RyanDwyer May 26, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not a fan either. The options I can think of for this are:

  1. Adjust the container's position temporarily as it currently does.
  2. Have file-scoped translate_x and translate_y variables, which are 0 if the container being rendered is tiled, and the inverse of the output's position if floating. The rendering functions would add the translation to the thing being rendered, so it's basically forced into output-level scope.
  3. Same as above, but using a wlr_matrix instead of the translate variables.
  4. Use layout-local coordinates for all swayc positions, then subtract the output's position when adding damage and rendering anything.

Options 2 and 3 are pretty complicated. To damage or render any view, you have to figure out if the view is itself floating or a child of a floating container (this isn't supported yet but will be later). If it is, its coordinates are layout-local and need to be translated to output-local coordinates.

I think the best option is option 4 - use layout-local coordinates for all swaycs. This would also resolve the "these coords might be layout-local or output-local" issue that you pointed out in #2027 (review).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went and implemented option 4. That particular commit was +71, -130. It has simplified other areas of the codebase and appears to have fixed my damage problems too.

}
}

static bool floater_intersects_output(struct sway_container *floater,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't enough, because popups/subsurfaces can be outside of this box and still need to get rendered.

@@ -839,6 +923,8 @@ static void render_output(struct sway_output *output, struct timespec *when,
&root_container.sway_root->xwayland_unmanaged);
render_layer(output, damage,
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);

render_floating(output, damage);
Copy link
Member

@emersion emersion May 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Floating is under the top layer and under xwayland unmanaged surfaces

@@ -915,6 +1001,7 @@ static void send_frame_done(struct sway_output *output, struct timespec *when) {

struct sway_container *workspace = output_get_active_workspace(output);
send_frame_done_container(&data, workspace);
send_frame_done_container(&data, workspace->sway_workspace->floating);

This comment was marked as resolved.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand this comment. Is this still relevant after my most recent commits, and if so can you please clarify what you mean?

@@ -1036,7 +1123,15 @@ static void output_damage_view(struct sway_output *output,

void output_damage_from_view(struct sway_output *output,
struct sway_view *view) {
output_damage_view(output, view, false);
if (container_self_or_parent_floating(view->swayc)) {
view->x -= output->swayc->x;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meh, I'm sure there's a nicer way to do this

@@ -117,6 +126,11 @@ static void set_fullscreen(struct sway_view *view, bool fullscreen) {
wlr_xdg_toplevel_set_fullscreen(surface, fullscreen);
}

static bool wants_floating(struct sway_view *view) {
// TODO
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can return true if the view isn't resizable, ie. if the min size is equal to the max size.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please clarify this? The wants_floating function is called when a view is mapped so that the implementation can decide whether it's floating by default (eg. for dialogs).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I'm just suggesting a way to implement this for xdg-shell.

// TODO: Let floating views do whatever
view_update_size(view, xdg_shell_view->pending_width,
xdg_shell_view->pending_height);
struct wlr_box *geometry = &view->wlr_xdg_surface->geometry;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The xdg-surface geometry can be unset, in which case the surface's size should be used.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure about that? wlr_xdg_shell contains these:

bool has_next_geometry;
struct wlr_box next_geometry;
struct wlr_box geometry;

...which suggests to me that the geometry struct is always present.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The client doesn't always set the geometry, so this box can be empty. We should probably document this, it's written in the protocol itself.

@@ -97,6 +97,7 @@ static void configure(struct sway_view *view, double ox, double oy, int width,
xdg_shell_view->pending_width = width;
xdg_shell_view->pending_height = height;
wlr_xdg_toplevel_set_size(view->wlr_xdg_surface, width, height);
view_update_position(view, ox, oy);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is documented to take layout coords

@@ -97,6 +97,7 @@ static void configure(struct sway_view *view, double ox, double oy, int width,
xdg_shell_v6_view->pending_width = width;
xdg_shell_v6_view->pending_height = height;
wlr_xdg_toplevel_v6_set_size(view->wlr_xdg_surface_v6, width, height);
view_update_position(view, ox, oy);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All my comments on xdg-shell also apply here

@@ -152,33 +152,43 @@ static uint32_t get_int_prop(struct sway_view *view, enum sway_view_prop prop) {
}
}

static void configure(struct sway_view *view, double ox, double oy, int width,
// The x and y arguments are output-local for tiled views, and layout
// coordinates for floating views.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm.

}
struct wlr_output_layout *layout = root->sway_root->output_layout;
struct wlr_output_layout_output *loutput =
wlr_output_layout_get(layout, output->sway_output->wlr_output);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to do all of this. Just take the struct sway_container *output's coordinates.

case 44: // NET_WM_WINDOW_TYPE_SPLASH
case 276: // ? PGP passphrase dialog
case 337: // ? Firefox open file dialog
case 338: // ? Firefox open file dialog
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's implement this instead of having these magic values :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wlroots needs to expose its atom names first. And I'm a bit confused with how this all works - wlroots lacks atom names DIALOG and TOOLBAR which are used by i3. And according to wlr_xwayland_surface_is_unmanaged, surfaces with atoms SPLASH and UTILITY will be unmanaged, but to match i3 these would need to be managed and floated.

BTW, according to Ongy the atom values are defined at runtime, so I've removed the hard coded values from my PR. Keeping them there may cause false positives.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can do the wlroots PR tonight if that helps

view->natural_height = xsurface->height;
}
if (view->swayc && container_is_floating(view->swayc)) {
view_update_size(view, xsurface->width, xsurface->height);

This comment was marked as resolved.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is resolved in commit "Don't let xwayland views set position unless unmanaged".

.width = floater->width,
.height = floater->height,
};
if (wlr_box_contains_point(&box, lx, ly)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't work with subsurfaces/popups outside the box

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I floated Firefox, then right clicked near the right side so the context menu popped up outside of the float. I can interact with the popup outside the floating area just fine. That's because layer surfaces are checked before floating_container_at and container_at are called.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is completely unrelated to layer surfaces. Firefox is xwayland, which uses unmanaged surfaces that are global to the whole layout and don't have a parent. I'm talking about xdg-popups and wayland subsurfaces.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can replicate this with FileZilla. However, I can also replicate it when tiled, and I can replicate in master, and I can replicate it in master from a week ago which was prior to when I split container_at into separate functions. So this problem has been around for a while.

I guess the solution will be to iterate the containers, check their subsurfaces first, then iterate them all again and check the toplevel surface. The same has to happen for rendering too - currently a tiled view can render over the top of its left sibling's context menu.

My preference is to make a separate PR for this because it's not specific to floating.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Filezilla is not using xdg-shell. Pick any GTK+3 app, right click, and you should get a popup.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bump

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, can you just remove this wlr_box_contains_point check and only use container_at?

container_damage_whole(container);
}

void container_set_geometry_from_view(struct sway_container *container) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name should make it more obvious that it expects a floating view - maybe container_set_geometry_from_floating_view?

container->height = top + view->height + border_width;
}

bool container_self_or_parent_floating(struct sway_container *container) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This name is weird, and doesn't match what the function really does?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the change of swayc coordinates from output-local to layout-local, this function was no longer needed so I've deleted it.

sway/tree/view.c Outdated
void view_update_position(struct sway_view *view, double ox, double oy) {
if (view->swayc->x == ox && view->swayc->y == oy) {
void view_update_position(struct sway_view *view, double lx, double ly) {
if (!container_is_floating(view->swayc)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should still do nothing if the position hasn't changed

@@ -450,8 +454,10 @@ static void render_titlebar(struct sway_output *output,
wlr_texture_get_size(marks_texture,
&texture_box.width, &texture_box.height);
texture_box.x =
(x + width - TITLEBAR_H_PADDING) * output_scale - texture_box.width;
texture_box.y = (y + TITLEBAR_V_PADDING) * output_scale;
(x - output->wlr_output->lx + width - TITLEBAR_H_PADDING)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use output->wlr_output->lx, use output->swayc->x instead

@emersion emersion mentioned this pull request May 26, 2018
13 tasks
@sam-lord
Copy link

sam-lord commented Jun 1, 2018

Tried using this, top borders not rendered on windows which start as floating (gnome-terminal preferences window and gnome-keyring when opening Geary).

@ddevault
Copy link
Contributor

ddevault commented Jun 1, 2018

I don't want to hold this up forever so I'm going to file a separate ticket for the border issue.

@ddevault ddevault merged commit 96446fd into swaywm:master Jun 1, 2018
@RyanDwyer RyanDwyer deleted the implement-floating branch June 2, 2018 00:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants