From add25edbdc30f1dfda7414867893ddcc402659ca Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 19 Apr 2026 15:57:01 -0400 Subject: [PATCH] working workspaces --- lib/controllers/workspaces_controller.dart | 6 +- lib/src/rust/api/workspace_api.dart | 4 +- lib/src/rust/frb_generated.dart | 56 +- lib/src/rust/frb_generated.io.dart | 28 +- lib/src/rust/frb_generated.web.dart | 28 +- lib/widgets/bar.dart | 101 ++-- rust/src/api/workspace_api.rs | 6 +- rust/src/frb_generated.rs | 576 ++++++++++++--------- rust/src/internal/wayland.rs | 124 +++-- 9 files changed, 576 insertions(+), 353 deletions(-) diff --git a/lib/controllers/workspaces_controller.dart b/lib/controllers/workspaces_controller.dart index fda948e..3a9b145 100644 --- a/lib/controllers/workspaces_controller.dart +++ b/lib/controllers/workspaces_controller.dart @@ -1,12 +1,12 @@ import "package:flight/src/rust/api/workspace_api.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; -class WorkspacesController extends StreamNotifier> { +class WorkspacesController extends StreamNotifier>> { @override - Stream> build() => listenWorkspaces(); + Stream>> build() => listenWorkspaces(); static final provider = - StreamNotifierProvider>( + StreamNotifierProvider>>( WorkspacesController.new, ); } diff --git a/lib/src/rust/api/workspace_api.dart b/lib/src/rust/api/workspace_api.dart index e743019..6dfbebf 100644 --- a/lib/src/rust/api/workspace_api.dart +++ b/lib/src/rust/api/workspace_api.dart @@ -6,9 +6,9 @@ import '../frb_generated.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; -// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone` +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `clone`, `fmt` -Stream> listenWorkspaces() => +Stream>> listenWorkspaces() => RustLib.instance.api.crateApiWorkspaceApiListenWorkspaces(); class Workspace { diff --git a/lib/src/rust/frb_generated.dart b/lib/src/rust/frb_generated.dart index d335ae7..514f0ac 100644 --- a/lib/src/rust/frb_generated.dart +++ b/lib/src/rust/frb_generated.dart @@ -75,7 +75,7 @@ class RustLib extends BaseEntrypoint { } abstract class RustLibApi extends BaseApi { - Stream> crateApiWorkspaceApiListenWorkspaces(); + Stream>> crateApiWorkspaceApiListenWorkspaces(); } class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @@ -87,14 +87,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { }); @override - Stream> crateApiWorkspaceApiListenWorkspaces() { - final sink = RustStreamSink>(); + Stream>> crateApiWorkspaceApiListenWorkspaces() { + final sink = RustStreamSink>>(); unawaited( handler.executeNormal( NormalTask( callFfi: (port_) { final serializer = SseSerializer(generalizedFrbRustBinding); - sse_encode_StreamSink_list_workspace_Sse(sink, serializer); + sse_encode_StreamSink_list_list_workspace_Sse(sink, serializer); pdeCallFfi( generalizedFrbRustBinding, serializer, @@ -125,9 +125,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - RustStreamSink> dco_decode_StreamSink_list_workspace_Sse( - dynamic raw, - ) { + RustStreamSink>> + dco_decode_StreamSink_list_list_workspace_Sse(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs throw UnimplementedError(); } @@ -144,6 +143,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw as bool; } + @protected + List> dco_decode_list_list_workspace(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List).map(dco_decode_list_workspace).toList(); + } + @protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -185,9 +190,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - RustStreamSink> sse_decode_StreamSink_list_workspace_Sse( - SseDeserializer deserializer, - ) { + RustStreamSink>> + sse_decode_StreamSink_list_list_workspace_Sse(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs throw UnimplementedError('Unreachable ()'); } @@ -205,6 +209,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return deserializer.buffer.getUint8() != 0; } + @protected + List> sse_decode_list_list_workspace( + SseDeserializer deserializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + + var len_ = sse_decode_i_32(deserializer); + var ans_ = >[]; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_list_workspace(deserializer)); + } + return ans_; + } + @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -258,15 +276,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } @protected - void sse_encode_StreamSink_list_workspace_Sse( - RustStreamSink> self, + void sse_encode_StreamSink_list_list_workspace_Sse( + RustStreamSink>> self, SseSerializer serializer, ) { // Codec=Sse (Serialization based), see doc to use other codecs sse_encode_String( self.setupAndSerialize( codec: SseCodec( - decodeSuccessData: sse_decode_list_workspace, + decodeSuccessData: sse_decode_list_list_workspace, decodeErrorData: sse_decode_AnyhowException, ), ), @@ -286,6 +304,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { serializer.buffer.putUint8(self ? 1 : 0); } + @protected + void sse_encode_list_list_workspace( + List> self, + SseSerializer serializer, + ) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_list_workspace(item, serializer); + } + } + @protected void sse_encode_list_prim_u_8_strict( Uint8List self, diff --git a/lib/src/rust/frb_generated.io.dart b/lib/src/rust/frb_generated.io.dart index 7e5fcc7..632cb69 100644 --- a/lib/src/rust/frb_generated.io.dart +++ b/lib/src/rust/frb_generated.io.dart @@ -22,9 +22,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { AnyhowException dco_decode_AnyhowException(dynamic raw); @protected - RustStreamSink> dco_decode_StreamSink_list_workspace_Sse( - dynamic raw, - ); + RustStreamSink>> + dco_decode_StreamSink_list_list_workspace_Sse(dynamic raw); @protected String dco_decode_String(dynamic raw); @@ -32,6 +31,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected bool dco_decode_bool(dynamic raw); + @protected + List> dco_decode_list_list_workspace(dynamic raw); + @protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); @@ -51,9 +53,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer); @protected - RustStreamSink> sse_decode_StreamSink_list_workspace_Sse( - SseDeserializer deserializer, - ); + RustStreamSink>> + sse_decode_StreamSink_list_list_workspace_Sse(SseDeserializer deserializer); @protected String sse_decode_String(SseDeserializer deserializer); @@ -61,6 +62,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected bool sse_decode_bool(SseDeserializer deserializer); + @protected + List> sse_decode_list_list_workspace( + SseDeserializer deserializer, + ); + @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); @@ -86,8 +92,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { ); @protected - void sse_encode_StreamSink_list_workspace_Sse( - RustStreamSink> self, + void sse_encode_StreamSink_list_list_workspace_Sse( + RustStreamSink>> self, SseSerializer serializer, ); @@ -97,6 +103,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_bool(bool self, SseSerializer serializer); + @protected + void sse_encode_list_list_workspace( + List> self, + SseSerializer serializer, + ); + @protected void sse_encode_list_prim_u_8_strict( Uint8List self, diff --git a/lib/src/rust/frb_generated.web.dart b/lib/src/rust/frb_generated.web.dart index 48a5e47..23b1137 100644 --- a/lib/src/rust/frb_generated.web.dart +++ b/lib/src/rust/frb_generated.web.dart @@ -24,9 +24,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { AnyhowException dco_decode_AnyhowException(dynamic raw); @protected - RustStreamSink> dco_decode_StreamSink_list_workspace_Sse( - dynamic raw, - ); + RustStreamSink>> + dco_decode_StreamSink_list_list_workspace_Sse(dynamic raw); @protected String dco_decode_String(dynamic raw); @@ -34,6 +33,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected bool dco_decode_bool(dynamic raw); + @protected + List> dco_decode_list_list_workspace(dynamic raw); + @protected Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); @@ -53,9 +55,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer); @protected - RustStreamSink> sse_decode_StreamSink_list_workspace_Sse( - SseDeserializer deserializer, - ); + RustStreamSink>> + sse_decode_StreamSink_list_list_workspace_Sse(SseDeserializer deserializer); @protected String sse_decode_String(SseDeserializer deserializer); @@ -63,6 +64,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected bool sse_decode_bool(SseDeserializer deserializer); + @protected + List> sse_decode_list_list_workspace( + SseDeserializer deserializer, + ); + @protected Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); @@ -88,8 +94,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { ); @protected - void sse_encode_StreamSink_list_workspace_Sse( - RustStreamSink> self, + void sse_encode_StreamSink_list_list_workspace_Sse( + RustStreamSink>> self, SseSerializer serializer, ); @@ -99,6 +105,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_bool(bool self, SseSerializer serializer); + @protected + void sse_encode_list_list_workspace( + List> self, + SseSerializer serializer, + ); + @protected void sse_encode_list_prim_u_8_strict( Uint8List self, diff --git a/lib/widgets/bar.dart b/lib/widgets/bar.dart index 2641de2..0f30a70 100644 --- a/lib/widgets/bar.dart +++ b/lib/widgets/bar.dart @@ -16,52 +16,67 @@ class Bar extends ConsumerWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ - ref - .watch(WorkspacesController.provider) - .whenOrNull( - error: (error, stackTrace) => [ - Text(error.toString()), - ], - data: (value) { - return value - .map( - (element) => IconButton( - onPressed: () {}, - icon: Icon( - element.activated - ? Icons.circle - : Icons.circle_outlined, + ...ref + .watch(WorkspacesController.provider) + .when( + error: (error, stackTrace) => [Text(error.toString())], + loading: () => [], + data: (value) => value + .map( + (group) => Row( + children: group + .map( + (workspace) => IconButton( + onPressed: () {}, + icon: Icon( + workspace.activated + ? Icons.circle + : Icons.circle_outlined, + ), ), - ), - ) - .toList(); - }, - ) ?? - [], - [ - TextButton( - onPressed: () {}, - child: Text( - DateFormat.Hm().format( - ref - .watch(TimeController.provider) - .when( - data: (time) => time, - loading: DateTime.now, - error: (_, _) => DateTime.now(), + ) + .toList(), ), - ), + ) + .toList(), ), + Center( + child: Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + TextButton( + onPressed: () {}, + child: Text( + DateFormat.Hm().format( + ref + .watch(TimeController.provider) + .when( + data: (time) => time, + loading: DateTime.now, + error: (_, _) => DateTime.now(), + ), + ), + ), + ), + ], ), - ], - [ - IconButton(onPressed: () {}, icon: Icon(Icons.wifi)), - IconButton(onPressed: () {}, icon: Icon(Icons.bluetooth)), - IconButton(onPressed: () {}, icon: Icon(Icons.volume_off)), - ], + ), + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + IconButton(onPressed: () {}, icon: Icon(Icons.wifi)), + IconButton(onPressed: () {}, icon: Icon(Icons.bluetooth)), + IconButton( + onPressed: () {}, + icon: Icon(Icons.volume_off), + ), + ], + ), ] .map( - (children) => Padding( + (child) => Padding( padding: EdgeInsetsGeometry.directional(bottom: 6), child: Container( height: 42, @@ -72,11 +87,7 @@ class Bar extends ConsumerWidget { ).colorScheme.surfaceContainerLow, borderRadius: BorderRadius.circular(999), ), - child: Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: children, - ), + child: child, ), ), ) diff --git a/rust/src/api/workspace_api.rs b/rust/src/api/workspace_api.rs index 991a0d2..997d82d 100644 --- a/rust/src/api/workspace_api.rs +++ b/rust/src/api/workspace_api.rs @@ -4,12 +4,12 @@ use std::collections::HashMap; use crate::{frb_generated::StreamSink, internal::wayland::AppState}; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Workspace { pub activated: bool, } -pub fn listen_workspaces(sink: StreamSink>) -> Result<()> { +pub fn listen_workspaces(sink: StreamSink>>) -> Result<()> { std::thread::spawn(move || { let conn = Connection::connect_to_env().expect("Failed to connect to Wayland"); @@ -18,6 +18,8 @@ pub fn listen_workspaces(sink: StreamSink>) -> Result<()> { let mut state = AppState { workspaces: HashMap::new(), + workspace_group: HashMap::new(), + workspace_coords: HashMap::new(), sink, }; diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index 94a03fc..d1bdee6 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -2,43 +2,42 @@ // @generated by `flutter_rust_bridge`@ 2.11.1. #![allow( -non_camel_case_types, -unused, -non_snake_case, -clippy::needless_return, -clippy::redundant_closure_call, -clippy::redundant_closure, -clippy::useless_conversion, -clippy::unit_arg, -clippy::unused_unit, -clippy::double_parens, -clippy::let_and_return, -clippy::too_many_arguments, -clippy::match_single_binding, -clippy::clone_on_copy, -clippy::let_unit_value, -clippy::deref_addrof, -clippy::explicit_auto_deref, -clippy::borrow_deref_ref, -clippy::needless_borrow + non_camel_case_types, + unused, + non_snake_case, + clippy::needless_return, + clippy::redundant_closure_call, + clippy::redundant_closure, + clippy::useless_conversion, + clippy::unit_arg, + clippy::unused_unit, + clippy::double_parens, + clippy::let_and_return, + clippy::too_many_arguments, + clippy::match_single_binding, + clippy::clone_on_copy, + clippy::let_unit_value, + clippy::deref_addrof, + clippy::explicit_auto_deref, + clippy::borrow_deref_ref, + clippy::needless_borrow )] // Section: imports +use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; +use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; use flutter_rust_bridge::{Handler, IntoIntoDart}; -use flutter_rust_bridge::for_generated::{Lockable, transform_result_dco, Lifetimeable}; -use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, WriteBytesExt, ReadBytesExt}; // Section: boilerplate flutter_rust_bridge::frb_generated_boilerplate!( - default_stream_sink_codec = SseCodec, - default_rust_opaque = RustOpaqueMoi, - default_rust_auto_opaque = RustAutoOpaqueMoi, - ); - pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1"; - pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1397669831; - + default_stream_sink_codec = SseCodec, + default_rust_opaque = RustOpaqueMoi, + default_rust_auto_opaque = RustAutoOpaqueMoi, +); +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1"; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1397669831; // Section: executor @@ -46,226 +45,333 @@ flutter_rust_bridge::frb_generated_default_handler!(); // Section: wire_funcs -fn wire__crate__api__workspace_api__listen_workspaces_impl(port_: flutter_rust_bridge::for_generated::MessagePort,ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,rust_vec_len_: i32,data_len_: i32) { - FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "listen_workspaces", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { - let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; - let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); - let api_sink = ,flutter_rust_bridge::for_generated::SseCodec>>::sse_decode(&mut deserializer);deserializer.end(); move |context| { - transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || { - let output_ok = crate::api::workspace_api::listen_workspaces(api_sink)?; Ok(output_ok) - })()) - } }) +fn wire__crate__api__workspace_api__listen_workspaces_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "listen_workspaces", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_sink = >, + flutter_rust_bridge::for_generated::SseCodec, + >>::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>( + (move || { + let output_ok = crate::api::workspace_api::listen_workspaces(api_sink)?; + Ok(output_ok) + })(), + ) } + }, + ) +} // Section: dart2rust +impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = ::sse_decode(deserializer); + return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner); + } +} - impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut inner = ::sse_decode(deserializer); - return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);} - } - - impl SseDecode for StreamSink,flutter_rust_bridge::for_generated::SseCodec> { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut inner = ::sse_decode(deserializer); - return StreamSink::deserialize(inner);} - } - - impl SseDecode for String { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut inner = >::sse_decode(deserializer); - return String::from_utf8(inner).unwrap();} - } - - impl SseDecode for bool { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {deserializer.cursor.read_u8().unwrap() != 0} - } - - impl SseDecode for Vec { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut len_ = ::sse_decode(deserializer); +impl SseDecode + for StreamSink< + Vec>, + flutter_rust_bridge::for_generated::SseCodec, + > +{ + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = ::sse_decode(deserializer); + return StreamSink::deserialize(inner); + } +} + +impl SseDecode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = >::sse_decode(deserializer); + return String::from_utf8(inner).unwrap(); + } +} + +impl SseDecode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() != 0 + } +} + +impl SseDecode for Vec> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); let mut ans_ = vec![]; - for idx_ in 0..len_ { ans_.push(::sse_decode(deserializer)); } - return ans_;} - } - - impl SseDecode for Vec { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut len_ = ::sse_decode(deserializer); + for idx_ in 0..len_ { + ans_.push(>::sse_decode( + deserializer, + )); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); let mut ans_ = vec![]; - for idx_ in 0..len_ { ans_.push(::sse_decode(deserializer)); } - return ans_;} - } - - impl SseDecode for u8 { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {deserializer.cursor.read_u8().unwrap()} - } - - impl SseDecode for () { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {} - } - - impl SseDecode for crate::api::workspace_api::Workspace { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut var_activated = ::sse_decode(deserializer); -return crate::api::workspace_api::Workspace{activated: var_activated};} - } - - impl SseDecode for i32 { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {deserializer.cursor.read_i32::().unwrap()} - } - - fn pde_ffi_dispatcher_primary_impl( - func_id: i32,port: flutter_rust_bridge::for_generated::MessagePort, - ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, - rust_vec_len: i32, - data_len: i32, - ) { - // Codec=Pde (Serialization + dispatch), see doc to use other codecs - match func_id { - 1 => wire__crate__api__workspace_api__listen_workspaces_impl(port, ptr, rust_vec_len, data_len), - _ => unreachable!(), - } - } - - fn pde_ffi_dispatcher_sync_impl( - func_id: i32, - ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, - rust_vec_len: i32, - data_len: i32, - ) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { - // Codec=Pde (Serialization + dispatch), see doc to use other codecs - match func_id { - - _ => unreachable!(), - } - } - + for idx_ in 0..len_ { + ans_.push(::sse_decode(deserializer)); + } + return ans_; + } +} + +impl SseDecode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(::sse_decode( + deserializer, + )); + } + return ans_; + } +} + +impl SseDecode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_u8().unwrap() + } +} + +impl SseDecode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {} +} + +impl SseDecode for crate::api::workspace_api::Workspace { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_activated = ::sse_decode(deserializer); + return crate::api::workspace_api::Workspace { + activated: var_activated, + }; + } +} + +impl SseDecode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_i32::().unwrap() + } +} + +fn pde_ffi_dispatcher_primary_impl( + func_id: i32, + port: flutter_rust_bridge::for_generated::MessagePort, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + 1 => wire__crate__api__workspace_api__listen_workspaces_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + _ => unreachable!(), + } +} + +fn pde_ffi_dispatcher_sync_impl( + func_id: i32, + ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len: i32, + data_len: i32, +) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { + // Codec=Pde (Serialization + dispatch), see doc to use other codecs + match func_id { + _ => unreachable!(), + } +} // Section: rust2dart // Codec=Dco (DartCObject based), see doc to use other codecs - impl flutter_rust_bridge::IntoDart for crate::api::workspace_api::Workspace { - fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { - [ - self.activated.into_into_dart().into_dart() - ].into_dart() - } - } - impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::workspace_api::Workspace {} -impl flutter_rust_bridge::IntoIntoDart for crate::api::workspace_api::Workspace { - fn into_into_dart(self) -> crate::api::workspace_api::Workspace { - self - } +impl flutter_rust_bridge::IntoDart for crate::api::workspace_api::Workspace { + fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { + [self.activated.into_into_dart().into_dart()].into_dart() + } +} +impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive + for crate::api::workspace_api::Workspace +{ +} +impl flutter_rust_bridge::IntoIntoDart + for crate::api::workspace_api::Workspace +{ + fn into_into_dart(self) -> crate::api::workspace_api::Workspace { + self + } +} + +impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(format!("{:?}", self), serializer); + } +} + +impl SseEncode + for StreamSink< + Vec>, + flutter_rust_bridge::for_generated::SseCodec, + > +{ + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + unimplemented!("") + } +} + +impl SseEncode for String { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.into_bytes(), serializer); + } +} + +impl SseEncode for bool { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self as _).unwrap(); + } +} + +impl SseEncode for Vec> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + >::sse_encode(item, serializer); } + } +} - impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {::sse_encode(format!("{:?}", self), serializer);} - } - - impl SseEncode for StreamSink,flutter_rust_bridge::for_generated::SseCodec> { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {unimplemented!("")} - } - - impl SseEncode for String { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {>::sse_encode(self.into_bytes(), serializer);} - } - - impl SseEncode for bool { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {serializer.cursor.write_u8(self as _).unwrap();} - } - - impl SseEncode for Vec { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {::sse_encode(self.len() as _, serializer); - for item in self { ::sse_encode(item, serializer); }} - } - - impl SseEncode for Vec { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {::sse_encode(self.len() as _, serializer); - for item in self { ::sse_encode(item, serializer); }} - } - - impl SseEncode for u8 { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {serializer.cursor.write_u8(self).unwrap();} - } - - impl SseEncode for () { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} - } - - impl SseEncode for crate::api::workspace_api::Workspace { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {::sse_encode(self.activated, serializer);} - } - - impl SseEncode for i32 { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {serializer.cursor.write_i32::(self).unwrap();} - } - - - - - - #[cfg(not(target_family = "wasm"))] - mod io { - // This file is automatically generated, so please do not edit it. -// @generated by `flutter_rust_bridge`@ 2.11.1. - - - -// Section: imports - -use flutter_rust_bridge::{Handler, IntoIntoDart}; -use flutter_rust_bridge::for_generated::{Lockable, transform_result_dco, Lifetimeable}; -use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, WriteBytesExt, ReadBytesExt};use super::*; - -// Section: boilerplate - -flutter_rust_bridge::frb_generated_boilerplate_io!(); - - +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); } - #[cfg(not(target_family = "wasm"))] - pub use io::*; - - - /// cbindgen:ignore - #[cfg(target_family = "wasm")] - mod web { - // This file is automatically generated, so please do not edit it. -// @generated by `flutter_rust_bridge`@ 2.11.1. - - - -// Section: imports - -use flutter_rust_bridge::{Handler, IntoIntoDart}; -use flutter_rust_bridge::for_generated::{Lockable, transform_result_dco, Lifetimeable}; -use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, WriteBytesExt, ReadBytesExt};use super::*; - use flutter_rust_bridge::for_generated::wasm_bindgen; - use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*; - - -// Section: boilerplate - -flutter_rust_bridge::frb_generated_boilerplate_web!(); - + } +} +impl SseEncode for Vec { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + ::sse_encode(item, serializer); } - #[cfg(target_family = "wasm")] - pub use web::*; - \ No newline at end of file + } +} + +impl SseEncode for u8 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_u8(self).unwrap(); + } +} + +impl SseEncode for () { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} +} + +impl SseEncode for crate::api::workspace_api::Workspace { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.activated, serializer); + } +} + +impl SseEncode for i32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_i32::(self).unwrap(); + } +} + +#[cfg(not(target_family = "wasm"))] +mod io { + // This file is automatically generated, so please do not edit it. + // @generated by `flutter_rust_bridge`@ 2.11.1. + + // Section: imports + + use super::*; + use flutter_rust_bridge::for_generated::byteorder::{ + NativeEndian, ReadBytesExt, WriteBytesExt, + }; + use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; + use flutter_rust_bridge::{Handler, IntoIntoDart}; + + // Section: boilerplate + + flutter_rust_bridge::frb_generated_boilerplate_io!(); +} +#[cfg(not(target_family = "wasm"))] +pub use io::*; + +/// cbindgen:ignore +#[cfg(target_family = "wasm")] +mod web { + // This file is automatically generated, so please do not edit it. + // @generated by `flutter_rust_bridge`@ 2.11.1. + + // Section: imports + + use super::*; + use flutter_rust_bridge::for_generated::byteorder::{ + NativeEndian, ReadBytesExt, WriteBytesExt, + }; + use flutter_rust_bridge::for_generated::wasm_bindgen; + use flutter_rust_bridge::for_generated::wasm_bindgen::prelude::*; + use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; + use flutter_rust_bridge::{Handler, IntoIntoDart}; + + // Section: boilerplate + + flutter_rust_bridge::frb_generated_boilerplate_web!(); +} +#[cfg(target_family = "wasm")] +pub use web::*; diff --git a/rust/src/internal/wayland.rs b/rust/src/internal/wayland.rs index c5622e6..ff06598 100644 --- a/rust/src/internal/wayland.rs +++ b/rust/src/internal/wayland.rs @@ -2,38 +2,62 @@ use crate::{frb_generated::StreamSink, workspace_api::Workspace}; use std::collections::HashMap; use wayland_client::{ - self, Connection, Dispatch, QueueHandle, backend::ObjectId, event_created_child, protocol::wl_registry + self, backend::ObjectId, Proxy, Connection, Dispatch, QueueHandle, event_created_child, + protocol::wl_registry, }; + use wayland_protocols::ext::workspace::v1::client::{ ext_workspace_group_handle_v1, ext_workspace_handle_v1, ext_workspace_manager_v1, }; +// ------------------------ +// App State +// ------------------------ + pub struct AppState { pub workspaces: HashMap, - pub sink: StreamSink>, + pub workspace_group: HashMap, // workspace -> group + pub workspace_coords: HashMap, + pub sink: StreamSink>>, } impl AppState { - fn emit(&self) { - let mut entries: Vec<(&ObjectId, &Workspace)> = self.workspaces.iter().collect(); + fn emit(&self) { + let mut groups: HashMap> = HashMap::new(); - entries.sort_by_key( - |entry: &(&ObjectId, &Workspace)| -> u32 { - entry.0.protocol_id() - }, - ); + for (ws_id, ws) in &self.workspaces { + if let Some(group_id) = self.workspace_group.get(ws_id) { + groups + .entry(group_id.clone()) + .or_insert_with(Vec::new) + .push((ws_id, ws)); + } + } - let sorted: Vec = entries - .into_iter() - .map( - |entry: (&ObjectId, &Workspace)| -> Workspace { - entry.1.clone() - }, - ) - .collect(); + let mut grouped: Vec<(ObjectId, Vec<(&ObjectId, &Workspace)>)> = + groups.into_iter().collect(); - let _ = self.sink.add(sorted); - } + grouped.sort_by_key(|(group_id, _)| group_id.protocol_id()); + + let result: Vec> = grouped + .into_iter() + .map(|(_, mut entries)| { + entries.sort_by_key(|(id, _)| { + self.workspace_coords + .get(id) + .copied() + .unwrap_or((0, 0)) + }); + + entries + .into_iter() + .map(|(_, ws)| ws.clone()) + .collect() + }) + .collect(); + + let _ = self.sink.add(result); + } } impl Dispatch for AppState { @@ -71,18 +95,17 @@ impl Dispatch for AppState _data: &(), _conn: &Connection, _qh: &QueueHandle, - ) { - } + ) {} event_created_child!( AppState, ext_workspace_manager_v1::ExtWorkspaceManagerV1, [ - wayland_protocols::ext::workspace::v1::client::ext_workspace_manager_v1::EVT_WORKSPACE_GROUP_OPCODE => ( + ext_workspace_manager_v1::EVT_WORKSPACE_GROUP_OPCODE => ( ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1, () ), - wayland_protocols::ext::workspace::v1::client::ext_workspace_manager_v1::EVT_WORKSPACE_OPCODE => ( + ext_workspace_manager_v1::EVT_WORKSPACE_OPCODE => ( ext_workspace_handle_v1::ExtWorkspaceHandleV1, () ) @@ -90,7 +113,6 @@ impl Dispatch for AppState ); } -use wayland_client::Proxy; impl Dispatch for AppState { fn event( state: &mut Self, @@ -100,23 +122,34 @@ impl Dispatch for AppState { _conn: &Connection, _qh: &QueueHandle, ) { - match event { - ext_workspace_handle_v1::Event::Id { id: _ } => { + let id = proxy.id(); + + match event { + ext_workspace_handle_v1::Event::Id { .. } => { + state.workspaces.insert( + id, + Workspace { activated: false }, + ); - state - .workspaces - .insert(proxy.id(), Workspace { activated: false }); state.emit(); } + ext_workspace_handle_v1::Event::Coordinates { coordinates } => { + let id = proxy.id(); + + if coordinates.len() >= 2 { + state.workspace_coords.insert(id, (coordinates[0], coordinates[1])); + } + + state.emit(); + } + ext_workspace_handle_v1::Event::State { state: flags } => { let active = matches!( flags, wayland_client::WEnum::Value(ext_workspace_handle_v1::State::Active) ); - let id = proxy.id(); - if let Some(ws) = state.workspaces.get_mut(&id) { ws.activated = active; } @@ -125,7 +158,8 @@ impl Dispatch for AppState { } ext_workspace_handle_v1::Event::Removed => { - state.workspaces.remove(&proxy.id()); + state.workspaces.remove(&id); + state.workspace_group.remove(&id); state.emit(); } @@ -136,13 +170,29 @@ impl Dispatch for AppState { impl Dispatch for AppState { fn event( - _state: &mut Self, - _proxy: &ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1, - _event: ext_workspace_group_handle_v1::Event, + state: &mut Self, + proxy: &ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1, + event: ext_workspace_group_handle_v1::Event, _data: &(), _conn: &Connection, _qh: &QueueHandle, ) { - // println!("workspace GROUP event: {:?}", event); + let group_id = proxy.id(); + + match event { + ext_workspace_group_handle_v1::Event::WorkspaceEnter { workspace } => { + state + .workspace_group + .insert(workspace.id(), group_id); + state.emit(); + } + + ext_workspace_group_handle_v1::Event::WorkspaceLeave { workspace } => { + state.workspace_group.remove(&workspace.id()); + state.emit(); + } + + _ => {} + } } -} +} \ No newline at end of file