-
-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add screenshot for single screen #32
Conversation
Sorry for the diffs, my formatter did that automatically. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assuming it builds changes look fine, although perhaps we should separate the format and changes into two commits.
src/main.rs
Outdated
@@ -1,4 +1,4 @@ | |||
// This Source Code Form is subject to the terms of the Mozilla Public | |||
// This Source Code Form is subject to the terms of the Mozilla& Public |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this change is necessary.
It doesn't seem to update the docs, other people would have to look at the code to know. |
|
Please split the reformatting out into a separate, dedicated commit. |
src/main.rs
Outdated
@@ -32,7 +32,7 @@ fn run() -> i32 { | |||
|
|||
let mut opts = Options::new(); | |||
opts.optopt("i", "id", "Window to capture", "ID"); | |||
opts.optopt("g", "geometry", "Area to capture", "WxH+X+Y"); | |||
opts.optflagopt("g", "geometry", "Area to capture", "WxH+X+Y"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I see what you did here. This means that -g
without specifying a region would capture the screen where the cursor is. This isn't good, please add a separate flag instead, and document it properly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @9ary. Please do not introduce options that optionally take values to this CLI. The functionality looks fine, if implemented differently.
Hi, I appreciate the reviews, my suggestion would be to revert the commit once and
Unfortunately I do not have much time, and therefore I cannot implement it right away. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking pretty good overall.
Another concern I have is you don't seem to handle passing both -g
and -s
gracefully. Currently, -s
will override -g
unconditionally. I would prefer to either switch that around, or take the intersection.
src/main.rs
Outdated
let sel = match matches.opt_str("g") { | ||
|
||
let mut sel: util::Rect; | ||
sel = match matches.opt_str("g") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think splitting this line in two or even specifying the type is strictly necessary here. Is it?
src/main.rs
Outdated
} | ||
}; | ||
|
||
let screen_rects = match display.get_screen_rects(display.get_default_root()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This introduces an additional call to get_screen_rects
which is a little inefficient. It should be cached, or better yet lazily initialized so it only gets called when needed. std::Lazy
is currently experimental, so we'll need to find a crate for this.
Since get_screen_rects
returns an iterator, you'll need to collect it into a vector, and then make the masking step reuse that. Maybe removing the iterator altogether would be a good idea. I believe I originally wrote it this way to avoid superfluous allocations, but that's already out of the window, so there's no point in keeping it.
We also already cache the result of get_default_root
during initialization. You should definitely use that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for this part, I think it should be fine if we cache it for now using a vector, I think we can still change that later on.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, do that, and adapt the masking step to reuse the same vector. Lazy evaluation might not even be necessary considering that masking always happens so forget about that.
src/main.rs
Outdated
sel = match screen_rects.enumerate().find(|(_, r)| r.contains(cursor)) { | ||
Some((_, r)) => r, | ||
None => { | ||
eprintln!("Failed to find screen containing cursor"); | ||
return 1; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright so under normal circumstances this shouldn't fail. That said, maybe we should only bother to mutate sel
if something is found? Honestly not sure what the best strategy is here. This seems sound enough all things considered.
src/xwrap.rs
Outdated
pub fn get_cursor_position(&self) -> Option<util::Pos> { | ||
let mut x = 0; | ||
let mut y = 0; | ||
|
||
let (mut win_x, mut win_y, mut mask) = (0, 0, 0); | ||
let mut root_win = self.get_default_root(); | ||
|
||
unsafe { | ||
xlib::XQueryPointer( | ||
self.handle, | ||
root_win, | ||
&mut root_win, | ||
&mut root_win, | ||
&mut x, | ||
&mut y, | ||
&mut win_x, | ||
&mut win_y, | ||
&mut mask, | ||
); | ||
} | ||
|
||
|
||
Some(util::Pos { x, y }) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function returns an Option
, but it doesn't appear to handle the failure case. If XQueryPointer
is fallible, then it should return None
on failure. Otherwise, get rid of the Option
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I see another call to get_default_root
. This method should probably be implemented for xlib::Window
instead, or take the root window as another parameter.
On this note, I would highly recommend at least reading the Command Line Arguments section of Fuchsia's Command-line Tools Rubric. Here's a relevant section from it:
|
Erroring out is also an acceptable solution yes. Either way. the conflict behavior should be documented. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think -s should also conflict with -i. -g + -i makes sense, and we just take the intersection there, but that wouldn't make sense with -s.
src/xwrap.rs
Outdated
pub fn get_cursor_position(&self, mut root_win: xlib::Window) -> util::Point { | ||
let mut x = 0; | ||
let mut y = 0; | ||
|
||
let (mut win_x, mut win_y, mut mask) = (0, 0, 0); | ||
|
||
unsafe { | ||
xlib::XQueryPointer( | ||
self.handle, | ||
root_win, | ||
&mut root_win, | ||
&mut root_win, | ||
&mut x, | ||
&mut y, | ||
&mut win_x, | ||
&mut win_y, | ||
&mut mask, | ||
); | ||
} | ||
|
||
util::Point { x, y } | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So according to the documentation, XQueryPointer is fallible. https://tronche.com/gui/x/xlib/window-information/XQueryPointer.html
The first failure mode is a BadWindow error if you pass in an invalid window. For our use that would be a programming error so you can just make that a panic. (actually xlib will very likely do that itself so maybe it's not necessary, try passing it some random integer and see what happens)
It looks like the other failure case is related to having multiple X screens (not the same as multiple monitors). That is a very uncommon configuration that we shouldn't bother supporting. Regardless, you should re-introduce the Option and the error message for when XQueryPointer returns false.
Lastly, the root_win argument should just be called window, and it shouldn't be mutable. This is a big C-ism that we don't have to deal with in Rust. If you want to use the values XQueryPointer puts in there, you should put them in the return struct. It's unnecessary in this case though, so you should just throw root_return and child_return away.
I do wonder, what happens if you pass 0 as the window argument? If it works, then we should still get the cursor position relative to the root window and you can get rid of the window argument. Otherwise, win_x and win_y are the values you should be returning, as they are relative to the window you're passing in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, I'll make sure that I get that done soon, unfortunately this is the first project I worked on with rust so I'll have to take a closer look to the error handing part.
src/main.rs
Outdated
@@ -133,20 +133,20 @@ fn run() -> i32 { | |||
}, | |||
}; | |||
|
|||
let screen_rects: Vec<util::Rect> = match display.get_screen_rects(root) { | |||
Some(r) => r.map(|r| r.clone()).collect(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some(r) => r.map(|r| r.clone()).collect(), | |
Some(r) => r.cloned().collect(), |
Some(r) => r.map(|r| r.clone()).collect(), | ||
None => { | ||
eprintln!("Failed to get screen rects"); | ||
return 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means that shotgun will always bail out if screens can't be enumerated, even when it's not strictly required. XRandR should be available on pretty much anything these days, do we care enough to support the failure case?
Alright I feel like I fixed all the stuff mentioned, did I miss anything? |
I'm still not sure the usage of XQueryPointer is correct, but I currently don't have the energy to continue the back and forth on this pull request (for reasons unrelated). If it works in its current state then I think it's okay to merge this as it is and we can fix that wrapper later. I'll leave it up to someone who can actually test this to merge the PR and prepare a new release. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's still some formatting changes but I don't think that's worth fighting over. Implementation seems fine if it gets the job done, Most if not all concerns have also been fixed so with @9ary's approval I'm going to go ahead and merge it. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I meant to approve, not request changes.)
Resolves #30