Skip to content

Commit

Permalink
Medium-level API: Add support for registering hwnd_info callback
Browse files Browse the repository at this point in the history
  • Loading branch information
helgoboss committed Aug 9, 2024
1 parent 5b64cd0 commit 9ae63ef
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 4 deletions.
3 changes: 3 additions & 0 deletions main/low/src/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,5 +213,8 @@ pub type HookPostCommand2 = extern "C" fn(
proj: *mut ReaProject,
);

/// Function pointer type that REAPER uses for querying information about a window.
pub type HwndInfo = extern "C" fn(hwnd: HWND, info_type: INT_PTR) -> c_int;

/// Function pointer type for exposing custom API functions to ReaScript.
pub type ApiVararg = unsafe extern "C" fn(*mut *mut c_void, c_int) -> *mut c_void;
25 changes: 23 additions & 2 deletions main/medium/src/fn_traits.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::{
ActionValueChange, CommandId, Hmenu, KbdSectionInfo, MenuHookFlag, ReaProject, ReaperStr,
SectionContext, WindowContext,
ActionValueChange, CommandId, Hmenu, Hwnd, HwndInfoType, KbdSectionInfo, MenuHookFlag,
ReaProject, ReaperStr, SectionContext, WindowContext,
};
use reaper_low::raw::{HWND, INT_PTR};
use reaper_low::{firewall, raw};
use std::ffi::c_char;
use std::os::raw::c_int;
Expand Down Expand Up @@ -64,6 +65,26 @@ pub(crate) extern "C" fn delegating_hook_command_2<T: HookCommand2>(
})
.unwrap_or(false)
}
/// Consumers need to implement this trait in order to define what should happen when REAPER wants to know something
/// about a specific window.
pub trait HwndInfo {
/// The actual callback function invoked by REAPER whenever it needs to know something about a window.
///
/// Return 0 if not a known window, or if `info_type` is unknown.
fn call(window: Hwnd, info_type: HwndInfoType) -> i32;
}

pub(crate) extern "C" fn delegating_hwnd_info<T: HwndInfo>(
hwnd: HWND,
info_type: INT_PTR,
) -> c_int {
firewall(|| {
let window = Hwnd::new(hwnd).expect("REAPER hwnd_info hwnd pointer was null");
let info_type = HwndInfoType::from_raw(info_type);
T::call(window, info_type)
})
.unwrap_or(0)
}

/// Consumers need to implement this trait in order to define what should happen when a custom menu is initialized or
/// populated.
Expand Down
34 changes: 34 additions & 0 deletions main/medium/src/misc_enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,34 @@ pub enum UndoBehavior {
AddUndoPoint,
}

/// Possible things that REAPER wants to know when calling the `hwnd_info` function.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum HwndInfoType {
/// REAPER queries if the window should be treated as a text-field for purposes of global hotkeys.
///
/// - Return 1 if text field
/// - Return -1 if not a text field
IsTextField,
/// REAPER queries if global hotkeys should be processed for this context (6.60+).
///
/// - Return 1 if global hotkey should be skipped (and default accelerator processing used instead)
/// - Return -1 if global hotkey should be forced
ShouldProcessGlobalHotkeys,
/// Represents a variant unknown to *reaper-rs*. Please contribute if you encounter a variant
/// that is supported by REAPER but not yet by *reaper-rs*. Thanks!
Unknown(Hidden<isize>),
}

impl HwndInfoType {
pub(crate) fn from_raw(value: isize) -> Self {
match value {
0 => Self::IsTextField,
1 => Self::ShouldProcessGlobalHotkeys,
x => Self::Unknown(Hidden(x)),
}
}
}

/// Determines whether to refresh the UI.
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum UiRefreshBehavior {
Expand Down Expand Up @@ -746,6 +774,8 @@ pub enum RegistrationObject<'a> {
HookPostCommand(raw::HookPostCommand),
/// A hook post command 2.
HookPostCommand2(raw::HookPostCommand2),
/// Function that REAPER calls in order to query information about a window.
HwndInfo(raw::HwndInfo),
/// A timer.
Timer(raw::TimerFunction),
/// A toggle action.
Expand Down Expand Up @@ -890,6 +920,10 @@ impl<'a> RegistrationObject<'a> {
key: reaper_str!("hookcustommenu").into(),
value: func as _,
},
HwndInfo(func) => PluginRegistration {
key: reaper_str!("hwnd_info").into(),
value: func as _,
},
Timer(func) => PluginRegistration {
key: reaper_str!("timer").into(),
value: func as _,
Expand Down
25 changes: 23 additions & 2 deletions main/medium/src/reaper_session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
delegating_hook_post_command, delegating_hook_post_command_2, delegating_toggle_action,
AcceleratorPosition, BufferingBehavior, CommandId, ControlSurface, ControlSurfaceAdapter,
FileInProjectCallback, GenericRegistrationHandle, Handle, HookCommand, HookCommand2,
HookCustomMenu, HookPostCommand, HookPostCommand2, MainThreadScope, MeasureAlignment,
HookCustomMenu, HookPostCommand, HookPostCommand2, HwndInfo, MainThreadScope, MeasureAlignment,
OnAudioBuffer, OwnedAcceleratorRegister, OwnedAudioHookRegister, OwnedGaccelRegister,
OwnedPreviewRegister, PluginRegistration, ProjectContext, ReaProject, RealTimeAudioThreadScope,
Reaper, ReaperFunctionError, ReaperFunctionResult, ReaperMutex, ReaperString, ReaperStringArg,
Expand All @@ -21,7 +21,9 @@ use crate::{
use reaper_low::raw::audio_hook_register_t;

use crate::file_in_project_hook::OwnedFileInProjectHook;
use crate::fn_traits::{delegating_hook_custom_menu, delegating_toolbar_icon_map};
use crate::fn_traits::{
delegating_hook_custom_menu, delegating_hwnd_info, delegating_toolbar_icon_map,
};
use enumflags2::BitFlags;
use std::collections::{HashMap, HashSet};
use std::os::raw::{c_char, c_void};
Expand Down Expand Up @@ -318,6 +320,25 @@ impl ReaperSession {
}
}

/// Registers a function that REAPER calls in order to query information about a window (REAPER 6.29+).
///
/// # Errors
///
/// Returns an error if the registration failed.
pub fn plugin_register_add_hwnd_info<T: HwndInfo>(&mut self) -> ReaperFunctionResult<()> {
unsafe {
self.plugin_register_add(RegistrationObject::HwndInfo(delegating_hwnd_info::<T>))?;
}
Ok(())
}

/// Unregisters a `hwnd_info` function.
pub fn plugin_register_remove_hwnd_info<T: HwndInfo>(&mut self) {
unsafe {
self.plugin_register_remove(RegistrationObject::HwndInfo(delegating_hwnd_info::<T>));
}
}

/// Registers a custom menu hook.
///
/// See [`plugin_register_add_hook_command`](#method.plugin_register_add_hook_command) for
Expand Down

0 comments on commit 9ae63ef

Please sign in to comment.