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:
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user