Last active
June 13, 2017 10:57
-
-
Save paulrouget/248c0d7bd308242c43e05648b1245fab to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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