1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
//! This module implements the `Application` trait with the corresponding function definitions found in the C code base of `browser-window-c`.
//! All functions are basically wrapping the FFI provided by crate `browser-window-c`.

use super::{ApplicationExt, ApplicationSettings};

use crate::{
	error::*,
	prelude::*
};

use std::{
	os::raw::{c_char, c_int, c_void},
	ptr,
	time::Duration
};



#[derive(Clone,Copy)]
pub struct ApplicationImpl {
	pub(in crate) inner: *mut cbw_Application
}

impl ApplicationExt for ApplicationImpl {

	fn assert_correct_thread( &self ) {
		unsafe { cbw_Application_assertCorrectThread( self.inner ) }
	}

	fn dispatch( &self, work: unsafe fn(ApplicationImpl, *mut ()), _data: *mut () ) -> bool {
		let data = Box::new( DispatchData {
			func: work,
			data: _data
		} );

		let data_ptr = Box::into_raw( data );

		unsafe { cbw_Application_dispatch( self.inner, Some( invocation_handler ), data_ptr as _ ) != 0 }
	}

	fn dispatch_delayed( &self, work: unsafe fn(ApplicationImpl, *mut ()), _data: *mut (), delay: Duration ) -> bool {
		let data = Box::new( DispatchData {
			func: work,
			data: _data
		} );

		let data_ptr = Box::into_raw( data );

		unsafe { cbw_Application_dispatchDelayed( self.inner, Some( invocation_handler ), data_ptr as _, delay.as_millis() as _ ) != 0 }
	}
	
	fn exit( &self, exit_code: i32 ) {
		unsafe { cbw_Application_exit( self.inner, exit_code as _ ) }
	}
	
	fn exit_threadsafe( self: &Self, exit_code: i32 ) {
		unsafe { cbw_Application_exitAsync( self.inner, exit_code ) }
	}
	
	fn finish( &self ) {
		unsafe { cbw_Application_finish( self.inner ) }
	}

	fn initialize( argc: c_int, argv: *mut *mut c_char, _settings: &ApplicationSettings ) -> CbwResult<Self> {

		let exec_path: &str = match _settings.engine_seperate_executable_path.as_ref() {
			None => "",
			Some(path) => path.to_str().unwrap()
		};

		let c_settings = cbw_ApplicationSettings {
			engine_seperate_executable_path: exec_path.into(),
			resource_dir: _settings.resource_dir.as_ref().unwrap_or(&"".to_owned()).as_str().into()
		};

		let mut c_handle: *mut cbw_Application = ptr::null_mut();
		let c_err = unsafe { cbw_Application_initialize( &mut c_handle, argc, argv, &c_settings ) };
		if c_err.code != 0 {
			return Err( c_err.into() )
		}

		Ok(Self {
			inner: c_handle
		})
	}

	fn mark_as_done(&self) {
		unsafe { cbw_Application_markAsDone(self.inner) };
	}

	fn run( &self, on_ready: unsafe fn( ApplicationImpl, *mut () ), _data: *mut () ) -> i32 {
		let data = Box::new( DispatchData {
			func: on_ready,
			data: _data
		} );

		let data_ptr = Box::into_raw( data );

		// The dispatch handler does exactly the same thing 
		unsafe { cbw_Application_run( self.inner, Some( invocation_handler ), data_ptr as _ ) }
	}
}



struct DispatchData {
	func: unsafe fn( ApplicationImpl, *mut () ),
	data: *mut ()
}

unsafe extern "C" fn invocation_handler( _handle: *mut cbw_Application, _data: *mut c_void ) {

	let data_ptr = _data as *mut DispatchData;
	let data = Box::from_raw( data_ptr );
	let handle = ApplicationImpl { inner: _handle };

	(data.func)( handle, data.data );
}