From 2897543acf655418e11b7f864f285d8bb6b163c5 Mon Sep 17 00:00:00 2001 From: "Tom A. Wagner" Date: Mon, 4 Jan 2021 08:19:05 +0100 Subject: [PATCH] Switch to gtk4 --- Cargo.lock | 463 ++++++++++++++++++++----------------- Cargo.toml | 9 +- src/main.rs | 23 +- src/pipewire_connection.rs | 18 +- src/view/graph_view.rs | 321 +++++++++++++++++-------- src/view/node.rs | 77 +++--- 6 files changed, 541 insertions(+), 370 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f9f926e..84fadc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,35 +20,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.34" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf8dcb5b4bbaa28653b647d8c77bd4ed40183b48882e130c1f1ffb73de069fd7" - -[[package]] -name = "atk" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812b4911e210bd51b24596244523c856ca749e6223c50a7fbbba3f89ee37c426" -dependencies = [ - "atk-sys", - "bitflags", - "glib", - "glib-sys", - "gobject-sys", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f530e4af131d94cc4fa15c5c9d0348f0ef28bac64ba660b6b2a1cf2605dedfce" -dependencies = [ - "glib-sys", - "gobject-sys", - "libc", - "system-deps 1.3.2", -] +checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86" [[package]] name = "atty" @@ -61,6 +35,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + [[package]] name = "bindgen" version = "0.56.0" @@ -92,35 +72,32 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "cairo-rs" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5c0f2e047e8ca53d0ff249c54ae047931d7a6ebe05d00af73e0ffeb6e34bdb8" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "bitflags", "cairo-sys-rs", + "freetype", "glib", - "glib-sys", - "gobject-sys", "libc", "thiserror", ] [[package]] name = "cairo-sys-rs" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ed2639b9ad5f1d6efa76de95558e11339e7318426d84ac4890b86c03e828ca7" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "glib-sys", "libc", - "system-deps 1.3.2", + "system-deps", ] [[package]] name = "cc" -version = "1.0.62" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1770ced377336a88a67c473594ccc14eca6f4559217c34f64aac8f83d641b40" +checksum = "4c0496836a84f8d0495758516b8621a622beb77c0fed418570e50764093ced48" [[package]] name = "cexpr" @@ -169,6 +146,15 @@ dependencies = [ "vec_map", ] +[[package]] +name = "cmake" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb6210b637171dfba4cda12e579ac6dc73f5165ad56133e5d72ef3131f320855" +dependencies = [ + "cc", +] + [[package]] name = "either" version = "1.6.1" @@ -188,6 +174,37 @@ dependencies = [ "termcolor", ] +[[package]] +name = "field-offset" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c40e7a744c1d22cd64783732a287dd5d08a9f0e1d89b685bf084aab753cb20d4" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "freetype" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee38378a9e3db1cc693b4f88d166ae375338a0ff75cb8263e1c601d51f35dc6" +dependencies = [ + "freetype-sys", + "libc", +] + +[[package]] +name = "freetype-sys" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a" +dependencies = [ + "cmake", + "libc", + "pkg-config", +] + [[package]] name = "futures" version = "0.3.8" @@ -283,59 +300,48 @@ dependencies = [ "slab", ] -[[package]] -name = "gdk" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db00839b2a68a7a10af3fa28dfb3febaba3a20c3a9ac2425a33b7df1f84a6b7d" -dependencies = [ - "bitflags", - "cairo-rs", - "cairo-sys-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "gio-sys", - "glib", - "glib-sys", - "gobject-sys", - "libc", - "pango", -] - [[package]] name = "gdk-pixbuf" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6dae3cb99dd49b758b88f0132f8d401108e63ae8edd45f432d42cdff99998a" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "gdk-pixbuf-sys", "gio", - "gio-sys", "glib", - "glib-sys", - "gobject-sys", "libc", ] [[package]] name = "gdk-pixbuf-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bfe468a7f43e97b8d193a762b6c5cf67a7d36cacbc0b9291dbcae24bfea1e8f" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "gio-sys", "glib-sys", "gobject-sys", "libc", - "system-deps 1.3.2", + "system-deps", ] [[package]] -name = "gdk-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a9653cfc500fd268015b1ac055ddbc3df7a5c9ea3f4ccef147b3957bd140d69" +name = "gdk4" +version = "0.1.0" +source = "git+https://github.com/gtk-rs/gtk4-rs/#c35ce2730663ee18dc21148f9ae87a19e35c10fd" +dependencies = [ + "bitflags", + "cairo-rs", + "gdk-pixbuf", + "gdk4-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk4-sys" +version = "0.1.0" +source = "git+https://github.com/gtk-rs/gtk4-rs/#c35ce2730663ee18dc21148f9ae87a19e35c10fd" dependencies = [ "cairo-sys-rs", "gdk-pixbuf-sys", @@ -344,15 +350,13 @@ dependencies = [ "gobject-sys", "libc", "pango-sys", - "pkg-config", - "system-deps 1.3.2", + "system-deps", ] [[package]] name = "gio" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb60242bfff700772dae5d9e3a1f7aa2e4ebccf18b89662a16acb2822568561" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "bitflags", "futures", @@ -362,8 +366,6 @@ dependencies = [ "futures-util", "gio-sys", "glib", - "glib-sys", - "gobject-sys", "libc", "once_cell", "thiserror", @@ -371,22 +373,20 @@ dependencies = [ [[package]] name = "gio-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e24fb752f8f5d2cf6bbc2c606fd2bc989c81c5e2fe321ab974d54f8b6344eac" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 1.3.2", + "system-deps", "winapi", ] [[package]] name = "glib" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c685013b7515e668f1b57a165b009d4d28cb139a8a989bbd699c10dad29d0c5" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "bitflags", "futures-channel", @@ -399,13 +399,13 @@ dependencies = [ "gobject-sys", "libc", "once_cell", + "smallvec", ] [[package]] name = "glib-macros" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41486a26d1366a8032b160b59065a59fb528530a46a49f627e7048fb8c064039" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "anyhow", "heck", @@ -419,12 +419,11 @@ dependencies = [ [[package]] name = "glib-sys" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7e9b997a66e9a23d073f2b1abb4dbfc3925e0b8952f67efd8d9b6e168e4cdc1" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "libc", - "system-deps 1.3.2", + "system-deps", ] [[package]] @@ -435,78 +434,132 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" [[package]] name = "gobject-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "952133b60c318a62bf82ee75b93acc7e84028a093e06b9e27981c2b6fe68218c" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "glib-sys", "libc", - "system-deps 1.3.2", + "system-deps", +] + +[[package]] +name = "graphene-rs" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" +dependencies = [ + "glib", + "graphene-sys", + "libc", +] + +[[package]] +name = "graphene-sys" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" +dependencies = [ + "glib-sys", + "libc", + "pkg-config", + "system-deps", ] [[package]] name = "graphui-rs" version = "0.0.1" dependencies = [ - "cairo-rs", - "gdk", - "gio", - "glib", - "gtk", + "gtk4", "pipewire", ] [[package]] -name = "gtk" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f022f2054072b3af07666341984562c8e626a79daa8be27b955d12d06a5ad6a" +name = "gsk4" +version = "0.1.0" +source = "git+https://github.com/gtk-rs/gtk4-rs/#c35ce2730663ee18dc21148f9ae87a19e35c10fd" dependencies = [ - "atk", "bitflags", "cairo-rs", - "cairo-sys-rs", - "cc", - "gdk", - "gdk-pixbuf", - "gdk-pixbuf-sys", - "gdk-sys", - "gio", - "gio-sys", + "gdk4", "glib", - "glib-sys", - "gobject-sys", - "gtk-sys", + "graphene-rs", + "gsk4-sys", "libc", - "once_cell", "pango", - "pango-sys", - "pkg-config", ] [[package]] -name = "gtk-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89acda6f084863307d948ba64a4b1ef674e8527dddab147ee4cdcc194c880457" +name = "gsk4-sys" +version = "0.1.0" +source = "git+https://github.com/gtk-rs/gtk4-rs/#c35ce2730663ee18dc21148f9ae87a19e35c10fd" +dependencies = [ + "cairo-sys-rs", + "gdk4-sys", + "glib-sys", + "gobject-sys", + "graphene-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk4" +version = "0.1.0" +source = "git+https://github.com/gtk-rs/gtk4-rs/#c35ce2730663ee18dc21148f9ae87a19e35c10fd" +dependencies = [ + "bitflags", + "cairo-rs", + "field-offset", + "gdk-pixbuf", + "gdk4", + "gio", + "glib", + "graphene-rs", + "gsk4", + "gtk4-macros", + "gtk4-sys", + "libc", + "once_cell", + "pango", +] + +[[package]] +name = "gtk4-macros" +version = "0.1.0" +source = "git+https://github.com/gtk-rs/gtk4-rs/#c35ce2730663ee18dc21148f9ae87a19e35c10fd" +dependencies = [ + "anyhow", + "heck", + "itertools", + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "gtk4-sys" +version = "0.1.0" +source = "git+https://github.com/gtk-rs/gtk4-rs/#c35ce2730663ee18dc21148f9ae87a19e35c10fd" dependencies = [ - "atk-sys", "cairo-sys-rs", "gdk-pixbuf-sys", - "gdk-sys", + "gdk4-sys", "gio-sys", "glib-sys", "gobject-sys", + "graphene-sys", + "gsk4-sys", "libc", "pango-sys", - "system-deps 1.3.2", + "system-deps", ] [[package]] name = "heck" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" dependencies = [ "unicode-segmentation", ] @@ -549,9 +602,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.80" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58d1b70b004888f764dfbf6a26a3b0342a1632d33968e4a179d8011c760614" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" [[package]] name = "libloading" @@ -578,7 +631,7 @@ version = "0.1.0" source = "git+https://gitlab.freedesktop.org/gdesmott/pipewire-rs?branch=proxies#6560d4f769cc0d9937d6091f2f3eb298ef31cbfc" dependencies = [ "bindgen", - "system-deps 2.0.2", + "system-deps", ] [[package]] @@ -596,6 +649,15 @@ version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +[[package]] +name = "memoffset" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" +dependencies = [ + "autocfg", +] + [[package]] name = "nix" version = "0.14.1" @@ -621,20 +683,17 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95c43eba5c640051fbde86a3377842386a94281df3ff0a5f0365c2075ed5c66f" +checksum = "13bd41f508810a131401606d54ac32a467c97172d74ba7662562ebba5ad07fa0" [[package]] name = "pango" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9937068580bebd8ced19975938573803273ccbcbd598c58d4906efd4ac87c438" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "bitflags", "glib", - "glib-sys", - "gobject-sys", "libc", "once_cell", "pango-sys", @@ -642,14 +701,13 @@ dependencies = [ [[package]] name = "pango-sys" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d2650c8b62d116c020abd0cea26a4ed96526afda89b1c4ea567131fdefc890" +version = "0.13.0" +source = "git+https://github.com/gtk-rs/gtk-rs#20bafd57e569abf3e3e1c3eefc658c2ac83735bd" dependencies = [ "glib-sys", "gobject-sys", "libc", - "system-deps 1.3.2", + "system-deps", ] [[package]] @@ -660,18 +718,18 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "pin-project" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee41d838744f60d959d7074e3afb6b35c7456d0f61cad38a24e35e6553f73841" +checksum = "9ccc2237c2c489783abd8c4c80e5450fc0e98644555b1364da68cc29aa151ca7" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81a4ffa594b66bff340084d4081df649a7dc049ac8d7fc458d8e628bfbbb2f86" +checksum = "f8e8d2bf0b23038a4424865103a4df472855692821aab4e4f5c3312d461d9e5f" dependencies = [ "proc-macro2", "quote", @@ -706,7 +764,7 @@ source = "git+https://gitlab.freedesktop.org/gdesmott/pipewire-rs?branch=proxies dependencies = [ "bindgen", "libspa-sys", - "system-deps 2.0.2", + "system-deps", ] [[package]] @@ -771,9 +829,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] @@ -803,10 +861,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "serde" -version = "1.0.117" +name = "rustc_version" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88fa983de7720629c9387e9f517353ed404164b1e482c970a90c1a4aaf7dc1a" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" [[package]] name = "shlex" @@ -830,36 +912,24 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "smallvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0" + [[package]] name = "strsim" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" -[[package]] -name = "strum" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57bd81eb48f4c437cadc685403cad539345bf703d78e63707418431cecd4522b" - [[package]] name = "strum" version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7318c509b5ba57f18533982607f24070a55d353e90d4cae30c467cdb2ad5ac5c" -[[package]] -name = "strum_macros" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87c85aa3f8ea653bfd3ddf25f7ee357ee4d204731f6aa9ad04002306f6e2774c" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "strum_macros" version = "0.20.1" @@ -874,30 +944,15 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.48" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc371affeffc477f42a221a1e4297aedcea33d47d19b61455588bd9d8f6b19ac" +checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6" dependencies = [ "proc-macro2", "quote", "unicode-xid", ] -[[package]] -name = "system-deps" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3ecc17269a19353b3558b313bba738b25d82993e30d62a18406a24aba4649b" -dependencies = [ - "heck", - "pkg-config", - "strum 0.18.0", - "strum_macros 0.18.0", - "thiserror", - "toml", - "version-compare 0.0.10", -] - [[package]] name = "system-deps" version = "2.0.2" @@ -906,11 +961,11 @@ checksum = "8f0e2c9cfeb7afa05a18802454f8b467ba12e459301af4b17ea69bce3f63e990" dependencies = [ "heck", "pkg-config", - "strum 0.20.0", - "strum_macros 0.20.1", + "strum", + "strum_macros", "thiserror", "toml", - "version-compare 0.0.11", + "version-compare", ] [[package]] @@ -933,18 +988,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e9ae34b84616eedaaf1e9dd6026dbe00dcafa92aa0c8077cb69df1fcfe5e53e" +checksum = "76cc616c6abf8c8928e2fdcc0dbfab37175edd8fb49a4641066ad1364fdab146" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba20f23e85b10754cd195504aebf6a27e2e6cbe28c17778a0c930724628dd56" +checksum = "9be73a2caec27583d0046ef3796c3794f868a5bc813db689eed00c7631275cd1" dependencies = [ "proc-macro2", "quote", @@ -962,18 +1017,18 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" dependencies = [ "serde", ] [[package]] name = "unicode-segmentation" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" [[package]] name = "unicode-width" @@ -993,12 +1048,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" -[[package]] -name = "version-compare" -version = "0.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1" - [[package]] name = "version-compare" version = "0.0.11" diff --git a/Cargo.toml b/Cargo.toml index 83260ed..970e7bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,10 +7,5 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -cairo-rs = "0.9.1" -glib = "0.10.3" -gdk = "0.13.2" -gtk = "0.9.2" -gio = "0.9.1" - -pipewire = { git = "https://gitlab.freedesktop.org/gdesmott/pipewire-rs", branch = "proxies"} \ No newline at end of file +pipewire = { git = "https://gitlab.freedesktop.org/gdesmott/pipewire-rs", branch = "proxies"} +gtk = { git = "https://github.com/gtk-rs/gtk4-rs/", package = "gtk4" } diff --git a/src/main.rs b/src/main.rs index 00fae46..221908d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,6 @@ mod pipewire_connection; mod view; -use gio::prelude::*; -use glib::clone; use gtk::prelude::*; use std::{cell::RefCell, rc::Rc}; @@ -25,24 +23,27 @@ fn main() -> Result<(), Box> { .expect("Failed to initialize pipewire connection"); pw_con.roundtrip(); // From now on, call roundtrip() every second. - glib::timeout_add_seconds_local(1, move || { + gtk::glib::timeout_add_seconds_local(1, move || { pw_con.roundtrip(); Continue(true) }); let app = gtk::Application::new( Some("org.freedesktop.pipewire.graphui"), - gio::ApplicationFlags::FLAGS_NONE, + Default::default() ) .expect("Application creation failed"); - app.connect_activate(clone!(@strong graphview => move |app| { - let window = gtk::ApplicationWindow::new(app); - window.set_default_size(800, 600); - window.set_title("Pipewire Graph Editor"); - window.add(&graphview.borrow().widget); - window.show_all(); - })); + app.connect_activate(move |app| { + let window = gtk::ApplicationWindowBuilder::new() + .application(app) + .default_width(800) + .default_height(600) + .title("Pipewire Graph Editor") + .child(&*graphview.borrow()) + .build(); + window.show(); + }); app.run(&std::env::args().collect::>()); diff --git a/src/pipewire_connection.rs b/src/pipewire_connection.rs index 1ef8a75..5ee6a25 100644 --- a/src/pipewire_connection.rs +++ b/src/pipewire_connection.rs @@ -1,14 +1,13 @@ +use crate::PipewireLink; + +use pipewire as pw; +use pw::{port::Direction, registry::ObjectType, PW_ID_CORE}; + use std::{ cell::{Cell, RefCell}, rc::Rc, }; -use glib::clone; -use pipewire as pw; -use pw::{port::Direction, registry::ObjectType, PW_ID_CORE}; - -use crate::PipewireLink; - pub struct PipewireConnection { mainloop: pw::MainLoop, _context: pw::Context, @@ -28,11 +27,12 @@ impl PipewireConnection { .map_err(|_| "Failed to connect to pipewire core")?; let registry = core.get_registry(); + let graphview = Rc::downgrade(&graphview.clone()); let reg_listeners = registry .add_listener_local() - .global(clone!(@weak graphview => @default-panic, move |global| { - PipewireConnection::handle_global(graphview, global) - })) + .global(move |global| { + PipewireConnection::handle_global(graphview.upgrade().unwrap(), global) + }) .global_remove(|_| { /* TODO */ }) .register(); diff --git a/src/view/graph_view.rs b/src/view/graph_view.rs index 472dd0c..335dc29 100644 --- a/src/view/graph_view.rs +++ b/src/view/graph_view.rs @@ -1,110 +1,247 @@ use super::Node; -use cairo::Context; -use glib::clone; -use gtk::{prelude::*, LayoutExt}; -use std::{cell::RefCell, collections::HashMap, rc::Rc}; -pub struct GraphView { - pub(crate) widget: gtk::Layout, - nodes: Rc>>, - links: Rc>>, +use gtk::{glib, prelude::*, subclass::prelude::ObjectSubclass, WidgetExt}; + +use std::collections::HashMap; + +mod imp { + use super::*; + + use gtk::{gdk, graphene, gsk, subclass::prelude::*, WidgetExt}; + + use std::{cell::RefCell, rc::Rc}; + + pub struct GraphView { + nodes: RefCell>, + links: RefCell>, + dragged: Rc>>, + } + + impl ObjectSubclass for GraphView { + const NAME: &'static str = "GraphView"; + type Type = super::GraphView; + type ParentType = gtk::Widget; + type Instance = glib::subclass::simple::InstanceStruct; + type Class = glib::subclass::simple::ClassStruct; + + glib::object_subclass!(); + + fn class_init(klass: &mut Self::Class) { + // The layout manager determines how child widgets are laid out. + klass.set_layout_manager_type::(); + } + + fn new() -> Self { + Self { + nodes: RefCell::new(HashMap::new()), + links: RefCell::new(HashMap::new()), + dragged: Rc::new(RefCell::new(None)), + } + } + } + + impl ObjectImpl for GraphView { + fn constructed(&self, obj: &Self::Type) { + self.parent_constructed(obj); + + let motion_controller = gtk::EventControllerMotion::new(); + motion_controller.connect_motion(|controller, x, y| { + if controller + .get_current_event() + .unwrap() + .get_modifier_state() + .contains(gdk::ModifierType::BUTTON1_MASK) + { + let instance = controller + .get_widget() + .unwrap() + .dynamic_cast::() + .unwrap(); + let this = imp::GraphView::from_instance(&instance); + if let Some(ref widget) = *this.dragged.borrow() { + this.move_node(&widget, x as f32, y as f32); + }; + } + }); + obj.add_controller(&motion_controller); + } + + fn dispose(&self, _obj: &Self::Type) { + self.nodes + .borrow() + .values() + .for_each(|node| node.widget.unparent()) + } + } + + impl WidgetImpl for GraphView { + fn snapshot(&self, widget: &Self::Type, snapshot: >k::Snapshot) { + // TODO: Draw links after we can move nodes + let snapshot = snapshot.downcast_ref::().unwrap(); + + let alloc = widget.get_allocation(); + let rect = gtk::graphene::Rect::new(0.0, 0.0, alloc.width as f32, alloc.height as f32); + + let cr = snapshot + .append_cairo(&rect) + .expect("Failed to get cairo context"); + + // Draw background + cr.set_source_rgb(255.0, 255.0, 255.0); + cr.paint(); + + // Draw all links + cr.set_line_width(2.0); + cr.set_source_rgb(0.0, 0.0, 0.0); + for link in self.links.borrow().values() { + if let Some((from_x, from_y, to_x, to_y)) = self.get_link_coordinates(link) { + cr.move_to(from_x, from_y); + cr.curve_to(from_x + 75.0, from_y, to_x - 75.0, to_y, to_x, to_y); + cr.stroke(); + } else { + eprintln!("Could not get allocation of ports of link: {:?}", link); + } + } + + // Draw all children + self.nodes + .borrow() + .values() + .for_each(|node| self.get_instance().snapshot_child(&node.widget, snapshot)); + } + } + + impl GraphView { + pub fn add_node(&self, id: u32, node: Node) { + // Place widgets in colums of 4, growing down, then right. + // TODO: Make a better positioning algorithm. + let x = (self.nodes.borrow().len() / 4) as f32 * 400.0; + let y = self.nodes.borrow().len() as f32 % 4.0 * 100.0; + + self.move_node(&node.widget.clone().upcast(), x, y); + + self.nodes.borrow_mut().insert(id, node); + } + + pub fn move_node(&self, node: >k::Widget, x: f32, y: f32) { + let layout_manager = self + .get_instance() + .get_layout_manager() + .expect("Failed to get layout manager") + .dynamic_cast::() + .expect("Failed to cast to FixedLayout"); + + let transform = gsk::Transform::new() + .translate(&graphene::Point::new(x, y)) + .unwrap(); + + layout_manager + .get_layout_child(node) + .expect("Could not get layout child") + .dynamic_cast::() + .expect("Could not cast to FixedLayoutChild") + .set_transform(&transform); + } + + pub fn add_port_to_node(&self, node_id: u32, port_id: u32, port: crate::view::port::Port) { + if let Some(node) = self.nodes.borrow_mut().get_mut(&node_id) { + node.add_port(port_id, port); + } else { + // FIXME: Log this instead + eprintln!( + "Node with id {} not found when trying to add port with id {} to graph", + node_id, port_id + ); + } + } + + /// Add a link to the graph. + /// + /// `add_link` takes three arguments: `link_id` is the id of the link as assigned by the pipewire server, + /// `from` and `to` are the id's of the ingoing and outgoing port, respectively. + pub fn add_link(&self, link_id: u32, link: crate::PipewireLink) { + self.links.borrow_mut().insert(link_id, link); + } + + pub fn set_dragged(&self, widget: Option) { + *self.dragged.borrow_mut() = widget; + } + + /// Get coordinates for the drawn link to start at and to end at. + /// + /// # Returns + /// Some((from_x, from_y, to_x, to_y)) if all objects the links refers to exist as widgets. + fn get_link_coordinates(&self, link: &crate::PipewireLink) -> Option<(f64, f64, f64, f64)> { + let nodes = self.nodes.borrow(); + + // For some reason, gtk4::WidgetExt::translate_coordinates gives me incorrect values, + // so we manually calculate the needed offsets here. + + let from_port = &nodes.get(&link.node_from)?.get_port(link.port_from)?.widget; + let gtk::Allocation { + x: mut fx, + y: mut fy, + width: fw, + height: fh, + } = from_port.get_allocation(); + let from_node = from_port.get_ancestor(gtk::Grid::static_type()).unwrap(); + let gtk::Allocation { x: fnx, y: fny, .. } = from_node.get_allocation(); + fx += fnx + fw; + fy += fny + (fh / 2); + + let to_port = &nodes.get(&link.node_to)?.get_port(link.port_to)?.widget; + let gtk::Allocation { + x: mut tx, + y: mut ty, + height: th, + .. + } = to_port.get_allocation(); + let to_node = to_port.get_ancestor(gtk::Grid::static_type()).unwrap(); + let gtk::Allocation { x: tnx, y: tny, .. } = to_node.get_allocation(); + tx += tnx; + ty += tny + (th / 2); + + Some((fx as f64, fy as f64, tx as f64, ty as f64)) + } + } +} + +glib::wrapper! { + pub struct GraphView(ObjectSubclass) + @extends gtk::Widget; } impl GraphView { pub fn new() -> Self { - let result = Self { - widget: gtk::Layout::new::(None, None), - nodes: Rc::new(RefCell::new(HashMap::new())), - links: Rc::new(RefCell::new(HashMap::new())), - }; - - result.widget.connect_draw(clone!( - @weak result.nodes as nodes, @weak result.links as links => @default-panic, - move |_, cr| { - draw(nodes, links, cr); - Inhibit(false) - })); - - result + glib::Object::new(&[]).expect("Failed to create GraphView") } - pub fn add_node(&mut self, id: u32, node: Node) { - // TODO: Find a free position to put the widget at. - self.widget.put( - &node.widget, - (self.nodes.borrow().len() / 4 * 400) as i32, - (self.nodes.borrow().len() % 4 * 100) as i32, - ); - node.widget.show_all(); - self.nodes.borrow_mut().insert(id, node); + pub fn add_node(&self, id: u32, node: Node) { + node.widget.set_parent(self); + imp::GraphView::from_instance(self).add_node(id, node) } - pub fn add_port_to_node(&mut self, node_id: u32, port_id: u32, port: super::port::Port) { - if let Some(node) = self.nodes.borrow_mut().get_mut(&node_id) { - node.add_port(port_id, port); - } else { - // FIXME: Log this instead - eprintln!( - "Node with id {} not found when trying to add port with id {} to graph", - node_id, port_id - ); - } + pub fn add_port_to_node(&self, node_id: u32, port_id: u32, port: crate::view::port::Port) { + imp::GraphView::from_instance(self).add_port_to_node(node_id, port_id, port) } /// Add a link to the graph. /// /// `add_link` takes three arguments: `link_id` is the id of the link as assigned by the pipewire server, /// `from` and `to` are the id's of the ingoing and outgoing port, respectively. - pub fn add_link(&mut self, link_id: u32, link: crate::PipewireLink) { - self.links.borrow_mut().insert(link_id, link); - self.widget.queue_draw(); + pub fn add_link(&self, link_id: u32, link: crate::PipewireLink) { + imp::GraphView::from_instance(self).add_link(link_id, link); + self.queue_draw(); + } + + pub fn set_dragged(&self, widget: Option) { + imp::GraphView::from_instance(self).set_dragged(widget) + } + + pub fn move_node(&self, node: >k::Widget, x: f32, y: f32) { + imp::GraphView::from_instance(self).move_node(node, x, y); + // FIXME: If links become proper widgets, + // we don't need to redraw the full graph everytime. + self.queue_draw(); } } - -fn draw( - nodes: Rc>>, - links: Rc>>, - cr: &Context, -) { - cr.set_line_width(2.0); - cr.set_source_rgb(255.0, 255.0, 255.0); - cr.paint(); - cr.set_source_rgb(0.0, 0.0, 0.0); - for link in links.borrow().values() { - if let Some((from_alloc, to_alloc)) = get_allocs(nodes.clone(), link) { - let from_x: f64 = (from_alloc.x + from_alloc.width).into(); - let from_y: f64 = (from_alloc.y + (from_alloc.height / 2)).into(); - cr.move_to(from_x, from_y); - - let to_x: f64 = to_alloc.x.into(); - let to_y: f64 = (to_alloc.y + (to_alloc.height / 2)).into(); - cr.curve_to(from_x + 75.0, from_y, to_x - 75.0, to_y, to_x, to_y); - - cr.stroke(); - } else { - eprintln!("Could not get allocation of ports of link: {:?}", link); - } - } -} - -fn get_allocs( - nodes: Rc>>, - link: &crate::PipewireLink, -) -> Option<(gtk::Allocation, gtk::Allocation)> { - println!(); - - let from_alloc = &nodes - .borrow() - .get(&link.node_from)? - .get_port(link.port_from)? - .widget - .get_allocation(); - let to_alloc = &nodes - .borrow() - .get(&link.node_to)? - .get_port(link.port_to)? - .widget - .get_allocation(); - - Some((from_alloc.to_owned(), to_alloc.to_owned())) -} diff --git a/src/view/node.rs b/src/view/node.rs index e10d0a2..a057993 100644 --- a/src/view/node.rs +++ b/src/view/node.rs @@ -1,13 +1,13 @@ -use gdk::prelude::*; -use gtk::prelude::*; -use std::collections::HashMap; +use super::graph_view::GraphView; use pipewire::port::Direction; +use gtk::prelude::*; + +use std::collections::HashMap; pub struct Node { pub(super) widget: gtk::Grid, label: gtk::Label, - label_box: gtk::EventBox, ports: HashMap, num_ports_in: u32, num_ports_out: u32, @@ -18,51 +18,41 @@ impl Node { let result = Self { widget: gtk::Grid::new(), label: gtk::Label::new(Some(name)), - label_box: gtk::EventBox::new(), ports: HashMap::new(), num_ports_in: 0, num_ports_out: 0, }; - result.label_box.add(&result.label); - result.widget.attach(&result.label_box, 0, 0, 2, 1); + let motion_controller = gtk::EventControllerMotion::new(); + // Tell the graphview that the Node is the target of a drag when the mouse enters its label + motion_controller.connect_enter(|controller, _, _| { + let widget = controller + .get_widget() + .expect("Controller with enter event has no widget") + .get_ancestor(gtk::Grid::static_type()) + .unwrap(); + widget + .get_ancestor(GraphView::static_type()) + .unwrap() + .dynamic_cast::() + .unwrap() + .set_dragged(Some(widget)); + }); + // Tell the graphview that the Node is no longer the target of a drag when the mouse leaves. + motion_controller.connect_leave(|controller| { + // FIXME: Check that we are the current target before setting none. + controller + .get_widget() + .expect("Controller with leave event has no widget") + .get_ancestor(GraphView::static_type()) + .unwrap() + .dynamic_cast::() + .unwrap() + .set_dragged(None); + }); + result.label.add_controller(&motion_controller); - // Setup needed events for dragging a node. - result - .label_box - .add_events(gdk::EventMask::BUTTON1_MOTION_MASK); - - // Setup callback for dragging the node. - result - .label_box - .connect_motion_notify_event(|label, event| { - let node_frame = label - .get_ancestor(gtk::Grid::static_type()) - .unwrap() - .dynamic_cast::() - .unwrap(); - let graphview = node_frame - .get_ancestor(gtk::Layout::static_type()) - .unwrap() - .dynamic_cast::() - .unwrap(); - - // Use root coordinates to prevent jumping around - // as moving the widget also influences the relative coordinates. - let (x, y) = event.get_root(); - let (offset_x, offset_y) = graphview.get_window().unwrap().get_root_origin(); - - // TODO: Calculate proper values to center the mouse on the label - // instead of using hardcoded offsets. - graphview.set_child_x(&node_frame, x as i32 - offset_x - 100); - graphview.set_child_y(&node_frame, y as i32 - offset_y - 50); - - // FIXME: If links become proper widgets, - // we don't need to redraw the full graph everytime. - graphview.queue_draw(); - - Inhibit(true) - }); + result.widget.attach(&result.label, 0, 0, 2, 1); result } @@ -81,7 +71,6 @@ impl Node { } } - port.widget.show_all(); self.ports.insert(id, port); }