tmerr / i3ipc-rs Goto Github PK
View Code? Open in Web Editor NEWA Rust library for controlling i3-wm through its IPC interface
License: MIT License
A Rust library for controlling i3-wm through its IPC interface
License: MIT License
I could utilize the code: https://github.com/tmerr/i3ipc-rs/blob/master/src/lib.rs#L123 in my own project. Any chance you are willing to make that trait public?
It's only a bit of code and I have already copied the interesting bits but seen as I am already using this library sharing those methods would be nice.
@soumya92 reported he was getting errors on an event workspace:reload
It looks like it has actually been around for a while but it was accidentally left undocumented until recently: i3/i3#2656 . We should add these cases to our WorkspaceChange enum, and probably "move" as well, which is also undocumented but hopefully not for long i3/i3#2847 .
Add the WorkspaceChangeEnum variants Rename
, Reload
, Restored
, Move
.
At first glance, I would assume that id should be a usize...
/// The internal ID (actually a C pointer value) of this container. Do not make any
/// assumptions about it. You can use it to (re-)identify and address containers when
/// talking to i3.
pub id: i64,
@leshow's implementation does it that way:
https://github.com/leshow/tokio-i3ipc/blob/0a8be5fa88982851f9d924ddff7c60b4bfa51fe8/i3ipc-types/src/reply.rs#L40-L43
/// Tree/Node reply
#[derive(Deserialize, Serialize, Clone, Debug)]
pub struct Node {
pub id: usize,
i3 appears to treat it as a uintptr_t
:
https://github.com/i3/i3/blob/f4964faef08d6add93afbd24cc00fef0c3f6c72a/src/ipc.c#L355-L358
void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
y(map_open);
ystr("id");
y(integer, (uintptr_t)con);
https://github.com/i3/i3/blob/6339427f017e1265a022e6537e16a8b4a921e52f/include/yajl_utils.h#L18-L19
/* Shorter names for all those yajl_gen_* functions */
#define y(x, ...) yajl_gen_##x(gen, ##__VA_ARGS__)
...but then yajl treats it as a long long int
/ %lld
?
https://github.com/lloyd/yajl/blob/5e3a7856e643b4d6410ddc3f84bc2f38174f2872/src/yajl_gen.c#L208-L218
yajl_gen_status
yajl_gen_integer(yajl_gen g, long long int number)
{
char i[32];
ENSURE_VALID_STATE; ENSURE_NOT_KEY; INSERT_SEP; INSERT_WHITESPACE;
sprintf(i, "%lld", number);
g->print(g->ctx, i, (unsigned int)strlen(i));
APPENDED_ATOM;
FINAL_NEWLINE;
return yajl_gen_status_ok;
}
I don't know anymore. Anyone care to verify this?
i3/i3@5062dd6 documented a few keys in the TREE reply that have been there all along: nodes
, floating_nodes
, and focus
, of which focus
is the only one that we have yet to implement.
When running the following code, a runtime error is generated, included below.
use i3ipc::I3EventListener;
use i3ipc::Subscription;
use i3ipc::event::Event;
fn main() {
let mut listener = I3EventListener::connect().unwrap();
let subs = [Subscription::Workspace];
listener.subscribe(&subs).unwrap();
for event in listener.listen() {
}
}
thread '<main>' panicked at 'internal error: entered unreachable code', /home/kerp/.cargo/registry/src/github.com-88ac128001ac3a9a/i3ipc-0.4.0/src/common.rs:38
stack backtrace:
1: 0x55565ae3f1d0 - sys::backtrace::tracing::imp::write::h09d7a562cdce3ef9Xcv
2: 0x55565ae431db - panicking::default_handler::_$u7b$$u7b$closure$u7d$$u7d$::closure.44519
3: 0x55565ae42e48 - panicking::default_handler::hf7fdb8082bcb0f80lSz
4: 0x55565ae35a3c - sys_common::unwind::begin_unwind_inner::hfa667eeafdcc5750g1t
5: 0x55565adf1627 - sys_common::unwind::begin_unwind::h11005261735870655457
at src/libstd/sys/common/unwind/mod.rs:219
6: 0x55565ae2302e - common::build_tree::h96a7d8fb1d22d801Uba
at /home/kerp/projects/rust/testproject/<std macros>:3
7: 0x55565ae2586a - common::build_tree::_$u7b$$u7b$closure$u7d$$u7d$::closure.10324
at /home/kerp/.cargo/registry/src/github.com-88ac128001ac3a9a/i3ipc-0.4.0/src/common.rs:13
8: 0x55565ae25843 - ops::impls::_&'a mut F.FnOnce<A>::call_once::h8679080268370381870
at src/libcore/ops.rs:1708
9: 0x55565ae257e0 - option::Option<T>::map::h6160316823303540631
at src/libcore/option.rs:390
10: 0x55565ae2577e - iter::Map<I, F>.Iterator::next::h6949550101614501572
at src/libcore/iter.rs:3342
11: 0x55565ae253d3 - vec::Vec<T>.FromIterator<T>::from_iter::h6849771975379282085
at src/libcollections/vec.rs:1292
12: 0x55565ae25369 - iter::Iterator::collect::h5970782354055407510
at src/libcore/iter.rs:1490
13: 0x55565ae22761 - common::build_tree::h96a7d8fb1d22d801Uba
at /home/kerp/.cargo/registry/src/github.com-88ac128001ac3a9a/i3ipc-0.4.0/src/common.rs:10
14: 0x55565adfbfd5 - event::WorkspaceEventInfo.FromStr::from_str::h52100c93567f9292S1a
at /home/kerp/.cargo/registry/src/github.com-88ac128001ac3a9a/i3ipc-0.4.0/src/event.rs:48
15: 0x55565adf8ea1 - EventIterator<'a>.Iterator::next::build_event::h65c8a9849ad9db34kzb
at /home/kerp/.cargo/registry/src/github.com-88ac128001ac3a9a/i3ipc-0.4.0/src/lib.rs:174
16: 0x55565adf8b8a - EventIterator<'a>.Iterator::next::h4c53229dde1206d7bzb
at /home/kerp/.cargo/registry/src/github.com-88ac128001ac3a9a/i3ipc-0.4.0/src/lib.rs:189
17: 0x55565adeb5f3 - main::h51b6e621fe2aa0d9iaa
at src/main.rs:11
18: 0x55565ae42aa4 - sys_common::unwind::try::try_fn::h17697512651770205889
19: 0x55565ae3e5cb - __rust_try
20: 0x55565ae4253b - rt::lang_start::h5628b9e1fb87c585rKz
21: 0x55565adeec19 - main
22: 0x7f283e91b740 - __libc_start_main
23: 0x55565adeb3a8 - _start
24: 0x0 - <unknown>
`
I Tested a few other events and they seem to work fine, I haven't tested all of them, though.
I have this running:
let mut event_listener = i3ipc::I3EventListener::connect().unwrap();
for event in event_listener.listen() {
match event.as_ref() {
...
}
}
Then I have a signal handler:
let signals = Signals::new(&[SIGINT, SIGTERM]).unwrap();
let signal_handler = thread::spawn(move || {
for sig in signals.forever() {
match sig {
signal_hook::SIGINT => on_exit(&con_thread),
signal_hook::SIGTERM => on_exit(&con_thread),
_ => unreachable!(),
}
}
});
There will be race-conditions, since on_exit
will trigger i3 events. How can I stop the event listener or unsubscribe from events? Running it in a separate thread isn't an option, because I can't kill that thread, since event listening is a blocking operation.
Encode/decode using native endian instead of little endian. While we're at it, get rid of the byteorder
dep now that https://doc.rust-lang.org/stable/std/primitive.i64.html#method.to_ne_bytes is available.
Sorry if my pull request wasn't as clear, I'm new to debugging Rust.
Marks showing up in the ipc json payload where introduced with i3 version 4.13 and it breaks i3ipc-rs.
Best regards and happy holidays,
Benny
There's a few features folks are wanting that are "unstable" in i3 - particularly Node attributes and the like. Since i3 changes quite slowly, these attrs can be around for years. It seems like they could be added and guarded by a feature.
Then it could be simply enabled by something like:
[Dependencies]
i3rpc = { features = ["i3-next", "unstable"] }
...
It also gives a nice path forward for when i3 does update its stable features to include them.
I'd like to be able to get the Node
from the Node
tree that represents the currently focused workspace.
I think in the current state a possible solution is to
I3Connection::get_workspaces()
,focused
is true
,I3Connection::get_tree()
,This seems very cumbersome. Also, I'm not 100% sure workspace names in i3 are guaranteed to always be unique. Are there any better solutions?
Also, would it be in the scope of this library to add a helper function for this?
Maybe we can fix this somehow?
running 19 tests
test test::connect ... FAILED
test test::from_str_barconfig ... ok
test test::from_str_binding_event ... ok
test test::event_subscribe ... FAILED
test test::from_str_window ... ok
test test::from_str_mode ... ok
test test::from_str_workspace ... ok
test test::get_bar_ids ... FAILED
test test::get_marks ... FAILED
test test::get_outputs ... FAILED
test test::get_bar_ids_and_one_config ... FAILED
test test::get_version ... FAILED
test test::get_workspaces ... FAILED
test test::from_str_output ... ok
test test::run_command_fail ... FAILED
test test::run_command_nothing ... FAILED
test test::run_command_multiple_success ... FAILED
test test::get_tree ... FAILED
test test::run_command_single_sucess ... FAILED
failures:
---- test::connect stdout ----
thread 'test::connect' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
---- test::event_subscribe stdout ----
thread 'test::event_subscribe' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::get_bar_ids stdout ----
thread 'test::get_bar_ids' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::get_marks stdout ----
thread 'test::get_marks' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::get_outputs stdout ----
thread 'test::get_outputs' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::get_bar_ids_and_one_config stdout ----
thread 'test::get_bar_ids_and_one_config' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::get_version stdout ----
thread 'test::get_version' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::get_workspaces stdout ----
thread 'test::get_workspaces' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::run_command_fail stdout ----
thread 'test::run_command_fail' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::run_command_nothing stdout ----
thread 'test::run_command_nothing' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::run_command_multiple_success stdout ----
thread 'test::run_command_multiple_success' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::get_tree stdout ----
thread 'test::get_tree' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
---- test::run_command_single_sucess stdout ----
thread 'test::run_command_single_sucess' panicked at 'called `Result::unwrap()` on an `Err` value: GetSocketPathError(Os { code: 2, kind: NotFound, message: "No such file or directory" })', src/libcore/result.rs:1165:5
failures:
test::connect
test::event_subscribe
test::get_bar_ids
test::get_bar_ids_and_one_config
test::get_marks
test::get_outputs
test::get_tree
test::get_version
test::get_workspaces
test::run_command_fail
test::run_command_multiple_success
test::run_command_nothing
test::run_command_single_sucess
test result: FAILED. 6 passed; 13 failed; 0 ignored; 0 measured; 0 filtered out
See i3/i3@607e97e
ipc: rename COMMAND to RUN_COMMAND for consistency
Authors of downstream IPC libraries are encouraged to keep the old name around
so as to not break existing code, but mark it as deprecated.
There's not much of a risk for i3ipc-rs since the README shows an example of using a specific i3ipc-rs version (no star) and we're still not 1.0. That said it would be interesting to do a quick github search to see if this is the case
A Node.find_focused function would be nice. I wrote out an example in #29 but we have to remember to check floating_nodes too.
An iterator across the entire tree might be helpful as well.
This was ninja'd into 4.14 and documented after i3/i3#2984
Hey @tmerr ,
I was wondering how stable/fully-featured this crate is. I was going to re-implement
https://github.com/open-dynaMIX/raiseorlaunch in Rust and stumbled upon your lib. It looks like a very useful thing for the task.
I'm just seeing if there's any interest in creating a struct to wrap the rects received from i3. Ideally these:
https://github.com/tmerr/i3ipc-rs/blob/master/src/reply.rs#L211
Could be changed to something along the lines of:
struct Rect {
top: i32,
left: i32,
width: i32,
height: i32,
}
Which would make things like:
let height = node.rect.3;
Become much more readable:
let height = node.rect.height;
I'm more than happy to create a PR with these changes if that's something that we can do.
Hey there!
First of all, thank you for all the work that went into writing this library! I'm really glad it exists :)
I've been playing around with it a little bit but there's something I'm not super sure about โ maybe because the i3 IPC interface is generally new to me.
I want to find out what client is actually focused. Now, there is the focused
field but it includes several id's and when I try to query those from the nodes
field I just get back generic eDP-1
or _i3
or whatever.
I guess I'm misunderstanding the API here? Any help would be appreciated! :)
Look into letting the user specify the minimum i3 version using conditional compilation. Then everyone can use the same i3ipc-rs from crates.io regardless of how up-to-date the i3-wm package is in their linux distribution's package manager.
Please update the crates.io package to include the fix for this issue: #1
Thanks in advance. (Got hit by the same bug just now.)
Unless I'm missing something (which is quite possible!) it looks like the marks
field of the IPC response to the get_tree
method is not present in i3ipc-rs. Is there a reason it's not present? There's a get_marks
method that returns the currently used marks, but there's no way to correlate them with the nodes that have the mark, AFAICT.
I'm open to making a PR to add this; I wanted to confirm I'm right and check in first.
Corresponding to i3/i3#2967
It seems they both access the same socket file, why are they separate types? Currently, if I want to get the current workspace state at the beginning of my program and then all subscribe to workspace updates, this requires opening the socket file twice.
At runtime i3ipc-rs shouldn't depend on i3 version == X. It should depend on i3 version >= X. In theory this should be possible since i3 aims to continually add things to its ipc interface while staying backwards compatible. In order to support this we need to change the way we work with the parsed JSON. It's OK to ask for the value of a field, but it's not OK to ask for the value to lie in a fixed set of possibilities, which we do when constructing many enums in events.rs. Rework this library so it doesn't break after routine i3 upgrades.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.