Skip to content

Instantly share code, notes, and snippets.

@paulrouget
Last active June 13, 2017 10:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paulrouget/248c0d7bd308242c43e05648b1245fab to your computer and use it in GitHub Desktop.
Save paulrouget/248c0d7bd308242c43e05648b1245fab to your computer and use it in GitHub Desktop.
// 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