1use ::{_API};
4use capi::scdef::SCITER_RT_OPTIONS;
5use capi::sctypes::*;
6use capi::screquest::HREQUEST;
7use capi::schandler::NativeHandler;
8use dom::{self, event::EventHandler};
9use eventhandler::*;
10use value::{Value};
11
12pub use capi::scdef::{LOAD_RESULT, OUTPUT_SUBSYTEMS, OUTPUT_SEVERITY};
13pub use capi::scdef::{SCN_LOAD_DATA, SCN_DATA_LOADED, SCN_ATTACH_BEHAVIOR, SCN_INVALIDATE_RECT};
14
15
16pub type Result<T> = ::std::result::Result<T, ()>;
18
19macro_rules! ok_or {
20 ($ok:ident) => {
21 if $ok != 0 {
22 Ok(())
23 } else {
24 Err(())
25 }
26 };
27
28 ($ok:ident, $rv:expr) => {
29 if $ok != 0 {
30 Ok($rv)
31 } else {
32 Err(())
33 }
34 };
35
36 ($ok:ident, $rv:expr, $err:expr) => {
37 if $ok != 0 {
38 Ok($rv)
39 } else {
40 Err($err)
41 }
42 };
43}
44
45
46#[allow(unused_variables)]
66pub trait HostHandler {
67
68 fn on_data_load(&mut self, pnm: &mut SCN_LOAD_DATA) -> Option<LOAD_RESULT> { return None; }
76
77 fn on_data_loaded(&mut self, pnm: &SCN_DATA_LOADED) { }
79
80 fn on_attach_behavior(&mut self, pnm: &mut SCN_ATTACH_BEHAVIOR) -> bool { return false; }
83
84 fn on_engine_destroyed(&mut self) { }
86
87 fn on_graphics_critical_failure(&mut self) { }
90
91 fn on_invalidate(&mut self, pnm: &SCN_INVALIDATE_RECT) {}
93
94 fn on_debug_output(&mut self, subsystem: OUTPUT_SUBSYTEMS, severity: OUTPUT_SEVERITY, message: &str) {
96 if !message.is_empty() {
97 if severity == OUTPUT_SEVERITY::INFO {
98 println!("{:?}:{:?}: {}", severity, subsystem, message);
100 } else {
101 eprintln!("{:?}:{:?}: {}", severity, subsystem, message);
103 }
104 }
105 }
106
107 fn data_ready(&self, hwnd: HWINDOW, uri: &str, data: &[u8], request_id: Option<HREQUEST>) {
112 let s = s2w!(uri);
113 match request_id {
114 Some(req) => {
115 (_API.SciterDataReadyAsync)(hwnd, s.as_ptr(), data.as_ptr(), data.len() as UINT, req)
116 },
117 None => {
118 (_API.SciterDataReady)(hwnd, s.as_ptr(), data.as_ptr(), data.len() as UINT)
119 },
120 };
121 }
122
123 fn attach_behavior<Handler: EventHandler>(&self, pnm: &mut SCN_ATTACH_BEHAVIOR, handler: Handler) {
126 let boxed = Box::new(handler);
128 let ptr = Box::into_raw(boxed); pnm.elementProc = ::eventhandler::_event_handler_proc::<Handler>;
130 pnm.elementTag = ptr as LPVOID;
131 }
132}
133
134
135#[derive(Default)]
137struct DefaultHandler;
138
139impl HostHandler for DefaultHandler {
141
142}
143
144use std::rc::Rc;
145use std::cell::RefCell;
146
147type BehaviorList = Vec<(String, Box<dyn Fn() -> Box<dyn EventHandler>>)>;
148type SharedBehaviorList = Rc<RefCell<BehaviorList>>;
149type SharedArchive = Rc<RefCell<Option<Archive>>>;
150
151#[repr(C)]
152struct HostCallback<Callback> {
153 sig: u32,
154 behaviors: SharedBehaviorList,
155 handler: Callback,
156 archive: SharedArchive,
157}
158
159pub struct Host {
161 hwnd: HWINDOW,
162 behaviors: SharedBehaviorList,
163 handler: RefCell<NativeHandler>,
164 archive: SharedArchive,
165}
166
167impl Host {
168
169 pub fn attach(hwnd: HWINDOW) -> Host {
178 let host = Host {
180 hwnd,
181 behaviors: Default::default(),
182 handler: Default::default(),
183 archive: Default::default(),
184 };
185 host.setup_callback(DefaultHandler::default());
186 return host;
187 }
188
189 pub fn attach_with<Handler: HostHandler>(hwnd: HWINDOW, handler: Handler) -> Host {
191 let host = Host {
192 hwnd,
193 behaviors: Default::default(),
194 handler: Default::default(),
195 archive: Default::default(),
196 };
197 host.setup_callback(handler);
198 return host;
199 }
200
201 pub fn event_handler<Handler: EventHandler>(&self, handler: Handler) {
203 self.attach_handler(handler)
204 }
205
206 #[doc(hidden)]
208 pub fn attach_handler<Handler: EventHandler>(&self, handler: Handler) {
209 let hwnd = self.get_hwnd();
210 let boxed = Box::new( WindowHandler { hwnd, handler } );
211 let ptr = Box::into_raw(boxed); let func = _event_handler_window_proc::<Handler>;
215 let flags = dom::event::default_events();
216 (_API.SciterWindowAttachEventHandler)(hwnd, func, ptr as LPVOID, flags as UINT);
217 }
218
219 pub(crate) fn setup_callback<Callback: HostHandler>(&self, handler: Callback) {
221
222 let payload: HostCallback<Callback> = HostCallback {
223 sig: 17,
224 behaviors: Rc::clone(&self.behaviors),
225 archive: Rc::clone(&self.archive),
226 handler: handler,
227 };
228
229 *self.handler.borrow_mut() = NativeHandler::from(payload);
230 let ptr = self.handler.borrow().as_mut_ptr();
231
232 (_API.SciterSetCallback)(self.get_hwnd(), _on_handle_notification::<Callback>, ptr);
233 (_API.SciterSetupDebugOutput)(0 as HWINDOW, ptr, _on_debug_notification::<Callback>);
234 }
235
236 pub fn register_behavior<Factory>(&self, name: &str, factory: Factory)
240 where
241 Factory: Fn() -> Box<dyn EventHandler> + 'static
242 {
243 let make: Box<dyn Fn() -> Box<dyn EventHandler>> = Box::new(factory);
244 let pair = (name.to_owned(), make);
245 self.behaviors.borrow_mut().push(pair);
246 }
247
248 pub fn register_archive(&self, resource: &[u8]) -> Result<()> {
252 *self.archive.borrow_mut() = Some(Archive::open(resource)?);
253 Ok(())
254 }
255
256 pub fn enable_debug(&self, enable: bool) {
258 (_API.SciterSetOption)(self.hwnd, SCITER_RT_OPTIONS::SCITER_SET_DEBUG_MODE, enable as UINT_PTR);
259 }
260
261 pub fn get_hwnd(&self) -> HWINDOW {
263 self.hwnd
264 }
265
266 pub fn get_root(&self) -> Option<dom::Element> {
268 dom::Element::from_window(self.hwnd).ok()
269 }
270
271 pub fn load_file(&self, uri: &str) -> bool {
273 let s = s2w!(uri);
275 (_API.SciterLoadFile)(self.hwnd, s.as_ptr()) != 0
276 }
277
278 pub fn load_html(&self, html: &[u8], uri: Option<&str>) -> bool {
280 match uri {
281 Some(uri) => {
282 let s = s2w!(uri);
283 (_API.SciterLoadHtml)(self.hwnd, html.as_ptr(), html.len() as UINT, s.as_ptr()) != 0
284 },
285 None => {
286 (_API.SciterLoadHtml)(self.hwnd, html.as_ptr(), html.len() as UINT, 0 as LPCWSTR) != 0
287 }
288 }
289 }
290
291 pub fn data_ready(&self, uri: &str, data: &[u8]) {
293 let s = s2w!(uri);
294 (_API.SciterDataReady)(self.hwnd, s.as_ptr(), data.as_ptr(), data.len() as UINT);
295 }
296
297 pub fn data_ready_async(&self, uri: &str, data: &[u8], request_id: Option<HREQUEST>) {
305 let s = s2w!(uri);
306 let req = request_id.unwrap_or(::std::ptr::null_mut());
307 (_API.SciterDataReadyAsync)(self.hwnd, s.as_ptr(), data.as_ptr(), data.len() as UINT, req);
308 }
309
310 pub fn eval_script(&self, script: &str) -> ::std::result::Result<Value, Value> {
314 let (s,n) = s2wn!(script);
315 let mut rv = Value::new();
316 let ok = (_API.SciterEval)(self.hwnd, s.as_ptr(), n, rv.as_ptr());
317 ok_or!(ok, rv, rv)
318 }
319
320 pub fn call_function(&self, name: &str, args: &[Value]) -> ::std::result::Result<Value, Value> {
327 let mut rv = Value::new();
328 let s = s2u!(name);
329 let argv = Value::pack_args(args);
330 let ok = (_API.SciterCall)(self.hwnd, s.as_ptr(), argv.len() as UINT, argv.as_ptr(), rv.as_ptr());
331 ok_or!(ok, rv, rv)
332 }
333
334 pub fn set_home_url(&self, url: &str) -> Result<()> {
343 let s = s2w!(url);
344 let ok = (_API.SciterSetHomeURL)(self.hwnd, s.as_ptr());
345 ok_or!(ok)
346 }
347
348 pub fn set_media_type(&self, media_type: &str) -> Result<()> {
357 let s = s2w!(media_type);
358 let ok = (_API.SciterSetMediaType)(self.hwnd, s.as_ptr());
359 ok_or!(ok)
360 }
361
362 pub fn set_media_vars(&self, media: &Value) -> Result<()> {
379 let ok = (_API.SciterSetMediaVars)(self.hwnd, media.as_cptr());
380 ok_or!(ok)
381 }
382
383 pub fn set_master_css(&self, css: &str, append: bool) -> Result<()> {
386 let s = s2u!(css);
387 let b = s.as_bytes();
388 let n = b.len() as UINT;
389 let ok = if append {
390 (_API.SciterAppendMasterCSS)(b.as_ptr(), n)
391 } else {
392 (_API.SciterSetMasterCSS)(b.as_ptr(), n)
393 };
394 ok_or!(ok)
395 }
396
397 pub fn set_window_css(&self, css: &str, base_url: &str, media_type: &str) -> Result<()> {
401 let s = s2u!(css);
402 let url = s2w!(base_url);
403 let media = s2w!(media_type);
404 let b = s.as_bytes();
405 let n = b.len() as UINT;
406 let ok = (_API.SciterSetCSS)(self.hwnd, b.as_ptr(), n, url.as_ptr(), media.as_ptr());
407 ok_or!(ok)
408 }
409
410}
411
412
413extern "system" fn _on_handle_notification<T: HostHandler>(pnm: *mut ::capi::scdef::SCITER_CALLBACK_NOTIFICATION, param: LPVOID) -> UINT
416{
417 use capi::scdef::{SCITER_NOTIFICATION, SCITER_CALLBACK_NOTIFICATION};
418
419 let callback = NativeHandler::get_data::<HostCallback<T>>(¶m);
421 let me: &mut T = &mut callback.handler;
422
423 let nm: &mut SCITER_CALLBACK_NOTIFICATION = unsafe { &mut *pnm };
425 let code: SCITER_NOTIFICATION = unsafe { ::std::mem::transmute(nm.code) };
426
427
428 let result: UINT = match code {
429 SCITER_NOTIFICATION::SC_LOAD_DATA => {
430 let scnm = pnm as *mut SCN_LOAD_DATA;
431 let scnm = unsafe { &mut *scnm };
432 let mut re = me.on_data_load(scnm);
433 if re.is_none() {
434 if let Some(archive) = callback.archive.borrow().as_ref() {
435 let uri = w2s!(scnm.uri);
436 if uri.starts_with("this://app/") {
437 if let Some(data) = archive.get(&uri) {
438 me.data_ready(scnm.hwnd, &uri, data, None);
439 } else {
440 eprintln!("[sciter] error: can't load {:?}", uri);
441 }
442 }
443 re = Some(LOAD_RESULT::LOAD_DEFAULT);
444 }
445 }
446 re.unwrap_or(LOAD_RESULT::LOAD_DEFAULT) as UINT
447 },
448
449 SCITER_NOTIFICATION::SC_DATA_LOADED => {
450 let scnm = pnm as *mut SCN_DATA_LOADED;
451 me.on_data_loaded(unsafe { &mut *scnm } );
452 0
453 },
454
455 SCITER_NOTIFICATION::SC_ATTACH_BEHAVIOR => {
456 let scnm = pnm as *mut SCN_ATTACH_BEHAVIOR;
457 let scnm = unsafe { &mut *scnm };
458 let mut re = me.on_attach_behavior(scnm);
459 if !re {
460 let name = u2s!(scnm.name);
461 let behavior = callback.behaviors
462 .borrow()
463 .iter()
464 .find(|x| x.0 == name)
465 .map(|x| x.1());
466
467 if let Some(behavior) = behavior {
468 let boxed = Box::new( BoxedHandler { handler: behavior } );
469 let ptr = Box::into_raw(boxed); scnm.elementProc = ::eventhandler::_event_handler_behavior_proc;
472 scnm.elementTag = ptr as LPVOID;
473 re = true;
474 }
475 }
476 re as UINT
477 },
478
479 SCITER_NOTIFICATION::SC_ENGINE_DESTROYED => {
480 me.on_engine_destroyed();
481 0
482 },
483
484 SCITER_NOTIFICATION::SC_GRAPHICS_CRITICAL_FAILURE => {
485 me.on_graphics_critical_failure();
486 0
487 },
488
489 SCITER_NOTIFICATION::SC_INVALIDATE_RECT => {
490 let scnm = pnm as *const SCN_INVALIDATE_RECT;
491 me.on_invalidate(unsafe { &*scnm });
492 0
493 }
494
495 _ => 0,
496 };
497
498 return result;
499}
500
501extern "system" fn _on_debug_notification<T: HostHandler>(param: LPVOID, subsystem: OUTPUT_SUBSYTEMS, severity: OUTPUT_SEVERITY,
503 text: LPCWSTR, _text_length: UINT)
504{
505 let me = NativeHandler::get_data::<HostCallback<T>>(¶m);
508 let message = ::utf::w2s(text).replace("\r", "\n");
509 me.handler.on_debug_output(subsystem, severity, message.trim_end());
510}
511
512
513pub struct Archive(HSARCHIVE);
541
542impl Drop for Archive {
544 fn drop(&mut self) {
545 (_API.SciterCloseArchive)(self.0);
546 }
547}
548
549impl Archive {
550 pub fn open(archived: &[u8]) -> Result<Self> {
552 let p = (_API.SciterOpenArchive)(archived.as_ptr(), archived.len() as u32);
553 if !p.is_null() {
554 Ok(Archive(p))
555 } else {
556 Err(())
557 }
558 }
559
560 pub fn get(&self, path: &str) -> Option<&[u8]> {
564 let skip = if path.starts_with("this://app/") {
566 "this://app/".len()
567 } else if path.starts_with("//") {
568 "//".len()
569 } else {
570 0
571 };
572
573 let wname = s2w!(path);
574 let name = &wname[skip..];
575
576 let mut pb = ::std::ptr::null();
577 let mut cb = 0;
578 let ok = (_API.SciterGetArchiveItem)(self.0, name.as_ptr(), &mut pb, &mut cb);
579 if ok != 0 && !pb.is_null() {
580 let data = unsafe { ::std::slice::from_raw_parts(pb, cb as usize) };
581 Some(data)
582 } else {
583 None
584 }
585 }
586}