{"id":16113808,"url":"https://github.com/idanarye/woab","last_synced_at":"2025-03-16T08:32:42.852Z","repository":{"id":48421535,"uuid":"289236504","full_name":"idanarye/woab","owner":"idanarye","description":"Widgets on Actors Bridge - a GUI microframework for combining GTK with Actix","archived":false,"fork":false,"pushed_at":"2024-04-18T21:00:23.000Z","size":485,"stargazers_count":14,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-02-27T05:56:29.006Z","etag":null,"topics":["actix","actors","gtk","gui","rust"],"latest_commit_sha":null,"homepage":"https://crates.io/crates/woab","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/idanarye.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2020-08-21T09:57:05.000Z","updated_at":"2024-05-05T12:02:37.000Z","dependencies_parsed_at":"2024-04-14T21:25:42.668Z","dependency_job_id":"69704abd-e30e-4894-94a4-a714b5f21d34","html_url":"https://github.com/idanarye/woab","commit_stats":{"total_commits":183,"total_committers":3,"mean_commits":61.0,"dds":0.4426229508196722,"last_synced_commit":"20138dbf307cd3b8c0de07c0dd85e71f5fa99202"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idanarye%2Fwoab","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idanarye%2Fwoab/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idanarye%2Fwoab/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/idanarye%2Fwoab/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/idanarye","download_url":"https://codeload.github.com/idanarye/woab/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243807464,"owners_count":20350999,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["actix","actors","gtk","gui","rust"],"created_at":"2024-10-09T20:13:25.846Z","updated_at":"2025-03-16T08:32:42.413Z","avatar_url":"https://github.com/idanarye.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://github.com/idanarye/woab/workflows/CI/badge.svg)](https://github.com/idanarye/woab/actions)\n[![Latest Version](https://img.shields.io/crates/v/woab.svg)](https://crates.io/crates/woab)\n[![Rust Documentation - Latest Version](https://img.shields.io/badge/docs-released-blue.svg)](https://docs.rs/woab)\n[![Rust Documentation - Nightly](https://img.shields.io/badge/docs-nightly-purple.svg)](https://idanarye.github.io/woab/)\n\n# WoAB\n\nWoAB (Widgets on Actors Bridge) is a GUI microframework for combining the\nwidgets toolkit [GTK](https://gtk-rs.org/) with the actors framework\n[Actix](https://actix.rs/). It helps with:\n\n* Running the actors inside the GTK thread, allowing message handlers to\n  interact with the widgets directly.\n* Routing GTK signals through the asynchronous runtime, so that the code\n  handling them can proceed naturally to interact with the actors.\n* Mapping widgets and signals from\n  [Cambalache](https://gitlab.gnome.org/jpu/cambalache) emitted XML files to\n  user types.\n\nRefer to [the docs](https://idanarye.github.io/woab/) for more explanation on\nhow to use WoAB, and to [the\nexamples](https://github.com/idanarye/woab/tree/master/examples) for a short\ndemonstration.\n\n```rust\nuse actix::prelude::*;\nuse gtk4::prelude::*;\n\nstruct MyActor {\n    widgets: MyWidgets,\n}\n\nimpl Actor for MyActor {\n    type Context = Context\u003cSelf\u003e;\n}\n\n// Use this derive to automatically populate a struct with GTK objects from a builder using their\n// object IDs.\n#[derive(woab::WidgetsFromBuilder)]\nstruct MyWidgets {\n    window: gtk4::ApplicationWindow,\n    button: gtk4::Button,\n}\n\n// WoAB converts GTK signals (defined) to Actix messages, which the user defined actors need handle.\nimpl Handler\u003cwoab::Signal\u003e for MyActor {\n    type Result = woab::SignalResult;\n\n    fn handle(\u0026mut self, msg: woab::Signal, _ctx: \u0026mut Self::Context) -\u003e Self::Result {\n        // All the signals get the same message type (`woab::Signal`), and need to be matched by\n        // the handler name.\n        Ok(match msg.name() {\n            \"button_clicked\" =\u003e {\n                // Handlers can freely use the GTK widget handles stored inside the actor to\n                // interact with the UI.\n                self.widgets.button.set_label(\"Hello World\");\n                // Some GTK signals require a `glib::Propagation` decision. Others, like\n                // `GtkButton::clicked` here, don't. It is up to the signal handler to return the\n                // correct type.\n                None\n            }\n            _ =\u003e msg.cant_handle()?,\n        })\n    }\n}\n\nfn main() -\u003e woab::Result\u003c()\u003e {\n    // Factories can be used to create the GUI and connect the signals.\n    let factory = woab::BuilderFactory::from(\n        // Typically the UI XML will be generated with Cambalache and loaded from a file, but for\n        // the sake of this simple example it is inlined here.\n        r#\"\n        \u003cinterface\u003e\n          \u003cobject class=\"GtkApplicationWindow\" id=\"window\"\u003e\n            \u003cchild\u003e\n              \u003cobject class=\"GtkButton\" id=\"button\"\u003e\n                \u003cproperty name=\"label\"\u003eClick Me!\u003c/property\u003e\n                \u003csignal name=\"clicked\" handler=\"button_clicked\"/\u003e\n              \u003c/object\u003e\n            \u003c/child\u003e\n          \u003c/object\u003e\n        \u003c/interface\u003e\n        \"#\n        .to_owned(),\n    );\n\n    // Setup the application inside `woab::main`. This handles starting/stopping GTK and Actix, and\n    // making them work together. The actual closure is run inside the application's `startup`\n    // signal.\n    woab::main(gtk4::Application::default(), move |app| {\n        // A useful helper so that when the last window is closed, the application will exit.\n        woab::shutdown_when_last_window_is_closed(app);\n\n        // We need the actor's address when instantiating the builder (because we need to connect\n        // the signals) and we need the builder result when we create the actor (because we want to\n        // provide it with the widgets). Thus, we usually want to use Actix's two-steps actor\n        // initialization.\n        let ctx = Context::new();\n\n        // This will create the UI widgets from the XML and route the signals to the actor.\n        let bld = factory.instantiate_route_to(ctx.address());\n\n        // Automatically assign all the windows inside the builder to the application. Without\n        // this, `woab::shutdown_when_last_window_is_closed` will be meaningless.\n        bld.set_application(app);\n\n        // Extract the newly created widgets from the builder.\n        let widgets: MyWidgets = bld.widgets()?;\n\n        // When the builder loads the window, it starts as hidden. We can use the extracted widgets\n        // to show it.\n        widgets.window.show();\n\n        // This is where the actor is actually launched.\n        ctx.run(MyActor { widgets });\n\n        Ok(())\n    })\n}\n```\n\n## Pitfalls\n\n* When starting Actix actors from outside Tokio/Actix, `woab::block_on` must be\n  used. This is a limitation of Actix that needs to be respected.\n* If an actor is created inside a `gtk::Application::connect_activate`, its\n  `started` method will run **after** the `activate` signal is done. This can\n  be a problem for methods like `set_application` that can segfault if they are\n  called outside the `activate` signal. A solution could be to either do the\n  startup inside `connect_activate` or use `woab::route_signal` to route the\n  application's `activate` signal to the actor and do the startup in the\n  actor's signal handler.\n* `woab::close_actix_runtime` must be called after `gtk::main()`, or else Tokio\n  will panic when GTK quits. If anyone knows how to automate it I'm open to\n  suggestions.\n\n## License\n\nLicensed under MIT license ([LICENSE](LICENSE) or http://opensource.org/licenses/MIT))\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidanarye%2Fwoab","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fidanarye%2Fwoab","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fidanarye%2Fwoab/lists"}