diff --git a/wfassoc-cdylib/src/lib.rs b/wfassoc-cdylib/src/lib.rs index 8c39661..7336569 100644 --- a/wfassoc-cdylib/src/lib.rs +++ b/wfassoc-cdylib/src/lib.rs @@ -191,10 +191,11 @@ static PROGRAM_POOL: LazyLock>> = static EXT_STATUS_POOL: LazyLock>> = LazyLock::new(|| RwLock::new(ObjectPool::new())); -static ICON_RC_POOL: LazyLock>> = - LazyLock::new(|| RwLock::new(ObjectPool::new())); +static SELF_EXT_STATUS_POOL: LazyLock< + RwLock>, +> = LazyLock::new(|| RwLock::new(ObjectPool::new())); -static EXT_POOL: LazyLock>> = +static ICON_RC_POOL: LazyLock>> = LazyLock::new(|| RwLock::new(ObjectPool::new())); // endregion @@ -218,8 +219,8 @@ pub extern "C" fn WFStartup() -> bool { let _pool = pull_writer!(SCHEMA_POOL)?; let _pool = pull_writer!(PROGRAM_POOL)?; let _pool = pull_writer!(EXT_STATUS_POOL)?; + let _pool = pull_writer!(SELF_EXT_STATUS_POOL)?; let _pool = pull_writer!(ICON_RC_POOL)?; - let _pool = pull_writer!(EXT_POOL)?; Ok(()) }) } @@ -234,9 +235,9 @@ pub extern "C" fn WFShutdown() -> bool { pool.clear(); let mut pool = pull_writer!(EXT_STATUS_POOL)?; pool.clear(); - let mut pool = pull_writer!(ICON_RC_POOL)?; + let mut pool = pull_writer!(SELF_EXT_STATUS_POOL)?; pool.clear(); - let mut pool = pull_writer!(EXT_POOL)?; + let mut pool = pull_writer!(ICON_RC_POOL)?; pool.clear(); Ok(()) }) @@ -539,23 +540,6 @@ pub extern "C" fn WFProgramExtsLen( }) } -#[unsafe(no_mangle)] -pub extern "C" fn WFProgramGetExt( - in_program: in_param_ty!(Token), - in_index: in_param_ty!(usize), - out_ext: out_param_ty!(Token), -) -> bool { - cffi_wrapper!(|in_program: Token, in_index: usize| -> (out_ext: Token) { - let mut pool = pull_writer!(PROGRAM_POOL)?; - let program = pool.get_mut(in_program)?; - - let ext = program.get_ext(in_index)?; - let mut pool = pull_writer!(EXT_POOL)?; - let token = pool.allocate(ext.clone())?; - Ok(token) - }) -} - #[unsafe(no_mangle)] pub extern "C" fn WFProgramFindExt( in_program: in_param_ty!(Token), @@ -575,6 +559,23 @@ pub extern "C" fn WFProgramFindExt( }) } +#[unsafe(no_mangle)] +pub extern "C" fn WFProgramResolveExt( + in_program: in_param_ty!(Token), + in_index: in_param_ty!(usize), + out_self_ext_status: out_param_ty!(Token), +) -> bool { + cffi_wrapper!(|in_program: Token, in_index: usize| -> (out_self_ext_status: Token) { + let mut pool = pull_writer!(PROGRAM_POOL)?; + let program = pool.get_mut(in_program)?; + + let self_ext_status = program.resolve_ext(in_index)?; + let mut pool = pull_writer!(SELF_EXT_STATUS_POOL)?; + let token = pool.allocate(self_ext_status)?; + Ok(token) + }) +} + #[unsafe(no_mangle)] pub extern "C" fn WFProgramRegister( in_program: in_param_ty!(Token), @@ -716,6 +717,77 @@ pub extern "C" fn WFExtStatusGetIcon( // endregion +// region: Self Extension Status + +#[unsafe(no_mangle)] +pub extern "C" fn WFSelfExtStatusDestroy(in_self_ext_status: in_param_ty!(Token)) -> bool { + cffi_wrapper!(|in_self_ext_status: Token| { + let mut pool = pull_writer!(SELF_EXT_STATUS_POOL)?; + Ok(pool.free(in_self_ext_status)?) + }) +} + +#[unsafe(no_mangle)] +pub extern "C" fn WFSelfExtStatusGetName( + in_self_ext_status: in_param_ty!(Token), + out_name: out_param_ty!(CStyleString), +) -> bool { + cffi_wrapper!(|in_self_ext_status: Token| -> (out_name: CStyleString) { + let pool = pull_reader!(SELF_EXT_STATUS_POOL)?; + let self_ext_status = pool.get(in_self_ext_status)?; + + cstr_ffi::set_ffi_string(self_ext_status.get_name())?; + Ok(cstr_ffi::get_ffi_string()) + }) +} + +#[unsafe(no_mangle)] +pub extern "C" fn WFSelfExtStatusGetIcon( + in_self_ext_status: in_param_ty!(Token), + out_icon: out_param_ty!(HICON), +) -> bool { + cffi_wrapper!(|in_self_ext_status: Token| -> (out_icon: HICON) { + let pool = pull_reader!(SELF_EXT_STATUS_POOL)?; + let self_ext_status = pool.get(in_self_ext_status)?; + + let icon = match self_ext_status.get_icon() { + Some(icon) => icon.get_icon(), + None => ffi_types::INVALID_HICON, + }; + Ok(icon) + }) +} + +#[unsafe(no_mangle)] +pub extern "C" fn WFSelfExtStatusGetExt( + in_self_ext_status: in_param_ty!(Token), + out_inner: out_param_ty!(CStyleString), +) -> bool { + cffi_wrapper!(|in_self_ext_status: Token| -> (out_inner: CStyleString) { + let pool = pull_reader!(SELF_EXT_STATUS_POOL)?; + let self_ext_status = pool.get(in_self_ext_status)?; + + cstr_ffi::set_ffi_string(self_ext_status.get_ext())?; + Ok(cstr_ffi::get_ffi_string()) + }) +} + +#[unsafe(no_mangle)] +pub extern "C" fn WFSelfExtStatusGetDottedExt( + in_self_ext_status: in_param_ty!(Token), + out_inner: out_param_ty!(CStyleString), +) -> bool { + cffi_wrapper!(|in_self_ext_status: Token| -> (out_inner: CStyleString) { + let pool = pull_reader!(SELF_EXT_STATUS_POOL)?; + let self_ext_status = pool.get(in_self_ext_status)?; + + cstr_ffi::set_ffi_string(self_ext_status.get_dotted_ext().as_str())?; + Ok(cstr_ffi::get_ffi_string()) + }) +} + +// endregion + // region: Icon Resource #[unsafe(no_mangle)] @@ -740,41 +812,3 @@ pub extern "C" fn WFIconRcGetIcon( } // endregion - -// region: File Extension - -#[unsafe(no_mangle)] -pub extern "C" fn WFExtDestroy(in_ext: in_param_ty!(Token)) -> bool { - cffi_wrapper!(|in_ext: Token| { - let mut pool = pull_writer!(EXT_POOL)?; - Ok(pool.free(in_ext)?) - }) -} - -#[unsafe(no_mangle)] -pub extern "C" fn WFExtGetInner( - in_ext: in_param_ty!(Token), - out_inner: out_param_ty!(CStyleString), -) -> bool { - cffi_wrapper!(|in_ext: Token| -> (out_inner: CStyleString) { - let pool = pull_reader!(EXT_POOL)?; - let ext = pool.get(in_ext)?; - cstr_ffi::set_ffi_string(ext.inner())?; - Ok(cstr_ffi::get_ffi_string()) - }) -} - -#[unsafe(no_mangle)] -pub extern "C" fn WFExtGetDottedInner( - in_ext: in_param_ty!(Token), - out_inner: out_param_ty!(CStyleString), -) -> bool { - cffi_wrapper!(|in_ext: Token| -> (out_inner: CStyleString) { - let pool = pull_reader!(EXT_POOL)?; - let ext = pool.get(in_ext)?; - cstr_ffi::set_ffi_string(&ext.dotted_inner())?; - Ok(cstr_ffi::get_ffi_string()) - }) -} - -// endregion diff --git a/wfassoc-exec/src/runner.rs b/wfassoc-exec/src/runner.rs index 63d0389..dc57b0c 100644 --- a/wfassoc-exec/src/runner.rs +++ b/wfassoc-exec/src/runner.rs @@ -126,7 +126,7 @@ fn run_ext_unlink( for index in exts { program.link_ext(scope, index)?; } - + println!("File extension now is unlinked."); Ok(()) } @@ -139,9 +139,12 @@ fn run_ext_list( // Fetch info let mut ext_list: HashMap> = HashMap::new(); for index in 0..program.exts_len() { - let ext = program.get_ext(index)?; + let self_ext_status = program.resolve_ext(index)?; let status = program.query_ext(view, index)?; - ext_list.insert(ext.dotted_inner(), status.map(|s| s.get_name().to_string())); + ext_list.insert( + self_ext_status.get_dotted_ext(), + status.map(|s| s.get_name().to_string()), + ); } // Output by styles diff --git a/wfassoc/src/highlevel.rs b/wfassoc/src/highlevel.rs index a38f02e..f96ea4d 100644 --- a/wfassoc/src/highlevel.rs +++ b/wfassoc/src/highlevel.rs @@ -27,7 +27,7 @@ mod schema; mod program; pub use schema::{Schema, SchemaError}; -pub use program::{Program, ParseProgramError, ProgramError, ProgramExtStatus}; +pub use program::{Program, ParseProgramError, ProgramError, ProgramSelfExtStatus, ProgramExtStatus}; pub use lowlevel::{Scope, View}; // endregion diff --git a/wfassoc/src/highlevel/program.rs b/wfassoc/src/highlevel/program.rs index e82ae92..7cd3aa4 100644 --- a/wfassoc/src/highlevel/program.rs +++ b/wfassoc/src/highlevel/program.rs @@ -269,6 +269,9 @@ impl Program { impl Program { pub fn resolve_name(&self) -> Result, ProgramError> { + // TODO: + // Add fallback: fetch it from executable manifest file. + // Add fallback: use executable name directly. Ok(self .name .as_ref() @@ -277,6 +280,9 @@ impl Program { } pub fn resolve_icon(&self) -> Result, ProgramError> { + // TODO: + // Add fallback: fetch it from the first icon of executable. + // Add fallback: use system default executable icon. Ok(self .icon .as_ref() @@ -288,19 +294,35 @@ impl Program { self.ext_keys.len() } - pub fn get_ext(&self, index: usize) -> Result<&concept::Ext, ProgramError> { - match self.ext_keys.get(index) { - Some(program_key) => { - let ext_key = &program_key.ext_key; - Ok(ext_key.inner()) - } - None => Err(ProgramError::BadIndex), - } - } - pub fn find_ext(&self, body: &str) -> Option { self.ext_keys_map.get(body).copied() } + + pub fn resolve_ext(&self, index: usize) -> Result { + // Fetch data + let progid_ext_key = self.ext_keys.get(index).ok_or(ProgramError::BadIndex)?; + + // Try resolving name with string resource first, + // and fallback to ProgId verbatim. + let name = progid_ext_key + .name + .inner + .extract() + .unwrap_or(progid_ext_key.progid_key.inner().to_string()); + // Try to fetch icon + let icon = progid_ext_key + .icon + .inner + .extract(concept::IconSizeKind::Small) + .ok(); + + // Okey, return it + Ok(ProgramSelfExtStatus::new( + progid_ext_key.ext_key.inner().clone(), + name, + icon, + )) + } } impl Program { @@ -589,6 +611,46 @@ struct ProgramProgIdExtKey { // region: Exposed Stuff +/// Exposed struct representing this program provided method for opening specific file extension. +/// +/// The data including the extension name, diaplay name and icon. +pub struct ProgramSelfExtStatus { + ext: concept::Ext, + name: String, + icon: Option, +} + +impl ProgramSelfExtStatus { + fn new(ext: concept::Ext, name: String, icon: Option) -> Self { + Self { ext, name, icon } + } + + /// Get the extension name without leading dot like `jpg`. + pub fn get_ext(&self) -> &str { + self.ext.inner() + } + + /// Get the extension name with leading dot like `.jpg`. + pub fn get_dotted_ext(&self) -> String { + self.ext.dotted_inner() + } + + /// Get the display name of this program. + /// + /// The program provided display name will be used firstly. + /// If this program has no display name, the stringified ProgId will be used instead. + pub fn get_name(&self) -> &str { + self.name.as_str() + } + + /// Get the icon of this program. + /// + /// Due to the icon is optional, if there is no icon, return None. + pub fn get_icon(&self) -> Option<&concept::IconRc> { + self.icon.as_ref() + } +} + /// Exposed struct representing the default associated program of specific file extension. /// /// The data including the diaplay name and icon.