Skip to content

Text Selection does not work correctly with multiple deferred viewports when the unfocused viewport requires repainting #4758

@lukexor

Description

@lukexor

Describe the bug

This is a bit of an odd case and took me a long time to track down.

Use case:

Two windows - a primary and a secondary.
Primary window requires re-painting at 60fps (rendering animations/frames/etc)
Secondary window only requires re-painting in response to user interaction (e.g. a preferences window)

Trying to select text in the secondary window works fine only when it's the one being repainted. If the primary window repaints after selection has started, selection is cleared.

The relevant lines of code are from the label_text_selection.rs module:

        if !state.has_reached_primary || !state.has_reached_secondary {
            // We didn't see both cursors this frame,
            // maybe because they are outside the visible area (scrolling),
            // or one disappeared. In either case we will have horrible glitches, so let's just deselect.

            let prev_selection = state.selection.take();

I suspect the reason this happens is because the store/load happening for the temporary selection state is not keyed at all by viewport, and because deferred viewports require their own begin/end frame cycle it ends up clearing the selection since the primary window was repainted and no widgets matched the current selection state.

    pub fn load(ctx: &Context) -> Self {
        ctx.data(|data| data.get_temp::<Self>(Id::NULL))
            .unwrap_or_default()
    }

    pub fn store(self, ctx: &Context) {
        ctx.data_mut(|data| {
            data.insert_temp(Id::NULL, self);
        });
    }

To Reproduce

  1. Modify the test_viewports example to add a ctx.request_repaint_of(ViewportId::ROOT); to the main update method
  2. Open a deferred viewport and try to select a label - it gets immediately cleared
  3. Open an immediate viewport and try to select a label - works as expected

Expected behavior

I'd expect selecting labels to work correctly

Desktop (please complete the following information):

  • OS: Linux

Additional context

I was able to get a working version with the following. If it's acceptable, I can create a PR:

    pub fn load(ctx: &Context) -> Self {
        let id = Id::new(ctx.viewport_id());
        ctx.data(|data| data.get_temp::<Self>(id))
            .unwrap_or_default()
    }

    pub fn store(self, ctx: &Context) {
        let id = Id::new(ctx.viewport_id());
        ctx.data_mut(|data| {
            data.insert_temp(id, self);
        });
    }

Metadata

Metadata

Assignees

Labels

bugSomething is brokenviewportsmultiple viewports, viewports API

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions