use std::ffi::CStr;
use std::os::raw::c_int;
use std::sync::OnceLock;
use cef::*;
use crate::ChromeCommandGroup;
use crate::macros::wrap_with_args;
const WINDOW_AND_TAB_COMMANDS: &[&CStr] = &[
cef::resources::IDC_NEW_WINDOW,
cef::resources::IDC_NEW_INCOGNITO_WINDOW,
cef::resources::IDC_NEW_TAB,
cef::resources::IDC_NEW_TAB_TO_RIGHT,
cef::resources::IDC_DUPLICATE_TAB,
cef::resources::IDC_RESTORE_TAB,
cef::resources::IDC_MOVE_TAB_TO_NEW_WINDOW,
cef::resources::IDC_MOVE_TAB_NEXT,
cef::resources::IDC_MOVE_TAB_PREVIOUS,
cef::resources::IDC_SHOW_AS_TAB,
cef::resources::IDC_SELECT_NEXT_TAB,
cef::resources::IDC_SELECT_PREVIOUS_TAB,
cef::resources::IDC_SELECT_LAST_TAB,
cef::resources::IDC_SELECT_TAB_0,
cef::resources::IDC_SELECT_TAB_1,
cef::resources::IDC_SELECT_TAB_2,
cef::resources::IDC_SELECT_TAB_3,
cef::resources::IDC_SELECT_TAB_4,
cef::resources::IDC_SELECT_TAB_5,
cef::resources::IDC_SELECT_TAB_6,
cef::resources::IDC_SELECT_TAB_7,
cef::resources::IDC_TAB_SEARCH,
];
const DOCUMENT_COMMANDS: &[&CStr] = &[
cef::resources::IDC_PRINT,
cef::resources::IDC_BASIC_PRINT,
cef::resources::IDC_SAVE_PAGE,
cef::resources::IDC_VIEW_SOURCE,
cef::resources::IDC_OPEN_FILE,
cef::resources::IDC_CREATE_SHORTCUT,
cef::resources::IDC_INSTALL_PWA,
];
const BROWSER_CHROME_COMMANDS: &[&CStr] = &[
cef::resources::IDC_FOCUS_LOCATION,
cef::resources::IDC_FOCUS_SEARCH,
cef::resources::IDC_FOCUS_TOOLBAR,
cef::resources::IDC_FOCUS_MENU_BAR,
cef::resources::IDC_FOCUS_BOOKMARKS,
cef::resources::IDC_OPEN_CURRENT_URL,
cef::resources::IDC_HOME,
cef::resources::IDC_SEARCH,
cef::resources::IDC_SHOW_APP_MENU,
];
const HISTORY_COMMANDS: &[&CStr] = &[cef::resources::IDC_BACK, cef::resources::IDC_FORWARD];
const BROWSER_SURFACE_COMMANDS: &[&CStr] = &[
cef::resources::IDC_SHOW_HISTORY,
cef::resources::IDC_SHOW_DOWNLOADS,
cef::resources::IDC_SHOW_BOOKMARK_MANAGER,
cef::resources::IDC_SHOW_BOOKMARK_BAR,
cef::resources::IDC_BOOKMARK_THIS_TAB,
cef::resources::IDC_BOOKMARK_ALL_TABS,
cef::resources::IDC_OPTIONS,
cef::resources::IDC_CLEAR_BROWSING_DATA,
cef::resources::IDC_IMPORT_SETTINGS,
cef::resources::IDC_TASK_MANAGER,
cef::resources::IDC_TASK_MANAGER_SHORTCUT,
cef::resources::IDC_SHOW_SIGNIN,
cef::resources::IDC_ABOUT,
cef::resources::IDC_FEEDBACK,
cef::resources::IDC_HELP_PAGE_VIA_KEYBOARD,
];
const DEVTOOLS_COMMANDS: &[&CStr] = &[
cef::resources::IDC_DEV_TOOLS,
cef::resources::IDC_DEV_TOOLS_CONSOLE,
cef::resources::IDC_DEV_TOOLS_DEVICES,
cef::resources::IDC_DEV_TOOLS_INSPECT,
cef::resources::IDC_DEV_TOOLS_TOGGLE,
];
const ZOOM_COMMANDS: &[&CStr] = &[
cef::resources::IDC_ZOOM_PLUS,
cef::resources::IDC_ZOOM_MINUS,
cef::resources::IDC_ZOOM_NORMAL,
];
fn group_commands(group: ChromeCommandGroup) -> &'static [&'static CStr] {
match group {
ChromeCommandGroup::WindowAndTab => WINDOW_AND_TAB_COMMANDS,
ChromeCommandGroup::Document => DOCUMENT_COMMANDS,
ChromeCommandGroup::BrowserChrome => BROWSER_CHROME_COMMANDS,
ChromeCommandGroup::BrowserSurface => BROWSER_SURFACE_COMMANDS,
ChromeCommandGroup::History => HISTORY_COMMANDS,
}
}
struct BlockedCommands {
groups: Vec<(ChromeCommandGroup, Vec<c_int>)>,
devtools: Vec<c_int>,
zoom: Vec<c_int>,
}
fn blocked_commands() -> &'static BlockedCommands {
static COMMANDS: OnceLock<BlockedCommands> = OnceLock::new();
COMMANDS.get_or_init(|| BlockedCommands {
groups: ChromeCommandGroup::ALL
.iter()
.map(|group| (*group, command_ids(&[group_commands(*group)])))
.collect(),
devtools: command_ids(&[DEVTOOLS_COMMANDS]),
zoom: command_ids(&[ZOOM_COMMANDS]),
})
}
fn command_ids(groups: &[&[&CStr]]) -> Vec<c_int> {
groups
.iter()
.flat_map(|names| names.iter())
.map(|name| unsafe { cef::sys::cef_id_for_command_id_name(name.as_ptr()) })
.filter(|id| *id != -1)
.collect()
}
wrap_with_args! {
wrap_command_handler => TauriCefCommandHandlerArgs;
pub struct TauriCefCommandHandler {
devtools_enabled: bool,
zoom_hotkeys_enabled: bool,
allowed_chrome_commands: Vec<ChromeCommandGroup>,
frame_navigation_state: crate::FrameNavigationState,
}
impl CommandHandler {
fn on_chrome_command(
&self,
browser: Option<&mut Browser>,
command_id: ::std::os::raw::c_int,
_disposition: WindowOpenDisposition,
) -> ::std::os::raw::c_int {
if !self.owns(browser) {
return 0;
}
if self.blocks(command_id) { 1 } else { 0 }
}
fn is_chrome_app_menu_item_visible(
&self,
_browser: Option<&mut Browser>,
_command_id: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int {
1
}
fn is_chrome_app_menu_item_enabled(
&self,
browser: Option<&mut Browser>,
command_id: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int {
if self.owns(browser) && self.blocks(command_id) { 0 } else { 1 }
}
fn is_chrome_page_action_icon_visible(
&self,
_icon_type: ChromePageActionIconType,
) -> ::std::os::raw::c_int {
1
}
fn is_chrome_toolbar_button_visible(
&self,
_button_type: ChromeToolbarButtonType,
) -> ::std::os::raw::c_int {
1
}
}
}
impl TauriCefCommandHandler {
fn owns(&self, browser: Option<&mut Browser>) -> bool {
browser
.map(|browser| {
self
.frame_navigation_state
.has_browser_id(browser.identifier())
})
.unwrap_or(false)
}
fn blocks(&self, command_id: c_int) -> bool {
let commands = blocked_commands();
commands
.groups
.iter()
.filter(|(group, _)| !self.allowed_chrome_commands.contains(group))
.any(|(_, ids)| ids.contains(&command_id))
|| (!self.devtools_enabled && commands.devtools.contains(&command_id))
|| (!self.zoom_hotkeys_enabled && commands.zoom.contains(&command_id))
}
}