| // Embedder implements: | |
| // Main thread only | |
| pub trait GLPlatormMethods { | |
| fn get_gl(&self) -> Rc<gl::Gl>; | |
| fn make_current(&self) -> Result<(),()>; | |
| fn swap_buffers(&self); | |
| } | |
| // Thread safe | |
| pub trait EventLoopWaker { | |
| fn clone(&self) -> Box<EventLoopWaker + Send>; | |
| fn wakeup(&self); | |
| } | |
| // Embedder receives: | |
| /// Coming from Browser (script -> constellation -> embedder). | |
| pub enum EventFromBrowser { | |
| SetWindowInnerSize(u32, u32), | |
| SetWindowPosition(i32, i32), | |
| SetFullScreenState(bool), | |
| TitleChanged(Option<String>), | |
| UnhandledURL(ServoUrl), | |
| AllowNavigation(ServoUrl, IpcSender<bool>), | |
| StatusChanged(Option<String>), | |
| LoadStart, | |
| LoadEnd, | |
| LoadError(String), | |
| HeadParsed, | |
| HistoryChanged(Vec<LoadData>, usize), | |
| CursorChanged(Cursor), | |
| FaviconChanged(ServoUrl), | |
| UnhandledKey(Option<char>, Key, constellation_msg::KeyModifiers), | |
| } | |
| // Embedder sends: | |
| /// Events created by the embedder for the constellation. | |
| /// The `top_level_browsing_context_id` is stored in the Browser struct, | |
| /// which implement handle_events(Vec<EventToBrowser>) | |
| pub enum EventToBrowser { | |
| LoadUrl(ServoUrl), | |
| Navigation(WindowNavigateMsg), | |
| Reload, | |
| KeyEvent(Option<char>, Key, KeyState, KeyModifiers), | |
| MouseWindowEventClass(MouseWindowEvent), | |
| MouseWindowMoveEventClass(TypedPoint2D<f32, DevicePixel>), | |
| Scroll(ScrollLocation, TypedPoint2D<i32, DevicePixel>, TouchEventType), | |
| Zoom(f32), | |
| ResetZoom, | |
| PanAndZoom(ScrollLocation, TypedPoint2D<i32, DevicePixel>, f32), | |
| /// Will trigger the resize + scroll events | |
| EndPanAndZoom(ScrollLocation, TypedPoint2D<i32, DevicePixel>, f32), | |
| Destroy, | |
| } | |
| // Browser | |
| struct Browser { | |
| top_level_browsing_context_id: TopLevelBrowsingContextId, | |
| } | |
| impl Browser { | |
| fn get_events() -> Vec<EventFromBrowser>; | |
| fn handle_events(Vec<EventToBrowser>); | |
| } | |
| struct View { | |
| compositor: &compositor | |
| // FIXME: more stuff | |
| } | |
| impl View { | |
| fn set_active_browser(Option<&View>); | |
| fn refresh(); | |
| fn parameters_changed(ViewParameters); | |
| } | |
| impl Compositor { | |
| pub fn perform_udpates(); | |
| } | |
| // Example: | |
| use std::rc::Rc; | |
| use std::collections::HashMap; | |
| use servo::{Browser, Compositor, View}; | |
| struct MyAppWindow { | |
| native_window: Rc<NativeWindow>, | |
| compositor: Compositor, | |
| browsers: Vec<Browser>, | |
| browser_idx: usize, | |
| view: Rc<View>, | |
| } | |
| fn create_one_window_with_two_tabs(windows: &mut HashMap<EmbedderWindowId, MyAppWindow>, url1: ServoUrl, url2: ServoUrl) { | |
| let win = Rc::new(NativeWindow::new()); // NativeWindow implements GLPlatormMethods | |
| let waker = win.create_event_loop_waker(); | |
| let compositor = Compositor::new(win.clone(), waker); | |
| // See https://github.com/servo/webrender/pull/1306#issuecomment-305151053 | |
| let rect = win.get_rect(); // Native method | |
| let hidpi_factor = win.hidpi_factor(); // Native method | |
| let view_parameters = ViewParameters { inner_rect: rect, outer_rect: rect, chrome_rect: rect, hidpi_factor: hidpi_factor }; | |
| let view = Rc::new(View::new(&compositor, view_parameters)); | |
| let browser1 = Browser::new(url1); | |
| let browser2 = Browser::new(url2); | |
| // Set which frame tree to draw. Call Constellation::send_frame_tree | |
| // Used to switch tabs. | |
| view.set_active_browser(Some(&browser1)); | |
| windows.insert(win.id(), MyAppWindow { | |
| native_window: win.clone(), | |
| compositor: compositor, | |
| browsers: vec![browser1, browser2], | |
| browser_idx: 0, | |
| view: view | |
| }); | |
| } | |
| fn main() { | |
| let mut windows = HashMap::new(); | |
| create_one_window_with_two_tabs(&windows, | |
| ServoUrl::parse("https://servo.org").unwrap(), | |
| ServoUrl::parse("https://example.com").unwrap()); | |
| create_one_window_with_two_tabs(&windows, | |
| ServoUrl::parse("https://blog.servo.org").unwrap(), | |
| ServoUrl::parse("https://mozilla.org").unwrap()); | |
| EmbedderEventLoop::run(|event: WindowEvent, win_id: EmbedderWindowId| { | |
| match (event, win_id) { | |
| (WindowEvent::Idle, win_id) => { | |
| // The main thread has been awaken. We need to go through all | |
| // the browsers and get their events. Ideally we would have a way | |
| // to know which browser woke up the event loop. | |
| let app_window = windows.get(&win_id).unwrap(); | |
| for browser in app_window.browsers { | |
| let browser_events = browser.get_events(); | |
| for e in browser_events { | |
| match e { | |
| BrowserEvent::TitleChanged(title) => { | |
| app_window.native_window.set_title(&title.unwrap_or("No Title".to_owned())); | |
| } | |
| _ => { /* more stuff */ } | |
| } | |
| } | |
| // See https://github.com/servo/servo/issues/15734#issuecomment-285077759 | |
| app_window.compositor.perform_udpates(); | |
| } | |
| } | |
| (WindowEvent::KeyEvent(_, Key::Tab, KeyState::Pressed, CONTROL), Some(id)) => { | |
| // Ctrl-Tab. Let's select tab #2 | |
| // Got an event from the native window. | |
| // Here we could interupt the | |
| let app_window = windows.get(&win_id).unwrap(); | |
| app_window.view.set_active_browser(&browsers[1]); | |
| app_window.view.browser_idx = 1; | |
| }, | |
| (e, Some(id)) => { | |
| // Got an event from the native window. | |
| // Here we could interupt the | |
| let app_window = windows.get(&win_id).unwrap(); | |
| let browser = app_window.browsers[app_window.browser_idx]; | |
| browser.handle_event(e); | |
| } | |
| (e, None) => { | |
| warn!("Got unexpected window-less window event: {:?}", e); | |
| }, | |
| } | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment