aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ports/libmlservo/src/lib.rs41
-rw-r--r--support/magicleap/Servo2D/code/inc/Servo2D.h12
-rw-r--r--support/magicleap/Servo2D/code/src/Servo2D.cpp47
3 files changed, 88 insertions, 12 deletions
diff --git a/ports/libmlservo/src/lib.rs b/ports/libmlservo/src/lib.rs
index 08b84ada37f..6b5bb2e6d00 100644
--- a/ports/libmlservo/src/lib.rs
+++ b/ports/libmlservo/src/lib.rs
@@ -40,6 +40,7 @@ use std::ffi::CStr;
use std::ffi::CString;
use std::io::Write;
use std::os::raw::c_char;
+use std::os::raw::c_void;
use std::path::PathBuf;
use std::rc::Rc;
@@ -56,13 +57,22 @@ pub enum MLLogLevel {
#[repr(transparent)]
pub struct MLLogger(extern "C" fn (MLLogLevel, *const c_char));
+#[repr(transparent)]
+pub struct MLHistoryUpdate(extern "C" fn (MLApp, bool, *const c_char, bool));
+
+#[repr(transparent)]
+#[derive(Clone, Copy)]
+pub struct MLApp(*mut c_void);
+
const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;
#[no_mangle]
pub unsafe extern "C" fn init_servo(ctxt: EGLContext,
surf: EGLSurface,
disp: EGLDisplay,
+ app: MLApp,
logger: MLLogger,
+ history_update: MLHistoryUpdate,
url: *const c_char,
width: u32,
height: u32,
@@ -100,7 +110,9 @@ pub unsafe extern "C" fn init_servo(ctxt: EGLContext,
]);
let result = Box::new(ServoInstance {
+ app: app,
browser_id: browser_id,
+ history_update: history_update,
servo: servo,
});
Box::into_raw(result)
@@ -130,10 +142,19 @@ pub unsafe extern "C" fn heartbeat_servo(servo: *mut ServoInstance) {
EmbedderMsg::AllowOpeningBrowser(sender) => {
let _ = sender.send(false);
},
+ // Update the history UI
+ EmbedderMsg::HistoryChanged(urls, index) => {
+ if let Some(url) = urls.get(index) {
+ if let Ok(cstr) = CString::new(url.as_str()) {
+ let can_go_back = index > 0;
+ let can_go_fwd = (index + 1) < urls.len();
+ (servo.history_update.0)(servo.app, can_go_back, cstr.as_ptr(), can_go_fwd);
+ }
+ }
+ },
// Ignore most messages for now
EmbedderMsg::ChangePageTitle(..) |
EmbedderMsg::BrowserCreated(..) |
- EmbedderMsg::HistoryChanged(..) |
EmbedderMsg::LoadStart |
EmbedderMsg::LoadComplete |
EmbedderMsg::CloseBrowser |
@@ -185,6 +206,22 @@ pub unsafe extern "C" fn traverse_servo(servo: *mut ServoInstance, delta: i32) {
}
#[no_mangle]
+pub unsafe extern "C" fn navigate_servo(servo: *mut ServoInstance, text: *const c_char) {
+ if let Some(servo) = servo.as_mut() {
+ let text = CStr::from_ptr(text).to_str().expect("Failed to convert text to UTF-8");
+ let url = ServoUrl::parse(text).unwrap_or_else(|_| {
+ let mut search = ServoUrl::parse("http://google.com/search")
+ .expect("Failed to parse search URL")
+ .into_url();
+ search.query_pairs_mut().append_pair("q", text);
+ ServoUrl::from_url(search)
+ });
+ let window_event = WindowEvent::LoadUrl(servo.browser_id, url);
+ servo.servo.handle_events(vec![window_event]);
+ }
+}
+
+#[no_mangle]
pub unsafe extern "C" fn discard_servo(servo: *mut ServoInstance) {
// Servo drop goes here!
if !servo.is_null() {
@@ -193,7 +230,9 @@ pub unsafe extern "C" fn discard_servo(servo: *mut ServoInstance) {
}
pub struct ServoInstance {
+ app: MLApp,
browser_id: BrowserId,
+ history_update: MLHistoryUpdate,
servo: Servo<WindowInstance>,
}
diff --git a/support/magicleap/Servo2D/code/inc/Servo2D.h b/support/magicleap/Servo2D/code/inc/Servo2D.h
index 490c6d60ece..29477cf3cd8 100644
--- a/support/magicleap/Servo2D/code/inc/Servo2D.h
+++ b/support/magicleap/Servo2D/code/inc/Servo2D.h
@@ -9,6 +9,9 @@
#include <lumin/event/ControlTouchPadInputEventData.h>
#include <lumin/node/QuadNode.h>
#include <lumin/resource/PlanarResource.h>
+#include <lumin/ui/KeyboardDefines.h>
+#include <lumin/ui/node/UiButton.h>
+#include <lumin/ui/node/UiTextEdit.h>
#include <SceneDescriptor.h>
typedef struct Opaque ServoInstance;
@@ -48,6 +51,11 @@ public:
*/
Servo2D& operator=(Servo2D&&) = delete;
+ /**
+ * Update the browser history UI
+ */
+ void updateHistory(bool canGoBack, const char* url, bool canGoForward);
+
protected:
/**
* Initializes the Landscape Application.
@@ -93,6 +101,7 @@ protected:
virtual bool eventListener(lumin::ServerEvent* event) override;
bool touchpadEventListener(lumin::ControlTouchPadInputEventData* event);
bool keyEventListener(lumin::KeyInputEventData* event);
+ void urlBarEventListener();
/**
* Get the current cursor position, with respect to the viewport.
@@ -104,5 +113,8 @@ private:
lumin::Prism* prism_ = nullptr; // represents the bounded space where the App renders.
lumin::PlanarResource* plane_ = nullptr; // the plane we're rendering into
lumin::QuadNode* content_node_ = nullptr; // the node containing the plane
+ lumin::ui::UiButton* back_button_ = nullptr; // the back button
+ lumin::ui::UiButton* fwd_button_ = nullptr; // the forward button
+ lumin::ui::UiTextEdit* url_bar_ = nullptr; // the URL bar
ServoInstance* servo_ = nullptr; // the servo instance we're embedding
};
diff --git a/support/magicleap/Servo2D/code/src/Servo2D.cpp b/support/magicleap/Servo2D/code/src/Servo2D.cpp
index 54600362d09..d24316490b6 100644
--- a/support/magicleap/Servo2D/code/src/Servo2D.cpp
+++ b/support/magicleap/Servo2D/code/src/Servo2D.cpp
@@ -6,7 +6,6 @@
#include <lumin/node/RootNode.h>
#include <lumin/node/QuadNode.h>
#include <lumin/ui/Cursor.h>
-#include <lumin/ui/node/UiButton.h>
#include <ml_logging.h>
#include <scenesGen.h>
#include <SceneDescriptor.h>
@@ -35,13 +34,20 @@ void logger(MLLogLevel lvl, char* msg) {
}
}
+// A function which updates the history ui, suitable for passing into Servo
+typedef void (*MLHistoryUpdate)(Servo2D* app, bool canGoBack, char* url, bool canGoForward);
+void history(Servo2D* app, bool canGoBack, char* url, bool canGoForward) {
+ app->updateHistory(canGoBack, url, canGoForward);
+}
+
// The functions Servo provides for hooking up to the ML.
-// For the moment, this doesn't handle input events.
-extern "C" ServoInstance* init_servo(EGLContext, EGLSurface, EGLDisplay, MLLogger,
- const char* url, int width, int height, float hidpi);
+extern "C" ServoInstance* init_servo(EGLContext, EGLSurface, EGLDisplay,
+ Servo2D*, MLLogger, MLHistoryUpdate,
+ const char* url, int width, int height, float hidpi);
extern "C" void heartbeat_servo(ServoInstance*);
extern "C" void cursor_servo(ServoInstance*, float x, float y, bool triggered);
extern "C" void traverse_servo(ServoInstance*, int delta);
+extern "C" void navigate_servo(ServoInstance*, const char* text);
extern "C" void discard_servo(ServoInstance*);
// Create a Servo2D instance
@@ -120,7 +126,7 @@ int Servo2D::init() {
EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
// Hook into servo
- servo_ = init_servo(ctx, surf, dpy, logger, "https://servo.org/", VIEWPORT_H, VIEWPORT_W, HIDPI);
+ servo_ = init_servo(ctx, surf, dpy, this, logger, history, "https://servo.org/", VIEWPORT_H, VIEWPORT_W, HIDPI);
if (!servo_) {
ML_LOG(Error, "Servo2D Failed to init servo instance");
abort();
@@ -129,24 +135,33 @@ int Servo2D::init() {
// Add a callback to the back button
std::string back_button_id = Servo2D_exportedNodes::backButton;
- lumin::ui::UiButton* back_button = lumin::ui::UiButton::CastFrom(prism_->findNode(back_button_id, root_node));
- if (!back_button) {
+ back_button_ = lumin::ui::UiButton::CastFrom(prism_->findNode(back_button_id, root_node));
+ if (!back_button_) {
ML_LOG(Error, "Servo2D Failed to get back button");
abort();
return 1;
}
- back_button->onActivateSub(std::bind(traverse_servo, servo_, -1));
+ back_button_->onActivateSub(std::bind(traverse_servo, servo_, -1));
// Add a callback to the forward button
std::string fwd_button_id = Servo2D_exportedNodes::fwdButton;
- lumin::ui::UiButton* fwd_button = lumin::ui::UiButton::CastFrom(prism_->findNode(fwd_button_id, root_node));
- if (!fwd_button) {
+ fwd_button_ = lumin::ui::UiButton::CastFrom(prism_->findNode(fwd_button_id, root_node));
+ if (!fwd_button_) {
ML_LOG(Error, "Servo2D Failed to get forward button");
abort();
return 1;
}
- fwd_button->onActivateSub(std::bind(traverse_servo, servo_, +1));
+ fwd_button_->onActivateSub(std::bind(traverse_servo, servo_, +1));
+ // Add a callback to the URL bar
+ std::string url_bar_id = Servo2D_exportedNodes::urlBar;
+ url_bar_ = lumin::ui::UiTextEdit::CastFrom(prism_->findNode(url_bar_id, root_node));
+ if (!url_bar_) {
+ ML_LOG(Error, "Servo2D Failed to get URL bar");
+ abort();
+ return 1;
+ }
+ url_bar_->onFocusLostSub(std::bind(&Servo2D::urlBarEventListener, this));
return 0;
}
@@ -268,3 +283,13 @@ bool Servo2D::keyEventListener(lumin::KeyInputEventData* event) {
cursor_servo(servo_, pos.x, pos.y, true);
return true;
}
+
+void Servo2D::urlBarEventListener() {
+ navigate_servo(servo_, url_bar_->getText().c_str());
+}
+
+void Servo2D::updateHistory(bool canGoBack, const char* url, bool canGoForward) {
+ back_button_->setEnabled(canGoBack);
+ fwd_button_->setEnabled(canGoForward);
+ url_bar_->setText(url);
+}