diff --git a/CHANGELOG.md b/CHANGELOG.md index 35b7b67e..72771047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Add `--parent` flag for recording/capturing the parent window ([#14](https://github.com/orhun/menyoki/issues/10)) + ### Changed - Use architecture compatible types for Xlib calls diff --git a/README.md b/README.md index 86dd16f2..74e99b08 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,7 @@ FLAGS: -r, --root Record the root window -f, --focus Record the focused window --select Select the window to record + --parent Record the parent of the window --with-alpha Record with the alpha channel --no-keys Disable the action keys while recording -h, --help Print help information @@ -328,6 +329,7 @@ SUBCOMMANDS: | `menyoki record --focus --with-alpha` | Record the focused window with the alpha channel (for transparency) | | `menyoki record --size 200x300 --duration 10` | Record an area of size 200x300 for 10 seconds | | `menyoki record --padding 20:10:0:10 --timeout 120` | Record an area with given padding and set window selection timeout to 120 seconds | +| `menyoki record --parent` | Record the parent window of the selected window | | `menyoki record --border 5` | Record the area selected by a border with 5 width | | `menyoki record --keys LControl-Q/W` | Record with the default settings using custom key bindings | | `menyoki record gif --fps 15 --quality 90` | Record 15 frames per second with 90% quality | @@ -435,6 +437,7 @@ FLAGS: -r, --root Capture the root window -f, --focus Capture the focused window --select Select the window to capture + --parent Record the parent of the window --with-alpha Capture with the alpha channel -h, --help Print help information @@ -794,6 +797,7 @@ color = 3AA431 root = false focus = true select = true +parent = false with-alpha = false no-keys = false keys = LAlt-S/Enter @@ -822,6 +826,7 @@ format = gif root = false focus = true select = true +parent = false with-alpha = false keys = LAlt-S/Enter border = 1 diff --git a/completions/menyoki.bash b/completions/menyoki.bash index 2f6d4e1e..f589de27 100644 --- a/completions/menyoki.bash +++ b/completions/menyoki.bash @@ -207,7 +207,7 @@ _menyoki() { return 0 ;; menyoki__capture) - opts=" -r -f -h -V -k -b -p -s -d -c -t -i --root --focus --select --with-alpha --no-keys --help --version --keys --border --padding --size --duration --countdown --timeout --interval --font png jpg bmp ico tiff tga pnm ff save help out" + opts=" -r -f -h -V -k -b -p -s -d -c -t -i --root --focus --select --parent --with-alpha --no-keys --help --version --keys --border --padding --size --duration --countdown --timeout --interval --font png jpg bmp ico tiff tga pnm ff save help out" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2298,7 +2298,7 @@ _menyoki() { return 0 ;; menyoki__record) - opts=" -r -f -h -V -k -b -p -s -d -c -t -i --root --focus --select --with-alpha --no-keys --help --version --keys --border --padding --size --duration --countdown --timeout --interval --font gif apng save help out" + opts=" -r -f -h -V -k -b -p -s -d -c -t -i --root --focus --select --parent --with-alpha --no-keys --help --version --keys --border --padding --size --duration --countdown --timeout --interval --font gif apng save help out" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2698,7 +2698,7 @@ _menyoki() { return 0 ;; menyoki__screenshot) - opts=" -r -f -h -V -k -b -p -s -d -c -t -i --root --focus --select --with-alpha --no-keys --help --version --keys --border --padding --size --duration --countdown --timeout --interval --font png jpg bmp ico tiff tga pnm ff save help out" + opts=" -r -f -h -V -k -b -p -s -d -c -t -i --root --focus --select --parent --with-alpha --no-keys --help --version --keys --border --padding --size --duration --countdown --timeout --interval --font png jpg bmp ico tiff tga pnm ff save help out" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -3513,7 +3513,7 @@ _menyoki() { return 0 ;; menyoki__ss) - opts=" -r -f -h -V -k -b -p -s -d -c -t -i --root --focus --select --with-alpha --no-keys --help --version --keys --border --padding --size --duration --countdown --timeout --interval --font png jpg bmp ico tiff tga pnm ff save help out" + opts=" -r -f -h -V -k -b -p -s -d -c -t -i --root --focus --select --parent --with-alpha --no-keys --help --version --keys --border --padding --size --duration --countdown --timeout --interval --font png jpg bmp ico tiff tga pnm ff save help out" if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 diff --git a/completions/menyoki.elvish b/completions/menyoki.elvish index bea84742..5cbbc722 100644 --- a/completions/menyoki.elvish +++ b/completions/menyoki.elvish @@ -58,6 +58,7 @@ edit:completion:arg-completer[menyoki] = [@words]{ cand -f 'Record the focused window' cand --focus 'Record the focused window' cand --select 'Select the window to record' + cand --parent 'Record the parent of the window' cand --with-alpha 'Record with the alpha channel' cand --no-keys 'Disable the action keys while recording' cand -h 'Print help information' @@ -493,6 +494,7 @@ edit:completion:arg-completer[menyoki] = [@words]{ cand -f 'Capture the focused window' cand --focus 'Capture the focused window' cand --select 'Select the window to capture' + cand --parent 'Capture the parent of the window' cand --with-alpha 'Capture with the alpha channel' cand --no-keys 'Disable the action keys while recording' cand -h 'Print help information' diff --git a/completions/menyoki.fish b/completions/menyoki.fish index 171ac924..b74db507 100644 --- a/completions/menyoki.fish +++ b/completions/menyoki.fish @@ -24,6 +24,7 @@ complete -c menyoki -n "__fish_seen_subcommand_from record" -l font -d 'Set the complete -c menyoki -n "__fish_seen_subcommand_from record" -s r -l root -d 'Record the root window' complete -c menyoki -n "__fish_seen_subcommand_from record" -s f -l focus -d 'Record the focused window' complete -c menyoki -n "__fish_seen_subcommand_from record" -l select -d 'Select the window to record' +complete -c menyoki -n "__fish_seen_subcommand_from record" -l parent -d 'Record the parent of the window' complete -c menyoki -n "__fish_seen_subcommand_from record" -l with-alpha -d 'Record with the alpha channel' complete -c menyoki -n "__fish_seen_subcommand_from record" -l no-keys -d 'Disable the action keys while recording' complete -c menyoki -n "__fish_seen_subcommand_from record" -s h -l help -d 'Print help information' @@ -230,6 +231,7 @@ complete -c menyoki -n "__fish_seen_subcommand_from capture" -l font -d 'Set the complete -c menyoki -n "__fish_seen_subcommand_from capture" -s r -l root -d 'Capture the root window' complete -c menyoki -n "__fish_seen_subcommand_from capture" -s f -l focus -d 'Capture the focused window' complete -c menyoki -n "__fish_seen_subcommand_from capture" -l select -d 'Select the window to capture' +complete -c menyoki -n "__fish_seen_subcommand_from capture" -l parent -d 'Capture the parent of the window' complete -c menyoki -n "__fish_seen_subcommand_from capture" -l with-alpha -d 'Capture with the alpha channel' complete -c menyoki -n "__fish_seen_subcommand_from capture" -l no-keys -d 'Disable the action keys while recording' complete -c menyoki -n "__fish_seen_subcommand_from capture" -s h -l help -d 'Print help information' diff --git a/completions/menyoki.powershell b/completions/menyoki.powershell index e2bd23f9..495fb7fb 100644 --- a/completions/menyoki.powershell +++ b/completions/menyoki.powershell @@ -64,6 +64,7 @@ Register-ArgumentCompleter -Native -CommandName 'menyoki' -ScriptBlock { [CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'Record the focused window') [CompletionResult]::new('--focus', 'focus', [CompletionResultType]::ParameterName, 'Record the focused window') [CompletionResult]::new('--select', 'select', [CompletionResultType]::ParameterName, 'Select the window to record') + [CompletionResult]::new('--parent', 'parent', [CompletionResultType]::ParameterName, 'Record the parent of the window') [CompletionResult]::new('--with-alpha', 'with-alpha', [CompletionResultType]::ParameterName, 'Record with the alpha channel') [CompletionResult]::new('--no-keys', 'no-keys', [CompletionResultType]::ParameterName, 'Disable the action keys while recording') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information') @@ -538,6 +539,7 @@ Register-ArgumentCompleter -Native -CommandName 'menyoki' -ScriptBlock { [CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'Capture the focused window') [CompletionResult]::new('--focus', 'focus', [CompletionResultType]::ParameterName, 'Capture the focused window') [CompletionResult]::new('--select', 'select', [CompletionResultType]::ParameterName, 'Select the window to capture') + [CompletionResult]::new('--parent', 'parent', [CompletionResultType]::ParameterName, 'Capture the parent of the window') [CompletionResult]::new('--with-alpha', 'with-alpha', [CompletionResultType]::ParameterName, 'Capture with the alpha channel') [CompletionResult]::new('--no-keys', 'no-keys', [CompletionResultType]::ParameterName, 'Disable the action keys while recording') [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help information') diff --git a/completions/menyoki.zsh b/completions/menyoki.zsh index 8c1fd337..0adfa9fe 100644 --- a/completions/menyoki.zsh +++ b/completions/menyoki.zsh @@ -59,6 +59,7 @@ _arguments "${_arguments_options[@]}" \ '(-r --root)-f[Record the focused window]' \ '(-r --root)--focus[Record the focused window]' \ '--select[Select the window to record]' \ +'--parent[Record the parent of the window]' \ '--with-alpha[Record with the alpha channel]' \ '--no-keys[Disable the action keys while recording]' \ '-h[Print help information]' \ @@ -1493,6 +1494,7 @@ _arguments "${_arguments_options[@]}" \ '(-r --root)-f[Capture the focused window]' \ '(-r --root)--focus[Capture the focused window]' \ '--select[Select the window to capture]' \ +'--parent[Capture the parent of the window]' \ '--with-alpha[Capture with the alpha channel]' \ '--no-keys[Disable the action keys while recording]' \ '-h[Print help information]' \ @@ -2041,6 +2043,7 @@ _arguments "${_arguments_options[@]}" \ '(-r --root)-f[Capture the focused window]' \ '(-r --root)--focus[Capture the focused window]' \ '--select[Select the window to capture]' \ +'--parent[Capture the parent of the window]' \ '--with-alpha[Capture with the alpha channel]' \ '--no-keys[Disable the action keys while recording]' \ '-h[Print help information]' \ @@ -2589,6 +2592,7 @@ _arguments "${_arguments_options[@]}" \ '(-r --root)-f[Capture the focused window]' \ '(-r --root)--focus[Capture the focused window]' \ '--select[Select the window to capture]' \ +'--parent[Capture the parent of the window]' \ '--with-alpha[Capture with the alpha channel]' \ '--no-keys[Disable the action keys while recording]' \ '-h[Print help information]' \ diff --git a/config/menyoki.conf b/config/menyoki.conf index 10a824c4..4e1b50d2 100644 --- a/config/menyoki.conf +++ b/config/menyoki.conf @@ -18,6 +18,8 @@ root = false focus = true # Select the window to record select = true +# Record the parent of the window +parent = false # Record with the alpha channel with-alpha = false # Disable the action keys while recording @@ -64,21 +66,23 @@ repeat = ∞ format = gif [capture] -# Record the root window +# Capture the root window root = false -# Record the focused window +# Capture the focused window focus = true -# Select the window to record +# Select the window to capture select = true -# Record with the alpha channel +# Capture the parent of the window +parent = false +# Capture with the alpha channel with-alpha = false # Set the action keys keys = LAlt-S/Enter # Set the border width border = 1 -# Set the record area padding +# Set the capture area padding #padding = T:R:B:L -# Set the record area size +# Set the capture area size #size = WxH # Set the countdown before recording countdown = 0 diff --git a/man/menyoki.1 b/man/menyoki.1 index 4488e684..a6551192 100644 --- a/man/menyoki.1 +++ b/man/menyoki.1 @@ -124,6 +124,7 @@ FLAGS: -r, --root Record the root window -f, --focus Record the focused window --select Select the window to record + --parent Record the parent of the window --with-alpha Record with the alpha channel --no-keys Disable the action keys while recording -h, --help Print help information @@ -371,6 +372,7 @@ FLAGS: -r, --root Capture the root window -f, --focus Capture the focused window --select Select the window to capture + --parent Record the parent of the window --with-alpha Capture with the alpha channel -h, --help Print help information diff --git a/man/menyoki.conf.5 b/man/menyoki.conf.5 index c5ce7512..fa700c1d 100644 --- a/man/menyoki.conf.5 +++ b/man/menyoki.conf.5 @@ -36,6 +36,9 @@ Record the focused window .B select Select the window to record .TP +.B parent +Record the parent of the window +.TP .B with-alpha Record with the alpha channel .TP @@ -111,6 +114,9 @@ Capture the focused window .B select Select the window to capture .TP +.B parent +Capture the parent of the window +.TP .B with-alpha Capture with the alpha channel .TP diff --git a/src/args/mod.rs b/src/args/mod.rs index c9a7ba7e..32899d95 100644 --- a/src/args/mod.rs +++ b/src/args/mod.rs @@ -220,6 +220,11 @@ where } else { "Select the window to record" })) + .arg(Arg::with_name("parent").long("parent").help(if capture { + "Capture the parent of the window" + } else { + "Record the parent of the window" + })) .arg( Arg::with_name("with-alpha") .long("with-alpha") diff --git a/src/record/settings.rs b/src/record/settings.rs index 51195898..540bc014 100644 --- a/src/record/settings.rs +++ b/src/record/settings.rs @@ -121,7 +121,7 @@ impl RecordFlag { /* Window to record, with geometric properties */ #[derive(Clone, Copy, Debug, PartialEq)] pub enum RecordWindow { - Focus(Option), + Focus(Option, bool), Root(Option), } @@ -146,11 +146,11 @@ impl RecordWindow { None }; if matches.is_present("focus") { - Self::Focus(size) + Self::Focus(size, matches.is_present("parent")) } else if matches.is_present("root") { Self::Root(size) } else { - Self::Focus(Some(size.unwrap_or_default())) + Self::Focus(Some(size.unwrap_or_default()), matches.is_present("parent")) } } } @@ -177,7 +177,7 @@ impl Default for RecordSettings { padding: Padding::default(), time: RecordTime::default(), flag: RecordFlag::default(), - window: RecordWindow::Focus(Some(Geometry::default())), + window: RecordWindow::Focus(Some(Geometry::default()), false), } } } diff --git a/src/settings.rs b/src/settings.rs index 2530a251..6bf74e11 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -147,13 +147,13 @@ impl<'a> AppSettings<'a> { fn set_icon_size(&mut self) { let ico_geometry = Geometry::new(0, 0, 256, 256); match self.record.window { - RecordWindow::Focus(None) => { - self.record.window = RecordWindow::Focus(Some(ico_geometry)) + RecordWindow::Focus(None, parent) => { + self.record.window = RecordWindow::Focus(Some(ico_geometry), parent) } RecordWindow::Root(None) => { self.record.window = RecordWindow::Root(Some(ico_geometry)) } - RecordWindow::Focus(Some(ref mut geometry)) + RecordWindow::Focus(Some(ref mut geometry), _) | RecordWindow::Root(Some(ref mut geometry)) => { if geometry.width == 0 || geometry.width > ico_geometry.width { geometry.width = ico_geometry.width; @@ -188,7 +188,8 @@ mod tests { settings.jpg.quality = 0; settings.anim.quality = 0; settings.save.file.format = FileFormat::Ico; - settings.record.window = RecordWindow::Focus(Some(Geometry::default())); + settings.record.window = + RecordWindow::Focus(Some(Geometry::default()), false); settings.check(); } } diff --git a/src/x11/display.rs b/src/x11/display.rs index fb371270..1d6cf198 100644 --- a/src/x11/display.rs +++ b/src/x11/display.rs @@ -91,9 +91,10 @@ impl Display { /** * Get the focused window. * + * @param parent * @return Window (Option) */ - pub fn get_focused_window(&self) -> Option { + pub fn get_focused_window(&self, parent: bool) -> Option { unsafe { let mut focus_window = MaybeUninit::::uninit(); let mut focus_state = MaybeUninit::::uninit(); @@ -104,7 +105,7 @@ impl Display { ); if focus_state.assume_init() != xlib::RevertToNone { let mut window = Window::new(*focus_window.as_ptr(), *self); - if window.geometry == Geometry::new(0, 0, 1, 1) { + if window.geometry == Geometry::new(0, 0, 1, 1) || parent { if let Some(parent) = window.get_parent() { window = parent; } @@ -136,8 +137,9 @@ impl Display { */ fn get_window(&self) -> (Window, Geometry) { match self.settings.window { - RecordWindow::Focus(geometry) => ( - self.get_focused_window().expect("Failed to get the window"), + RecordWindow::Focus(geometry, parent) => ( + self.get_focused_window(parent) + .expect("Failed to get the window"), geometry.unwrap_or_default(), ), RecordWindow::Root(geometry) => { @@ -359,7 +361,7 @@ mod tests { display.update_padding(Geometry::new(0, 0, 10, 10), Geometry::default()); assert_eq!( display.get_root_window().xid, - display.get_focused_window().unwrap().xid + display.get_focused_window(false).unwrap().xid ); let input_state = InputState::default(); assert!(display.select_window(&input_state).is_none()); diff --git a/src/x11/mod.rs b/src/x11/mod.rs index e879c232..b86257f3 100644 --- a/src/x11/mod.rs +++ b/src/x11/mod.rs @@ -42,11 +42,18 @@ impl<'a> Access<'a, Window> for WindowSystem<'a> { fn get_window(&mut self) -> Option { debug!("Record window: {:?}", self.settings.record.window); match self.settings.record.window { - RecordWindow::Focus(None) => self.display.get_focused_window(), + RecordWindow::Focus(None, parent) => { + self.display.get_focused_window(parent) + } RecordWindow::Root(None) => Some(self.display.get_root_window()), _ => { if self.settings.record.command.is_some() { - self.display.get_focused_window() + self.display.get_focused_window( + match self.settings.record.window { + RecordWindow::Focus(_, parent) => parent, + _ => false, + }, + ) } else { self.display.select_window( &self @@ -126,13 +133,14 @@ mod tests { .unwrap() .get_window() .is_none()); - settings.record.window = RecordWindow::Focus(Some(Geometry::default())); + settings.record.window = + RecordWindow::Focus(Some(Geometry::default()), false); settings.record.command = Some("test"); assert!(WindowSystem::init(&settings) .unwrap() .get_window() .is_some()); - settings.record.window = RecordWindow::Focus(None); + settings.record.window = RecordWindow::Focus(None, false); let mut window_system = WindowSystem::init(&settings).unwrap(); window_system.display.set_focused_window( window_system.display.get_root_window().xid,