├── .github └── workflows │ ├── bundle.yml │ ├── release.yml │ └── rust.yml ├── .gitignore ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── assets ├── Roboto-Medium.ttf ├── icon.ico ├── icon.png └── sysinfo-gui.desktop ├── build.rs └── src ├── gui ├── app.rs ├── message.rs ├── mod.rs ├── styles │ ├── colors.rs │ ├── mod.rs │ └── svgs.rs └── widgets │ ├── mod.rs │ └── svg_button.rs ├── main.rs ├── utils.rs └── view ├── cpu.rs ├── disk.rs ├── general.rs ├── info.rs ├── mem.rs ├── mod.rs ├── net.rs ├── procs.rs └── settings.rs /.github/workflows/bundle.yml: -------------------------------------------------------------------------------- 1 | name: bundle 2 | 3 | on: 4 | pull_request: 5 | branches: [ release ] 6 | 7 | env: 8 | CARGO_TERM_COLOR: always 9 | 10 | jobs: 11 | macos: 12 | runs-on: macos-11 13 | steps: 14 | - uses: actions/checkout@v3 15 | - name: Build 16 | run: | 17 | cargo install cargo-bundle 18 | cargo bundle --release 19 | zip -r sysinfo-gui.app.zip target/release/bundle/osx/sysinfo-gui.app 20 | - name: Upload a Build Artifact 21 | uses: actions/upload-artifact@v2 22 | with: 23 | name: sysinfo-gui-bundle 24 | path: sysinfo-gui.app.zip -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | pull_request: 5 | branches: [ release ] 6 | 7 | jobs: 8 | windows: 9 | name: run on windows 10 | runs-on: windows-latest 11 | steps: 12 | - uses: actions/checkout@v2 13 | - name: Build 14 | shell: bash 15 | run: cargo build --release --features=fltk/fltk-bundled 16 | - name: Upload a Build Artifact 17 | uses: actions/upload-artifact@v2 18 | with: 19 | name: sysinfo-gui-windows 20 | path: target/release/sysinfo-gui.exe 21 | mac-and-ubuntu: 22 | runs-on: ${{ matrix.os }} 23 | strategy: 24 | matrix: 25 | os: [macos-11, ubuntu-20.04] 26 | 27 | steps: 28 | - name: Download deps 29 | run: | 30 | if [ "$RUNNER_OS" == "Linux" ]; then 31 | sudo apt-get update && sudo apt-get install -y libpango1.0-dev libx11-dev libxext-dev libxft-dev libxinerama-dev libxcursor-dev libxrender-dev libxfixes-dev 32 | fi 33 | shell: bash 34 | - uses: actions/checkout@v2 35 | - name: Build 36 | shell: bash 37 | run: cargo build --release 38 | - name: Upload a Build Artifact 39 | uses: actions/upload-artifact@v2 40 | with: 41 | name: sysinfo-gui-${{ matrix.os }} 42 | path: target/release/sysinfo-gui 43 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | jobs: 10 | ubuntu: 11 | runs-on: ${{ matrix.os }} 12 | strategy: 13 | matrix: 14 | os: [ubuntu-20.04] 15 | 16 | steps: 17 | - name: Download deps 18 | run: | 19 | if [ "$RUNNER_OS" == "Linux" ]; then 20 | sudo apt-get update && sudo apt-get install -y libpango1.0-dev libx11-dev libxext-dev libxft-dev libxinerama-dev libxcursor-dev libxrender-dev libxfixes-dev 21 | fi 22 | shell: bash 23 | - uses: actions/checkout@v2 24 | - name: Build 25 | shell: bash 26 | run: cargo check 27 | 28 | 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.7.6" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" 10 | dependencies = [ 11 | "getrandom", 12 | "once_cell", 13 | "version_check", 14 | ] 15 | 16 | [[package]] 17 | name = "aho-corasick" 18 | version = "1.0.1" 19 | source = "registry+https://github.com/rust-lang/crates.io-index" 20 | checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" 21 | dependencies = [ 22 | "memchr", 23 | ] 24 | 25 | [[package]] 26 | name = "async-broadcast" 27 | version = "0.5.1" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" 30 | dependencies = [ 31 | "event-listener", 32 | "futures-core", 33 | ] 34 | 35 | [[package]] 36 | name = "async-executor" 37 | version = "1.5.1" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "6fa3dc5f2a8564f07759c008b9109dc0d39de92a88d5588b8a5036d286383afb" 40 | dependencies = [ 41 | "async-lock", 42 | "async-task", 43 | "concurrent-queue", 44 | "fastrand", 45 | "futures-lite", 46 | "slab", 47 | ] 48 | 49 | [[package]] 50 | name = "async-io" 51 | version = "1.13.0" 52 | source = "registry+https://github.com/rust-lang/crates.io-index" 53 | checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" 54 | dependencies = [ 55 | "async-lock", 56 | "autocfg", 57 | "cfg-if", 58 | "concurrent-queue", 59 | "futures-lite", 60 | "log", 61 | "parking", 62 | "polling", 63 | "rustix", 64 | "slab", 65 | "socket2", 66 | "waker-fn", 67 | ] 68 | 69 | [[package]] 70 | name = "async-lock" 71 | version = "2.7.0" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "fa24f727524730b077666307f2734b4a1a1c57acb79193127dcc8914d5242dd7" 74 | dependencies = [ 75 | "event-listener", 76 | ] 77 | 78 | [[package]] 79 | name = "async-recursion" 80 | version = "1.0.4" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba" 83 | dependencies = [ 84 | "proc-macro2", 85 | "quote", 86 | "syn 2.0.16", 87 | ] 88 | 89 | [[package]] 90 | name = "async-task" 91 | version = "4.4.0" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "ecc7ab41815b3c653ccd2978ec3255c81349336702dfdf62ee6f7069b12a3aae" 94 | 95 | [[package]] 96 | name = "async-trait" 97 | version = "0.1.68" 98 | source = "registry+https://github.com/rust-lang/crates.io-index" 99 | checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" 100 | dependencies = [ 101 | "proc-macro2", 102 | "quote", 103 | "syn 2.0.16", 104 | ] 105 | 106 | [[package]] 107 | name = "autocfg" 108 | version = "1.1.0" 109 | source = "registry+https://github.com/rust-lang/crates.io-index" 110 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 111 | 112 | [[package]] 113 | name = "bitflags" 114 | version = "1.3.2" 115 | source = "registry+https://github.com/rust-lang/crates.io-index" 116 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 117 | 118 | [[package]] 119 | name = "bitflags" 120 | version = "2.3.1" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" 123 | 124 | [[package]] 125 | name = "block-buffer" 126 | version = "0.10.4" 127 | source = "registry+https://github.com/rust-lang/crates.io-index" 128 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 129 | dependencies = [ 130 | "generic-array", 131 | ] 132 | 133 | [[package]] 134 | name = "bumpalo" 135 | version = "3.12.2" 136 | source = "registry+https://github.com/rust-lang/crates.io-index" 137 | checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" 138 | 139 | [[package]] 140 | name = "byteorder" 141 | version = "1.4.3" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" 144 | 145 | [[package]] 146 | name = "cc" 147 | version = "1.0.79" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" 150 | 151 | [[package]] 152 | name = "cfg-if" 153 | version = "1.0.0" 154 | source = "registry+https://github.com/rust-lang/crates.io-index" 155 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 156 | 157 | [[package]] 158 | name = "cmake" 159 | version = "0.1.50" 160 | source = "registry+https://github.com/rust-lang/crates.io-index" 161 | checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" 162 | dependencies = [ 163 | "cc", 164 | ] 165 | 166 | [[package]] 167 | name = "concurrent-queue" 168 | version = "2.2.0" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c" 171 | dependencies = [ 172 | "crossbeam-utils", 173 | ] 174 | 175 | [[package]] 176 | name = "core-foundation-sys" 177 | version = "0.8.4" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" 180 | 181 | [[package]] 182 | name = "cpufeatures" 183 | version = "0.2.7" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" 186 | dependencies = [ 187 | "libc", 188 | ] 189 | 190 | [[package]] 191 | name = "crossbeam-channel" 192 | version = "0.5.8" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" 195 | dependencies = [ 196 | "cfg-if", 197 | "crossbeam-utils", 198 | ] 199 | 200 | [[package]] 201 | name = "crossbeam-utils" 202 | version = "0.8.15" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" 205 | dependencies = [ 206 | "cfg-if", 207 | ] 208 | 209 | [[package]] 210 | name = "crypto-common" 211 | version = "0.1.6" 212 | source = "registry+https://github.com/rust-lang/crates.io-index" 213 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 214 | dependencies = [ 215 | "generic-array", 216 | "typenum", 217 | ] 218 | 219 | [[package]] 220 | name = "dark-light" 221 | version = "0.2.3" 222 | source = "registry+https://github.com/rust-lang/crates.io-index" 223 | checksum = "413487ef345ab5cdfbf23e66070741217a701bce70f2f397a54221b4f2b6056a" 224 | dependencies = [ 225 | "dconf_rs", 226 | "detect-desktop-environment", 227 | "dirs", 228 | "objc", 229 | "rust-ini", 230 | "web-sys", 231 | "winreg", 232 | "zbus", 233 | "zvariant", 234 | ] 235 | 236 | [[package]] 237 | name = "dconf_rs" 238 | version = "0.3.0" 239 | source = "registry+https://github.com/rust-lang/crates.io-index" 240 | checksum = "7046468a81e6a002061c01e6a7c83139daf91b11c30e66795b13217c2d885c8b" 241 | 242 | [[package]] 243 | name = "derivative" 244 | version = "2.2.0" 245 | source = "registry+https://github.com/rust-lang/crates.io-index" 246 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 247 | dependencies = [ 248 | "proc-macro2", 249 | "quote", 250 | "syn 1.0.109", 251 | ] 252 | 253 | [[package]] 254 | name = "detect-desktop-environment" 255 | version = "0.2.0" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "21d8ad60dd5b13a4ee6bd8fa2d5d88965c597c67bce32b5fc49c94f55cb50810" 258 | 259 | [[package]] 260 | name = "digest" 261 | version = "0.10.7" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 264 | dependencies = [ 265 | "block-buffer", 266 | "crypto-common", 267 | ] 268 | 269 | [[package]] 270 | name = "dirs" 271 | version = "4.0.0" 272 | source = "registry+https://github.com/rust-lang/crates.io-index" 273 | checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" 274 | dependencies = [ 275 | "dirs-sys", 276 | ] 277 | 278 | [[package]] 279 | name = "dirs-sys" 280 | version = "0.3.7" 281 | source = "registry+https://github.com/rust-lang/crates.io-index" 282 | checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" 283 | dependencies = [ 284 | "libc", 285 | "redox_users", 286 | "winapi", 287 | ] 288 | 289 | [[package]] 290 | name = "dlv-list" 291 | version = "0.3.0" 292 | source = "registry+https://github.com/rust-lang/crates.io-index" 293 | checksum = "0688c2a7f92e427f44895cd63841bff7b29f8d7a1648b9e7e07a4a365b2e1257" 294 | 295 | [[package]] 296 | name = "enumflags2" 297 | version = "0.7.7" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "c041f5090df68b32bcd905365fd51769c8b9d553fe87fde0b683534f10c01bd2" 300 | dependencies = [ 301 | "enumflags2_derive", 302 | "serde", 303 | ] 304 | 305 | [[package]] 306 | name = "enumflags2_derive" 307 | version = "0.7.7" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "5e9a1f9f7d83e59740248a6e14ecf93929ade55027844dfcea78beafccc15745" 310 | dependencies = [ 311 | "proc-macro2", 312 | "quote", 313 | "syn 2.0.16", 314 | ] 315 | 316 | [[package]] 317 | name = "errno" 318 | version = "0.3.1" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" 321 | dependencies = [ 322 | "errno-dragonfly", 323 | "libc", 324 | "windows-sys 0.48.0", 325 | ] 326 | 327 | [[package]] 328 | name = "errno-dragonfly" 329 | version = "0.1.2" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" 332 | dependencies = [ 333 | "cc", 334 | "libc", 335 | ] 336 | 337 | [[package]] 338 | name = "event-listener" 339 | version = "2.5.3" 340 | source = "registry+https://github.com/rust-lang/crates.io-index" 341 | checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" 342 | 343 | [[package]] 344 | name = "fastrand" 345 | version = "1.9.0" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" 348 | dependencies = [ 349 | "instant", 350 | ] 351 | 352 | [[package]] 353 | name = "fltk" 354 | version = "1.4.3" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "9aaf7cacace3db3d685f447f54b69fdc73c757fac0a00b5d965c4592e01de343" 357 | dependencies = [ 358 | "bitflags 2.3.1", 359 | "crossbeam-channel", 360 | "fltk-sys", 361 | "paste", 362 | "ttf-parser", 363 | ] 364 | 365 | [[package]] 366 | name = "fltk-extras" 367 | version = "0.1.3" 368 | source = "registry+https://github.com/rust-lang/crates.io-index" 369 | checksum = "0ecf62c65291b007833650a939911de8eb309783daefa8f94a85e7a5d5456fcb" 370 | dependencies = [ 371 | "fltk", 372 | ] 373 | 374 | [[package]] 375 | name = "fltk-sys" 376 | version = "1.4.3" 377 | source = "registry+https://github.com/rust-lang/crates.io-index" 378 | checksum = "f4e06030256cc3edd00bfc01f5730a2ec08bf16086be01721d67980f753ac2db" 379 | dependencies = [ 380 | "cmake", 381 | ] 382 | 383 | [[package]] 384 | name = "futures-core" 385 | version = "0.3.28" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" 388 | 389 | [[package]] 390 | name = "futures-io" 391 | version = "0.3.28" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" 394 | 395 | [[package]] 396 | name = "futures-lite" 397 | version = "1.13.0" 398 | source = "registry+https://github.com/rust-lang/crates.io-index" 399 | checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" 400 | dependencies = [ 401 | "fastrand", 402 | "futures-core", 403 | "futures-io", 404 | "memchr", 405 | "parking", 406 | "pin-project-lite", 407 | "waker-fn", 408 | ] 409 | 410 | [[package]] 411 | name = "futures-sink" 412 | version = "0.3.28" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" 415 | 416 | [[package]] 417 | name = "futures-task" 418 | version = "0.3.28" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" 421 | 422 | [[package]] 423 | name = "futures-util" 424 | version = "0.3.28" 425 | source = "registry+https://github.com/rust-lang/crates.io-index" 426 | checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" 427 | dependencies = [ 428 | "futures-core", 429 | "futures-sink", 430 | "futures-task", 431 | "pin-project-lite", 432 | "pin-utils", 433 | "slab", 434 | ] 435 | 436 | [[package]] 437 | name = "generic-array" 438 | version = "0.14.7" 439 | source = "registry+https://github.com/rust-lang/crates.io-index" 440 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 441 | dependencies = [ 442 | "typenum", 443 | "version_check", 444 | ] 445 | 446 | [[package]] 447 | name = "getrandom" 448 | version = "0.2.9" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" 451 | dependencies = [ 452 | "cfg-if", 453 | "libc", 454 | "wasi", 455 | ] 456 | 457 | [[package]] 458 | name = "hashbrown" 459 | version = "0.12.3" 460 | source = "registry+https://github.com/rust-lang/crates.io-index" 461 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 462 | dependencies = [ 463 | "ahash", 464 | ] 465 | 466 | [[package]] 467 | name = "hermit-abi" 468 | version = "0.3.1" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" 471 | 472 | [[package]] 473 | name = "hex" 474 | version = "0.4.3" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 477 | 478 | [[package]] 479 | name = "indexmap" 480 | version = "1.9.3" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 483 | dependencies = [ 484 | "autocfg", 485 | "hashbrown", 486 | ] 487 | 488 | [[package]] 489 | name = "instant" 490 | version = "0.1.12" 491 | source = "registry+https://github.com/rust-lang/crates.io-index" 492 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" 493 | dependencies = [ 494 | "cfg-if", 495 | ] 496 | 497 | [[package]] 498 | name = "io-lifetimes" 499 | version = "1.0.10" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" 502 | dependencies = [ 503 | "hermit-abi", 504 | "libc", 505 | "windows-sys 0.48.0", 506 | ] 507 | 508 | [[package]] 509 | name = "js-sys" 510 | version = "0.3.63" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" 513 | dependencies = [ 514 | "wasm-bindgen", 515 | ] 516 | 517 | [[package]] 518 | name = "libc" 519 | version = "0.2.144" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" 522 | 523 | [[package]] 524 | name = "linux-raw-sys" 525 | version = "0.3.8" 526 | source = "registry+https://github.com/rust-lang/crates.io-index" 527 | checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" 528 | 529 | [[package]] 530 | name = "lock_api" 531 | version = "0.4.9" 532 | source = "registry+https://github.com/rust-lang/crates.io-index" 533 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" 534 | dependencies = [ 535 | "autocfg", 536 | "scopeguard", 537 | ] 538 | 539 | [[package]] 540 | name = "log" 541 | version = "0.4.17" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" 544 | dependencies = [ 545 | "cfg-if", 546 | ] 547 | 548 | [[package]] 549 | name = "malloc_buf" 550 | version = "0.0.6" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" 553 | dependencies = [ 554 | "libc", 555 | ] 556 | 557 | [[package]] 558 | name = "memchr" 559 | version = "2.5.0" 560 | source = "registry+https://github.com/rust-lang/crates.io-index" 561 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 562 | 563 | [[package]] 564 | name = "memoffset" 565 | version = "0.6.5" 566 | source = "registry+https://github.com/rust-lang/crates.io-index" 567 | checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" 568 | dependencies = [ 569 | "autocfg", 570 | ] 571 | 572 | [[package]] 573 | name = "nix" 574 | version = "0.25.1" 575 | source = "registry+https://github.com/rust-lang/crates.io-index" 576 | checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" 577 | dependencies = [ 578 | "autocfg", 579 | "bitflags 1.3.2", 580 | "cfg-if", 581 | "libc", 582 | "memoffset", 583 | "pin-utils", 584 | ] 585 | 586 | [[package]] 587 | name = "ntapi" 588 | version = "0.4.1" 589 | source = "registry+https://github.com/rust-lang/crates.io-index" 590 | checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" 591 | dependencies = [ 592 | "winapi", 593 | ] 594 | 595 | [[package]] 596 | name = "objc" 597 | version = "0.2.7" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" 600 | dependencies = [ 601 | "malloc_buf", 602 | ] 603 | 604 | [[package]] 605 | name = "once_cell" 606 | version = "1.17.1" 607 | source = "registry+https://github.com/rust-lang/crates.io-index" 608 | checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" 609 | 610 | [[package]] 611 | name = "ordered-multimap" 612 | version = "0.4.3" 613 | source = "registry+https://github.com/rust-lang/crates.io-index" 614 | checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" 615 | dependencies = [ 616 | "dlv-list", 617 | "hashbrown", 618 | ] 619 | 620 | [[package]] 621 | name = "ordered-stream" 622 | version = "0.2.0" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" 625 | dependencies = [ 626 | "futures-core", 627 | "pin-project-lite", 628 | ] 629 | 630 | [[package]] 631 | name = "parking" 632 | version = "2.1.0" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e" 635 | 636 | [[package]] 637 | name = "parking_lot" 638 | version = "0.12.1" 639 | source = "registry+https://github.com/rust-lang/crates.io-index" 640 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" 641 | dependencies = [ 642 | "lock_api", 643 | "parking_lot_core", 644 | ] 645 | 646 | [[package]] 647 | name = "parking_lot_core" 648 | version = "0.9.7" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" 651 | dependencies = [ 652 | "cfg-if", 653 | "libc", 654 | "redox_syscall 0.2.16", 655 | "smallvec", 656 | "windows-sys 0.45.0", 657 | ] 658 | 659 | [[package]] 660 | name = "paste" 661 | version = "1.0.12" 662 | source = "registry+https://github.com/rust-lang/crates.io-index" 663 | checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" 664 | 665 | [[package]] 666 | name = "pin-project-lite" 667 | version = "0.2.9" 668 | source = "registry+https://github.com/rust-lang/crates.io-index" 669 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 670 | 671 | [[package]] 672 | name = "pin-utils" 673 | version = "0.1.0" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 676 | 677 | [[package]] 678 | name = "polling" 679 | version = "2.8.0" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" 682 | dependencies = [ 683 | "autocfg", 684 | "bitflags 1.3.2", 685 | "cfg-if", 686 | "concurrent-queue", 687 | "libc", 688 | "log", 689 | "pin-project-lite", 690 | "windows-sys 0.48.0", 691 | ] 692 | 693 | [[package]] 694 | name = "ppv-lite86" 695 | version = "0.2.17" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 698 | 699 | [[package]] 700 | name = "proc-macro-crate" 701 | version = "1.3.1" 702 | source = "registry+https://github.com/rust-lang/crates.io-index" 703 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" 704 | dependencies = [ 705 | "once_cell", 706 | "toml_edit", 707 | ] 708 | 709 | [[package]] 710 | name = "proc-macro2" 711 | version = "1.0.58" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" 714 | dependencies = [ 715 | "unicode-ident", 716 | ] 717 | 718 | [[package]] 719 | name = "quote" 720 | version = "1.0.27" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" 723 | dependencies = [ 724 | "proc-macro2", 725 | ] 726 | 727 | [[package]] 728 | name = "rand" 729 | version = "0.8.5" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 732 | dependencies = [ 733 | "libc", 734 | "rand_chacha", 735 | "rand_core", 736 | ] 737 | 738 | [[package]] 739 | name = "rand_chacha" 740 | version = "0.3.1" 741 | source = "registry+https://github.com/rust-lang/crates.io-index" 742 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 743 | dependencies = [ 744 | "ppv-lite86", 745 | "rand_core", 746 | ] 747 | 748 | [[package]] 749 | name = "rand_core" 750 | version = "0.6.4" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 753 | dependencies = [ 754 | "getrandom", 755 | ] 756 | 757 | [[package]] 758 | name = "redox_syscall" 759 | version = "0.2.16" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" 762 | dependencies = [ 763 | "bitflags 1.3.2", 764 | ] 765 | 766 | [[package]] 767 | name = "redox_syscall" 768 | version = "0.3.5" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" 771 | dependencies = [ 772 | "bitflags 1.3.2", 773 | ] 774 | 775 | [[package]] 776 | name = "redox_users" 777 | version = "0.4.3" 778 | source = "registry+https://github.com/rust-lang/crates.io-index" 779 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" 780 | dependencies = [ 781 | "getrandom", 782 | "redox_syscall 0.2.16", 783 | "thiserror", 784 | ] 785 | 786 | [[package]] 787 | name = "regex" 788 | version = "1.8.1" 789 | source = "registry+https://github.com/rust-lang/crates.io-index" 790 | checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" 791 | dependencies = [ 792 | "aho-corasick", 793 | "memchr", 794 | "regex-syntax", 795 | ] 796 | 797 | [[package]] 798 | name = "regex-syntax" 799 | version = "0.7.1" 800 | source = "registry+https://github.com/rust-lang/crates.io-index" 801 | checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" 802 | 803 | [[package]] 804 | name = "rust-ini" 805 | version = "0.18.0" 806 | source = "registry+https://github.com/rust-lang/crates.io-index" 807 | checksum = "f6d5f2436026b4f6e79dc829837d467cc7e9a55ee40e750d716713540715a2df" 808 | dependencies = [ 809 | "cfg-if", 810 | "ordered-multimap", 811 | ] 812 | 813 | [[package]] 814 | name = "rustix" 815 | version = "0.37.19" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" 818 | dependencies = [ 819 | "bitflags 1.3.2", 820 | "errno", 821 | "io-lifetimes", 822 | "libc", 823 | "linux-raw-sys", 824 | "windows-sys 0.48.0", 825 | ] 826 | 827 | [[package]] 828 | name = "scopeguard" 829 | version = "1.1.0" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" 832 | 833 | [[package]] 834 | name = "serde" 835 | version = "1.0.163" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" 838 | dependencies = [ 839 | "serde_derive", 840 | ] 841 | 842 | [[package]] 843 | name = "serde_derive" 844 | version = "1.0.163" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" 847 | dependencies = [ 848 | "proc-macro2", 849 | "quote", 850 | "syn 2.0.16", 851 | ] 852 | 853 | [[package]] 854 | name = "serde_repr" 855 | version = "0.1.12" 856 | source = "registry+https://github.com/rust-lang/crates.io-index" 857 | checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab" 858 | dependencies = [ 859 | "proc-macro2", 860 | "quote", 861 | "syn 2.0.16", 862 | ] 863 | 864 | [[package]] 865 | name = "sha1" 866 | version = "0.10.5" 867 | source = "registry+https://github.com/rust-lang/crates.io-index" 868 | checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" 869 | dependencies = [ 870 | "cfg-if", 871 | "cpufeatures", 872 | "digest", 873 | ] 874 | 875 | [[package]] 876 | name = "slab" 877 | version = "0.4.8" 878 | source = "registry+https://github.com/rust-lang/crates.io-index" 879 | checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" 880 | dependencies = [ 881 | "autocfg", 882 | ] 883 | 884 | [[package]] 885 | name = "smallvec" 886 | version = "1.10.0" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" 889 | 890 | [[package]] 891 | name = "socket2" 892 | version = "0.4.9" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" 895 | dependencies = [ 896 | "libc", 897 | "winapi", 898 | ] 899 | 900 | [[package]] 901 | name = "static_assertions" 902 | version = "1.1.0" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 905 | 906 | [[package]] 907 | name = "syn" 908 | version = "1.0.109" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 911 | dependencies = [ 912 | "proc-macro2", 913 | "quote", 914 | "unicode-ident", 915 | ] 916 | 917 | [[package]] 918 | name = "syn" 919 | version = "2.0.16" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" 922 | dependencies = [ 923 | "proc-macro2", 924 | "quote", 925 | "unicode-ident", 926 | ] 927 | 928 | [[package]] 929 | name = "sysinfo" 930 | version = "0.28.4" 931 | source = "registry+https://github.com/rust-lang/crates.io-index" 932 | checksum = "b4c2f3ca6693feb29a89724516f016488e9aafc7f37264f898593ee4b942f31b" 933 | dependencies = [ 934 | "cfg-if", 935 | "core-foundation-sys", 936 | "libc", 937 | "ntapi", 938 | "once_cell", 939 | "winapi", 940 | ] 941 | 942 | [[package]] 943 | name = "sysinfo-gui" 944 | version = "0.1.16" 945 | dependencies = [ 946 | "dark-light", 947 | "fltk", 948 | "fltk-extras", 949 | "parking_lot", 950 | "sysinfo", 951 | "winres", 952 | ] 953 | 954 | [[package]] 955 | name = "tempfile" 956 | version = "3.5.0" 957 | source = "registry+https://github.com/rust-lang/crates.io-index" 958 | checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" 959 | dependencies = [ 960 | "cfg-if", 961 | "fastrand", 962 | "redox_syscall 0.3.5", 963 | "rustix", 964 | "windows-sys 0.45.0", 965 | ] 966 | 967 | [[package]] 968 | name = "thiserror" 969 | version = "1.0.40" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" 972 | dependencies = [ 973 | "thiserror-impl", 974 | ] 975 | 976 | [[package]] 977 | name = "thiserror-impl" 978 | version = "1.0.40" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" 981 | dependencies = [ 982 | "proc-macro2", 983 | "quote", 984 | "syn 2.0.16", 985 | ] 986 | 987 | [[package]] 988 | name = "toml" 989 | version = "0.5.11" 990 | source = "registry+https://github.com/rust-lang/crates.io-index" 991 | checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" 992 | dependencies = [ 993 | "serde", 994 | ] 995 | 996 | [[package]] 997 | name = "toml_datetime" 998 | version = "0.6.2" 999 | source = "registry+https://github.com/rust-lang/crates.io-index" 1000 | checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" 1001 | 1002 | [[package]] 1003 | name = "toml_edit" 1004 | version = "0.19.9" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f" 1007 | dependencies = [ 1008 | "indexmap", 1009 | "toml_datetime", 1010 | "winnow", 1011 | ] 1012 | 1013 | [[package]] 1014 | name = "tracing" 1015 | version = "0.1.37" 1016 | source = "registry+https://github.com/rust-lang/crates.io-index" 1017 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 1018 | dependencies = [ 1019 | "cfg-if", 1020 | "pin-project-lite", 1021 | "tracing-attributes", 1022 | "tracing-core", 1023 | ] 1024 | 1025 | [[package]] 1026 | name = "tracing-attributes" 1027 | version = "0.1.24" 1028 | source = "registry+https://github.com/rust-lang/crates.io-index" 1029 | checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" 1030 | dependencies = [ 1031 | "proc-macro2", 1032 | "quote", 1033 | "syn 2.0.16", 1034 | ] 1035 | 1036 | [[package]] 1037 | name = "tracing-core" 1038 | version = "0.1.31" 1039 | source = "registry+https://github.com/rust-lang/crates.io-index" 1040 | checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" 1041 | dependencies = [ 1042 | "once_cell", 1043 | ] 1044 | 1045 | [[package]] 1046 | name = "ttf-parser" 1047 | version = "0.19.0" 1048 | source = "registry+https://github.com/rust-lang/crates.io-index" 1049 | checksum = "44dcf002ae3b32cd25400d6df128c5babec3927cd1eb7ce813cfff20eb6c3746" 1050 | 1051 | [[package]] 1052 | name = "typenum" 1053 | version = "1.16.0" 1054 | source = "registry+https://github.com/rust-lang/crates.io-index" 1055 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" 1056 | 1057 | [[package]] 1058 | name = "uds_windows" 1059 | version = "1.0.2" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d" 1062 | dependencies = [ 1063 | "tempfile", 1064 | "winapi", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "unicode-ident" 1069 | version = "1.0.8" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" 1072 | 1073 | [[package]] 1074 | name = "version_check" 1075 | version = "0.9.4" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 1078 | 1079 | [[package]] 1080 | name = "waker-fn" 1081 | version = "1.1.0" 1082 | source = "registry+https://github.com/rust-lang/crates.io-index" 1083 | checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" 1084 | 1085 | [[package]] 1086 | name = "wasi" 1087 | version = "0.11.0+wasi-snapshot-preview1" 1088 | source = "registry+https://github.com/rust-lang/crates.io-index" 1089 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 1090 | 1091 | [[package]] 1092 | name = "wasm-bindgen" 1093 | version = "0.2.86" 1094 | source = "registry+https://github.com/rust-lang/crates.io-index" 1095 | checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" 1096 | dependencies = [ 1097 | "cfg-if", 1098 | "wasm-bindgen-macro", 1099 | ] 1100 | 1101 | [[package]] 1102 | name = "wasm-bindgen-backend" 1103 | version = "0.2.86" 1104 | source = "registry+https://github.com/rust-lang/crates.io-index" 1105 | checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" 1106 | dependencies = [ 1107 | "bumpalo", 1108 | "log", 1109 | "once_cell", 1110 | "proc-macro2", 1111 | "quote", 1112 | "syn 2.0.16", 1113 | "wasm-bindgen-shared", 1114 | ] 1115 | 1116 | [[package]] 1117 | name = "wasm-bindgen-macro" 1118 | version = "0.2.86" 1119 | source = "registry+https://github.com/rust-lang/crates.io-index" 1120 | checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" 1121 | dependencies = [ 1122 | "quote", 1123 | "wasm-bindgen-macro-support", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "wasm-bindgen-macro-support" 1128 | version = "0.2.86" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" 1131 | dependencies = [ 1132 | "proc-macro2", 1133 | "quote", 1134 | "syn 2.0.16", 1135 | "wasm-bindgen-backend", 1136 | "wasm-bindgen-shared", 1137 | ] 1138 | 1139 | [[package]] 1140 | name = "wasm-bindgen-shared" 1141 | version = "0.2.86" 1142 | source = "registry+https://github.com/rust-lang/crates.io-index" 1143 | checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" 1144 | 1145 | [[package]] 1146 | name = "web-sys" 1147 | version = "0.3.63" 1148 | source = "registry+https://github.com/rust-lang/crates.io-index" 1149 | checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" 1150 | dependencies = [ 1151 | "js-sys", 1152 | "wasm-bindgen", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "winapi" 1157 | version = "0.3.9" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 1160 | dependencies = [ 1161 | "winapi-i686-pc-windows-gnu", 1162 | "winapi-x86_64-pc-windows-gnu", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "winapi-i686-pc-windows-gnu" 1167 | version = "0.4.0" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1170 | 1171 | [[package]] 1172 | name = "winapi-x86_64-pc-windows-gnu" 1173 | version = "0.4.0" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1176 | 1177 | [[package]] 1178 | name = "windows-sys" 1179 | version = "0.45.0" 1180 | source = "registry+https://github.com/rust-lang/crates.io-index" 1181 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 1182 | dependencies = [ 1183 | "windows-targets 0.42.2", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "windows-sys" 1188 | version = "0.48.0" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" 1191 | dependencies = [ 1192 | "windows-targets 0.48.0", 1193 | ] 1194 | 1195 | [[package]] 1196 | name = "windows-targets" 1197 | version = "0.42.2" 1198 | source = "registry+https://github.com/rust-lang/crates.io-index" 1199 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" 1200 | dependencies = [ 1201 | "windows_aarch64_gnullvm 0.42.2", 1202 | "windows_aarch64_msvc 0.42.2", 1203 | "windows_i686_gnu 0.42.2", 1204 | "windows_i686_msvc 0.42.2", 1205 | "windows_x86_64_gnu 0.42.2", 1206 | "windows_x86_64_gnullvm 0.42.2", 1207 | "windows_x86_64_msvc 0.42.2", 1208 | ] 1209 | 1210 | [[package]] 1211 | name = "windows-targets" 1212 | version = "0.48.0" 1213 | source = "registry+https://github.com/rust-lang/crates.io-index" 1214 | checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" 1215 | dependencies = [ 1216 | "windows_aarch64_gnullvm 0.48.0", 1217 | "windows_aarch64_msvc 0.48.0", 1218 | "windows_i686_gnu 0.48.0", 1219 | "windows_i686_msvc 0.48.0", 1220 | "windows_x86_64_gnu 0.48.0", 1221 | "windows_x86_64_gnullvm 0.48.0", 1222 | "windows_x86_64_msvc 0.48.0", 1223 | ] 1224 | 1225 | [[package]] 1226 | name = "windows_aarch64_gnullvm" 1227 | version = "0.42.2" 1228 | source = "registry+https://github.com/rust-lang/crates.io-index" 1229 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" 1230 | 1231 | [[package]] 1232 | name = "windows_aarch64_gnullvm" 1233 | version = "0.48.0" 1234 | source = "registry+https://github.com/rust-lang/crates.io-index" 1235 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" 1236 | 1237 | [[package]] 1238 | name = "windows_aarch64_msvc" 1239 | version = "0.42.2" 1240 | source = "registry+https://github.com/rust-lang/crates.io-index" 1241 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" 1242 | 1243 | [[package]] 1244 | name = "windows_aarch64_msvc" 1245 | version = "0.48.0" 1246 | source = "registry+https://github.com/rust-lang/crates.io-index" 1247 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" 1248 | 1249 | [[package]] 1250 | name = "windows_i686_gnu" 1251 | version = "0.42.2" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" 1254 | 1255 | [[package]] 1256 | name = "windows_i686_gnu" 1257 | version = "0.48.0" 1258 | source = "registry+https://github.com/rust-lang/crates.io-index" 1259 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" 1260 | 1261 | [[package]] 1262 | name = "windows_i686_msvc" 1263 | version = "0.42.2" 1264 | source = "registry+https://github.com/rust-lang/crates.io-index" 1265 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" 1266 | 1267 | [[package]] 1268 | name = "windows_i686_msvc" 1269 | version = "0.48.0" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" 1272 | 1273 | [[package]] 1274 | name = "windows_x86_64_gnu" 1275 | version = "0.42.2" 1276 | source = "registry+https://github.com/rust-lang/crates.io-index" 1277 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" 1278 | 1279 | [[package]] 1280 | name = "windows_x86_64_gnu" 1281 | version = "0.48.0" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" 1284 | 1285 | [[package]] 1286 | name = "windows_x86_64_gnullvm" 1287 | version = "0.42.2" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" 1290 | 1291 | [[package]] 1292 | name = "windows_x86_64_gnullvm" 1293 | version = "0.48.0" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" 1296 | 1297 | [[package]] 1298 | name = "windows_x86_64_msvc" 1299 | version = "0.42.2" 1300 | source = "registry+https://github.com/rust-lang/crates.io-index" 1301 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" 1302 | 1303 | [[package]] 1304 | name = "windows_x86_64_msvc" 1305 | version = "0.48.0" 1306 | source = "registry+https://github.com/rust-lang/crates.io-index" 1307 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" 1308 | 1309 | [[package]] 1310 | name = "winnow" 1311 | version = "0.4.6" 1312 | source = "registry+https://github.com/rust-lang/crates.io-index" 1313 | checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" 1314 | dependencies = [ 1315 | "memchr", 1316 | ] 1317 | 1318 | [[package]] 1319 | name = "winreg" 1320 | version = "0.10.1" 1321 | source = "registry+https://github.com/rust-lang/crates.io-index" 1322 | checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" 1323 | dependencies = [ 1324 | "winapi", 1325 | ] 1326 | 1327 | [[package]] 1328 | name = "winres" 1329 | version = "0.1.12" 1330 | source = "registry+https://github.com/rust-lang/crates.io-index" 1331 | checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" 1332 | dependencies = [ 1333 | "toml", 1334 | ] 1335 | 1336 | [[package]] 1337 | name = "zbus" 1338 | version = "3.10.0" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "f770930448dd412a4a7131dd968a8e6df0064db4d7916fbbd2d6c3f26b566938" 1341 | dependencies = [ 1342 | "async-broadcast", 1343 | "async-executor", 1344 | "async-io", 1345 | "async-lock", 1346 | "async-recursion", 1347 | "async-task", 1348 | "async-trait", 1349 | "byteorder", 1350 | "derivative", 1351 | "dirs", 1352 | "enumflags2", 1353 | "event-listener", 1354 | "futures-core", 1355 | "futures-sink", 1356 | "futures-util", 1357 | "hex", 1358 | "nix", 1359 | "once_cell", 1360 | "ordered-stream", 1361 | "rand", 1362 | "serde", 1363 | "serde_repr", 1364 | "sha1", 1365 | "static_assertions", 1366 | "tracing", 1367 | "uds_windows", 1368 | "winapi", 1369 | "zbus_macros", 1370 | "zbus_names", 1371 | "zvariant", 1372 | ] 1373 | 1374 | [[package]] 1375 | name = "zbus_macros" 1376 | version = "3.10.0" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "4832059b438689017db7340580ebabba07f114eab91bf990c6e55052408b40d8" 1379 | dependencies = [ 1380 | "proc-macro-crate", 1381 | "proc-macro2", 1382 | "quote", 1383 | "regex", 1384 | "syn 1.0.109", 1385 | ] 1386 | 1387 | [[package]] 1388 | name = "zbus_names" 1389 | version = "2.5.1" 1390 | source = "registry+https://github.com/rust-lang/crates.io-index" 1391 | checksum = "82441e6033be0a741157a72951a3e4957d519698f3a824439cc131c5ba77ac2a" 1392 | dependencies = [ 1393 | "serde", 1394 | "static_assertions", 1395 | "zvariant", 1396 | ] 1397 | 1398 | [[package]] 1399 | name = "zvariant" 1400 | version = "3.14.0" 1401 | source = "registry+https://github.com/rust-lang/crates.io-index" 1402 | checksum = "622cc473f10cef1b0d73b7b34a266be30ebdcfaea40ec297dd8cbda088f9f93c" 1403 | dependencies = [ 1404 | "byteorder", 1405 | "enumflags2", 1406 | "libc", 1407 | "serde", 1408 | "static_assertions", 1409 | "zvariant_derive", 1410 | ] 1411 | 1412 | [[package]] 1413 | name = "zvariant_derive" 1414 | version = "3.14.0" 1415 | source = "registry+https://github.com/rust-lang/crates.io-index" 1416 | checksum = "5d9c1b57352c25b778257c661f3c4744b7cefb7fc09dd46909a153cce7773da2" 1417 | dependencies = [ 1418 | "proc-macro-crate", 1419 | "proc-macro2", 1420 | "quote", 1421 | "syn 1.0.109", 1422 | "zvariant_utils", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "zvariant_utils" 1427 | version = "1.0.1" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "7234f0d811589db492d16893e3f21e8e2fd282e6d01b0cddee310322062cc200" 1430 | dependencies = [ 1431 | "proc-macro2", 1432 | "quote", 1433 | "syn 1.0.109", 1434 | ] 1435 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sysinfo-gui" 3 | version = "0.1.17" 4 | edition = "2021" 5 | repository = "https://github.com/MoAlyousef/sysinfo-gui" 6 | keywords = ["cross-platform", "monitoring", "gui"] 7 | license = "MIT" 8 | categories = ["visualization"] 9 | description = "A cross-platform system-monitoring gui application based on sysinfo and fltk" 10 | documentation = "https://docs.rs/sysinfo-gui" 11 | readme = "README.md" 12 | build = "build.rs" 13 | 14 | [package.metadata.bundle] 15 | identifier = "io.github.moalyousef" 16 | icon = ["assets/icon.png"] 17 | 18 | [dependencies] 19 | sysinfo = { version = "0.28", default-features = false } 20 | fltk = "1.3.16" 21 | fltk-extras = "0.1" 22 | parking_lot = "0.12" 23 | dark-light = { version = "0.2.2", optional = true } 24 | 25 | [target.'cfg(target_os = "windows")'.build-dependencies] 26 | winres = "0.1" 27 | 28 | [profile.release] 29 | opt-level = 3 30 | strip = true 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sysinfo-gui 2 | 3 | ![alt_test](https://github.com/MoAlyousef/sysinfo-gui/raw/main/assets/icon.png) 4 | 5 | A lightweight cross-platform system-monitoring [fltk](https://github.com/fltk-rs/fltk-rs) gui application based on [sysinfo](https://github.com/GuillaumeGomez/sysinfo). 6 | 7 | The UI design is inspired by [stacer](https://github.com/oguzhaninan/Stacer). 8 | 9 | The svg icons are taken from: https://icons.getbootstrap.com/. The ascending and descending icons from https://www.svgrepo.com/. 10 | 11 | The font is Roboto Medium. 12 | 13 | ## Screenshots 14 | 15 | - Dashboard 16 | ![image](https://user-images.githubusercontent.com/37966791/209539808-dba1412c-a38f-4fdd-b143-9d991d1e4e49.png) 17 | 18 | - Processes 19 | ![image](https://user-images.githubusercontent.com/37966791/209539668-3dcc559b-d9ad-47f3-9055-c2216e29fac5.png) 20 | 21 | - Cpu 22 | ![image](https://user-images.githubusercontent.com/37966791/209539860-8d28adf5-13de-4a0b-8600-fbeed6be95bc.png) 23 | 24 | - Memory 25 | ![image](https://user-images.githubusercontent.com/37966791/209539910-845c082b-6e0b-4467-b00e-167fe15fa010.png) 26 | 27 | - Disk info 28 | ![image](https://user-images.githubusercontent.com/37966791/209539970-521037b9-6fd1-495f-a92f-c42daeb56d70.png) 29 | 30 | - Networking 31 | ![image](https://user-images.githubusercontent.com/37966791/209540014-1421639c-6430-490a-9c75-74c40228717f.png) 32 | 33 | - Settings 34 | ![image](https://user-images.githubusercontent.com/37966791/209540135-5a390e60-849c-4b93-b05a-a411924642e2.png) 35 | 36 | ## Features 37 | - Supports window transparency. 38 | - Realtime monitoring. 39 | - End processes by sending a kill signal in the processes view. 40 | - Both dark and light modes. 41 | ![image](https://user-images.githubusercontent.com/37966791/209540190-4fd60269-34ad-4775-85f2-3b64be5763f1.png) 42 | 43 | ## Getting the application: 44 | 45 | - Prebuilt standalone releases: 46 | 47 | These are built using github actions, and can be found here: 48 | https://github.com/MoAlyousef/sysinfo-gui/releases 49 | 50 | - You can use cargo to install the application: 51 | `cargo install sysinfo-gui` 52 | 53 | ## Building from source: 54 | 55 | You can clone the repo and build using: 56 | `cargo build --release` 57 | 58 | If you would like to use the bundled version of fltk-rs (for supported platforms (x86_64 windows, macos and linux)): 59 | `cargo build --features=fltk/fltk-bundled --release` 60 | 61 | ## TODO 62 | - Support more things in the right click popup menu in the processes view. 63 | - Map uid to User and display a user name in the processes view. 64 | - Add downloand and upload speed. 65 | - Use better colors for the cpus. 66 | - Add more setting tweaks. 67 | -------------------------------------------------------------------------------- /assets/Roboto-Medium.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoAlyousef/sysinfo-gui/95c70af48023cc95eb03deb46c605b403fdb0804/assets/Roboto-Medium.ttf -------------------------------------------------------------------------------- /assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoAlyousef/sysinfo-gui/95c70af48023cc95eb03deb46c605b403fdb0804/assets/icon.ico -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MoAlyousef/sysinfo-gui/95c70af48023cc95eb03deb46c605b403fdb0804/assets/icon.png -------------------------------------------------------------------------------- /assets/sysinfo-gui.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=sysinfo-gui 4 | Comment=A cross-platform system-monitoring gui application based on sysinfo and fltk 5 | Exec=sysinfo-gui 6 | Icon=icon 7 | Terminal=false 8 | Categories=System; -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | #[cfg(target_os = "windows")] 2 | fn main() { 3 | let mut res = winres::WindowsResource::new(); 4 | res.set_icon("assets/icon.ico"); 5 | res.compile().unwrap(); 6 | } 7 | 8 | #[cfg(not(target_os = "windows"))] 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /src/gui/app.rs: -------------------------------------------------------------------------------- 1 | use super::styles::colors::*; 2 | use super::styles::svgs::*; 3 | use super::widgets::*; 4 | use super::{message::Message, View}; 5 | use fltk::{enums::*, prelude::*, *}; 6 | 7 | const ICON: &[u8] = include_bytes!("../../assets/icon.png"); 8 | 9 | pub struct App { 10 | a: app::App, 11 | r: app::Receiver, 12 | main_view: group::Flex, 13 | } 14 | 15 | impl App { 16 | pub fn new() -> Self { 17 | std::panic::set_hook(Box::new(|info| { 18 | if let Some(s) = info.payload().downcast_ref::<&str>() { 19 | // we shamefully use those to end spawned threads 20 | if !s.contains("self.was_deleted") { 21 | fltk::dialog::message_default(s); 22 | } 23 | } else if let Some(s) = info.payload().downcast_ref::() { 24 | if !s.contains("self.was_deleted") { 25 | fltk::dialog::message_default(s); 26 | } 27 | } else { 28 | fltk::dialog::message_default(&format!("{:?}", info)); 29 | } 30 | })); 31 | let a = app::App::default(); 32 | let (r, g, b) = GRAY.to_rgb(); 33 | app::background(r, g, b); 34 | app::foreground(255, 255, 255); 35 | app::set_frame_type2(FrameType::UpBox, FrameType::FlatBox); 36 | let (r, g, b) = SEL_BLUE.to_rgb(); 37 | app::set_selection_color(r, g, b); 38 | app::set_font_size(16); 39 | misc::Tooltip::set_color(Color::from_rgb(0xFF, 0xFF, 0xF0)); 40 | misc::Tooltip::set_font_size(app::font_size() - 4); 41 | let temp = std::env::temp_dir().join("Roboto-Medium.ttf"); 42 | if !temp.exists() { 43 | let bytes = include_bytes!("../../assets/Roboto-Medium.ttf"); 44 | std::fs::write(&temp, bytes).ok(); 45 | } 46 | if let Ok(f) = Font::load_font(temp) { 47 | Font::set_font(Font::Helvetica, &f); 48 | } 49 | let (s, r) = app::channel(); 50 | let mut win = window::Window::default() 51 | .with_size(800, 600) 52 | .with_label("sysinfo-gui"); 53 | win.set_xclass("sysinfo"); 54 | win.set_icon(Some(image::PngImage::from_data(ICON).unwrap())); 55 | let mut main_col = group::Column::default_fill(); 56 | main_col.set_pad(0); 57 | let mut grp = group::Group::default() 58 | .with_label("\tSysinfo") 59 | .with_align(Align::Left | Align::Inside); 60 | main_col.set_size(&grp, 50); 61 | grp.set_label_color(Color::White); 62 | grp.set_label_size(app::font_size() + 5); 63 | grp.set_frame(FrameType::FlatBox); 64 | grp.set_color(BLUE); 65 | grp.end(); 66 | let mut main_row = group::Row::default_fill(); 67 | main_row.set_pad(0); 68 | let mut col = group::Column::default(); 69 | main_row.set_size(&*col, 60); 70 | col.set_frame(FrameType::FlatBox); 71 | col.set_color(BLUE); 72 | col.set_pad(10); 73 | SvgButton::new(""); 74 | SvgButton::new(GENERAL) 75 | .with_tooltip("Home") 76 | .toggled(true) 77 | .emit(s, Message::General); 78 | SvgButton::new(LIST) 79 | .with_tooltip("Processes") 80 | .emit(s, Message::Procs); 81 | SvgButton::new(PROC) 82 | .with_tooltip("Processors info") 83 | .emit(s, Message::Proc); 84 | SvgButton::new(MEMORY) 85 | .with_tooltip("Memory info") 86 | .emit(s, Message::Memory); 87 | SvgButton::new(DISKS) 88 | .with_tooltip("Disks info") 89 | .emit(s, Message::Disks); 90 | SvgButton::new(NET) 91 | .with_tooltip("Network info") 92 | .emit(s, Message::Net); 93 | SvgButton::new(WRENCH) 94 | .with_tooltip("Settings") 95 | .emit(s, Message::Settings); 96 | SvgButton::new(ABOUT) 97 | .with_tooltip("About") 98 | .emit(s, Message::Info); 99 | col.end(); 100 | let mut main_view = group::Flex::default().column(); 101 | main_view.set_margin(50); 102 | main_view.end(); 103 | main_row.end(); 104 | main_col.end(); 105 | win.end(); 106 | win.resizable(&main_view); 107 | win.size_range(800, 600, 0, 0); 108 | win.show(); 109 | win.set_callback(|w| { 110 | if app::event() == Event::Close { 111 | w.hide(); 112 | } 113 | }); 114 | Self { a, r, main_view } 115 | } 116 | pub fn run(mut self, view: impl View + 'static) { 117 | self.main_view.begin(); 118 | let cb = view.view(Message::General); 119 | Self::dispatch(cb, view.sleep_duration()); 120 | self.main_view.end(); 121 | while self.a.wait() { 122 | if let Some(msg) = self.r.recv() { 123 | self.main_view.clear(); 124 | self.main_view.begin(); 125 | let cb = view.view(msg); 126 | Self::dispatch(cb, view.sleep_duration()); 127 | self.main_view.end(); 128 | app::redraw(); 129 | } 130 | } 131 | } 132 | fn dispatch(cb: Option>, sleep: u64) { 133 | if let Some(mut cb) = cb { 134 | std::thread::spawn({ 135 | move || loop { 136 | cb(); 137 | std::thread::sleep(std::time::Duration::from_millis(sleep)); 138 | } 139 | }); 140 | } 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /src/gui/message.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] 2 | pub enum Message { 3 | General, 4 | Disks, 5 | Proc, 6 | Memory, 7 | Procs, 8 | Net, 9 | Settings, 10 | Info, 11 | } 12 | -------------------------------------------------------------------------------- /src/gui/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod app; 2 | pub mod message; 3 | pub mod styles; 4 | pub mod widgets; 5 | 6 | pub trait View { 7 | fn view(&self, msg: message::Message) -> Option>; 8 | fn sleep_duration(&self) -> u64; 9 | fn light_mode(&self) -> bool; 10 | } 11 | -------------------------------------------------------------------------------- /src/gui/styles/colors.rs: -------------------------------------------------------------------------------- 1 | use fltk::enums::Color; 2 | 3 | pub const BLUE: Color = Color::from_hex(0x0d47a1); 4 | pub const SEL_BLUE: Color = Color::from_hex(0x1a56b7); 5 | pub const GRAY: Color = Color::from_hex(0x323232); 6 | pub const CPU_GREEN: Color = Color::from_hex(0x82c74b); 7 | pub const DISK_PURPLE: Color = Color::from_hex(0xae3361); 8 | pub const MEM_YELLOW: Color = Color::from_hex(0xf6a22f); 9 | -------------------------------------------------------------------------------- /src/gui/styles/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod colors; 2 | pub mod svgs; 3 | -------------------------------------------------------------------------------- /src/gui/styles/svgs.rs: -------------------------------------------------------------------------------- 1 | pub const GENERAL: &str = r#" 2 | 3 | 4 | "#; 5 | 6 | pub const LIST: &str = r#" 7 | 8 | "#; 9 | 10 | pub const WRENCH: &str = r#" 11 | 12 | 13 | "#; 14 | 15 | pub const MEMORY: &str = r#" 16 | 17 | 18 | "#; 19 | 20 | pub const DISKS: &str = r#" 21 | 22 | 23 | "#; 24 | 25 | pub const PROC: &str = r#" 26 | 27 | "#; 28 | 29 | pub const NET: &str = r#" 30 | 31 | 32 | "#; 33 | 34 | pub const DESC: &str = r#" 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | "#; 43 | 44 | pub const ASC: &str = r#" 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | "#; 53 | 54 | pub const ABOUT: &str = r#" 55 | 56 | 57 | "#; 58 | -------------------------------------------------------------------------------- /src/gui/widgets/mod.rs: -------------------------------------------------------------------------------- 1 | mod svg_button; 2 | pub use svg_button::*; 3 | -------------------------------------------------------------------------------- /src/gui/widgets/svg_button.rs: -------------------------------------------------------------------------------- 1 | use crate::gui::styles::colors::*; 2 | use fltk::{enums::*, prelude::*, *}; 3 | 4 | pub struct SvgButton { 5 | btn: button::RadioButton, 6 | } 7 | 8 | impl SvgButton { 9 | pub fn new(svg: &str) -> SvgButton { 10 | let mut btn = button::RadioButton::new(0, 0, 50, 50, None); 11 | btn.set_frame(FrameType::FlatBox); 12 | btn.set_down_frame(FrameType::FlatBox); 13 | btn.set_color(BLUE); 14 | btn.set_selection_color(SEL_BLUE); 15 | btn.clear_visible_focus(); 16 | if let Ok(mut image) = image::SvgImage::from_data(svg) { 17 | image.scale(30, 30, true, true); 18 | btn.set_image(Some(image)); 19 | } 20 | Self { btn } 21 | } 22 | 23 | pub fn with_tooltip(mut self, label: &str) -> Self { 24 | self.btn.set_tooltip(label); 25 | self 26 | } 27 | 28 | pub fn toggled(mut self, flag: bool) -> Self { 29 | self.btn.toggle(flag); 30 | self 31 | } 32 | } 33 | 34 | fltk::widget_extends!(SvgButton, button::RadioButton, btn); 35 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] 2 | #![doc = include_str!("../README.md")] 3 | 4 | mod gui; 5 | mod utils; 6 | mod view; 7 | 8 | fn main() { 9 | gui::app::App::new().run(view::MyView::default()); 10 | } 11 | -------------------------------------------------------------------------------- /src/utils.rs: -------------------------------------------------------------------------------- 1 | use fltk::{prelude::*, *}; 2 | 3 | pub fn scroll_resize_cb(s: &mut group::Scroll, x: i32, y: i32, w: i32, h: i32) { 4 | let mut c = s.child(0).unwrap(); 5 | c.resize(x, y, w, h); 6 | } 7 | 8 | pub fn fix_scroll_cb(s: &mut group::Scroll) { 9 | let mut scrollbar = s.scrollbar(); 10 | // To work around Card resizing on macos 11 | scrollbar.set_callback({ 12 | let mut old_cb = scrollbar.callback(); 13 | move |s| { 14 | if let Some(cb) = old_cb.as_mut() { 15 | (*cb)(); 16 | } 17 | s.parent().unwrap().redraw(); 18 | } 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /src/view/cpu.rs: -------------------------------------------------------------------------------- 1 | use super::MyView; 2 | use fltk::{enums::*, prelude::*, *}; 3 | use fltk_extras::card::Card; 4 | use parking_lot::Mutex; 5 | use std::collections::VecDeque; 6 | use std::sync::Arc; 7 | use sysinfo::CpuExt; 8 | use sysinfo::System; 9 | use sysinfo::SystemExt; 10 | 11 | mod cpu_color { 12 | #![allow(non_upper_case_globals)] 13 | use fltk::enums::Color; 14 | 15 | const Col0: Color = Color::from_rgb(255, 0, 0); 16 | const Col1: Color = Color::from_rgb(255, 127, 0); 17 | const Col2: Color = Color::from_rgb(255, 212, 0); 18 | const Col3: Color = Color::from_rgb(255, 255, 0); 19 | const Col4: Color = Color::from_rgb(191, 255, 0); 20 | const Col5: Color = Color::from_rgb(106, 255, 0); 21 | const Col6: Color = Color::from_rgb(0, 234, 255); 22 | const Col7: Color = Color::from_rgb(0, 149, 255); 23 | const Col8: Color = Color::from_rgb(0, 64, 255); 24 | const Col9: Color = Color::from_rgb(170, 0, 255); 25 | const Col10: Color = Color::from_rgb(255, 0, 170); 26 | const Col11: Color = Color::from_rgb(237, 185, 185); 27 | const Col12: Color = Color::from_rgb(231, 233, 185); 28 | const Col13: Color = Color::from_rgb(185, 237, 224); 29 | const Col14: Color = Color::from_rgb(185, 215, 237); 30 | const Col15: Color = Color::from_rgb(220, 185, 237); 31 | const Col16: Color = Color::from_rgb(143, 35, 35); 32 | const Col17: Color = Color::from_rgb(143, 106, 35); 33 | const Col18: Color = Color::from_rgb(79, 143, 35); 34 | const Col19: Color = Color::from_rgb(35, 98, 143); 35 | const Col20: Color = Color::from_rgb(107, 35, 143); 36 | const Col21: Color = Color::from_rgb(115, 115, 115); 37 | const Col22: Color = Color::from_rgb(204, 204, 204); 38 | 39 | pub fn by_index(idx: u8) -> Color { 40 | match idx { 41 | 0 => Col0, 42 | 1 => Col1, 43 | 2 => Col2, 44 | 3 => Col3, 45 | 4 => Col4, 46 | 5 => Col5, 47 | 6 => Col6, 48 | 7 => Col7, 49 | 8 => Col8, 50 | 9 => Col9, 51 | 10 => Col10, 52 | 11 => Col11, 53 | 12 => Col12, 54 | 13 => Col13, 55 | 14 => Col14, 56 | 15 => Col15, 57 | 16 => Col16, 58 | 17 => Col17, 59 | 18 => Col18, 60 | 19 => Col19, 61 | 20 => Col20, 62 | 21 => Col21, 63 | 22 => Col22, 64 | _ => Color::by_index(idx), 65 | } 66 | } 67 | } 68 | 69 | pub fn proc(view: &MyView) -> Option> { 70 | let mut sys = view.system.lock(); 71 | sys.refresh_cpu(); 72 | let first = sys.cpus().first().unwrap(); 73 | let vendor_id = first.vendor_id().to_string(); 74 | let t = Card::default().with_label(first.brand()); 75 | let mut parent = group::Flex::from_dyn_widget(&t.parent().unwrap()).unwrap(); 76 | parent.set_size(&*t, 60); 77 | t.begin(); 78 | let mut f = frame::Frame::default().with_size(80, 30).center_of_parent(); 79 | t.end(); 80 | let g = group::Group::default().with_size(400, 300); 81 | let mut num_cpus = 0; 82 | let mut c = misc::Chart::default_fill(); 83 | c.set_color(Color::color_average(c.color(), Color::Foreground, 0.9)); 84 | c.set_bounds(0., 100.); 85 | c.set_type(misc::ChartType::Line); 86 | c.add(50.0, "50%", Color::Foreground); 87 | for _ in 1..20 { 88 | c.add(50.0, "", Color::Foreground); 89 | } 90 | c.set_text_color(Color::Foreground); 91 | let mut charts = vec![]; 92 | for proc in sys.cpus() { 93 | let mut c = misc::Chart::default_fill(); 94 | c.set_bounds(0., 100.); 95 | c.set_type(misc::ChartType::Line); 96 | c.set_frame(FrameType::NoBox); 97 | let name = proc.name().to_string(); 98 | c.draw(move |c| { 99 | let row = num_cpus / 8; 100 | let col = num_cpus % 8; 101 | draw::draw_rect_fill( 102 | (55 * col) + c.x() + 5, 103 | c.y() + row * 15 + 5, 104 | 10, 105 | 10, 106 | cpu_color::by_index(num_cpus as u8), 107 | ); 108 | draw::set_font(Font::Helvetica, 12); 109 | draw::set_draw_color(Color::Foreground); 110 | draw::draw_text2( 111 | &name, 112 | (55 * col) + c.x() + 20, 113 | c.y() + row * 15 + 5, 114 | 10, 115 | 10, 116 | Align::Left | Align::Inside, 117 | ); 118 | }); 119 | charts.push(c); 120 | num_cpus += 1; 121 | } 122 | f.set_label(&format!("Vendor ID: {}\nCores: {}", vendor_id, num_cpus)); 123 | for c in &mut charts { 124 | for _ in 0..18 { 125 | c.add(0., "", Color::Red); 126 | } 127 | } 128 | g.end(); 129 | let charts = Arc::new(Mutex::new(charts)); 130 | let sys = Arc::new(Mutex::new(System::new_all())); 131 | let mut v = vec![]; 132 | for _ in 0..num_cpus { 133 | let mut d = VecDeque::new(); 134 | for _ in 0..20 { 135 | d.push_back(0.); 136 | } 137 | v.push(d); 138 | } 139 | let cb = move || { 140 | if let Some(mut sys) = sys.try_lock() { 141 | sys.refresh_cpu(); 142 | for (i, proc) in sys.cpus().iter().enumerate() { 143 | v[i].push_back(proc.cpu_usage() as f64); 144 | v[i].pop_front(); 145 | } 146 | for (count, c) in (*charts.lock()).iter_mut().enumerate() { 147 | for i in 1..20 { 148 | let last = if let Some(val) = v[count].get(i) { 149 | *val 150 | } else { 151 | 0. 152 | }; 153 | c.replace((i - 1) as i32, last, "", cpu_color::by_index(count as u8)); 154 | } 155 | } 156 | app::awake(); 157 | app::redraw(); 158 | } 159 | }; 160 | Some(Box::new(cb)) 161 | } 162 | -------------------------------------------------------------------------------- /src/view/disk.rs: -------------------------------------------------------------------------------- 1 | use super::MyView; 2 | use crate::gui::styles::colors::*; 3 | use crate::utils; 4 | use fltk::{prelude::*, *}; 5 | use fltk_extras::card::Card; 6 | use fltk_extras::dial::Dial; 7 | use sysinfo::DiskExt; 8 | use sysinfo::SystemExt; 9 | 10 | pub fn disks(view: &MyView) -> Option> { 11 | let mut sys = view.system.lock(); 12 | sys.refresh_disks(); 13 | let mut scroll = group::Scroll::default_fill().with_type(group::ScrollType::Vertical); 14 | scroll.resize_callback(utils::scroll_resize_cb); 15 | scroll.set_scrollbar_size(-1); 16 | utils::fix_scroll_cb(&mut scroll); 17 | let mut vpack = group::Pack::default() 18 | .with_size(300, 300) 19 | .with_type(group::PackType::Vertical) 20 | .center_of_parent(); 21 | vpack.set_spacing(50); 22 | frame::Frame::default().with_size(0, 30); 23 | for disk in sys.disks() { 24 | let mut row = group::Flex::default().row().with_size(0, 130); 25 | row.set_margin(10); 26 | let t = Card::default() 27 | .with_size(300, 130) 28 | .with_label(disk.name().to_str().unwrap()); 29 | t.begin(); 30 | let vpack = group::Pack::default() 31 | .with_size(130, 130) 32 | .center_of_parent(); 33 | let mut f = frame::Frame::default() 34 | .with_size(80, 35) 35 | .with_label(disk.mount_point().to_str().unwrap()); 36 | f.set_label_size(14); 37 | frame::Frame::default() 38 | .with_size(80, 35) 39 | .with_label(&format!( 40 | "{:?}: {} - Space: {:.02} GiB", 41 | disk.type_(), 42 | String::from_utf8(disk.file_system().to_vec()).unwrap(), 43 | disk.total_space() as f64 / 2_f64.powf(30.) 44 | )); 45 | frame::Frame::default() 46 | .with_size(80, 35) 47 | .with_label(&format!( 48 | "Removable: {}", 49 | if disk.is_removable() { "Yes" } else { "No" } 50 | )); 51 | vpack.end(); 52 | t.end(); 53 | let mut dial = Dial::default().with_label("Used space %"); 54 | row.set_size(&*dial, 120); 55 | dial.modifiable(false); 56 | dial.set_value( 57 | ((disk.total_space() - disk.available_space()) as f64 * 100. 58 | / disk.total_space() as f64) as i32, 59 | ); 60 | dial.set_selection_color(DISK_PURPLE); 61 | row.end(); 62 | } 63 | vpack.end(); 64 | scroll.end(); 65 | None 66 | } 67 | -------------------------------------------------------------------------------- /src/view/general.rs: -------------------------------------------------------------------------------- 1 | use super::MyView; 2 | use crate::gui::styles::colors::*; 3 | use fltk::{enums::*, prelude::*, *}; 4 | use fltk_extras::card::Card; 5 | use fltk_extras::dial::HalfDial; 6 | use parking_lot::Mutex; 7 | use std::sync::Arc; 8 | use sysinfo::{DiskExt, NetworkExt, NetworksExt, ProcessExt, System, SystemExt}; 9 | 10 | pub fn general(view: &MyView) -> Option> { 11 | let mut sys = view.system.lock(); 12 | sys.refresh_all(); 13 | let mem = (sys.used_memory() as f64 / sys.total_memory() as f64) * 100.; 14 | let mut total_space = 0; 15 | let mut avail_space = 0; 16 | for disk in sys.disks() { 17 | total_space += disk.total_space(); 18 | avail_space += disk.available_space(); 19 | } 20 | let used_space = ((total_space - avail_space) as f64 * 100. / total_space as f64) as i32; 21 | let mut cpu_usage = 0.; 22 | for process in sys.processes().values() { 23 | cpu_usage += process.cpu_usage(); 24 | } 25 | let mut dials = vec![]; 26 | let row = group::Flex::default().row(); 27 | let mut dial = HalfDial::default().with_size(200, 200).with_label("CPU %"); 28 | dial.set_value(cpu_usage as i32); 29 | dial.set_selection_color(CPU_GREEN); 30 | dials.push(dial); 31 | let mut dial = HalfDial::default() 32 | .with_size(200, 200) 33 | .with_label("Memory %"); 34 | dial.set_selection_color(MEM_YELLOW); 35 | dial.set_value(mem as i32); 36 | dials.push(dial); 37 | let mut dial = HalfDial::default().with_size(200, 200).with_label("Disk %"); 38 | dial.set_selection_color(DISK_PURPLE); 39 | dial.set_value(used_space); 40 | dials.push(dial); 41 | row.end(); 42 | let mut row = group::Flex::default().row(); 43 | let t = Card::default() 44 | .with_size(450, 250) 45 | .with_label("System info"); 46 | t.begin(); 47 | let mut pack = group::Pack::default().with_size(450, 300); 48 | pack.set_spacing(-15); 49 | frame::Frame::default() 50 | .with_align(Align::Left | Align::Inside) 51 | .with_size(80, 60) 52 | .with_label(&format!( 53 | "System name: {}", 54 | &sys.name().unwrap_or_else(|| "".to_owned()) 55 | )); 56 | frame::Frame::default() 57 | .with_align(Align::Left | Align::Inside) 58 | .with_size(80, 60) 59 | .with_label(&format!( 60 | "Kernel version: {}", 61 | &sys.kernel_version() 62 | .unwrap_or_else(|| "".to_owned()), 63 | )); 64 | frame::Frame::default() 65 | .with_align(Align::Left | Align::Inside) 66 | .with_size(80, 60) 67 | .with_label(&format!( 68 | "OS version: {}", 69 | &sys.os_version().unwrap_or_else(|| "".to_owned()) 70 | )); 71 | frame::Frame::default() 72 | .with_align(Align::Left | Align::Inside) 73 | .with_size(80, 60) 74 | .with_label(&format!( 75 | "Long OS version: {}", 76 | &sys.long_os_version() 77 | .unwrap_or_else(|| "".to_owned()) 78 | )); 79 | frame::Frame::default() 80 | .with_align(Align::Left | Align::Inside) 81 | .with_size(80, 60) 82 | .with_label(&format!( 83 | "Host name: {}", 84 | &sys.host_name().unwrap_or_else(|| "".to_owned()) 85 | )); 86 | t.end(); 87 | let mut vpack = group::Flex::default().column(); 88 | vpack.set_pad(30); 89 | row.set_size(&vpack, 160); 90 | let t = Card::default().with_size(200, 100).with_label("Download"); 91 | t.begin(); 92 | let mut download = frame::Frame::default() 93 | .with_align(Align::Left | Align::Inside) 94 | .with_size(80, 60) 95 | .with_label("0") 96 | .center_of_parent(); 97 | t.end(); 98 | let t = Card::default().with_size(200, 100).with_label("Upload"); 99 | t.begin(); 100 | let mut upload = frame::Frame::default() 101 | .with_align(Align::Left | Align::Inside) 102 | .with_size(80, 60) 103 | .with_label("0") 104 | .center_of_parent(); 105 | upload.set_align(Align::Center | Align::Wrap); 106 | t.end(); 107 | vpack.end(); 108 | pack.end(); 109 | t.end(); 110 | row.end(); 111 | drop(sys); 112 | let dials = Arc::new(Mutex::new(dials)); 113 | let sys = Arc::new(Mutex::new(System::new_all())); 114 | let cb = move || { 115 | if let Some(mut sys) = sys.try_lock() { 116 | sys.refresh_all(); 117 | let mem = (sys.used_memory() as f64 / sys.total_memory() as f64) * 100.; 118 | let mut total_space = 0; 119 | let mut avail_space = 0; 120 | for disk in sys.disks() { 121 | total_space += disk.total_space(); 122 | avail_space += disk.available_space(); 123 | } 124 | let used_space = 125 | ((total_space - avail_space) as f64 * 100. / total_space as f64) as i32; 126 | let mut cpu_usage = 0.; 127 | for process in sys.processes().values() { 128 | cpu_usage += process.cpu_usage(); 129 | } 130 | let mut total_recv = 0; 131 | let mut total_transm = 0; 132 | for comp in sys.networks().iter() { 133 | total_recv += comp.1.total_received(); 134 | total_transm += comp.1.total_transmitted(); 135 | } 136 | dials.lock()[0].set_value(cpu_usage as i32); 137 | dials.lock()[1].set_value(mem as i32); 138 | dials.lock()[2].set_value(used_space); 139 | download.set_label(&format!("{:.02} MiB", total_recv as f64 / 2_f64.powf(20.))); 140 | upload.set_label(&format!( 141 | "{:.02} Mib", 142 | total_transm as f64 / 2_f64.powf(20.) 143 | )); 144 | app::awake(); 145 | } 146 | }; 147 | Some(Box::new(cb)) 148 | } 149 | -------------------------------------------------------------------------------- /src/view/info.rs: -------------------------------------------------------------------------------- 1 | use crate::view::MyView; 2 | use fltk::{enums::*, prelude::*, *}; 3 | 4 | const INFO: &str = r#"Sysinfo-gui is a lightweight cross-platform system-monitoring 5 | fltk gui application based on 6 | sysinfo. 7 |
8 | Sysinfo-gui is MIT licensed. 9 | "#; 10 | 11 | pub fn info(_view: &MyView) -> Option> { 12 | let mut frame = misc::HelpView::default() 13 | .with_size(500, 300) 14 | .center_of_parent(); 15 | frame.set_frame(FrameType::FlatBox); 16 | frame.set_color(frame.parent().unwrap().color()); 17 | frame.set_value(INFO); 18 | frame.set_text_size(16); 19 | frame.set_text_font(Font::Helvetica); 20 | None 21 | } 22 | -------------------------------------------------------------------------------- /src/view/mem.rs: -------------------------------------------------------------------------------- 1 | use super::MyView; 2 | use crate::gui::styles::colors::MEM_YELLOW; 3 | use fltk::{prelude::*, *}; 4 | use fltk_extras::card::Card; 5 | use fltk_extras::dial::Dial; 6 | use parking_lot::Mutex; 7 | use std::sync::Arc; 8 | use sysinfo::System; 9 | use sysinfo::SystemExt; 10 | 11 | pub fn memory(view: &MyView) -> Option> { 12 | let mut sys = view.system.lock(); 13 | sys.refresh_memory(); 14 | let mut dials = vec![]; 15 | let mut scroll = group::Scroll::default_fill().with_type(group::ScrollType::Vertical); 16 | scroll.resize_callback(crate::utils::scroll_resize_cb); 17 | scroll.set_scrollbar_size(-1); 18 | crate::utils::fix_scroll_cb(&mut scroll); 19 | let mut vpack = group::Pack::default() 20 | .with_size(300, 300) 21 | .with_type(group::PackType::Vertical) 22 | .center_of_parent(); 23 | vpack.set_spacing(50); 24 | frame::Frame::default().with_size(0, 30); 25 | let mut row = group::Flex::default().with_size(0, 150).row(); 26 | let t = Card::default().with_label("Memory").with_size(300, 130); 27 | t.begin(); 28 | let pack = group::Pack::default() 29 | .with_size(300, 130) 30 | .center_of_parent(); 31 | frame::Frame::default() 32 | .with_size(0, 60) 33 | .with_label(&format!( 34 | "Total: {:.02} GiB", 35 | sys.total_memory() as f64 / 2_f64.powf(20.) 36 | )); 37 | let mut used_mem = frame::Frame::default() 38 | .with_size(0, 60) 39 | .with_label(&format!( 40 | "Used: {:.02} GiB", 41 | sys.used_memory() as f64 / 2_f64.powf(20.) 42 | )); 43 | pack.end(); 44 | t.end(); 45 | let mut dial = Dial::default().with_label("Memory Usage %"); 46 | row.set_size(&*dial, 150); 47 | dial.modifiable(false); 48 | dial.set_selection_color(MEM_YELLOW); 49 | dial.set_value((sys.used_memory() as f64 / sys.total_memory() as f64 * 100.) as i32); 50 | dials.push(dial); 51 | row.end(); 52 | let mut row = group::Flex::default().with_size(0, 150).row(); 53 | let t = Card::default().with_label("Swap").with_size(300, 130); 54 | t.begin(); 55 | let pack = group::Pack::default().with_size(300, 130); 56 | frame::Frame::default() 57 | .with_size(0, 60) 58 | .with_label(&format!( 59 | "Total: {:.02} GiB", 60 | sys.total_swap() as f64 / 2_f64.powf(20.) 61 | )); 62 | let mut used_swap = frame::Frame::default() 63 | .with_size(0, 60) 64 | .with_label(&format!( 65 | "Used: {:.02} GiB", 66 | sys.used_swap() as f64 / 2_f64.powf(20.) 67 | )); 68 | pack.end(); 69 | t.end(); 70 | let mut dial = Dial::default().with_label("Swap Usage %"); 71 | row.set_size(&*dial, 150); 72 | dial.modifiable(false); 73 | dial.set_selection_color(MEM_YELLOW); 74 | dial.set_value((sys.used_swap() as f64 / sys.total_swap() as f64 * 100.) as i32); 75 | dials.push(dial); 76 | row.end(); 77 | vpack.end(); 78 | scroll.end(); 79 | let dials = Arc::new(Mutex::new(dials)); 80 | let sys = Arc::new(Mutex::new(System::new_all())); 81 | let cb = move || { 82 | if let Some(mut sys) = sys.try_lock() { 83 | sys.refresh_memory(); 84 | dials.lock()[0] 85 | .set_value((sys.used_memory() as f64 / sys.total_memory() as f64 * 100.) as i32); 86 | used_mem.set_label(&format!( 87 | "Used: {:.02} GiB", 88 | sys.used_memory() as f64 / 2_f64.powf(20.) 89 | )); 90 | dials.lock()[1] 91 | .set_value((sys.used_swap() as f64 / sys.total_swap() as f64 * 100.) as i32); 92 | used_swap.set_label(&format!( 93 | "Used: {:.02} GiB", 94 | sys.used_swap() as f64 / 2_f64.powf(20.) 95 | )); 96 | app::awake(); 97 | } 98 | }; 99 | Some(Box::new(cb)) 100 | } 101 | -------------------------------------------------------------------------------- /src/view/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cpu; 2 | pub mod disk; 3 | pub mod general; 4 | pub mod info; 5 | pub mod mem; 6 | pub mod net; 7 | pub mod procs; 8 | pub mod settings; 9 | 10 | use crate::gui::{message::Message, styles::colors::GRAY, View}; 11 | use fltk::app; 12 | use parking_lot::Mutex; 13 | use std::sync::{ 14 | atomic::{AtomicBool, AtomicU64, Ordering}, 15 | Arc, 16 | }; 17 | use sysinfo::{System, SystemExt}; 18 | 19 | #[repr(i32)] 20 | #[derive(Debug, Clone, Copy, PartialEq)] 21 | enum SortOrder { 22 | Pid, 23 | Mem, 24 | Virt, 25 | Cpu, 26 | Exe, 27 | RevPid, 28 | RevMem, 29 | RevVirt, 30 | RevCpu, 31 | RevExe, 32 | } 33 | 34 | pub struct MyView { 35 | system: Arc>, 36 | sleep: Arc, 37 | light_mode: Arc, 38 | ordering: Arc>, 39 | } 40 | 41 | impl Default for MyView { 42 | fn default() -> Self { 43 | #[cfg(feature = "dark-light")] 44 | let mode = dark_light::detect() == dark_light::Mode::Light; 45 | #[cfg(not(feature = "dark-light"))] 46 | let mode = false; 47 | 48 | if mode { 49 | app::foreground(50, 50, 50); 50 | app::background(255, 255, 255); 51 | } else { 52 | app::foreground(255, 255, 255); 53 | let (r, g, b) = GRAY.to_rgb(); 54 | app::background(r, g, b); 55 | } 56 | let mut sys = System::new_all(); 57 | sys.refresh_all(); 58 | let system = Arc::new(Mutex::new(sys)); 59 | Self { 60 | system, 61 | sleep: Arc::new(AtomicU64::from(300)), 62 | light_mode: Arc::new(AtomicBool::from(mode)), 63 | ordering: Arc::new(Mutex::new(SortOrder::Pid)), 64 | } 65 | } 66 | } 67 | 68 | impl View for MyView { 69 | fn view(&self, msg: Message) -> Option> { 70 | match msg { 71 | Message::General => self.general(), 72 | Message::Disks => self.disks(), 73 | Message::Proc => self.cpu(), 74 | Message::Memory => self.memory(), 75 | Message::Procs => self.procs(), 76 | Message::Net => self.network(), 77 | Message::Settings => self.settings(), 78 | Message::Info => self.info(), 79 | } 80 | } 81 | fn sleep_duration(&self) -> u64 { 82 | self.sleep.load(Ordering::Relaxed) 83 | } 84 | fn light_mode(&self) -> bool { 85 | self.light_mode.load(Ordering::Relaxed) 86 | } 87 | } 88 | 89 | impl MyView { 90 | pub fn general(&self) -> Option> { 91 | general::general(self) 92 | } 93 | pub fn memory(&self) -> Option> { 94 | mem::memory(self) 95 | } 96 | pub fn settings(&self) -> Option> { 97 | settings::settings(self) 98 | } 99 | pub fn network(&self) -> Option> { 100 | net::network(self) 101 | } 102 | pub fn cpu(&self) -> Option> { 103 | cpu::proc(self) 104 | } 105 | pub fn disks(&self) -> Option> { 106 | disk::disks(self) 107 | } 108 | pub fn procs(&self) -> Option> { 109 | procs::procs(self) 110 | } 111 | pub fn info(&self) -> Option> { 112 | info::info(self) 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /src/view/net.rs: -------------------------------------------------------------------------------- 1 | use super::MyView; 2 | use crate::utils; 3 | use fltk::{prelude::*, *}; 4 | use fltk_extras::card::Card; 5 | use parking_lot::Mutex; 6 | use std::sync::{atomic::Ordering, Arc}; 7 | use sysinfo::NetworkExt; 8 | use sysinfo::NetworksExt; 9 | use sysinfo::System; 10 | use sysinfo::SystemExt; 11 | 12 | pub fn network(view: &MyView) -> Option> { 13 | let mut sys = view.system.lock(); 14 | sys.refresh_networks(); 15 | let mut frames = vec![]; 16 | let mut scroll = group::Scroll::default_fill().with_type(group::ScrollType::Vertical); 17 | scroll.resize_callback(utils::scroll_resize_cb); 18 | scroll.set_scrollbar_size(-1); 19 | utils::fix_scroll_cb(&mut scroll); 20 | let mut vpack = group::Pack::default() 21 | .with_size(300, 300) 22 | .with_type(group::PackType::Vertical) 23 | .center_of_parent(); 24 | vpack.set_spacing(50); 25 | frame::Frame::default().with_size(0, 30); 26 | for comp in sys.networks().iter() { 27 | let t = Card::default().with_size(300, 130).with_label(comp.0); 28 | t.begin(); 29 | let p = group::Pack::default() 30 | .with_size(280, 130) 31 | .center_of_parent(); 32 | let f = frame::Frame::default() 33 | .with_size(80, 60) 34 | .with_label(&format!( 35 | "Received: {} B - Transmitted: {} B", 36 | comp.1.received(), 37 | comp.1.transmitted() 38 | )); 39 | frames.push(f); 40 | let f = frame::Frame::default() 41 | .with_size(80, 60) 42 | .with_label(&format!( 43 | "Total Received: {:.02} MiB - Total Transmitted: {:.02} MiB", 44 | comp.1.total_received() as f64 / 2_f64.powf(20.), 45 | comp.1.total_transmitted() as f64 / 2_f64.powf(20.) 46 | )); 47 | frames.push(f); 48 | p.end(); 49 | t.end(); 50 | } 51 | vpack.end(); 52 | scroll.end(); 53 | let frames = Arc::new(Mutex::new(frames)); 54 | let sys = Arc::new(Mutex::new(System::new_all())); 55 | let sleep = view.sleep.clone(); 56 | let cb = move || { 57 | if let Some(mut sys) = sys.try_lock() { 58 | sys.refresh_networks(); 59 | let mut i = 0; 60 | for comp in sys.networks() { 61 | frames.lock()[i].set_label(&format!( 62 | "Received: {} B - Transmitted: {} B", 63 | comp.1.received(), 64 | comp.1.transmitted() 65 | )); 66 | frames.lock()[i + 1].set_label(&format!( 67 | "Total Received: {:.02} MiB - Total Transmitted: {:.02} MiB", 68 | comp.1.total_received() as f64 / 2_f64.powf(20.), 69 | comp.1.total_transmitted() as f64 / 2_f64.powf(20.) 70 | )); 71 | i += 2; 72 | } 73 | app::awake(); 74 | } 75 | std::thread::sleep(std::time::Duration::from_millis( 76 | sleep.load(Ordering::Relaxed), 77 | )); 78 | }; 79 | Some(Box::new(cb)) 80 | } 81 | -------------------------------------------------------------------------------- /src/view/procs.rs: -------------------------------------------------------------------------------- 1 | use super::{MyView, SortOrder}; 2 | use crate::gui::styles; 3 | use crate::gui::styles::colors::*; 4 | use fltk::{app::MouseButton, enums::*, prelude::*, *}; 5 | use parking_lot::Mutex; 6 | use std::str::FromStr; 7 | use std::sync::atomic::Ordering; 8 | use std::sync::Arc; 9 | use sysinfo::ProcessExt; 10 | use sysinfo::System; 11 | use sysinfo::SystemExt; 12 | 13 | struct ProcToggle { 14 | b: button::RadioButton, 15 | } 16 | 17 | impl ProcToggle { 18 | pub fn new(label: &str, ord: Arc>) -> Self { 19 | let mut b = button::RadioButton::default() 20 | .with_size(70, 0) 21 | .with_label(label) 22 | .with_align(Align::Left | Align::Inside); 23 | b.set_down_frame(FrameType::FlatBox); 24 | b.set_selection_color(Color::color_average(b.color(), Color::Foreground, 0.9)); 25 | b.clear_visible_focus(); 26 | b.set_label_size(app::font_size() - 2); 27 | b.draw(move |b| { 28 | if b.value() { 29 | let mut image = if (*ord.lock() as i32) < 5 { 30 | image::SvgImage::from_data(styles::svgs::DESC).unwrap() 31 | } else { 32 | image::SvgImage::from_data(styles::svgs::ASC).unwrap() 33 | }; 34 | image.scale(15, 15, true, true); 35 | image.draw(b.x() + (b.w() * 2 / 3) + 5, b.y() + 10, b.w() / 3, b.h()); 36 | } 37 | }); 38 | b.set_frame(FrameType::FlatBox); 39 | Self { b } 40 | } 41 | } 42 | 43 | fltk::widget_extends!(ProcToggle, button::RadioButton, b); 44 | 45 | struct Proc { 46 | pub pid: sysinfo::Pid, 47 | pub memory: u64, 48 | pub virt: u64, 49 | pub cpu: f32, 50 | pub exe: String, 51 | // pub total_written_bytes: u64, 52 | // pub written_bytes: u64, 53 | // pub total_read_bytes: u64, 54 | // pub read_bytes: u64, 55 | } 56 | 57 | impl Proc { 58 | pub fn new(pid: &sysinfo::Pid, proc: &sysinfo::Process) -> Self { 59 | Self { 60 | pid: *pid, 61 | memory: proc.memory(), 62 | virt: proc.virtual_memory(), 63 | cpu: proc.cpu_usage(), 64 | exe: proc.name().to_string(), 65 | // total_written_bytes: 0, 66 | // written_bytes: 0, 67 | // total_read_bytes: 0, 68 | // read_bytes: 0, 69 | } 70 | } 71 | pub fn fmt(&self, light: bool) -> String { 72 | if !light { 73 | format!( 74 | "@C255 {}\t@C255 {:.01}\t@C255 {:.01}\t@C255 {:.01}\t@C255{}", 75 | self.pid, 76 | self.memory as f64 / 2_f64.powf(20.), 77 | self.virt as f64 / 2_f64.powf(20.), 78 | self.cpu, 79 | self.exe 80 | ) 81 | } else { 82 | format!( 83 | " {}\t {:.01}\t {:.01}\t {:.01}\t{}", 84 | self.pid, 85 | self.memory as f64 / 2_f64.powf(20.), 86 | self.virt as f64 / 2_f64.powf(20.), 87 | self.cpu, 88 | self.exe 89 | ) 90 | } 91 | } 92 | } 93 | 94 | pub fn procs(view: &MyView) -> Option> { 95 | let mut ord = view.ordering.lock(); 96 | *ord = SortOrder::Pid; 97 | drop(ord); 98 | let mut sys = view.system.lock(); 99 | sys.refresh_processes(); 100 | let hpack = group::Pack::default().with_type(group::PackType::Horizontal); 101 | let mut parent = group::Flex::from_dyn_widget(&hpack.parent().unwrap()).unwrap(); 102 | parent.set_size(&hpack, 30); 103 | let mut b = ProcToggle::new("pid", view.ordering.clone()); 104 | b.set_value(true); 105 | b.handle({ 106 | let ord = view.ordering.clone(); 107 | move |_, e| { 108 | if e == Event::Push { 109 | let mut ord = ord.lock(); 110 | if *ord == SortOrder::Pid { 111 | *ord = SortOrder::RevPid; 112 | } else { 113 | *ord = SortOrder::Pid; 114 | } 115 | true 116 | } else { 117 | false 118 | } 119 | } 120 | }); 121 | ProcToggle::new("mem%", view.ordering.clone()).handle({ 122 | let ord = view.ordering.clone(); 123 | move |_, e| { 124 | if e == Event::Push { 125 | let mut ord = ord.lock(); 126 | if *ord == SortOrder::Mem { 127 | *ord = SortOrder::RevMem; 128 | } else { 129 | *ord = SortOrder::Mem; 130 | } 131 | true 132 | } else { 133 | false 134 | } 135 | } 136 | }); 137 | let mut b = ProcToggle::new("virt", view.ordering.clone()); 138 | b.handle({ 139 | let ord = view.ordering.clone(); 140 | move |_, e| { 141 | if e == Event::Push { 142 | let mut ord = ord.lock(); 143 | if *ord == SortOrder::Virt { 144 | *ord = SortOrder::RevVirt; 145 | } else { 146 | *ord = SortOrder::Virt; 147 | } 148 | true 149 | } else { 150 | false 151 | } 152 | } 153 | }); 154 | b.set_tooltip("Virtual memory in Kb"); 155 | ProcToggle::new("cpu%", view.ordering.clone()).handle({ 156 | let ord = view.ordering.clone(); 157 | move |_, e| { 158 | if e == Event::Push { 159 | let mut ord = ord.lock(); 160 | if *ord == SortOrder::Cpu { 161 | *ord = SortOrder::RevCpu; 162 | } else { 163 | *ord = SortOrder::Cpu; 164 | } 165 | true 166 | } else { 167 | false 168 | } 169 | } 170 | }); 171 | ProcToggle::new("exe", view.ordering.clone()).handle({ 172 | let ord = view.ordering.clone(); 173 | move |_, e| { 174 | if e == Event::Push { 175 | let mut ord = ord.lock(); 176 | if *ord == SortOrder::Exe { 177 | *ord = SortOrder::RevExe; 178 | } else { 179 | *ord = SortOrder::Exe; 180 | } 181 | true 182 | } else { 183 | false 184 | } 185 | } 186 | }); 187 | hpack.end(); 188 | let mut grp = group::Group::default(); 189 | let mut b = browser::HoldBrowser::default(); 190 | b.clear_visible_focus(); 191 | b.set_text_size(app::font_size() - 2); 192 | b.set_color(Color::color_average(b.color(), Color::Background, 0.1)); 193 | b.set_selection_color(SEL_BLUE); 194 | b.set_scrollbar_size(5); 195 | b.scrollbar() 196 | .set_selection_color(Color::color_average(b.color(), Color::Foreground, 0.9)); 197 | b.hscrollbar() 198 | .set_selection_color(Color::color_average(b.color(), Color::Foreground, 0.9)); 199 | b.set_frame(FrameType::GtkDownBox); 200 | let widths = &[70, 70, 70, 70, 70]; 201 | b.set_column_widths(widths); 202 | b.set_column_char('\t'); 203 | let mut ps = vec![]; 204 | for (pid, process) in sys.processes() { 205 | ps.push(Proc::new(pid, process)); 206 | } 207 | ps.sort_by(|p1, p2| p1.pid.cmp(&p2.pid)); 208 | let light_mode = view.light_mode.load(Ordering::Relaxed); 209 | for p in ps { 210 | b.add(&p.fmt(light_mode)); 211 | } 212 | let mut menu = menu::MenuButton::default().with_type(menu::MenuButtonType::Popup3); 213 | menu.set_frame(FrameType::FlatBox); 214 | menu.set_text_size(app::font_size() - 2); 215 | menu.set_color(Color::color_average(menu.color(), Color::Background, 0.9)); 216 | drop(sys); 217 | menu.add_choice("End Task\t\t"); 218 | b.set_callback({ 219 | let menu = menu.clone(); 220 | move |_| { 221 | if app::event_mouse_button() == MouseButton::Right { 222 | menu.popup(); 223 | } 224 | } 225 | }); 226 | grp.end(); 227 | let mut row = group::Flex::default().row(); 228 | parent.set_size(&row, 30); 229 | frame::Frame::default(); 230 | let mut btn = button::Button::default().with_label("End task"); 231 | btn.set_frame(FrameType::RFlatBox); 232 | btn.set_color(BLUE); 233 | btn.set_selection_color(SEL_BLUE); 234 | btn.clear_visible_focus(); 235 | btn.set_callback({ 236 | let sys = view.system.clone(); 237 | let b = b.clone(); 238 | move |_| { 239 | let val = b.value(); 240 | if val != 0 { 241 | if let Some(text) = b.text(val) { 242 | let sys = sys.lock(); 243 | let v: Vec<&str> = text.split_ascii_whitespace().collect(); 244 | let pid = if light_mode { v[0] } else { v[1] }; 245 | let pid = sysinfo::Pid::from_str(pid).unwrap(); 246 | if let Some(p) = sys.process(pid) { 247 | p.kill_with(sysinfo::Signal::Kill).unwrap(); 248 | } 249 | drop(sys); 250 | } 251 | } 252 | } 253 | }); 254 | frame::Frame::default(); 255 | row.set_size(&btn, 80); 256 | row.end(); 257 | menu.set_callback(move |m| { 258 | if let Some(v) = m.choice() { 259 | if v == "End Task" { 260 | btn.do_callback(); 261 | } 262 | } 263 | }); 264 | grp.resize_callback({ 265 | let mut b = b.clone(); 266 | move |_, x, y, w, h| { 267 | b.resize(x, y, w, h); 268 | menu.resize(x, y, w, h); 269 | } 270 | }); 271 | let sys = Arc::new(Mutex::new(System::new_all())); 272 | let light_mode = view.light_mode.clone(); 273 | let ord = view.ordering.clone(); 274 | let cb = move || { 275 | if let Some(mut sys) = sys.try_lock() { 276 | sys.refresh_processes(); 277 | let mut ps = vec![]; 278 | for (pid, process) in sys.processes() { 279 | ps.push(Proc::new(pid, process)); 280 | } 281 | ps.sort_by(|p1, p2| match *ord.lock() { 282 | SortOrder::Pid => p1.pid.cmp(&p2.pid), 283 | SortOrder::Mem => p1.memory.cmp(&p2.memory), 284 | SortOrder::Virt => p1.virt.cmp(&p2.virt), 285 | SortOrder::Cpu => p1.cpu.partial_cmp(&p2.cpu).unwrap(), 286 | SortOrder::Exe => p1.exe.cmp(&p2.exe), 287 | SortOrder::RevPid => p2.pid.cmp(&p1.pid), 288 | SortOrder::RevMem => p2.memory.cmp(&p1.memory), 289 | SortOrder::RevVirt => p2.virt.cmp(&p1.virt), 290 | SortOrder::RevCpu => p2.cpu.partial_cmp(&p1.cpu).unwrap(), 291 | SortOrder::RevExe => p2.exe.cmp(&p1.exe), 292 | }); 293 | let light_mode = light_mode.load(Ordering::Relaxed); 294 | for (i, p) in ps.iter().enumerate() { 295 | b.set_text(i as i32 + 1, &p.fmt(light_mode)); 296 | } 297 | app::awake(); 298 | } 299 | }; 300 | Some(Box::new(cb)) 301 | } 302 | -------------------------------------------------------------------------------- /src/view/settings.rs: -------------------------------------------------------------------------------- 1 | use crate::gui::styles::colors::*; 2 | use crate::view::MyView; 3 | use fltk::{enums::*, prelude::*, *}; 4 | use fltk_extras::{ 5 | button::{RoundToggle, Toggle}, 6 | slider::FancyHorSlider, 7 | }; 8 | use std::sync::atomic::Ordering; 9 | 10 | pub fn settings(view: &MyView) -> Option> { 11 | let mut win = unsafe { 12 | let mut win = window::Window::from_widget_ptr(app::first_window().unwrap().as_widget_ptr()); 13 | win.assume_derived(); 14 | win 15 | }; 16 | let mut row = group::Flex::default().row(); 17 | { 18 | frame::Frame::default() 19 | .with_align(Align::Left | Align::Inside) 20 | .with_label("Light mode:"); 21 | let col = group::Flex::default().column(); 22 | frame::Frame::default(); 23 | let mut t = Toggle::default(); 24 | t.set_value(view.light_mode.load(Ordering::Relaxed)); 25 | let light_mode = view.light_mode.clone(); 26 | t.set_callback(move |t| { 27 | if t.value() { 28 | app::foreground(50, 50, 50); 29 | app::background(255, 255, 255); 30 | light_mode.store(true, Ordering::Relaxed); 31 | } else { 32 | app::foreground(255, 255, 255); 33 | let (r, g, b) = GRAY.to_rgb(); 34 | app::background(r, g, b); 35 | light_mode.store(false, Ordering::Relaxed); 36 | } 37 | app::redraw(); 38 | }); 39 | frame::Frame::default(); 40 | col.end(); 41 | row.set_size(&col, 80); 42 | row.end(); 43 | let mut row = group::Flex::default().row(); 44 | frame::Frame::default() 45 | .with_align(Align::Left | Align::Inside) 46 | .with_label("Enable logging:"); 47 | let col = group::Flex::default().column(); 48 | frame::Frame::default(); 49 | let mut t = RoundToggle::default(); 50 | t.set_value(false); 51 | t.set_callback({ 52 | move |t| { 53 | if t.value() { 54 | eprintln!("Logging is not yet added!"); 55 | } 56 | app::redraw(); 57 | } 58 | }); 59 | frame::Frame::default(); 60 | col.end(); 61 | row.set_size(&col, 80); 62 | row.end(); 63 | let mut row = group::Flex::default().row(); 64 | frame::Frame::default() 65 | .with_align(Align::Left | Align::Inside) 66 | .with_label("Sleep duration:"); 67 | let col = group::Flex::default().column(); 68 | frame::Frame::default(); 69 | let mut slider = FancyHorSlider::default().with_size(40, 10); 70 | let val = view.sleep.load(Ordering::Relaxed); 71 | let mut f = frame::Frame::default() 72 | .with_size(0, 40) 73 | .with_label(&format!("{} ms", val)); 74 | slider.set_value((val as f64 - 100.) / 1000.); 75 | let sleep = view.sleep.clone(); 76 | slider.set_callback(move |s| { 77 | let val = (s.value() * 1000.) as u64 + 100; 78 | f.set_label(&format!("{} ms", val)); 79 | sleep.store(val, Ordering::Relaxed); 80 | }); 81 | frame::Frame::default(); 82 | col.end(); 83 | row.set_size(&col, 80); 84 | row.end(); 85 | let mut row = group::Flex::default().row(); 86 | frame::Frame::default() 87 | .with_align(Align::Left | Align::Inside) 88 | .with_label("Window Opacity:"); 89 | let col = group::Flex::default().column(); 90 | frame::Frame::default(); 91 | let mut slider = FancyHorSlider::default().with_size(40, 20); 92 | let opacity = win.opacity(); 93 | let mut f = frame::Frame::default() 94 | .with_size(0, 40) 95 | .with_label(&format!("{}%", ((opacity * 100.) as i32))); 96 | slider.set_value(opacity); 97 | slider.set_callback(move |s| { 98 | let val = s.value(); 99 | f.set_label(&format!("{}%", ((val * 100.) as i32))); 100 | win.set_opacity(val); 101 | }); 102 | frame::Frame::default(); 103 | col.end(); 104 | row.set_size(&col, 80); 105 | } 106 | row.end(); 107 | None 108 | } 109 | --------------------------------------------------------------------------------