working workspaces

This commit is contained in:
Henry Hiles 2026-04-19 15:57:01 -04:00
commit add25edbdc
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
9 changed files with 581 additions and 358 deletions

View file

@ -1,12 +1,12 @@
import "package:flight/src/rust/api/workspace_api.dart"; import "package:flight/src/rust/api/workspace_api.dart";
import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:flutter_riverpod/flutter_riverpod.dart";
class WorkspacesController extends StreamNotifier<List<Workspace>> { class WorkspacesController extends StreamNotifier<List<List<Workspace>>> {
@override @override
Stream<List<Workspace>> build() => listenWorkspaces(); Stream<List<List<Workspace>>> build() => listenWorkspaces();
static final provider = static final provider =
StreamNotifierProvider<WorkspacesController, List<Workspace>>( StreamNotifierProvider<WorkspacesController, List<List<Workspace>>>(
WorkspacesController.new, WorkspacesController.new,
); );
} }

View file

@ -6,9 +6,9 @@
import '../frb_generated.dart'; import '../frb_generated.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_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<List<Workspace>> listenWorkspaces() => Stream<List<List<Workspace>>> listenWorkspaces() =>
RustLib.instance.api.crateApiWorkspaceApiListenWorkspaces(); RustLib.instance.api.crateApiWorkspaceApiListenWorkspaces();
class Workspace { class Workspace {

View file

@ -75,7 +75,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
} }
abstract class RustLibApi extends BaseApi { abstract class RustLibApi extends BaseApi {
Stream<List<Workspace>> crateApiWorkspaceApiListenWorkspaces(); Stream<List<List<Workspace>>> crateApiWorkspaceApiListenWorkspaces();
} }
class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
@ -87,14 +87,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
}); });
@override @override
Stream<List<Workspace>> crateApiWorkspaceApiListenWorkspaces() { Stream<List<List<Workspace>>> crateApiWorkspaceApiListenWorkspaces() {
final sink = RustStreamSink<List<Workspace>>(); final sink = RustStreamSink<List<List<Workspace>>>();
unawaited( unawaited(
handler.executeNormal( handler.executeNormal(
NormalTask( NormalTask(
callFfi: (port_) { callFfi: (port_) {
final serializer = SseSerializer(generalizedFrbRustBinding); final serializer = SseSerializer(generalizedFrbRustBinding);
sse_encode_StreamSink_list_workspace_Sse(sink, serializer); sse_encode_StreamSink_list_list_workspace_Sse(sink, serializer);
pdeCallFfi( pdeCallFfi(
generalizedFrbRustBinding, generalizedFrbRustBinding,
serializer, serializer,
@ -125,9 +125,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
} }
@protected @protected
RustStreamSink<List<Workspace>> dco_decode_StreamSink_list_workspace_Sse( RustStreamSink<List<List<Workspace>>>
dynamic raw, dco_decode_StreamSink_list_list_workspace_Sse(dynamic raw) {
) {
// Codec=Dco (DartCObject based), see doc to use other codecs // Codec=Dco (DartCObject based), see doc to use other codecs
throw UnimplementedError(); throw UnimplementedError();
} }
@ -144,6 +143,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return raw as bool; return raw as bool;
} }
@protected
List<List<Workspace>> dco_decode_list_list_workspace(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs
return (raw as List<dynamic>).map(dco_decode_list_workspace).toList();
}
@protected @protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) { Uint8List dco_decode_list_prim_u_8_strict(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs // Codec=Dco (DartCObject based), see doc to use other codecs
@ -185,9 +190,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
} }
@protected @protected
RustStreamSink<List<Workspace>> sse_decode_StreamSink_list_workspace_Sse( RustStreamSink<List<List<Workspace>>>
SseDeserializer deserializer, sse_decode_StreamSink_list_list_workspace_Sse(SseDeserializer deserializer) {
) {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
throw UnimplementedError('Unreachable ()'); throw UnimplementedError('Unreachable ()');
} }
@ -205,6 +209,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return deserializer.buffer.getUint8() != 0; return deserializer.buffer.getUint8() != 0;
} }
@protected
List<List<Workspace>> 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_ = <List<Workspace>>[];
for (var idx_ = 0; idx_ < len_; ++idx_) {
ans_.add(sse_decode_list_workspace(deserializer));
}
return ans_;
}
@protected @protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) { Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
@ -258,15 +276,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
} }
@protected @protected
void sse_encode_StreamSink_list_workspace_Sse( void sse_encode_StreamSink_list_list_workspace_Sse(
RustStreamSink<List<Workspace>> self, RustStreamSink<List<List<Workspace>>> self,
SseSerializer serializer, SseSerializer serializer,
) { ) {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_String( sse_encode_String(
self.setupAndSerialize( self.setupAndSerialize(
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_list_workspace, decodeSuccessData: sse_decode_list_list_workspace,
decodeErrorData: sse_decode_AnyhowException, decodeErrorData: sse_decode_AnyhowException,
), ),
), ),
@ -286,6 +304,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
serializer.buffer.putUint8(self ? 1 : 0); serializer.buffer.putUint8(self ? 1 : 0);
} }
@protected
void sse_encode_list_list_workspace(
List<List<Workspace>> 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 @protected
void sse_encode_list_prim_u_8_strict( void sse_encode_list_prim_u_8_strict(
Uint8List self, Uint8List self,

View file

@ -22,9 +22,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
AnyhowException dco_decode_AnyhowException(dynamic raw); AnyhowException dco_decode_AnyhowException(dynamic raw);
@protected @protected
RustStreamSink<List<Workspace>> dco_decode_StreamSink_list_workspace_Sse( RustStreamSink<List<List<Workspace>>>
dynamic raw, dco_decode_StreamSink_list_list_workspace_Sse(dynamic raw);
);
@protected @protected
String dco_decode_String(dynamic raw); String dco_decode_String(dynamic raw);
@ -32,6 +31,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
bool dco_decode_bool(dynamic raw); bool dco_decode_bool(dynamic raw);
@protected
List<List<Workspace>> dco_decode_list_list_workspace(dynamic raw);
@protected @protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@ -51,9 +53,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer); AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
@protected @protected
RustStreamSink<List<Workspace>> sse_decode_StreamSink_list_workspace_Sse( RustStreamSink<List<List<Workspace>>>
SseDeserializer deserializer, sse_decode_StreamSink_list_list_workspace_Sse(SseDeserializer deserializer);
);
@protected @protected
String sse_decode_String(SseDeserializer deserializer); String sse_decode_String(SseDeserializer deserializer);
@ -61,6 +62,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
bool sse_decode_bool(SseDeserializer deserializer); bool sse_decode_bool(SseDeserializer deserializer);
@protected
List<List<Workspace>> sse_decode_list_list_workspace(
SseDeserializer deserializer,
);
@protected @protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@ -86,8 +92,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
); );
@protected @protected
void sse_encode_StreamSink_list_workspace_Sse( void sse_encode_StreamSink_list_list_workspace_Sse(
RustStreamSink<List<Workspace>> self, RustStreamSink<List<List<Workspace>>> self,
SseSerializer serializer, SseSerializer serializer,
); );
@ -97,6 +103,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_bool(bool self, SseSerializer serializer); void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_list_list_workspace(
List<List<Workspace>> self,
SseSerializer serializer,
);
@protected @protected
void sse_encode_list_prim_u_8_strict( void sse_encode_list_prim_u_8_strict(
Uint8List self, Uint8List self,

View file

@ -24,9 +24,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
AnyhowException dco_decode_AnyhowException(dynamic raw); AnyhowException dco_decode_AnyhowException(dynamic raw);
@protected @protected
RustStreamSink<List<Workspace>> dco_decode_StreamSink_list_workspace_Sse( RustStreamSink<List<List<Workspace>>>
dynamic raw, dco_decode_StreamSink_list_list_workspace_Sse(dynamic raw);
);
@protected @protected
String dco_decode_String(dynamic raw); String dco_decode_String(dynamic raw);
@ -34,6 +33,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
bool dco_decode_bool(dynamic raw); bool dco_decode_bool(dynamic raw);
@protected
List<List<Workspace>> dco_decode_list_list_workspace(dynamic raw);
@protected @protected
Uint8List dco_decode_list_prim_u_8_strict(dynamic raw); Uint8List dco_decode_list_prim_u_8_strict(dynamic raw);
@ -53,9 +55,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer); AnyhowException sse_decode_AnyhowException(SseDeserializer deserializer);
@protected @protected
RustStreamSink<List<Workspace>> sse_decode_StreamSink_list_workspace_Sse( RustStreamSink<List<List<Workspace>>>
SseDeserializer deserializer, sse_decode_StreamSink_list_list_workspace_Sse(SseDeserializer deserializer);
);
@protected @protected
String sse_decode_String(SseDeserializer deserializer); String sse_decode_String(SseDeserializer deserializer);
@ -63,6 +64,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
bool sse_decode_bool(SseDeserializer deserializer); bool sse_decode_bool(SseDeserializer deserializer);
@protected
List<List<Workspace>> sse_decode_list_list_workspace(
SseDeserializer deserializer,
);
@protected @protected
Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer); Uint8List sse_decode_list_prim_u_8_strict(SseDeserializer deserializer);
@ -88,8 +94,8 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
); );
@protected @protected
void sse_encode_StreamSink_list_workspace_Sse( void sse_encode_StreamSink_list_list_workspace_Sse(
RustStreamSink<List<Workspace>> self, RustStreamSink<List<List<Workspace>>> self,
SseSerializer serializer, SseSerializer serializer,
); );
@ -99,6 +105,12 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
void sse_encode_bool(bool self, SseSerializer serializer); void sse_encode_bool(bool self, SseSerializer serializer);
@protected
void sse_encode_list_list_workspace(
List<List<Workspace>> self,
SseSerializer serializer,
);
@protected @protected
void sse_encode_list_prim_u_8_strict( void sse_encode_list_prim_u_8_strict(
Uint8List self, Uint8List self,

View file

@ -16,52 +16,67 @@ class Bar extends ConsumerWidget {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: children:
[ [
ref ...ref
.watch(WorkspacesController.provider) .watch(WorkspacesController.provider)
.whenOrNull( .when(
error: (error, stackTrace) => [ error: (error, stackTrace) => [Text(error.toString())],
Text(error.toString()), loading: () => [],
], data: (value) => value
data: (value) { .map(
return value (group) => Row(
.map( children: group
(element) => IconButton( .map(
onPressed: () {}, (workspace) => IconButton(
icon: Icon( onPressed: () {},
element.activated icon: Icon(
? Icons.circle workspace.activated
: Icons.circle_outlined, ? Icons.circle
: Icons.circle_outlined,
),
), ),
), )
) .toList(),
.toList();
},
) ??
[],
[
TextButton(
onPressed: () {},
child: Text(
DateFormat.Hm().format(
ref
.watch(TimeController.provider)
.when(
data: (time) => time,
loading: DateTime.now,
error: (_, _) => DateTime.now(),
), ),
), )
.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(),
),
),
),
),
],
), ),
], ),
[ Row(
IconButton(onPressed: () {}, icon: Icon(Icons.wifi)), mainAxisSize: MainAxisSize.min,
IconButton(onPressed: () {}, icon: Icon(Icons.bluetooth)), crossAxisAlignment: CrossAxisAlignment.center,
IconButton(onPressed: () {}, icon: Icon(Icons.volume_off)), children: [
], IconButton(onPressed: () {}, icon: Icon(Icons.wifi)),
IconButton(onPressed: () {}, icon: Icon(Icons.bluetooth)),
IconButton(
onPressed: () {},
icon: Icon(Icons.volume_off),
),
],
),
] ]
.map( .map(
(children) => Padding( (child) => Padding(
padding: EdgeInsetsGeometry.directional(bottom: 6), padding: EdgeInsetsGeometry.directional(bottom: 6),
child: Container( child: Container(
height: 42, height: 42,
@ -72,11 +87,7 @@ class Bar extends ConsumerWidget {
).colorScheme.surfaceContainerLow, ).colorScheme.surfaceContainerLow,
borderRadius: BorderRadius.circular(999), borderRadius: BorderRadius.circular(999),
), ),
child: Row( child: child,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: children,
),
), ),
), ),
) )

View file

@ -4,12 +4,12 @@ use std::collections::HashMap;
use crate::{frb_generated::StreamSink, internal::wayland::AppState}; use crate::{frb_generated::StreamSink, internal::wayland::AppState};
#[derive(Clone)] #[derive(Clone, Debug)]
pub struct Workspace { pub struct Workspace {
pub activated: bool, pub activated: bool,
} }
pub fn listen_workspaces(sink: StreamSink<Vec<Workspace>>) -> Result<()> { pub fn listen_workspaces(sink: StreamSink<Vec<Vec<Workspace>>>) -> Result<()> {
std::thread::spawn(move || { std::thread::spawn(move || {
let conn = Connection::connect_to_env().expect("Failed to connect to Wayland"); let conn = Connection::connect_to_env().expect("Failed to connect to Wayland");
@ -18,6 +18,8 @@ pub fn listen_workspaces(sink: StreamSink<Vec<Workspace>>) -> Result<()> {
let mut state = AppState { let mut state = AppState {
workspaces: HashMap::new(), workspaces: HashMap::new(),
workspace_group: HashMap::new(),
workspace_coords: HashMap::new(),
sink, sink,
}; };

View file

@ -2,43 +2,42 @@
// @generated by `flutter_rust_bridge`@ 2.11.1. // @generated by `flutter_rust_bridge`@ 2.11.1.
#![allow( #![allow(
non_camel_case_types, non_camel_case_types,
unused, unused,
non_snake_case, non_snake_case,
clippy::needless_return, clippy::needless_return,
clippy::redundant_closure_call, clippy::redundant_closure_call,
clippy::redundant_closure, clippy::redundant_closure,
clippy::useless_conversion, clippy::useless_conversion,
clippy::unit_arg, clippy::unit_arg,
clippy::unused_unit, clippy::unused_unit,
clippy::double_parens, clippy::double_parens,
clippy::let_and_return, clippy::let_and_return,
clippy::too_many_arguments, clippy::too_many_arguments,
clippy::match_single_binding, clippy::match_single_binding,
clippy::clone_on_copy, clippy::clone_on_copy,
clippy::let_unit_value, clippy::let_unit_value,
clippy::deref_addrof, clippy::deref_addrof,
clippy::explicit_auto_deref, clippy::explicit_auto_deref,
clippy::borrow_deref_ref, clippy::borrow_deref_ref,
clippy::needless_borrow clippy::needless_borrow
)] )]
// Section: imports // 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::{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 // Section: boilerplate
flutter_rust_bridge::frb_generated_boilerplate!( flutter_rust_bridge::frb_generated_boilerplate!(
default_stream_sink_codec = SseCodec, default_stream_sink_codec = SseCodec,
default_rust_opaque = RustOpaqueMoi, default_rust_opaque = RustOpaqueMoi,
default_rust_auto_opaque = RustAutoOpaqueMoi, default_rust_auto_opaque = RustAutoOpaqueMoi,
); );
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1"; pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.11.1";
pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1397669831; pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1397669831;
// Section: executor // Section: executor
@ -46,226 +45,333 @@ flutter_rust_bridge::frb_generated_default_handler!();
// Section: wire_funcs // 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) { fn wire__crate__api__workspace_api__listen_workspaces_impl(
FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec,_,_>(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "listen_workspaces", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { port_: flutter_rust_bridge::for_generated::MessagePort,
let message = unsafe { flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire(ptr_, rust_vec_len_, data_len_) }; ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
let mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message); rust_vec_len_: i32,
let api_sink = <StreamSink<Vec<crate::api::workspace_api::Workspace>,flutter_rust_bridge::for_generated::SseCodec>>::sse_decode(&mut deserializer);deserializer.end(); move |context| { data_len_: i32,
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) FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::<flutter_rust_bridge::for_generated::SseCodec, _, _>(
})()) 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 = <StreamSink<
Vec<Vec<crate::api::workspace_api::Workspace>>,
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 // 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 = <String>::sse_decode(deserializer);
return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);
}
}
impl SseDecode for flutter_rust_bridge::for_generated::anyhow::Error { impl SseDecode
// Codec=Sse (Serialization based), see doc to use other codecs for StreamSink<
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut inner = <String>::sse_decode(deserializer); Vec<Vec<crate::api::workspace_api::Workspace>>,
return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);} 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 = <String>::sse_decode(deserializer);
return StreamSink::deserialize(inner);
}
}
impl SseDecode for StreamSink<Vec<crate::api::workspace_api::Workspace>,flutter_rust_bridge::for_generated::SseCodec> { impl SseDecode for String {
// Codec=Sse (Serialization based), see doc to use other codecs // 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 = <String>::sse_decode(deserializer); fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
return StreamSink::deserialize(inner);} let mut inner = <Vec<u8>>::sse_decode(deserializer);
} return String::from_utf8(inner).unwrap();
}
}
impl SseDecode for String { impl SseDecode for bool {
// Codec=Sse (Serialization based), see doc to use other codecs // 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 = <Vec<u8>>::sse_decode(deserializer); fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
return String::from_utf8(inner).unwrap();} deserializer.cursor.read_u8().unwrap() != 0
} }
}
impl SseDecode for bool { impl SseDecode for Vec<Vec<crate::api::workspace_api::Workspace>> {
// Codec=Sse (Serialization based), see doc to use other codecs // 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} fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
} let mut len_ = <i32>::sse_decode(deserializer);
impl SseDecode for Vec<u8> {
// 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_ = <i32>::sse_decode(deserializer);
let mut ans_ = vec![]; let mut ans_ = vec![];
for idx_ in 0..len_ { ans_.push(<u8>::sse_decode(deserializer)); } for idx_ in 0..len_ {
return ans_;} ans_.push(<Vec<crate::api::workspace_api::Workspace>>::sse_decode(
} deserializer,
));
}
return ans_;
}
}
impl SseDecode for Vec<crate::api::workspace_api::Workspace> { impl SseDecode for Vec<u8> {
// Codec=Sse (Serialization based), see doc to use other codecs // 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_ = <i32>::sse_decode(deserializer); fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
let mut len_ = <i32>::sse_decode(deserializer);
let mut ans_ = vec![]; let mut ans_ = vec![];
for idx_ in 0..len_ { ans_.push(<crate::api::workspace_api::Workspace>::sse_decode(deserializer)); } for idx_ in 0..len_ {
return ans_;} ans_.push(<u8>::sse_decode(deserializer));
} }
return ans_;
}
}
impl SseDecode for u8 { impl SseDecode for Vec<crate::api::workspace_api::Workspace> {
// Codec=Sse (Serialization based), see doc to use other codecs // 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()} fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
} let mut len_ = <i32>::sse_decode(deserializer);
let mut ans_ = vec![];
for idx_ in 0..len_ {
ans_.push(<crate::api::workspace_api::Workspace>::sse_decode(
deserializer,
));
}
return ans_;
}
}
impl SseDecode for () { impl SseDecode for u8 {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {} fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
} deserializer.cursor.read_u8().unwrap()
}
}
impl SseDecode for crate::api::workspace_api::Workspace { impl SseDecode for () {
// Codec=Sse (Serialization based), see doc to use other codecs // 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 = <bool>::sse_decode(deserializer); fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {}
return crate::api::workspace_api::Workspace{activated: var_activated};} }
}
impl SseDecode for i32 { impl SseDecode for crate::api::workspace_api::Workspace {
// Codec=Sse (Serialization based), see doc to use other codecs // 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::<NativeEndian>().unwrap()} fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
} let mut var_activated = <bool>::sse_decode(deserializer);
return crate::api::workspace_api::Workspace {
activated: var_activated,
};
}
}
fn pde_ffi_dispatcher_primary_impl( impl SseDecode for i32 {
func_id: i32,port: flutter_rust_bridge::for_generated::MessagePort, // Codec=Sse (Serialization based), see doc to use other codecs
ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
rust_vec_len: i32, deserializer.cursor.read_i32::<NativeEndian>().unwrap()
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( fn pde_ffi_dispatcher_primary_impl(
func_id: i32, func_id: i32,
ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, port: flutter_rust_bridge::for_generated::MessagePort,
rust_vec_len: i32, ptr: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr,
data_len: i32, rust_vec_len: i32,
) -> flutter_rust_bridge::for_generated::WireSyncRust2DartSse { data_len: i32,
// Codec=Pde (Serialization + dispatch), see doc to use other codecs ) {
match func_id { // Codec=Pde (Serialization + dispatch), see doc to use other codecs
match func_id {
_ => unreachable!(), 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 // Section: rust2dart
// Codec=Dco (DartCObject based), see doc to use other codecs // Codec=Dco (DartCObject based), see doc to use other codecs
impl flutter_rust_bridge::IntoDart for crate::api::workspace_api::Workspace { impl flutter_rust_bridge::IntoDart for crate::api::workspace_api::Workspace {
fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
[ [self.activated.into_into_dart().into_dart()].into_dart()
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::for_generated::IntoDartExceptPrimitive for crate::api::workspace_api::Workspace {} {
impl flutter_rust_bridge::IntoIntoDart<crate::api::workspace_api::Workspace> for crate::api::workspace_api::Workspace { }
fn into_into_dart(self) -> crate::api::workspace_api::Workspace { impl flutter_rust_bridge::IntoIntoDart<crate::api::workspace_api::Workspace>
self 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) {
<String>::sse_encode(format!("{:?}", self), serializer);
}
}
impl SseEncode
for StreamSink<
Vec<Vec<crate::api::workspace_api::Workspace>>,
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) {
<Vec<u8>>::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<Vec<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) {
<i32>::sse_encode(self.len() as _, serializer);
for item in self {
<Vec<crate::api::workspace_api::Workspace>>::sse_encode(item, serializer);
} }
}
}
impl SseEncode for flutter_rust_bridge::for_generated::anyhow::Error { impl SseEncode for Vec<u8> {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<String>::sse_encode(format!("{:?}", self), serializer);} fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
} <i32>::sse_encode(self.len() as _, serializer);
for item in self {
impl SseEncode for StreamSink<Vec<crate::api::workspace_api::Workspace>,flutter_rust_bridge::for_generated::SseCodec> { <u8>::sse_encode(item, serializer);
// 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) {<Vec<u8>>::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<u8> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<i32>::sse_encode(self.len() as _, serializer);
for item in self { <u8>::sse_encode(item, serializer); }}
}
impl SseEncode for Vec<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) {<i32>::sse_encode(self.len() as _, serializer);
for item in self { <crate::api::workspace_api::Workspace>::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) {<bool>::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::<NativeEndian>(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!();
} }
#[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<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) {
<i32>::sse_encode(self.len() as _, serializer);
for item in self {
<crate::api::workspace_api::Workspace>::sse_encode(item, serializer);
} }
#[cfg(target_family = "wasm")] }
pub use web::*; }
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) {
<bool>::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::<NativeEndian>(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::*;

View file

@ -2,38 +2,62 @@ use crate::{frb_generated::StreamSink, workspace_api::Workspace};
use std::collections::HashMap; use std::collections::HashMap;
use wayland_client::{ 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::{ use wayland_protocols::ext::workspace::v1::client::{
ext_workspace_group_handle_v1, ext_workspace_handle_v1, ext_workspace_manager_v1, ext_workspace_group_handle_v1, ext_workspace_handle_v1, ext_workspace_manager_v1,
}; };
// ------------------------
// App State
// ------------------------
pub struct AppState { pub struct AppState {
pub workspaces: HashMap<ObjectId, Workspace>, pub workspaces: HashMap<ObjectId, Workspace>,
pub sink: StreamSink<Vec<Workspace>>, pub workspace_group: HashMap<ObjectId, ObjectId>, // workspace -> group
pub workspace_coords: HashMap<ObjectId, (u8, u8)>,
pub sink: StreamSink<Vec<Vec<Workspace>>>,
} }
impl AppState { impl AppState {
fn emit(&self) { fn emit(&self) {
let mut entries: Vec<(&ObjectId, &Workspace)> = self.workspaces.iter().collect(); let mut groups: HashMap<ObjectId, Vec<(&ObjectId, &Workspace)>> = HashMap::new();
entries.sort_by_key( for (ws_id, ws) in &self.workspaces {
|entry: &(&ObjectId, &Workspace)| -> u32 { if let Some(group_id) = self.workspace_group.get(ws_id) {
entry.0.protocol_id() groups
}, .entry(group_id.clone())
); .or_insert_with(Vec::new)
.push((ws_id, ws));
}
}
let sorted: Vec<Workspace> = entries let mut grouped: Vec<(ObjectId, Vec<(&ObjectId, &Workspace)>)> =
.into_iter() groups.into_iter().collect();
.map(
|entry: (&ObjectId, &Workspace)| -> Workspace {
entry.1.clone()
},
)
.collect();
let _ = self.sink.add(sorted); grouped.sort_by_key(|(group_id, _)| group_id.protocol_id());
}
let result: Vec<Vec<Workspace>> = 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<wl_registry::WlRegistry, ()> for AppState { impl Dispatch<wl_registry::WlRegistry, ()> for AppState {
@ -71,18 +95,17 @@ impl Dispatch<ext_workspace_manager_v1::ExtWorkspaceManagerV1, ()> for AppState
_data: &(), _data: &(),
_conn: &Connection, _conn: &Connection,
_qh: &QueueHandle<Self>, _qh: &QueueHandle<Self>,
) { ) {}
}
event_created_child!( event_created_child!(
AppState, AppState,
ext_workspace_manager_v1::ExtWorkspaceManagerV1, 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, 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, ext_workspace_handle_v1::ExtWorkspaceHandleV1,
() ()
) )
@ -90,7 +113,6 @@ impl Dispatch<ext_workspace_manager_v1::ExtWorkspaceManagerV1, ()> for AppState
); );
} }
use wayland_client::Proxy;
impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState { impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
fn event( fn event(
state: &mut Self, state: &mut Self,
@ -100,23 +122,34 @@ impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
_conn: &Connection, _conn: &Connection,
_qh: &QueueHandle<Self>, _qh: &QueueHandle<Self>,
) { ) {
match event { let id = proxy.id();
ext_workspace_handle_v1::Event::Id { 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(); 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 } => { ext_workspace_handle_v1::Event::State { state: flags } => {
let active = matches!( let active = matches!(
flags, flags,
wayland_client::WEnum::Value(ext_workspace_handle_v1::State::Active) wayland_client::WEnum::Value(ext_workspace_handle_v1::State::Active)
); );
let id = proxy.id();
if let Some(ws) = state.workspaces.get_mut(&id) { if let Some(ws) = state.workspaces.get_mut(&id) {
ws.activated = active; ws.activated = active;
} }
@ -125,7 +158,8 @@ impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
} }
ext_workspace_handle_v1::Event::Removed => { ext_workspace_handle_v1::Event::Removed => {
state.workspaces.remove(&proxy.id()); state.workspaces.remove(&id);
state.workspace_group.remove(&id);
state.emit(); state.emit();
} }
@ -136,13 +170,29 @@ impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
impl Dispatch<ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1, ()> for AppState { impl Dispatch<ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1, ()> for AppState {
fn event( fn event(
_state: &mut Self, state: &mut Self,
_proxy: &ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1, proxy: &ext_workspace_group_handle_v1::ExtWorkspaceGroupHandleV1,
_event: ext_workspace_group_handle_v1::Event, event: ext_workspace_group_handle_v1::Event,
_data: &(), _data: &(),
_conn: &Connection, _conn: &Connection,
_qh: &QueueHandle<Self>, _qh: &QueueHandle<Self>,
) { ) {
// 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();
}
_ => {}
}
} }
} }