egui
This commit is contained in:
parent
d4e310293d
commit
097635a784
795
Cargo.lock
generated
795
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,11 @@ libservo = { git = "https://github.com/servo/servo" }
|
|||||||
surfman = "0.9.3"
|
surfman = "0.9.3"
|
||||||
|
|
||||||
winit = "0.30.0"
|
winit = "0.30.0"
|
||||||
|
glow = "0.13.1"
|
||||||
|
glutin = "0.32.0"
|
||||||
|
egui = { git = "https://github.com/AndriBaal/egui", branch = "winit-0.30" }
|
||||||
|
egui_glow = { git = "https://github.com/AndriBaal/egui", branch = "winit-0.30", features = [ "winit" ] }
|
||||||
|
egui-winit = { git = "https://github.com/AndriBaal/egui", branch = "winit-0.30", default-features = false, features = [ "wayland", "x11" ] }
|
||||||
|
|
||||||
toml = "0.5.11"
|
toml = "0.5.11"
|
||||||
serde-inline-default = "0.2.0"
|
serde-inline-default = "0.2.0"
|
||||||
@ -15,4 +20,4 @@ serde = "1.0.203"
|
|||||||
xdg = "2.5.2"
|
xdg = "2.5.2"
|
||||||
|
|
||||||
log = "0.4.21"
|
log = "0.4.21"
|
||||||
env_logger = "0.11.3"
|
env_logger = "0.10.2"
|
||||||
|
243
src/app.rs
243
src/app.rs
@ -18,11 +18,11 @@ use winit::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
embedder::EmbedderCallbacks, window::Window, winit_mouse_to_servo_mouse,
|
browser::Browser, embedder::EmbedderCallbacks, window::Window, winit_mouse_to_servo_mouse,
|
||||||
winit_position_to_euclid_point, ServoEvent,
|
winit_position_to_euclid_point, ServoEvent,
|
||||||
};
|
};
|
||||||
|
|
||||||
type Frame = (Rc<Window>, Servo<Window>);
|
type Frame = (Rc<Window>, Servo<Window>, Browser);
|
||||||
type ButtonPress = (MouseButton, Point2D<f64, DevicePixel>);
|
type ButtonPress = (MouseButton, Point2D<f64, DevicePixel>);
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
@ -33,6 +33,7 @@ pub struct App {
|
|||||||
current_url: Option<ServoUrl>,
|
current_url: Option<ServoUrl>,
|
||||||
mouse_pos: Cell<Point2D<f64, DevicePixel>>,
|
mouse_pos: Cell<Point2D<f64, DevicePixel>>,
|
||||||
mouse_down: Cell<Option<ButtonPress>>,
|
mouse_down: Cell<Option<ButtonPress>>,
|
||||||
|
event_queue: Vec<EmbedderEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
@ -45,8 +46,113 @@ impl App {
|
|||||||
current_url: None,
|
current_url: None,
|
||||||
mouse_pos: Cell::new(Point2D::default()),
|
mouse_pos: Cell::new(Point2D::default()),
|
||||||
mouse_down: Cell::new(None),
|
mouse_down: Cell::new(None),
|
||||||
|
event_queue: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_events(&mut self) -> bool {
|
||||||
|
let (window, servo, browser) = match self.frame.as_mut() {
|
||||||
|
Some((w, s, b)) => (w, s, b),
|
||||||
|
None => return false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut present = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut servo_events = servo.get_events();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
for (webview_id, msg) in servo_events {
|
||||||
|
trace!("servo event: view: {:?} msg: {:?}", webview_id, msg);
|
||||||
|
|
||||||
|
match msg {
|
||||||
|
EmbedderMsg::ReadyToPresent(_) => window.request_redraw(),
|
||||||
|
EmbedderMsg::WebViewOpened(new_webview_id) => {
|
||||||
|
let rect = window.get_coordinates().get_viewport().to_f32();
|
||||||
|
self.webviews.push(new_webview_id);
|
||||||
|
self.event_queue.extend_from_slice(&[
|
||||||
|
EmbedderEvent::FocusWebView(new_webview_id),
|
||||||
|
EmbedderEvent::MoveResizeWebView(new_webview_id, rect),
|
||||||
|
EmbedderEvent::RaiseWebViewToTop(new_webview_id, true),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
EmbedderMsg::WebViewFocused(webview_id) => {
|
||||||
|
self.focused_webview = Some(webview_id);
|
||||||
|
self.event_queue
|
||||||
|
.push(EmbedderEvent::ShowWebView(webview_id, true));
|
||||||
|
}
|
||||||
|
EmbedderMsg::LoadStart
|
||||||
|
| EmbedderMsg::LoadComplete
|
||||||
|
| EmbedderMsg::HeadParsed => present = true,
|
||||||
|
EmbedderMsg::HistoryChanged(urls, current) => {
|
||||||
|
self.current_url = Some(urls[current].clone());
|
||||||
|
browser.set_location(self.current_url.as_ref().map(|x| x.to_string()));
|
||||||
|
present = true;
|
||||||
|
}
|
||||||
|
EmbedderMsg::ChangePageTitle(title) => window.set_title(
|
||||||
|
&title
|
||||||
|
.or(self.current_url.as_ref().map(|x| x.to_string()))
|
||||||
|
.unwrap_or("Servo".into()),
|
||||||
|
),
|
||||||
|
EmbedderMsg::SetCursor(cursor) => window.set_cursor(cursor),
|
||||||
|
EmbedderMsg::EventDelivered(event) => {
|
||||||
|
if let (Some(wvid), CompositorEventVariant::MouseButtonEvent) =
|
||||||
|
(webview_id, event)
|
||||||
|
{
|
||||||
|
self.event_queue.extend_from_slice(&[
|
||||||
|
EmbedderEvent::RaiseWebViewToTop(wvid, true),
|
||||||
|
EmbedderEvent::FocusWebView(wvid),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EmbedderMsg::WebViewClosed(webview_id) => {
|
||||||
|
self.webviews.retain(|&x| x != webview_id);
|
||||||
|
self.focused_webview = None;
|
||||||
|
self.event_queue.push(
|
||||||
|
self.webviews
|
||||||
|
.last()
|
||||||
|
.map(|&x| EmbedderEvent::FocusWebView(x))
|
||||||
|
.unwrap_or(EmbedderEvent::Quit),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
EmbedderMsg::Shutdown => {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
EmbedderMsg::AllowNavigationRequest(pipeline_id, _url) => {
|
||||||
|
if webview_id.is_some() {
|
||||||
|
self.event_queue
|
||||||
|
.push(EmbedderEvent::AllowNavigationResponse(
|
||||||
|
pipeline_id,
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
present |= servo.handle_events(self.event_queue.drain(..));
|
||||||
|
servo_events = servo.get_events();
|
||||||
|
|
||||||
|
if servo_events.len() == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if present {
|
||||||
|
servo.present();
|
||||||
|
let w = window.winit_window();
|
||||||
|
self.event_queue.extend(browser.update(
|
||||||
|
w,
|
||||||
|
self.focused_webview,
|
||||||
|
servo.offscreen_framebuffer_id(),
|
||||||
|
));
|
||||||
|
browser.paint(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ApplicationHandler<ServoEvent> for App {
|
impl ApplicationHandler<ServoEvent> for App {
|
||||||
@ -60,17 +166,26 @@ impl ApplicationHandler<ServoEvent> for App {
|
|||||||
) {
|
) {
|
||||||
trace!("window event: {:?}", event);
|
trace!("window event: {:?}", event);
|
||||||
|
|
||||||
let (window, servo) = match self.frame.as_mut() {
|
let (window, servo, browser) = match self.frame.as_mut() {
|
||||||
Some((w, s)) => (w, s),
|
Some((w, s, b)) => (w, s, b),
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut events = vec![];
|
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
|
WindowEvent::RedrawRequested => {
|
||||||
|
servo.present();
|
||||||
|
let w = window.winit_window();
|
||||||
|
self.event_queue.extend(browser.update(
|
||||||
|
w,
|
||||||
|
self.focused_webview,
|
||||||
|
servo.offscreen_framebuffer_id(),
|
||||||
|
));
|
||||||
|
browser.paint(w);
|
||||||
|
return;
|
||||||
|
}
|
||||||
WindowEvent::Resized(size) => {
|
WindowEvent::Resized(size) => {
|
||||||
window.resize(size);
|
window.resize(size);
|
||||||
events.push(EmbedderEvent::WindowResize);
|
self.event_queue.push(EmbedderEvent::WindowResize);
|
||||||
}
|
}
|
||||||
WindowEvent::CursorMoved {
|
WindowEvent::CursorMoved {
|
||||||
device_id: _,
|
device_id: _,
|
||||||
@ -78,7 +193,8 @@ impl ApplicationHandler<ServoEvent> for App {
|
|||||||
} => {
|
} => {
|
||||||
let position = winit_position_to_euclid_point(position);
|
let position = winit_position_to_euclid_point(position);
|
||||||
self.mouse_pos.set(position);
|
self.mouse_pos.set(position);
|
||||||
events.push(EmbedderEvent::MouseWindowMoveEventClass(position.to_f32()));
|
self.event_queue
|
||||||
|
.push(EmbedderEvent::MouseWindowMoveEventClass(position.to_f32()));
|
||||||
}
|
}
|
||||||
WindowEvent::MouseInput {
|
WindowEvent::MouseInput {
|
||||||
device_id: _,
|
device_id: _,
|
||||||
@ -87,12 +203,14 @@ impl ApplicationHandler<ServoEvent> for App {
|
|||||||
} => match button {
|
} => match button {
|
||||||
winit::event::MouseButton::Back => {
|
winit::event::MouseButton::Back => {
|
||||||
if let Some(x) = self.focused_webview {
|
if let Some(x) = self.focused_webview {
|
||||||
events.push(EmbedderEvent::Navigation(x, TraversalDirection::Back(1)));
|
self.event_queue
|
||||||
|
.push(EmbedderEvent::Navigation(x, TraversalDirection::Back(1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
winit::event::MouseButton::Forward => {
|
winit::event::MouseButton::Forward => {
|
||||||
if let Some(x) = self.focused_webview {
|
if let Some(x) = self.focused_webview {
|
||||||
events.push(EmbedderEvent::Navigation(x, TraversalDirection::Forward(1)));
|
self.event_queue
|
||||||
|
.push(EmbedderEvent::Navigation(x, TraversalDirection::Forward(1)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -103,12 +221,12 @@ impl ApplicationHandler<ServoEvent> for App {
|
|||||||
match state {
|
match state {
|
||||||
ElementState::Pressed => {
|
ElementState::Pressed => {
|
||||||
self.mouse_down.set(Some((sbutton, position)));
|
self.mouse_down.set(Some((sbutton, position)));
|
||||||
events.push(EmbedderEvent::MouseWindowEventClass(
|
self.event_queue.push(EmbedderEvent::MouseWindowEventClass(
|
||||||
MouseWindowEvent::MouseDown(sbutton, pos),
|
MouseWindowEvent::MouseDown(sbutton, pos),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
ElementState::Released => {
|
ElementState::Released => {
|
||||||
events.push(EmbedderEvent::MouseWindowEventClass(
|
self.event_queue.push(EmbedderEvent::MouseWindowEventClass(
|
||||||
MouseWindowEvent::MouseUp(sbutton, pos),
|
MouseWindowEvent::MouseUp(sbutton, pos),
|
||||||
));
|
));
|
||||||
if let Some((dbut, dpos)) = self.mouse_down.get() {
|
if let Some((dbut, dpos)) = self.mouse_down.get() {
|
||||||
@ -117,9 +235,11 @@ impl ApplicationHandler<ServoEvent> for App {
|
|||||||
+ pixel_dist.y * pixel_dist.y)
|
+ pixel_dist.y * pixel_dist.y)
|
||||||
.sqrt();
|
.sqrt();
|
||||||
if pixel_dist < 10.0 * window.hidpi_factor() {
|
if pixel_dist < 10.0 * window.hidpi_factor() {
|
||||||
events.push(EmbedderEvent::MouseWindowEventClass(
|
self.event_queue.push(
|
||||||
MouseWindowEvent::Click(sbutton, pos),
|
EmbedderEvent::MouseWindowEventClass(
|
||||||
));
|
MouseWindowEvent::Click(sbutton, pos),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -127,12 +247,12 @@ impl ApplicationHandler<ServoEvent> for App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
WindowEvent::CloseRequested => events.push(EmbedderEvent::Quit),
|
WindowEvent::CloseRequested => self.event_queue.push(EmbedderEvent::Quit),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if event == WindowEvent::RedrawRequested || servo.handle_events(events) {
|
if self.handle_events() {
|
||||||
servo.present();
|
event_loop.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,24 +261,25 @@ impl ApplicationHandler<ServoEvent> for App {
|
|||||||
|
|
||||||
if cause == StartCause::Init {
|
if cause == StartCause::Init {
|
||||||
let window = Rc::new(Window::new(event_loop));
|
let window = Rc::new(Window::new(event_loop));
|
||||||
|
let browser = Browser::new(event_loop, &window.rendering_context());
|
||||||
|
|
||||||
let embedder = Box::new(EmbedderCallbacks::new(self.ev_waker.clone()));
|
let embedder = Box::new(EmbedderCallbacks::new(self.ev_waker.clone()));
|
||||||
|
|
||||||
let servo_data = Servo::new(embedder, window.clone(), None, CompositeTarget::Window);
|
let servo_data = Servo::new(embedder, window.clone(), None, CompositeTarget::Fbo);
|
||||||
let mut servo = servo_data.servo;
|
let mut servo = servo_data.servo;
|
||||||
|
|
||||||
servo.handle_events([EmbedderEvent::NewWebView(
|
servo.handle_events([EmbedderEvent::NewWebView(
|
||||||
ServoUrl::parse("https://gnu.org").unwrap(),
|
ServoUrl::parse("https://browserleaks.com").unwrap(),
|
||||||
servo_data.browser_id,
|
servo_data.browser_id,
|
||||||
)]);
|
)]);
|
||||||
|
|
||||||
self.frame = Some((window, servo));
|
self.frame = Some((window, servo, browser));
|
||||||
|
|
||||||
debug!("init done");
|
debug!("init done");
|
||||||
}
|
}
|
||||||
|
|
||||||
let (window, servo) = match self.frame.as_mut() {
|
let (window, servo, browser) = match self.frame.as_mut() {
|
||||||
Some((w, s)) => (w, s),
|
Some((w, s, b)) => (w, s, b),
|
||||||
None => return,
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -170,80 +291,8 @@ impl ApplicationHandler<ServoEvent> for App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn user_event(&mut self, event_loop: &ActiveEventLoop, _event: ServoEvent) {
|
fn user_event(&mut self, event_loop: &ActiveEventLoop, _event: ServoEvent) {
|
||||||
let (window, servo) = match self.frame.as_mut() {
|
if self.handle_events() {
|
||||||
Some((w, s)) => (w, s),
|
event_loop.exit();
|
||||||
None => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut events = vec![];
|
|
||||||
let mut present = false;
|
|
||||||
|
|
||||||
for (webview_id, msg) in servo.get_events() {
|
|
||||||
trace!("servo event: view: {:?} msg: {:?}", webview_id, msg);
|
|
||||||
|
|
||||||
match msg {
|
|
||||||
EmbedderMsg::ReadyToPresent(_) => window.request_redraw(),
|
|
||||||
EmbedderMsg::WebViewOpened(new_webview_id) => {
|
|
||||||
let rect = window.get_coordinates().get_viewport().to_f32();
|
|
||||||
self.webviews.push(new_webview_id);
|
|
||||||
events.extend_from_slice(&[
|
|
||||||
EmbedderEvent::FocusWebView(new_webview_id),
|
|
||||||
EmbedderEvent::MoveResizeWebView(new_webview_id, rect),
|
|
||||||
EmbedderEvent::RaiseWebViewToTop(new_webview_id, true),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
EmbedderMsg::WebViewFocused(webview_id) => {
|
|
||||||
self.focused_webview = Some(webview_id);
|
|
||||||
events.push(EmbedderEvent::ShowWebView(webview_id, true));
|
|
||||||
}
|
|
||||||
EmbedderMsg::LoadStart | EmbedderMsg::LoadComplete | EmbedderMsg::HeadParsed => {
|
|
||||||
present = true
|
|
||||||
}
|
|
||||||
EmbedderMsg::HistoryChanged(urls, current) => {
|
|
||||||
self.current_url = Some(urls[current].clone());
|
|
||||||
present = true;
|
|
||||||
}
|
|
||||||
EmbedderMsg::ChangePageTitle(title) => window.set_title(
|
|
||||||
&title
|
|
||||||
.or(self.current_url.as_ref().map(|x| x.to_string()))
|
|
||||||
.unwrap_or("Servo".into()),
|
|
||||||
),
|
|
||||||
EmbedderMsg::SetCursor(cursor) => window.set_cursor(cursor),
|
|
||||||
EmbedderMsg::EventDelivered(event) => {
|
|
||||||
if let (Some(wvid), CompositorEventVariant::MouseButtonEvent) =
|
|
||||||
(webview_id, event)
|
|
||||||
{
|
|
||||||
events.extend_from_slice(&[
|
|
||||||
EmbedderEvent::RaiseWebViewToTop(wvid, true),
|
|
||||||
EmbedderEvent::FocusWebView(wvid),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EmbedderMsg::WebViewClosed(webview_id) => {
|
|
||||||
self.webviews.retain(|&x| x != webview_id);
|
|
||||||
self.focused_webview = None;
|
|
||||||
events.push(
|
|
||||||
self.webviews
|
|
||||||
.last()
|
|
||||||
.map(|&x| EmbedderEvent::FocusWebView(x))
|
|
||||||
.unwrap_or(EmbedderEvent::Quit),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
EmbedderMsg::Shutdown => {
|
|
||||||
event_loop.exit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
EmbedderMsg::AllowNavigationRequest(pipeline_id, _url) => {
|
|
||||||
if webview_id.is_some() {
|
|
||||||
events.push(EmbedderEvent::AllowNavigationResponse(pipeline_id, true));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if servo.handle_events(events) || present {
|
|
||||||
servo.present();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
198
src/browser.rs
Normal file
198
src/browser.rs
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
use egui::{CentralPanel, Frame, PaintCallback, Pos2, TopBottomPanel, Vec2};
|
||||||
|
use egui_glow::{CallbackFn, EguiGlow};
|
||||||
|
use glow::NativeFramebuffer;
|
||||||
|
use servo::{
|
||||||
|
base::id::TopLevelBrowsingContextId as WebViewId,
|
||||||
|
compositing::windowing::EmbedderEvent,
|
||||||
|
euclid::{Box2D, Point2D, Scale, Size2D},
|
||||||
|
gl,
|
||||||
|
servo_geometry::DeviceIndependentPixel,
|
||||||
|
style_traits::DevicePixel,
|
||||||
|
webrender_api::units::DeviceRect,
|
||||||
|
webrender_traits::RenderingContext,
|
||||||
|
};
|
||||||
|
use std::{num::NonZeroU32, sync::Arc};
|
||||||
|
use surfman::GLApi;
|
||||||
|
use winit::event_loop::ActiveEventLoop;
|
||||||
|
|
||||||
|
pub struct Browser {
|
||||||
|
widget_surface_fbo: Option<glow::NativeFramebuffer>,
|
||||||
|
egui_glow: EguiGlow,
|
||||||
|
shapes: Vec<egui::epaint::ClippedShape>,
|
||||||
|
textures_delta: egui::TexturesDelta,
|
||||||
|
location: Option<String>,
|
||||||
|
rect: DeviceRect,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Browser {
|
||||||
|
pub fn new(event_loop: &ActiveEventLoop, rendering_context: &RenderingContext) -> Self {
|
||||||
|
let webrender_gl = match rendering_context.connection().gl_api() {
|
||||||
|
GLApi::GL => unsafe { gl::GlFns::load_with(|s| rendering_context.get_proc_address(s)) },
|
||||||
|
GLApi::GLES => unsafe {
|
||||||
|
gl::GlesFns::load_with(|s| rendering_context.get_proc_address(s))
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if webrender_gl.get_error() != gl::NO_ERROR
|
||||||
|
|| rendering_context.make_gl_context_current().is_err()
|
||||||
|
{
|
||||||
|
panic!("gl error");
|
||||||
|
}
|
||||||
|
|
||||||
|
let gl = unsafe {
|
||||||
|
glow::Context::from_loader_function(|s| rendering_context.get_proc_address(s))
|
||||||
|
};
|
||||||
|
|
||||||
|
let egui_glow = egui_glow::EguiGlow::new(&event_loop, Arc::new(gl), None, None);
|
||||||
|
|
||||||
|
let widget_surface_fbo = rendering_context
|
||||||
|
.context_surface_info()
|
||||||
|
.ok()
|
||||||
|
.and_then(|x| x.and_then(|x| NonZeroU32::new(x.framebuffer_object)))
|
||||||
|
.map(NativeFramebuffer);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
widget_surface_fbo,
|
||||||
|
egui_glow,
|
||||||
|
shapes: vec![],
|
||||||
|
textures_delta: Default::default(),
|
||||||
|
location: None,
|
||||||
|
rect: DeviceRect::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_location(&mut self, x: Option<String>) {
|
||||||
|
self.location = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn paint(&mut self, window: &winit::window::Window) {
|
||||||
|
unsafe {
|
||||||
|
use glow::HasContext as _;
|
||||||
|
self.egui_glow
|
||||||
|
.painter
|
||||||
|
.gl()
|
||||||
|
.bind_framebuffer(gl::FRAMEBUFFER, self.widget_surface_fbo);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut textures_delta = self.textures_delta.to_owned();
|
||||||
|
for (id, image_delta) in textures_delta.set {
|
||||||
|
self.egui_glow.painter.set_texture(id, &image_delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
let pixels_per_point = self.egui_glow.egui_ctx.pixels_per_point();
|
||||||
|
let clipped_primitives = self
|
||||||
|
.egui_glow
|
||||||
|
.egui_ctx
|
||||||
|
.tessellate(self.shapes.to_owned(), pixels_per_point);
|
||||||
|
self.egui_glow.painter.paint_primitives(
|
||||||
|
window.inner_size().into(),
|
||||||
|
pixels_per_point,
|
||||||
|
&clipped_primitives,
|
||||||
|
);
|
||||||
|
|
||||||
|
for id in textures_delta.free.drain(..) {
|
||||||
|
self.egui_glow.painter.free_texture(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
window: &winit::window::Window,
|
||||||
|
focused_webview: Option<WebViewId>,
|
||||||
|
servo_framebuffer_id: Option<gl::GLuint>,
|
||||||
|
) -> Vec<EmbedderEvent> {
|
||||||
|
let mut events = vec![];
|
||||||
|
|
||||||
|
let raw_input = self.egui_glow.egui_winit.take_egui_input(window);
|
||||||
|
let widget_fbo = self.widget_surface_fbo;
|
||||||
|
let label = self.location.to_owned().unwrap_or("...".into());
|
||||||
|
|
||||||
|
let full_output = self.egui_glow.egui_ctx.run(raw_input, |ctx| {
|
||||||
|
TopBottomPanel::bottom("locbar").show(ctx, |ui| {
|
||||||
|
ui.allocate_ui_with_layout(
|
||||||
|
ui.available_size(),
|
||||||
|
egui::Layout::left_to_right(egui::Align::Center),
|
||||||
|
|ui| {
|
||||||
|
ui.label(label);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let scale =
|
||||||
|
Scale::<_, DeviceIndependentPixel, DevicePixel>::new(ctx.pixels_per_point());
|
||||||
|
|
||||||
|
CentralPanel::default()
|
||||||
|
.frame(Frame::none())
|
||||||
|
.show(ctx, |ui| {
|
||||||
|
let Pos2 { x, y } = ui.cursor().min;
|
||||||
|
let Vec2 {
|
||||||
|
x: width,
|
||||||
|
y: height,
|
||||||
|
} = ui.available_size();
|
||||||
|
let rect =
|
||||||
|
Box2D::from_origin_and_size(Point2D::new(x, y), Size2D::new(width, height))
|
||||||
|
* scale;
|
||||||
|
if rect != self.rect {
|
||||||
|
self.rect = rect;
|
||||||
|
if let Some(x) = focused_webview {
|
||||||
|
events.push(EmbedderEvent::MoveResizeWebView(x, rect));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let min = ui.cursor().min;
|
||||||
|
let size = ui.available_size();
|
||||||
|
let rect = egui::Rect::from_min_size(min, size);
|
||||||
|
ui.allocate_space(size);
|
||||||
|
|
||||||
|
let servo_fbo = servo_framebuffer_id
|
||||||
|
.and_then(NonZeroU32::new)
|
||||||
|
.map(NativeFramebuffer);
|
||||||
|
|
||||||
|
ui.painter().add(PaintCallback {
|
||||||
|
rect,
|
||||||
|
callback: Arc::new(CallbackFn::new(move |info, painter| {
|
||||||
|
let clip = info.viewport_in_pixels();
|
||||||
|
let x = clip.left_px;
|
||||||
|
let y = clip.from_bottom_px;
|
||||||
|
let width = clip.width_px;
|
||||||
|
let height = clip.height_px;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
use glow::HasContext as _;
|
||||||
|
painter.gl().clear_color(0.0, 0.0, 0.0, 0.0);
|
||||||
|
painter.gl().scissor(x, y, width, height);
|
||||||
|
painter.gl().enable(gl::SCISSOR_TEST);
|
||||||
|
painter.gl().clear(gl::COLOR_BUFFER_BIT);
|
||||||
|
painter.gl().disable(gl::SCISSOR_TEST);
|
||||||
|
painter
|
||||||
|
.gl()
|
||||||
|
.bind_framebuffer(gl::READ_FRAMEBUFFER, servo_fbo);
|
||||||
|
painter
|
||||||
|
.gl()
|
||||||
|
.bind_framebuffer(gl::DRAW_FRAMEBUFFER, widget_fbo);
|
||||||
|
painter.gl().blit_framebuffer(
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
x + width,
|
||||||
|
y + height,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
x + width,
|
||||||
|
y + height,
|
||||||
|
gl::COLOR_BUFFER_BIT,
|
||||||
|
gl::NEAREST,
|
||||||
|
);
|
||||||
|
painter.gl().bind_framebuffer(gl::FRAMEBUFFER, widget_fbo);
|
||||||
|
}
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
self.egui_glow
|
||||||
|
.egui_winit
|
||||||
|
.handle_platform_output(window, full_output.platform_output);
|
||||||
|
self.shapes = full_output.shapes;
|
||||||
|
self.textures_delta.append(full_output.textures_delta);
|
||||||
|
|
||||||
|
events
|
||||||
|
}
|
||||||
|
}
|
@ -14,8 +14,7 @@ macro_rules! def {
|
|||||||
|
|
||||||
#[serde_inline_default]
|
#[serde_inline_default]
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct Keys {
|
pub struct Keys {}
|
||||||
}
|
|
||||||
def!(Keys);
|
def!(Keys);
|
||||||
|
|
||||||
#[serde_inline_default]
|
#[serde_inline_default]
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
extern crate log;
|
extern crate log;
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
|
mod browser;
|
||||||
mod embedder;
|
mod embedder;
|
||||||
mod event_loop;
|
mod event_loop;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
@ -27,7 +27,7 @@ pub struct Window {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub fn new(event_loop: &ActiveEventLoop) -> Window {
|
pub fn new(event_loop: &ActiveEventLoop) -> Self {
|
||||||
let opts = opts::get();
|
let opts = opts::get();
|
||||||
|
|
||||||
let win_size = opts.initial_window_size.to_untyped().to_i32();
|
let win_size = opts.initial_window_size.to_untyped().to_i32();
|
||||||
@ -66,7 +66,7 @@ impl Window {
|
|||||||
let rendering_context = RenderingContext::create(&connection, &adapter, surface_type)
|
let rendering_context = RenderingContext::create(&connection, &adapter, surface_type)
|
||||||
.expect("Failed to create WR surfman");
|
.expect("Failed to create WR surfman");
|
||||||
|
|
||||||
Window {
|
Self {
|
||||||
winit_window,
|
winit_window,
|
||||||
rendering_context,
|
rendering_context,
|
||||||
animation_state: Cell::new(AnimationState::Idle),
|
animation_state: Cell::new(AnimationState::Idle),
|
||||||
@ -147,6 +147,10 @@ impl Window {
|
|||||||
pub fn is_animating(&self) -> bool {
|
pub fn is_animating(&self) -> bool {
|
||||||
self.animation_state.get() == AnimationState::Animating
|
self.animation_state.get() == AnimationState::Animating
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn winit_window(&self) -> &winit::window::Window {
|
||||||
|
&self.winit_window
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WindowMethods for Window {
|
impl WindowMethods for Window {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user