servo/ports/winit/minibrowser.rs
Delan Azabani 2778beeb7a
winit: initial minibrowser (#29976)
* winit: add minibrowser feature that depends on egui{,-winit}

* winit: carve out some space at the top of headed windows

* winit: minimal toolbar and egui/winit integration (but no painting)

* winit: try to paint with egui_glow (doesn’t work yet)

* winit: add comment about toolbar size

* Add framebuffer object, set it as glow's target

* compositing: clear only the viewport, not the whole framebuffer

* plumb the actual size of the egui toolbar to webrender

* fix formatting

* winit: fix crash when fbo is zero

* winit: don’t bother binding the framebuffer object

* winit: remove unsafe and get toolbar_height

* winit: location field should reflect the current top-level url

* [NFC] winit: move Minibrowser out of App::run

* winit: clean up toolbar height code

* winit: make App own the Minibrowser if any

* winit: make the go button work

* winit:make the location field reflect the current top-level url

* winit: allow enabling minibrowser from command line

* winit: tell compositor to repaint WR and flush when we repaint

* winit: fix bug where location field edits would get overridden

* winit: borrow the minibrowser once in App::handle_events

* winit: address todo about viewport origin coordinates

* winit: fix some minor problems with comments and errors

* winit: update location field once per HistoryChanged event

* winit: rename Window::set_toolbar_size to set_toolbar_height

* winit: take toolbar height into account in hit testing

* winit: pass egui only relevant CursorMoved events

* winit: scratch that, coalesce minibrowser updates instead

* ensure both minibrowser and WR are repainted on every frame

* compositing: only skip framebuffer clear in external present mode

* winit: destroy egui glow Painter when shutting down

* winit: clean up and fix license lint

* fix duplicate versions lint by downgrading bytemuck_derive

was egui_glow ^0.22.0 (0.22.0)
→ egui/bytemuck ^0.22.0 (0.22.0)
→ epaint/bytemuck ^0.22.0 (0.22.0)
→ bytemuck ^1.7.2 (1.13.1)
→ bytemuck_derive ^1.4 (1.4.1)
→ syn ^2.0.1 (2.0.28)

now lock has bytemuck_derive 1.4.0
→ syn ^1.0.99 (1.0.103)

* fix duplicate versions lint by disabling egui-winit/links

(we don’t need support for hyperlinks in our use of egui)

* squelch duplicate versions lint by excluding clipboard-win

* winit: fix compile warnings

* winit: make gleam an optional dependency under /minibrowser

* winit: remove cargo feature, since it’s not really optional

* winit: extract Minibrowser and related code to separate module

* winit: remove unnecessary trailing comma

* winit: simplify the ServoUrl serialisation optimisation

---------

Co-authored-by: atbrakhi <atbrakhi@igalia.com>
2023-08-15 08:08:50 +00:00

110 lines
4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::{cell::{RefCell, Cell}, sync::Arc};
use egui::TopBottomPanel;
use servo::{servo_url::ServoUrl, compositing::windowing::EmbedderEvent};
use servo::webrender_surfman::WebrenderSurfman;
use crate::{egui_glue::EguiGlow, events_loop::EventsLoop, browser::Browser, window_trait::WindowPortsMethods};
pub struct Minibrowser {
pub context: EguiGlow,
pub event_queue: RefCell<Vec<MinibrowserEvent>>,
pub toolbar_height: Cell<f32>,
location: RefCell<String>,
/// Whether the location has been edited by the user without clicking Go.
location_dirty: Cell<bool>,
}
pub enum MinibrowserEvent {
/// Go button clicked.
Go,
}
impl Minibrowser {
pub fn new(webrender_surfman: &WebrenderSurfman, events_loop: &EventsLoop) -> Self {
let gl = unsafe {
glow::Context::from_loader_function(|s| {
webrender_surfman.get_proc_address(s)
})
};
Self {
context: EguiGlow::new(events_loop.as_winit(), Arc::new(gl), None),
event_queue: RefCell::new(vec![]),
toolbar_height: 0f32.into(),
location: RefCell::new(String::default()),
location_dirty: false.into(),
}
}
/// Update the minibrowser, but dont paint.
pub fn update(&mut self, window: &winit::window::Window) {
let Self { context, event_queue, location, location_dirty, toolbar_height } = self;
let _duration = context.run(window, |ctx| {
TopBottomPanel::top("toolbar").show(ctx, |ui| {
ui.allocate_ui_with_layout(
ui.available_size(),
egui::Layout::right_to_left(egui::Align::Center),
|ui| {
if ui.button("go").clicked() {
event_queue.borrow_mut().push(MinibrowserEvent::Go);
location_dirty.set(false);
}
if ui.add_sized(
ui.available_size(),
egui::TextEdit::singleline(&mut *location.borrow_mut()),
).changed() {
location_dirty.set(true);
}
},
);
});
toolbar_height.set(ctx.used_rect().height());
});
}
/// Paint the minibrowser, as of the last update.
pub fn paint(&mut self, window: &winit::window::Window) {
self.context.paint(window);
}
/// Takes any outstanding events from the [Minibrowser], converting them to [EmbedderEvent] and
/// routing those to the App event queue.
pub fn queue_embedder_events_for_minibrowser_events(
&self, browser: &Browser<dyn WindowPortsMethods>,
app_event_queue: &mut Vec<EmbedderEvent>,
) {
for event in self.event_queue.borrow_mut().drain(..) {
match event {
MinibrowserEvent::Go => {
let browser_id = browser.browser_id().unwrap();
let location = self.location.borrow();
let Ok(url) = ServoUrl::parse(&location) else {
warn!("failed to parse location");
break;
};
app_event_queue.push(EmbedderEvent::LoadUrl(browser_id, url));
},
}
}
}
/// Updates the location field when the [Browser] says it has changed, unless the user has
/// started editing it without clicking Go.
pub fn update_location_in_toolbar(&mut self, browser: &mut Browser<dyn WindowPortsMethods>) -> bool {
if !self.location_dirty.get() {
if let Some(location) = browser.current_url_string() {
self.location = RefCell::new(location.to_owned());
return true;
}
}
false
}
}