Skip to content

Commit b39a9c3

Browse files
committed
Merge branch 'grouped_nodes'
- Pipewire Nodes with the same name are grouped together and rendered as a single node ( #1 ), in the debug view(on pressing Ctrl), the description and node id of the underlying pipewire node is shown - Support cycles ( #5 ), graphs in cycles in them are a supported now - Add support for customizing node background colors (with transparency) - Add an Arrange button ( related to #7 ), which relayouts the nodes automatically when clicked, the layout algorithm (topological sort) is temporary, will be replaced in the future - Updated README.md to include better build instructions
1 parent d792a07 commit b39a9c3

File tree

15 files changed

+587
-309
lines changed

15 files changed

+587
-309
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/target
2+
.vscode/*

Cargo.lock

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ simple_logger = "1.13.0"
2121
# egui stuff
2222
eframe = { version = "0.15.0", features = ["persistence"] }
2323
egui = "0.15.0"
24-
egui_nodes = {git = "https://github.com/Ax9D/egui_nodes", rev="74eccc4"}
24+
egui_nodes = {git = "https://github.com/Ax9D/egui_nodes", rev="3544d61"}
2525
serde = { version = "1", features = ["derive"] }
2626

2727
[profile.release]

README.md

+11-8
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,22 @@
1010
This is still a WIP, node layouting is kinda jank at the moment.
1111

1212
# Installation
13-
1413
A compiled binary is available on the [releases page](https://github.com/Ax9D/pw-viz/releases).
1514

1615
## Building from source
17-
Clone the repo:
16+
To build pw-viz, you will need to have Rust installed. The recommended way to install Rust is from the [official download page](https://www.rust-lang.org/tools/install), using rustup.
17+
18+
### Stable Release
19+
Download and extract the source code to the latest release over on the [releases page](https://github.com/Ax9D/pw-viz/releases).
20+
21+
### Main branch
22+
Alternatively, you can clone the main branch, although its NOT guaranteed to be stable or bug free.
1823
```
1924
git clone https://github.com/Ax9D/pw-viz
20-
cd pw-viz
2125
```
22-
To build pw-viz, you will need to have Rust installed. The recommended way to install Rust is from the [official download page](https://www.rust-lang.org/tools/install), using rustup.
23-
24-
Once Rust is installed, you can build pw-viz:
2526

27+
### Build
28+
Next, `cd` into your source folder and then start the build using:
2629
```
2730
cargo build --release
2831
```
@@ -47,8 +50,8 @@ Zooming is not supported currently
4750
* A modified fork of [egui-nodes](https://github.com/haighcam/egui_nodes): A egui port of [imnodes](https://github.com/Nelarius/imnodes)
4851

4952
# Thanks / Alternatives
50-
Pipewire connection code is inspired by helvum's implementation,
51-
[helvum](https://gitlab.freedesktop.org/ryuukyu/helvum): A GTK patchbay for pipewire.
53+
Pipewire connection code is inspired by helvum's implementation
54+
* [helvum](https://gitlab.freedesktop.org/ryuukyu/helvum): A GTK patchbay for pipewire.
5255

5356
# License
5457
pw-viz is licensed under the terms of the GNU General Public License v3.0. See LICENSE for more information.

assets/demo.png

45.8 KB
Loading

src/id.rs

Whitespace-only changes.

src/main.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
1313
let (sender, receiver) = std::sync::mpsc::channel();
1414
let (pwsender, pwreciever) = pipewire::channel::channel();
1515

16-
// Set up pipewire thread
17-
let pw_thread_handle = thread::spawn(move || {
18-
let sender = Rc::new(sender);
19-
pipewire_impl::thread_main(sender, pwreciever).expect("Failed to init pipewire client");
20-
});
16+
//Set's up pipewire thread
17+
let pw_thread_handle = thread::Builder::new()
18+
.name("Pipewire".to_string())
19+
.spawn(move || {
20+
let sender = Rc::new(sender);
21+
22+
pipewire_impl::thread_main(sender, pwreciever).expect("Failed to init pipewire client");
23+
})
24+
.expect("Failed to create pipewire thread");
2125

2226
ui::run_graph_ui(receiver, pwsender);
2327

src/pipewire_impl/mod.rs

+80-18
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,20 @@ pub enum PipewireMessage {
1616
NodeAdded {
1717
id: u32,
1818
name: String,
19+
description: Option<String>,
1920
media_type: Option<MediaType>,
2021
},
2122
PortAdded {
23+
node_name: String,
2224
node_id: u32,
2325
id: u32,
2426
name: String,
2527
port_type: PortType,
2628
},
2729
LinkAdded {
2830
id: u32,
29-
from_node: u32,
30-
to_node: u32,
31+
from_node_name: String,
32+
to_node_name: String,
3133

3234
from_port: u32,
3335
to_port: u32,
@@ -37,9 +39,11 @@ pub enum PipewireMessage {
3739
active: bool,
3840
},
3941
NodeRemoved {
42+
name: String,
4043
id: u32,
4144
},
4245
PortRemoved {
46+
node_name: String,
4347
node_id: u32,
4448
id: u32,
4549
},
@@ -113,11 +117,17 @@ pub fn thread_main(
113117
.global_remove(move |id| match state_rm.borrow_mut().remove(id) {
114118
Some(object) => {
115119
let message = match object {
116-
state::GlobalObject::Node => PipewireMessage::NodeRemoved { id },
120+
state::GlobalObject::Node { name } => PipewireMessage::NodeRemoved { name, id },
117121
state::GlobalObject::Link => PipewireMessage::LinkRemoved { id },
118-
state::GlobalObject::Port { node_id, id } => {
119-
PipewireMessage::PortRemoved { node_id, id }
120-
}
122+
state::GlobalObject::Port {
123+
node_name,
124+
node_id,
125+
id,
126+
} => PipewireMessage::PortRemoved {
127+
node_name,
128+
node_id,
129+
id,
130+
},
121131
};
122132
sender_rm
123133
.send(message)
@@ -141,12 +151,9 @@ pub fn thread_main(
141151
UiMessage::RemoveLink(link_id) => {
142152
remove_link(link_id, &state, &registry);
143153
}
144-
UiMessage::AddLink {
145-
from_node,
146-
to_node,
147-
from_port,
148-
to_port,
149-
} => add_link(from_port, to_port, from_node, to_node, &core),
154+
UiMessage::AddLink { from_port, to_port } => {
155+
add_link(&state, from_port, to_port, &core)
156+
}
150157
UiMessage::Exit => mainloop.quit(),
151158
}
152159
});
@@ -166,9 +173,11 @@ fn handle_node(
166173
.as_ref()
167174
.expect("Node object doesn't have properties");
168175

176+
let description = props.get("node.description");
177+
169178
let name = props
170179
.get("node.nick")
171-
.or_else(|| props.get("node.description"))
180+
.or(description)
172181
.or_else(|| props.get("node.name"))
173182
.unwrap_or_default()
174183
.to_string();
@@ -185,12 +194,16 @@ fn handle_node(
185194
}
186195
});
187196

188-
state.borrow_mut().add(node.id, state::GlobalObject::Node);
197+
state
198+
.borrow_mut()
199+
.add(node.id, state::GlobalObject::Node { name: name.clone() });
189200

201+
let description = description.map(|desc| desc.to_string());
190202
sender
191203
.send(PipewireMessage::NodeAdded {
192204
id: node.id,
193205
name,
206+
description,
194207
media_type,
195208
})
196209
.expect("Failed to send pipewire message");
@@ -219,6 +232,16 @@ fn handle_link(
219232
let to_port = info.input_port_id();
220233

221234
let mut state = state.borrow_mut();
235+
236+
let from_node_name = match state.get(from_node).expect("Id wasn't registered") {
237+
state::GlobalObject::Node { name } => name.clone(),
238+
_ => unreachable!(),
239+
};
240+
let to_node_name = match state.get(to_node).expect("Id wasn't registered") {
241+
state::GlobalObject::Node { name } => name.clone(),
242+
_ => unreachable!(),
243+
};
244+
222245
if let Some(&state::GlobalObject::Link) = state.get(id) {
223246
if info.change_mask().contains(LinkChangeMask::STATE) {
224247
sender
@@ -230,8 +253,8 @@ fn handle_link(
230253
log::debug!("New pipewire link was added : {}", id);
231254
sender
232255
.send(PipewireMessage::LinkAdded {
233-
from_node,
234-
to_node,
256+
from_node_name,
257+
to_node_name,
235258
from_port,
236259
to_port,
237260
id,
@@ -245,8 +268,32 @@ fn handle_link(
245268
.borrow_mut()
246269
.insert(link.id, ProxyLink { proxy, listener });
247270
}
271+
fn add_link(state: &Rc<RefCell<State>>, from_port: u32, to_port: u32, core: &Rc<Core>) {
272+
let state = state.borrow();
273+
let from_port_ob = state
274+
.get(from_port)
275+
.expect(&format!("Port with id {} was never registered", from_port));
276+
let from_node = *match from_port_ob {
277+
state::GlobalObject::Port {
278+
node_name: _,
279+
node_id,
280+
id: _,
281+
} => node_id,
282+
_ => unreachable!(),
283+
};
284+
285+
let to_port_ob = state
286+
.get(to_port)
287+
.expect(&format!("Port with id {} was never registered", to_port));
288+
let to_node = *match to_port_ob {
289+
state::GlobalObject::Port {
290+
node_name: _,
291+
node_id,
292+
id: _,
293+
} => node_id,
294+
_ => unreachable!(),
295+
};
248296

249-
fn add_link(from_port: u32, to_port: u32, from_node: u32, to_node: u32, core: &Rc<Core>) {
250297
core.create_object::<pipewire::link::Link, _>(
251298
"link-factory",
252299
&pipewire::properties! {
@@ -288,22 +335,37 @@ fn handle_port(
288335
.parse::<u32>()
289336
.expect("Couldn't parse node.id as u32");
290337

338+
let mut state = state.borrow_mut();
339+
340+
let node_name = match state
341+
.get(node_id)
342+
.expect(&format!("Node with id {} was never registered", node_id))
343+
{
344+
state::GlobalObject::Node { name } => name,
345+
_ => {
346+
unreachable!()
347+
}
348+
}
349+
.clone();
350+
291351
let port_type = match props.get("port.direction") {
292352
Some("in") => PortType::Input,
293353
Some("out") => PortType::Output,
294354
_ => PortType::Unknown,
295355
};
296356

297-
state.borrow_mut().add(
357+
state.add(
298358
port.id,
299359
state::GlobalObject::Port {
360+
node_name: node_name.clone(),
300361
node_id,
301362
id: port.id,
302363
},
303364
);
304365

305366
sender
306367
.send(PipewireMessage::PortAdded {
368+
node_name,
307369
node_id,
308370
id: port.id,
309371
name,

src/pipewire_impl/state.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
use std::collections::HashMap;
22

33
pub enum GlobalObject {
4-
Node,
4+
Node {
5+
name: String,
6+
},
57
Link,
6-
Port { node_id: u32, id: u32 },
8+
Port {
9+
node_name: String,
10+
node_id: u32,
11+
id: u32,
12+
},
713
}
814

915
/// For internal state tracking, this has to be done because pipewire only provides ids of the objects it removes,

0 commit comments

Comments
 (0)