event_loop: route take_focus_request to widgets on overlay surfaces

The `take_focus_request` block in `try_run` only searched `data.main.widget_rects` for the requested `WidgetId`, so an app that wanted to focus a widget living on an overlay surface (a search field on a launcher overlay, a text edit on a dialog modal, a password field on a popup) silently no-op'd: the widget existed and had been laid out, but the lookup never found it because it was scanning the wrong `widget_rects`. Crustace hit this trying to put cursor focus on the launcher search field when the launcher slides up — the field rendered with a visible caret but typing went to whoever the keyboard had been focused on before.
The lookup now falls through to `data.overlays.iter()` if the main scan misses, returning the first `(SurfaceFocus::Overlay(id), flat_idx)` whose surface carries a widget with that id. `data.set_focus` already accepts the `SurfaceFocus` discriminant, so the call site just forwards what the lookup found and requests a redraw on the matching surface instead of unconditionally on main. No effect on apps that target main-surface widgets — the main scan still runs first and short-circuits the overlay walk.
This commit is contained in:
2026-05-13 13:47:01 +02:00
parent c3839060cc
commit 96f437544a

View File

@@ -497,17 +497,41 @@ pub( crate ) fn try_run<A: App>( app: A ) -> Result<(), RunError>
draw_frame( &mut data ); draw_frame( &mut data );
} }
// Focus the widget with the requested WidgetId if the app requests it // Focus the widget with the requested WidgetId if the app requests it.
// Walks main + every overlay because the targeted widget can live
// on any of them (a search field on a launcher overlay, a text
// edit on a dialog modal, …).
if let Some( id ) = data.app.take_focus_request() if let Some( id ) = data.app.take_focus_request()
{ {
let found = data.main.widget_rects.iter() let mut hit: Option<( SurfaceFocus, usize )> = data.main.widget_rects.iter()
.find( |w| w.id == Some( id ) ) .find( |w| w.id == Some( id ) )
.map( |w| w.flat_idx ); .map( |w| ( SurfaceFocus::Main, w.flat_idx ) );
if let Some( flat_idx ) = found if hit.is_none()
{
for ( ov_id, surf ) in &data.overlays
{
if let Some( w ) = surf.widget_rects.iter().find( |w| w.id == Some( id ) )
{
hit = Some( ( SurfaceFocus::Overlay( *ov_id ), w.flat_idx ) );
break;
}
}
}
if let Some( ( focus, flat_idx ) ) = hit
{ {
let qh = data.qh.clone(); let qh = data.qh.clone();
data.set_focus( SurfaceFocus::Main, Some( flat_idx ), &qh ); data.set_focus( focus, Some( flat_idx ), &qh );
data.main.request_redraw(); match focus
{
SurfaceFocus::Main => data.main.request_redraw(),
SurfaceFocus::Overlay( id ) =>
{
if let Some( s ) = data.overlays.get_mut( &id )
{
s.request_redraw();
}
}
}
} }
} }
} }