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

Atomic layout updates #1650

Closed
5 tasks
ddevault opened this issue Mar 30, 2018 · 1 comment
Closed
5 tasks

Atomic layout updates #1650

ddevault opened this issue Mar 30, 2018 · 1 comment

Comments

@ddevault
Copy link
Contributor

ddevault commented Mar 30, 2018

We want every frame to be perfect - every buffer shown at its native size, no windows overlaying (in the tiled layout), etc. Accomplishing this is non-trivial.

  • Atomic tree updates
  • Atomic modeset updates
  • Atomic fullscreen toggle
  • Atomic floating windows
  • Atomic focus updates

The plan is, in discrete tasks:

1. Refactor arrange_windows

Currently, arrange_windows lays out the windows, writes the desired boxes of everything to the tree, and sends configure events to clients. This needs to be broken into three steps, which will currently just be called at once (not attempting to be atomic, just refactoring the current behavior). The three steps are:

Call arrange_layout, which should most of the work arrange_windows does today, but outputs a list of:

struct container_layout {
    struct sway_container *container;
    struct wlr_box box;
};

We will call this list the "layout". Next, call configure_layout, which should send configure events to clients affected by the layout update.

for pending in layout:
   client.send_configure <- pending.box

Finally, call apply_layout to syncronize a potential layout with the actual sway tree.

for pending in layout:
    swayc.box <- pending.box

Now, let's change arrange_windows to look like this:

void arrange_windows(struct sway_container *container) {
    struct wl_list layout; // container_layout::link
    layout <- arrange_layout <- container
    configure_layout <- layout
    apply_layout <- layout
}

2. Wait to apply layouts until all clients are ready

We now need to stash the configure serials for each client that was notified of pending changes. We define this data structure:

struct pending_configure {
    int serial;
    struct wl_list link;
};

struct pending_layout {
    struct wl_list layout; // container_layout::link
    struct wl_list configures; // pending_configure::link
};

Then we update arrange_windows:

void arrange_windows(struct sway_container *container) {
    struct pending_layout pending;
    pending.layout <- arrange_layout <- container
    pending.configures <- configure_layout <- pending.layout
    root_container.pending layouts <- pending
}

Notably, we don't call apply_layout. Instead, we stow the pending layout somewhere and we update the ack_configure handler for the shell to look up the pending layout.

handle_ack_configure(...) {
    pending_layout <- find pending layout
    pending_configure <- find pending configure
    wl_list_remove(pending_configure.link)
    if empty(pending_layout.configures):
        apply_layout <- pending_layout.layout
}

Milestone: non-interactive updates will be atomic (mode changes, switch layout from splitv to splith, etc)

3. Stash textures on each ack configure

Then we can render the latest known good version of old clients, even if they ack different frames at different times.

Milestone: interactive updates will be atomic, but may be laggy

4. Time out pending layouts to deal with slow clients

Periodically check the list of pending layouts and apply them anyway if they get too old.

Milestone: interactive updates are atomic for fast clients but don't let slow clients cause lag (will instead render slow clients incorrectly)

@ddevault
Copy link
Contributor Author

Something else to consider is that eventually we'll probably want to have some kind of callback function that gets hit when it's time to apply the layout, in addition to simply applying it. This could be used, for example, during modeswitching (arrange layout for the new mode, wait for all clients to be ready, then change the mode and apply the layout) or workspace switching (wait to actually switch the workspace until the new focused client has acked the focus change).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

1 participant