Skip to content

Commit

Permalink
fix(window-id): closes #13
Browse files Browse the repository at this point in the history
 - check for window id very early
 - grab a screenshot before recording starts, to verify it works
 - present a nice error message to show what is wrong
  • Loading branch information
sassman committed Nov 17, 2020
1 parent 8c0e4d4 commit 22eaa6b
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 18 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## 🎯 [Unreleased]

## [0.2.1] - 2020-11-17
- improve error handling for invalid window id [issue/13] / [pull/14]

[issue/13]: https://github.com/sassman/t-rec-rs/issues/13
[pull/14]: https://github.com/sassman/t-rec-rs/pull/14

## [0.2.0] - 2020-10-12
### Added
- command line parameter for natural recording `-n` or `--natural`
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "t-rec"
version = "0.2.0"
version = "0.2.1"
authors = ["Sven Assmann <[email protected]>"]
edition = "2018"
license = "GPL-3.0-only"
Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Blazingly fast terminal recorder that generates animated gif images for the web

## Install

**NOTE** for now `t-rec` depends on `imagemagick`, but this is going to change soon.
**NOTE** for now `t-rec` depends on `imagemagick`.

```sh
❯ brew install imagemagick
Expand All @@ -53,7 +53,7 @@ or with specifying a different program to launch

```sh
❯ t-rec --help
t-rec 0.2.0
t-rec 0.2.1
Sven Assmann <[email protected]>
Blazingly fast terminal recorder that generates animated gif images for the web written in rust.

Expand Down Expand Up @@ -89,9 +89,11 @@ You can record not only the terminal but also every other window. There 2 ways t
```sh
❯ TERM_PROGRAM="google chrome" t-rec
Frame cache dir: "/var/folders/m8/084p1v0x4770rpwpkrgl5b6h0000gn/T/trec-74728.rUxBx3ohGiQ2"
Recording window: "Google Chrome 2"
Press Ctrl+D to end recording
Recording Window: "Google Chrome 2"
```
this is how it looks then:
Expand All @@ -111,6 +113,7 @@ Code | 27600
❯ WINDOWID=27600 t-rec
Frame cache dir: "/var/folders/m8/084p1v0x4770rpwpkrgl5b6h0000gn/T/trec-77862.BMYiHNRWqv9Y"
Recording window id: 27600
Press Ctrl+D to end recording
```
Expand Down
5 changes: 4 additions & 1 deletion src/macos/screenshot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ pub fn capture_window_screenshot(win_id: u32) -> Result<ImageOnHeap> {
| kCGWindowImageShouldBeOpaque,
)
}
.context("Cannot gather screenshot")?;
.context(format!(
"Cannot grab screenshot from CGDisplay of window id {}",
win_id
))?;

let img_ref: &CGImageRef = &image;
let (_wrong_width, h) = (img_ref.width() as u32, img_ref.height() as u32);
Expand Down
5 changes: 2 additions & 3 deletions src/macos/window_id.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,15 @@ pub fn ls_win() -> anyhow::Result<()> {
/// https://stackoverflow.com/questions/60117318/getting-window-owner-names-via-cgwindowlistcopywindowinfo-in-rust
/// then some more PRs where needed:
/// https://github.com/servo/core-foundation-rs/pulls?q=is%3Apr+author%3Asassman+
pub fn get_window_id_for(terminal: String) -> Result<u32> {
pub fn get_window_id_for(terminal: String) -> Result<(u32, String)> {
for term in terminal.to_lowercase().split('.') {
for (window_owner, window_id, _) in window_list()? {
if let DictEntryValue::_Number(window_id) = window_id {
if let DictEntryValue::_String(window_owner) = window_owner {
let window = &window_owner.to_lowercase();
let terminal = &terminal.to_lowercase();
if window.contains(term) || terminal.contains(window) {
println!("Recording Window: {:?}", window_owner);
return Ok(window_id as u32);
return Ok((window_id as u32, window_owner));
}
}
}
Expand Down
29 changes: 20 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ fn main() -> Result<()> {
env::var("SHELL").unwrap_or(default)
}
};
let (win_id, window_name) =
current_win_id().context("Cannot retrieve the window id of the to be recorded window.")?;
capture_window_screenshot(win_id)?;

let force_natural = args.is_present("natural-mode");

Expand All @@ -68,7 +71,7 @@ fn main() -> Result<()> {
let time_codes = time_codes.clone();
let force_natural = force_natural;
thread::spawn(move || -> Result<()> {
capture_thread(&rx, time_codes, tempdir, force_natural)
capture_thread(&rx, win_id, time_codes, tempdir, force_natural)
})
};
let interact = thread::spawn(move || -> Result<()> { sub_shell_thread(&program).map(|_| ()) });
Expand All @@ -78,6 +81,11 @@ fn main() -> Result<()> {
"Frame cache dir: {:?}",
tempdir.lock().expect("Cannot lock tempdir resource").path()
);
if let Some(window) = window_name {
println!("Recording window: {:?}", window);
} else {
println!("Recording window id: {}", win_id);
}
println!("Press Ctrl+D to end recording");

interact
Expand Down Expand Up @@ -110,11 +118,11 @@ fn clear_screen() {
/// stops once receiving something in rx
fn capture_thread(
rx: &Receiver<()>,
win_id: u32,
time_codes: Arc<Mutex<Vec<u128>>>,
tempdir: Arc<Mutex<TempDir>>,
force_natural: bool,
) -> Result<()> {
let win_id = current_win_id()?;
let duration = Duration::from_millis(250);
let start = Instant::now();
let mut idle_duration = Duration::from_millis(0);
Expand Down Expand Up @@ -192,19 +200,22 @@ fn sub_shell_thread<T: AsRef<OsStr> + Clone>(program: T) -> Result<ExitStatus> {
/// or by the env var 'TERM_PROGRAM' and then asking the window manager for all visible windows
/// and finding the Terminal in that list
/// panics if WindowId was not was not there
fn current_win_id() -> Result<u32> {
fn current_win_id() -> Result<(u32, Option<String>)> {
if env::var("WINDOWID").is_ok() {
env::var("WINDOWID")
let win_id = env::var("WINDOWID")
.unwrap()
.parse::<u32>()
.context("Cannot parse env variable 'WINDOWID' as number")
.context("Cannot parse env variable 'WINDOWID' as number")?;
Ok((win_id, None))
} else {
let terminal = env::var("TERM_PROGRAM").context(
"Env variable 'TERM_PROGRAM' was empty but is needed for figure out the WindowId",
"Env variable 'TERM_PROGRAM' was empty but it is needed for determine the window id",
)?;
let (win_id, name) = get_window_id_for(terminal.to_owned()).context(
format!(
"Cannot determine the window id of {}. Please set env variable 'WINDOWID' and try again.", terminal),
)?;
get_window_id_for(terminal).context(
"Cannot determine the WindowId of this terminal. Please set env variable 'WINDOWID' and try again.",
)
Ok((win_id, Some(name)))
}
}

Expand Down

0 comments on commit 22eaa6b

Please sign in to comment.