diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f9c02eb..a6ebd0b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,9 +8,6 @@ on: branches: - master -env: - DONT_USE_GENERATED_BINDINGS: "true" - jobs: cargo_fmt: runs-on: ubuntu-latest @@ -20,6 +17,8 @@ jobs: submodules: true - uses: dtolnay/rust-toolchain@1.74.0 + with: + components: rustfmt - uses: Swatinem/rust-cache@v2 @@ -33,6 +32,8 @@ jobs: submodules: true - uses: dtolnay/rust-toolchain@1.74.0 + with: + components: clippy - uses: Swatinem/rust-cache@v2 @@ -40,6 +41,8 @@ jobs: build_linux: runs-on: ubuntu-latest + env: + DONT_USE_GENERATED_BINDINGS: "true" steps: - uses: actions/checkout@v4 with: @@ -51,6 +54,7 @@ jobs: - run: | sudo add-apt-repository ppa:obsproject/obs-studio + sudo apt-get remove libclang1-15 sudo apt-get update sudo apt-get install obs-studio libxcb-randr0-dev libxcb-ewmh-dev @@ -60,6 +64,8 @@ jobs: build_windows: runs-on: windows-latest + env: + DONT_USE_GENERATED_BINDINGS: "true" steps: - uses: actions/checkout@v4 with: @@ -77,7 +83,9 @@ jobs: build_macos: runs-on: macos-latest - if: github.ref == 'refs/heads/master' + env: + DONT_USE_GENERATED_BINDINGS: "true" + # if: github.ref == 'refs/heads/master' steps: - uses: actions/checkout@v4 with: @@ -92,3 +100,9 @@ jobs: - run: cargo build --verbose --workspace --exclude scroll-focus-filter - run: cargo test --workspace --exclude scroll-focus-filter + env: + # Set this so that the test pass! + # Maybe you don't need to do this when running the plugin from OBS? I don't know. + # If you own a Mac please do something better. + DYLD_FALLBACK_FRAMEWORK_PATH: "/Applications/OBS.app/Contents/Frameworks" + DYLD_FALLBACK_LIBRARY_PATH: "/Applications/OBS.app/Contents/Frameworks" diff --git a/obs-sys/build.rs b/obs-sys/build.rs index 280be15..997fbcd 100644 --- a/obs-sys/build.rs +++ b/obs-sys/build.rs @@ -13,6 +13,7 @@ mod build_mac; fn main() { // Tell cargo to invalidate the built crate whenever the wrapper changes println!("cargo:rerun-if-changed=wrapper.h"); + println!("cargo:rerun-if-env-changed=DONT_USE_GENERATED_BINDINGS"); #[cfg(not(target_os = "macos"))] { @@ -20,39 +21,46 @@ fn main() { println!("cargo:rustc-link-lib=dylib=obs-frontend-api"); } - // mac OBS only ships with libobs.0.dylib for some reason #[cfg(target_os = "macos")] - println!("cargo:rustc-link-lib=dylib=obs.0"); + build_mac::find_mac_obs_lib(); #[cfg(windows)] build_win::find_windows_obs_lib(); - #[cfg(target_os = "macos")] - build_mac::find_mac_obs_lib(); - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs"); - if let Ok(bindings) = bindgen::Builder::default() + let builder = bindgen::Builder::default() .header("wrapper.h") - .clang_arg("-I./obs/libobs/") + .clang_args([ + // Windows has an issue with the _udiv128 function not being declared + // So just ignore for now! + #[cfg(windows)] + "-Wno-error=implicit-function-declaration", + "-I./obs/libobs/", + "-I./obs/UI/obs-frontend-api/", + ]) .blocklist_type("_bindgen_ty_2") .blocklist_type("_bindgen_ty_3") .blocklist_type("_bindgen_ty_4") .derive_default(true) - .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())) - .generate() - { - bindings - .write_to_file(&out_path) - .expect("Couldn't write bindings!"); - fs::copy(&out_path, "generated/bindings.rs").expect("Could not copy bindings!"); - } else { - if env::var("DONT_USE_GENERATED_BINDINGS").is_ok() { - panic!("Could not find obs headers - aborting!"); + .parse_callbacks(Box::new(bindgen::CargoCallbacks::new())); + + match builder.generate() { + Ok(bindings) => { + bindings + .write_to_file(&out_path) + .expect("Couldn't write bindings!"); + fs::copy(&out_path, "generated/bindings.rs").expect("Could not copy bindings!"); } - println!("cargo:warning=Could not find obs headers - using pre-compiled."); - println!("cargo:warning=This could result in a library that doesn't work."); - fs::copy("generated/bindings.rs", out_path).expect("Could not copy bindings!"); + Err(e) => { + if env::var("DONT_USE_GENERATED_BINDINGS").is_ok() { + panic!("Failed to generate headers with bindgen: {}", e); + } + + println!("cargo:warning=Could not find obs headers - using pre-compiled."); + println!("cargo:warning=This could result in a library that doesn't work."); + fs::copy("generated/bindings.rs", out_path).expect("Could not copy bindings!"); + } } } diff --git a/obs-sys/build_mac.rs b/obs-sys/build_mac.rs index 271605a..a06878d 100644 --- a/obs-sys/build_mac.rs +++ b/obs-sys/build_mac.rs @@ -12,18 +12,51 @@ pub fn find_mac_obs_lib() { PathBuf::from(&*shellexpand::tilde( "~/Applications/OBS.app/Contents/MacOS", )), + PathBuf::from(&*shellexpand::tilde( + "~/Applications/OBS.app/Contents/Frameworks", + )), PathBuf::from("/Applications/OBS.app/Contents/Frameworks"), PathBuf::from("/Applications/OBS.app/Contents/MacOS"), ]; + let mut found_obs = false; + let mut found_obs_frontend = false; + for c in candidates.iter() { - if let Ok(meta) = fs::metadata(c.join("libobs.0.dylib")) { - if meta.is_file() { - println!("cargo:rustc-link-search=native={}", c.display()); - return; + if !found_obs { + if let Ok(meta) = fs::metadata(c.join("libobs.0.dylib")) { + if meta.is_file() { + println!("cargo:rustc-link-search={}", c.display()); + println!("cargo:rustc-link-lib=dylib=obs.0"); + found_obs = true; + } + } + + if let Ok(meta) = fs::metadata(c.join("libobs.framework")) { + if meta.is_dir() { + println!("cargo:rustc-link-search=framework={}", c.display()); + println!("cargo:rustc-link-lib=framework=libobs"); + found_obs = true; + } + } + } + + if !found_obs_frontend { + if let Ok(meta) = fs::metadata(c.join("libobs-frontend-api.1.dylib")) { + if meta.is_file() { + println!("cargo:rustc-link-search={}", c.display()); + println!("cargo:rustc-link-lib=dylib=obs-frontend-api.1"); + found_obs_frontend = true; + } } } } - panic!("could not find libobs - install OBS or set LIBOBS_PATH"); + if !found_obs { + panic!("could not find libobs - install OBS or set LIBOBS_PATH"); + } + + if !found_obs_frontend { + panic!("could not find libobs-frontend-api - install OBS or set LIBOBS_PATH"); + } } diff --git a/obs-sys/generated/bindings.rs b/obs-sys/generated/bindings.rs index 1bdd768..12892bc 100644 --- a/obs-sys/generated/bindings.rs +++ b/obs-sys/generated/bindings.rs @@ -21535,6 +21535,51 @@ extern "C" { extern "C" { pub fn obs_source_get_icon_type(id: *const ::std::os::raw::c_char) -> obs_icon_type; } +extern "C" { + #[doc = " Required: Called when the module is loaded. Use this function to load all\n the sources/encoders/outputs/services for your module, or anything else that\n may need loading.\n\n @return Return true to continue loading the module, otherwise\n false to indicate failure and unload the module"] + pub fn obs_module_load() -> bool; +} +extern "C" { + #[doc = " Optional: Called when the module is unloaded."] + pub fn obs_module_unload(); +} +extern "C" { + #[doc = " Optional: Called when all modules have finished loading"] + pub fn obs_module_post_load(); +} +extern "C" { + #[doc = " Called to set the current locale data for the module."] + pub fn obs_module_set_locale(locale: *const ::std::os::raw::c_char); +} +extern "C" { + #[doc = " Called to free the current locale data for the module."] + pub fn obs_module_free_locale(); +} +extern "C" { + #[doc = " Helper function for looking up locale if default locale handler was used"] + pub fn obs_module_text( + lookup_string: *const ::std::os::raw::c_char, + ) -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Helper function for looking up locale if default locale handler was used,\n returns true if text found, otherwise false"] + pub fn obs_module_get_string( + lookup_string: *const ::std::os::raw::c_char, + translated_string: *mut *const ::std::os::raw::c_char, + ) -> bool; +} +extern "C" { + #[doc = " Helper function that returns the current module"] + pub fn obs_current_module() -> *mut obs_module_t; +} +extern "C" { + #[doc = " Optional: Returns the full name of the module"] + pub fn obs_module_name() -> *const ::std::os::raw::c_char; +} +extern "C" { + #[doc = " Optional: Returns a description of the module"] + pub fn obs_module_description() -> *const ::std::os::raw::c_char; +} #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct config_data { diff --git a/obs-sys/wrapper.h b/obs-sys/wrapper.h index 77104b7..5633879 100644 --- a/obs-sys/wrapper.h +++ b/obs-sys/wrapper.h @@ -1,2 +1,2 @@ -#include "obs/libobs/obs.h" -#include "obs/UI/obs-frontend-api/obs-frontend-api.h" +#include +#include diff --git a/src/source/ffi.rs b/src/source/ffi.rs index af7dc07..b40df7e 100644 --- a/src/source/ffi.rs +++ b/src/source/ffi.rs @@ -86,7 +86,7 @@ pub unsafe extern "C" fn create( settings: *mut obs_data_t, source: *mut obs_source_t, ) -> *mut c_void { - let mut global = GlobalContext::default(); + let mut global = GlobalContext; let settings = DataObj::from_raw(settings); let mut context = CreatableSourceContext::from_raw(settings, &mut global); let source_context = SourceContext::from_raw(source); @@ -113,7 +113,7 @@ pub unsafe extern "C" fn destroy(data: *mut c_void) { } pub unsafe extern "C" fn update(data: *mut c_void, settings: *mut obs_data_t) { - let mut global = GlobalContext::default(); + let mut global = GlobalContext; let data: &mut DataWrapper = &mut *(data as *mut DataWrapper); let mut settings = DataObj::from_raw(settings); D::update(&mut data.data, &mut settings, &mut global); @@ -125,8 +125,8 @@ pub unsafe extern "C" fn video_render( _effect: *mut gs_effect_t, ) { let wrapper: &mut DataWrapper = &mut *(data as *mut DataWrapper); - let mut global = GlobalContext::default(); - let mut render = VideoRenderContext::default(); + let mut global = GlobalContext; + let mut render = VideoRenderContext; D::video_render(&mut wrapper.data, &mut global, &mut render); } @@ -139,7 +139,7 @@ pub unsafe extern "C" fn audio_render( _sample_rate: size_t, ) -> bool { let wrapper: &mut DataWrapper = &mut *(data as *mut DataWrapper); - let mut global = GlobalContext::default(); + let mut global = GlobalContext; D::audio_render(&mut wrapper.data, &mut global); // TODO: understand what this bool is true