1use crate::{AviUtl2Info, generic::EditSection};
2use pastey::paste;
3
4pub struct HostAppHandle<'a> {
11 internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
12 global_leak_manager: &'a mut crate::common::LeakManager,
13 kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
14 plugin_registry: &'a mut crate::generic::PluginRegistry,
15}
16
17pub struct SubPlugin<T> {
19 plugin: std::marker::PhantomData<T>,
20 internal: std::sync::Arc<InternalReferenceHandle>,
21}
22struct InternalReferenceHandle {
23 uninitialize_fn: fn(),
24}
25impl Drop for InternalReferenceHandle {
26 fn drop(&mut self) {
27 (self.uninitialize_fn)();
28 }
29}
30
31impl<'a> HostAppHandle<'a> {
32 pub(crate) unsafe fn new(
33 internal: *mut aviutl2_sys::plugin2::HOST_APP_TABLE,
34 global_leak_manager: &'a mut crate::common::LeakManager,
35 kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
36 plugin_registry: &'a mut crate::generic::PluginRegistry,
37 ) -> Self {
38 Self {
39 internal,
40 global_leak_manager,
41 kill_switch,
42 plugin_registry,
43 }
44 }
45
46 fn assert_not_killed(&self) {
47 if self.kill_switch.load(std::sync::atomic::Ordering::SeqCst) {
48 panic!("This HostAppHandle is no longer valid.");
49 }
50 }
51
52 pub fn set_plugin_information(&mut self, information: &str) {
55 self.assert_not_killed();
56 let information = if cfg!(debug_assertions) {
57 format!("{information} (Debug Build)")
58 } else {
59 information.to_string()
60 };
61 unsafe {
62 ((*self.internal).set_plugin_information)(
63 self.global_leak_manager.leak_as_wide_string(&information),
64 )
65 }
66 }
67
68 pub fn create_edit_handle(&mut self) -> crate::generic::EditHandle {
70 self.assert_not_killed();
71 let raw_handle = unsafe { ((*self.internal).create_edit_handle)() };
72 unsafe { crate::generic::EditHandle::new(raw_handle) }
73 }
74
75 pub fn register_import_menu(
81 &mut self,
82 name: &str,
83 callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
84 ) {
85 self.assert_not_killed();
86 unsafe {
87 ((*self.internal).register_import_menu)(
88 self.global_leak_manager.leak_as_wide_string(name),
89 callback,
90 )
91 }
92 }
93
94 pub fn register_export_menu(
100 &mut self,
101 name: &str,
102 callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
103 ) {
104 self.assert_not_killed();
105 unsafe {
106 ((*self.internal).register_export_menu)(
107 self.global_leak_manager.leak_as_wide_string(name),
108 callback,
109 )
110 }
111 }
112
113 pub fn register_layer_menu(
120 &mut self,
121 name: &str,
122 callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
123 ) {
124 self.assert_not_killed();
125 unsafe {
126 ((*self.internal).register_layer_menu)(
127 self.global_leak_manager.leak_as_wide_string(name),
128 callback,
129 )
130 }
131 }
132
133 pub fn register_object_menu(
140 &mut self,
141 name: &str,
142 callback: extern "C" fn(*mut aviutl2_sys::plugin2::EDIT_SECTION),
143 ) {
144 self.assert_not_killed();
145 unsafe {
146 ((*self.internal).register_object_menu)(
147 self.global_leak_manager.leak_as_wide_string(name),
148 callback,
149 )
150 }
151 }
152
153 pub fn register_window_client<T: raw_window_handle::HasWindowHandle>(
159 &mut self,
160 name: &str,
161 instance: &T,
162 ) -> Result<(), raw_window_handle::HandleError> {
163 self.assert_not_killed();
164 let raw_handle = instance.window_handle()?;
165 let hwnd = match raw_handle.as_raw() {
166 raw_window_handle::RawWindowHandle::Win32(handle) => handle.hwnd,
167 _ => panic!("Only Win32WindowHandle is supported"),
168 };
169 unsafe {
170 ((*self.internal).register_window_client)(
171 self.global_leak_manager.leak_as_wide_string(name),
172 hwnd.get() as *mut std::ffi::c_void,
173 );
174 }
175 Ok(())
176 }
177
178 pub fn register_menus<T: GenericPluginMenus>(&mut self) {
184 self.assert_not_killed();
185 T::register_menus(self);
186 }
187
188 pub fn register_project_load_handler(
196 &mut self,
197 callback: extern "C" fn(*mut aviutl2_sys::plugin2::PROJECT_FILE),
198 ) {
199 self.assert_not_killed();
200 unsafe {
201 ((*self.internal).register_project_load_handler)(callback);
202 }
203 }
204
205 pub fn register_project_save_handler(
212 &mut self,
213 callback: extern "C" fn(*mut aviutl2_sys::plugin2::PROJECT_FILE),
214 ) {
215 self.assert_not_killed();
216 unsafe {
217 ((*self.internal).register_project_save_handler)(callback);
218 }
219 }
220}
221
222pub trait GenericPluginMenus {
224 fn register_menus(host: &mut HostAppHandle);
225}
226
227#[doc(inline)]
228pub use aviutl2_macros::generic_menus as menus;
229
230#[derive(Default)]
231pub(crate) struct PluginRegistry {
232 #[cfg(feature = "input")]
233 input_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
234 #[cfg(feature = "output")]
235 output_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
236 #[cfg(feature = "filter")]
237 filter_plugins: Vec<std::sync::Arc<InternalReferenceHandle>>,
238 #[cfg(feature = "module")]
239 script_modules: Vec<std::sync::Arc<InternalReferenceHandle>>,
240}
241impl PluginRegistry {
242 pub(crate) fn new() -> Self {
243 Self::default()
244 }
245}
246
247macro_rules! impl_plugin_registry {
248 (
249 $description:literal,
250 $feature:literal,
251 $module:ident,
252 $name:ident,
253 $register_method:ident,
254 $PluginTrait:path,
255 $SingletonTrait:path,
256 $TableType:ty
257 ) => {
258 paste! {
259 impl<T> SubPlugin<T> {
260 #[cfg(feature = $feature)]
261 #[doc = concat!($description, "の新しいインスタンスを作成します。")]
262 pub fn [<new_ $name>](info: AviUtl2Info) -> crate::AnyResult<Self>
263 where
264 T: $PluginTrait + $SingletonTrait + 'static
265 {
266 crate::$module::__bridge::initialize_plugin::<T>(info.version.into())?;
267 let internal = std::sync::Arc::new(InternalReferenceHandle {
268 uninitialize_fn: || {
269 unsafe {
270 crate::$module::__bridge::uninitialize_plugin::<T>();
271 }
272 },
273 });
274 Ok(Self {
275 plugin: std::marker::PhantomData,
276 internal,
277 })
278 }
279 }
280 #[cfg(feature = $feature)]
281 impl<'a> HostAppHandle<'a> {
282 #[doc = concat!($description, "を登録します。")]
283 pub fn [<register_ $name>]<T: $PluginTrait + $SingletonTrait + 'static>(
284 &mut self,
285 handle: &SubPlugin<T>,
286 ) {
287 self.assert_not_killed();
288 unsafe { ((*self.internal).$register_method)(crate::$module::__bridge::create_table::<T>()) };
289 self.plugin_registry
290 .[<$name s>]
291 .push(std::sync::Arc::clone(&handle.internal));
292 }
293 }
294 }
295 };
296}
297
298impl_plugin_registry!(
299 "入力プラグイン",
300 "input",
301 input,
302 input_plugin,
303 register_input_plugin,
304 crate::input::InputPlugin,
305 crate::input::__bridge::InputSingleton,
306 aviutl2_sys::input2::INPUT_PLUGIN_TABLE
307);
308impl_plugin_registry!(
309 "出力プラグイン",
310 "output",
311 output,
312 output_plugin,
313 register_output_plugin,
314 crate::output::OutputPlugin,
315 crate::output::__bridge::OutputSingleton,
316 aviutl2_sys::output2::OUTPUT_PLUGIN_TABLE
317);
318impl_plugin_registry!(
319 "フィルタープラグイン",
320 "filter",
321 filter,
322 filter_plugin,
323 register_filter_plugin,
324 crate::filter::FilterPlugin,
325 crate::filter::__bridge::FilterSingleton,
326 aviutl2_sys::filter2::FILTER_PLUGIN_TABLE
327);
328impl_plugin_registry!(
329 "スクリプトモジュール",
330 "module",
331 module,
332 script_module,
333 register_script_module,
334 crate::module::ScriptModule,
335 crate::module::__bridge::ScriptModuleSingleton,
336 aviutl2_sys::module2::SCRIPT_MODULE_TABLE
337);
338
339#[derive(Debug)]
341pub struct EditHandle {
342 pub(crate) internal: *mut aviutl2_sys::plugin2::EDIT_HANDLE,
343}
344
345unsafe impl Send for EditHandle {}
346unsafe impl Sync for EditHandle {}
347
348#[derive(thiserror::Error, Debug)]
350pub enum EditHandleError {
351 #[error("api call failed")]
352 ApiCallFailed,
353}
354
355impl EditHandle {
356 pub(crate) unsafe fn new(internal: *mut aviutl2_sys::plugin2::EDIT_HANDLE) -> Self {
357 Self { internal }
358 }
359
360 pub fn call_edit_section<'a, T, F>(&self, callback: F) -> Result<T, EditHandleError>
366 where
367 T: Send + 'static,
368 F: FnOnce(&mut EditSection) -> T + Send + 'a,
369 {
370 type CallbackParam<'a, F, T> = (ChildKillablePointer<Option<F>>, &'a mut Option<T>);
371
372 let closure = Some(callback);
373 let param = KillablePointer::new(closure);
374 let child_param = param.create_child();
375
376 extern "C" fn trampoline<F, T>(
377 param: *mut std::ffi::c_void,
378 edit_section: *mut aviutl2_sys::plugin2::EDIT_SECTION,
379 ) where
380 T: Send + 'static,
381 F: FnOnce(&mut EditSection) -> T,
382 {
383 unsafe {
384 let (child_param, result_ptr) = &mut *(param as *mut CallbackParam<F, T>);
385 let callback = child_param
386 .as_mut()
387 .take()
388 .expect("Callback has already been called");
389 let mut edit_section = EditSection::from_ptr(edit_section);
390 let res = callback(&mut edit_section);
391
392 result_ptr.replace(res);
393 }
394 }
395
396 let trampoline_static = trampoline::<F, T>
397 as extern "C" fn(*mut std::ffi::c_void, *mut aviutl2_sys::plugin2::EDIT_SECTION);
398
399 let mut result = None;
400 let param = Box::<CallbackParam<F, T>>::new((child_param, &mut result));
401 let param_ptr = Box::into_raw(param);
402
403 let success = unsafe {
404 ((*self.internal).call_edit_section_param)(
405 param_ptr as *mut std::ffi::c_void,
406 trampoline_static,
407 )
408 };
409
410 if success {
411 Ok(result.expect("Callback did not set result"))
412 } else {
413 Err(EditHandleError::ApiCallFailed)
414 }
415 }
416}
417
418struct KillablePointer<T> {
419 kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
420 inner: *mut T,
421}
422unsafe impl<T> Send for KillablePointer<T> {}
423unsafe impl<T> Sync for KillablePointer<T> {}
424impl<T> Drop for KillablePointer<T> {
425 fn drop(&mut self) {
426 self.kill_switch
427 .store(true, std::sync::atomic::Ordering::SeqCst);
428 }
429}
430impl<T> KillablePointer<T> {
431 pub fn new(inner: T) -> Self {
432 Self {
433 kill_switch: std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false)),
434 inner: Box::into_raw(Box::new(inner)),
435 }
436 }
437
438 pub fn create_child(&self) -> ChildKillablePointer<T> {
439 ChildKillablePointer {
440 kill_switch: std::sync::Arc::clone(&self.kill_switch),
441 inner: self.inner,
442 }
443 }
444}
445
446struct ChildKillablePointer<T> {
447 kill_switch: std::sync::Arc<std::sync::atomic::AtomicBool>,
448 inner: *mut T,
449}
450unsafe impl<T> Send for ChildKillablePointer<T> {}
451unsafe impl<T> Sync for ChildKillablePointer<T> {}
452impl<T> ChildKillablePointer<T> {
453 pub fn is_killed(&self) -> bool {
454 self.kill_switch.load(std::sync::atomic::Ordering::SeqCst)
455 }
456
457 pub unsafe fn as_mut(&mut self) -> &mut T {
458 if self.is_killed() {
459 panic!("parent KillablePointer has been dropped");
460 }
461 unsafe { &mut *self.inner }
462 }
463}