diff --git a/flutter_rust_bridge.yaml b/flutter_rust_bridge.yaml index e15ed91..83d00f9 100644 --- a/flutter_rust_bridge.yaml +++ b/flutter_rust_bridge.yaml @@ -1,3 +1,4 @@ rust_input: crate::api rust_root: rust/ -dart_output: lib/src/rust \ No newline at end of file +dart_output: lib/src/rust +enable_lifetime: true \ No newline at end of file diff --git a/lib/controllers/workspaces_controller.dart b/lib/controllers/workspaces_controller.dart index 2356b2d..fda948e 100644 --- a/lib/controllers/workspaces_controller.dart +++ b/lib/controllers/workspaces_controller.dart @@ -1,10 +1,9 @@ -import "package:flight/src/rust/api/model.dart"; import "package:flight/src/rust/api/workspace_api.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; class WorkspacesController extends StreamNotifier> { @override - Stream> build() => startWorkspaceStream(); + Stream> build() => listenWorkspaces(); static final provider = StreamNotifierProvider>( diff --git a/lib/src/rust/api/model.dart b/lib/src/rust/api/model.dart deleted file mode 100644 index 726c162..0000000 --- a/lib/src/rust/api/model.dart +++ /dev/null @@ -1,29 +0,0 @@ -// This file is automatically generated, so please do not edit it. -// @generated by `flutter_rust_bridge`@ 2.11.1. - -// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import - -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`, `fmt` - -class Workspace { - final String? id; - final String name; - final bool active; - - const Workspace({this.id, required this.name, required this.active}); - - @override - int get hashCode => id.hashCode ^ name.hashCode ^ active.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is Workspace && - runtimeType == other.runtimeType && - id == other.id && - name == other.name && - active == other.active; -} diff --git a/lib/src/rust/api/workspace_api.dart b/lib/src/rust/api/workspace_api.dart index 4c6c162..e743019 100644 --- a/lib/src/rust/api/workspace_api.dart +++ b/lib/src/rust/api/workspace_api.dart @@ -4,8 +4,25 @@ // ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import import '../frb_generated.dart'; -import 'model.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; -Stream> startWorkspaceStream() => - RustLib.instance.api.crateApiWorkspaceApiStartWorkspaceStream(); +// 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` + +Stream> listenWorkspaces() => + RustLib.instance.api.crateApiWorkspaceApiListenWorkspaces(); + +class Workspace { + final bool activated; + + const Workspace({required this.activated}); + + @override + int get hashCode => activated.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Workspace && + runtimeType == other.runtimeType && + activated == other.activated; +} diff --git a/lib/src/rust/api/workspace_api/ext_workspace_group_handle_v1.dart b/lib/src/rust/api/workspace_api/ext_workspace_group_handle_v1.dart new file mode 100644 index 0000000..408d2f0 --- /dev/null +++ b/lib/src/rust/api/workspace_api/ext_workspace_group_handle_v1.dart @@ -0,0 +1,31 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +import '../../frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `GroupCapabilities` +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `assert_receiver_is_total_eq`, `backend`, `bits`, `borrow`, `clone`, `clone`, `data`, `eq`, `eq`, `eq`, `fmt`, `fmt`, `fmt`, `fmt`, `from_bits_retain`, `from_id`, `from`, `hash`, `hash`, `id`, `inert`, `interface`, `object_data`, `parse_event`, `send_constructor`, `send_request`, `try_from`, `version`, `write_request` + +// Rust type: RustOpaqueMoi> +abstract class ExtWorkspaceGroupHandleV1 implements RustOpaqueInterface { + ///create a new workspace + /// + ///Request that the compositor create a new workspace with the given name + ///and assign it to this group. + /// + ///There is no guarantee that the compositor will create a new workspace, + ///or that the created workspace will have the provided name. + Future createWorkspace({required String workspace}); + + ///destroy the ext_workspace_group_handle_v1 object + /// + ///Destroys the ext_workspace_group_handle_v1 object. + /// + ///This request should be send either when the client does not want to + ///use the workspace group object any more or after the removed event to finalize + ///the destruction of the object. + Future destroy(); +} diff --git a/lib/src/rust/api/workspace_api/ext_workspace_handle_v1.dart b/lib/src/rust/api/workspace_api/ext_workspace_handle_v1.dart new file mode 100644 index 0000000..6c7e828 --- /dev/null +++ b/lib/src/rust/api/workspace_api/ext_workspace_handle_v1.dart @@ -0,0 +1,54 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +import '../../frb_generated.dart'; +import 'ext_workspace_group_handle_v1.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `State`, `WorkspaceCapabilities` +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `assert_receiver_is_total_eq`, `assert_receiver_is_total_eq`, `backend`, `bits`, `bits`, `borrow`, `clone`, `clone`, `clone`, `data`, `eq`, `eq`, `eq`, `eq`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `from_bits_retain`, `from_bits_retain`, `from_id`, `from`, `from`, `hash`, `hash`, `hash`, `id`, `inert`, `interface`, `object_data`, `parse_event`, `send_constructor`, `send_request`, `try_from`, `try_from`, `version`, `write_request` + +// Rust type: RustOpaqueMoi> +abstract class ExtWorkspaceHandleV1 implements RustOpaqueInterface { + ///activate the workspace + /// + ///Request that this workspace be activated. + /// + ///There is no guarantee the workspace will be actually activated, and + ///behaviour may be compositor-dependent. For example, activating a + ///workspace may or may not deactivate all other workspaces in the same + ///group. + Future activate(); + + ///assign workspace to group + /// + ///Requests that this workspace is assigned to the given workspace group. + /// + ///There is no guarantee the workspace will be assigned. + Future assign({required ExtWorkspaceGroupHandleV1 workspaceGroup}); + + ///deactivate the workspace + /// + ///Request that this workspace be deactivated. + /// + ///There is no guarantee the workspace will be actually deactivated. + Future deactivate(); + + ///destroy the ext_workspace_handle_v1 object + /// + ///Destroys the ext_workspace_handle_v1 object. + /// + ///This request should be made either when the client does not want to + ///use the workspace object any more or after the remove event to finalize + ///the destruction of the object. + Future destroy(); + + ///remove the workspace + /// + ///Request that this workspace be removed. + /// + ///There is no guarantee the workspace will be actually removed. + Future remove(); +} diff --git a/lib/src/rust/api/workspace_api/ext_workspace_manager_v1.dart b/lib/src/rust/api/workspace_api/ext_workspace_manager_v1.dart new file mode 100644 index 0000000..8a5581f --- /dev/null +++ b/lib/src/rust/api/workspace_api/ext_workspace_manager_v1.dart @@ -0,0 +1,47 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +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): `backend`, `borrow`, `clone`, `data`, `eq`, `eq`, `fmt`, `fmt`, `fmt`, `from_id`, `hash`, `id`, `inert`, `interface`, `object_data`, `parse_event`, `send_constructor`, `send_request`, `version`, `write_request` + +// Rust type: RustOpaqueMoi>> +abstract class Event implements RustOpaqueInterface { + ///Get the opcode number of this message + Future opcode(); +} + +// Rust type: RustOpaqueMoi> +abstract class ExtWorkspaceManagerV1 implements RustOpaqueInterface { + ///all requests about the workspaces have been sent + /// + ///The client must send this request after it has finished sending other + ///requests. The compositor must process a series of requests preceding a + ///commit request atomically. + /// + ///This allows changes to the workspace properties to be seen as atomic, + ///even if they happen via multiple events, and even if they involve + ///multiple ext_workspace_handle_v1 objects, for example, deactivating one + ///workspace and activating another. + Future commit(); + + ///stop sending events + /// + ///Indicates the client no longer wishes to receive events for new + ///workspace groups. However the compositor may emit further workspace + ///events, until the finished event is emitted. The compositor is expected + ///to send the finished event eventually once the stop request has been processed. + /// + ///The client must not send any requests after this one, doing so will raise a wl_display + ///invalid_object error. + Future stop(); +} + +// Rust type: RustOpaqueMoi >>> +abstract class Request implements RustOpaqueInterface { + ///Get the opcode number of this message + Future opcode(); +} diff --git a/lib/src/rust/api/workspace_api/generated/ext_workspace_group_handle_v1.dart b/lib/src/rust/api/workspace_api/generated/ext_workspace_group_handle_v1.dart new file mode 100644 index 0000000..0863a7c --- /dev/null +++ b/lib/src/rust/api/workspace_api/generated/ext_workspace_group_handle_v1.dart @@ -0,0 +1,31 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +import '../../../frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `GroupCapabilities` +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `assert_receiver_is_total_eq`, `backend`, `bits`, `borrow`, `clone`, `clone`, `data`, `eq`, `eq`, `eq`, `fmt`, `fmt`, `fmt`, `fmt`, `from_bits_retain`, `from_id`, `from`, `hash`, `hash`, `id`, `inert`, `interface`, `object_data`, `parse_event`, `send_constructor`, `send_request`, `try_from`, `version`, `write_request` + +// Rust type: RustOpaqueMoi> +abstract class ExtWorkspaceGroupHandleV1 implements RustOpaqueInterface { + ///create a new workspace + /// + ///Request that the compositor create a new workspace with the given name + ///and assign it to this group. + /// + ///There is no guarantee that the compositor will create a new workspace, + ///or that the created workspace will have the provided name. + Future createWorkspace({required String workspace}); + + ///destroy the ext_workspace_group_handle_v1 object + /// + ///Destroys the ext_workspace_group_handle_v1 object. + /// + ///This request should be send either when the client does not want to + ///use the workspace group object any more or after the removed event to finalize + ///the destruction of the object. + Future destroy(); +} diff --git a/lib/src/rust/api/workspace_api/generated/ext_workspace_handle_v1.dart b/lib/src/rust/api/workspace_api/generated/ext_workspace_handle_v1.dart new file mode 100644 index 0000000..6c9aa1d --- /dev/null +++ b/lib/src/rust/api/workspace_api/generated/ext_workspace_handle_v1.dart @@ -0,0 +1,54 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +import '../../../frb_generated.dart'; +import 'ext_workspace_group_handle_v1.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + +// These types are ignored because they are neither used by any `pub` functions nor (for structs and enums) marked `#[frb(unignore)]`: `State`, `WorkspaceCapabilities` +// These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `assert_receiver_is_total_eq`, `assert_receiver_is_total_eq`, `backend`, `bits`, `bits`, `borrow`, `clone`, `clone`, `clone`, `data`, `eq`, `eq`, `eq`, `eq`, `fmt`, `fmt`, `fmt`, `fmt`, `fmt`, `from_bits_retain`, `from_bits_retain`, `from_id`, `from`, `from`, `hash`, `hash`, `hash`, `id`, `inert`, `interface`, `object_data`, `parse_event`, `send_constructor`, `send_request`, `try_from`, `try_from`, `version`, `write_request` + +// Rust type: RustOpaqueMoi> +abstract class ExtWorkspaceHandleV1 implements RustOpaqueInterface { + ///activate the workspace + /// + ///Request that this workspace be activated. + /// + ///There is no guarantee the workspace will be actually activated, and + ///behaviour may be compositor-dependent. For example, activating a + ///workspace may or may not deactivate all other workspaces in the same + ///group. + Future activate(); + + ///assign workspace to group + /// + ///Requests that this workspace is assigned to the given workspace group. + /// + ///There is no guarantee the workspace will be assigned. + Future assign({required ExtWorkspaceGroupHandleV1 workspaceGroup}); + + ///deactivate the workspace + /// + ///Request that this workspace be deactivated. + /// + ///There is no guarantee the workspace will be actually deactivated. + Future deactivate(); + + ///destroy the ext_workspace_handle_v1 object + /// + ///Destroys the ext_workspace_handle_v1 object. + /// + ///This request should be made either when the client does not want to + ///use the workspace object any more or after the remove event to finalize + ///the destruction of the object. + Future destroy(); + + ///remove the workspace + /// + ///Request that this workspace be removed. + /// + ///There is no guarantee the workspace will be actually removed. + Future remove(); +} diff --git a/lib/src/rust/api/workspace_api/generated/ext_workspace_manager_v1.dart b/lib/src/rust/api/workspace_api/generated/ext_workspace_manager_v1.dart new file mode 100644 index 0000000..65900dd --- /dev/null +++ b/lib/src/rust/api/workspace_api/generated/ext_workspace_manager_v1.dart @@ -0,0 +1,47 @@ +// This file is automatically generated, so please do not edit it. +// @generated by `flutter_rust_bridge`@ 2.11.1. + +// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import + +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): `backend`, `borrow`, `clone`, `data`, `eq`, `eq`, `fmt`, `fmt`, `fmt`, `from_id`, `hash`, `id`, `inert`, `interface`, `object_data`, `parse_event`, `send_constructor`, `send_request`, `version`, `write_request` + +// Rust type: RustOpaqueMoi>> +abstract class Event implements RustOpaqueInterface { + ///Get the opcode number of this message + Future opcode(); +} + +// Rust type: RustOpaqueMoi> +abstract class ExtWorkspaceManagerV1 implements RustOpaqueInterface { + ///all requests about the workspaces have been sent + /// + ///The client must send this request after it has finished sending other + ///requests. The compositor must process a series of requests preceding a + ///commit request atomically. + /// + ///This allows changes to the workspace properties to be seen as atomic, + ///even if they happen via multiple events, and even if they involve + ///multiple ext_workspace_handle_v1 objects, for example, deactivating one + ///workspace and activating another. + Future commit(); + + ///stop sending events + /// + ///Indicates the client no longer wishes to receive events for new + ///workspace groups. However the compositor may emit further workspace + ///events, until the finished event is emitted. The compositor is expected + ///to send the finished event eventually once the stop request has been processed. + /// + ///The client must not send any requests after this one, doing so will raise a wl_display + ///invalid_object error. + Future stop(); +} + +// Rust type: RustOpaqueMoi >>> +abstract class Request implements RustOpaqueInterface { + ///Get the opcode number of this message + Future opcode(); +} diff --git a/lib/src/rust/frb_generated.dart b/lib/src/rust/frb_generated.dart index 481ee86..d335ae7 100644 --- a/lib/src/rust/frb_generated.dart +++ b/lib/src/rust/frb_generated.dart @@ -3,7 +3,6 @@ // ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field -import 'api/model.dart'; import 'api/workspace_api.dart'; import 'dart:async'; import 'dart:convert'; @@ -65,7 +64,7 @@ class RustLib extends BaseEntrypoint { String get codegenVersion => '2.11.1'; @override - int get rustContentHash => 804335101; + int get rustContentHash => 1397669831; static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( @@ -76,7 +75,7 @@ class RustLib extends BaseEntrypoint { } abstract class RustLibApi extends BaseApi { - Stream> crateApiWorkspaceApiStartWorkspaceStream(); + Stream> crateApiWorkspaceApiListenWorkspaces(); } class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @@ -88,7 +87,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { }); @override - Stream> crateApiWorkspaceApiStartWorkspaceStream() { + Stream> crateApiWorkspaceApiListenWorkspaces() { final sink = RustStreamSink>(); unawaited( handler.executeNormal( @@ -105,9 +104,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { }, codec: SseCodec( decodeSuccessData: sse_decode_unit, - decodeErrorData: null, + decodeErrorData: sse_decode_AnyhowException, ), - constMeta: kCrateApiWorkspaceApiStartWorkspaceStreamConstMeta, + constMeta: kCrateApiWorkspaceApiListenWorkspacesConstMeta, argValues: [sink], apiImpl: this, ), @@ -116,11 +115,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return sink.stream; } - TaskConstMeta get kCrateApiWorkspaceApiStartWorkspaceStreamConstMeta => - const TaskConstMeta( - debugName: "start_workspace_stream", - argNames: ["sink"], - ); + TaskConstMeta get kCrateApiWorkspaceApiListenWorkspacesConstMeta => + const TaskConstMeta(debugName: "listen_workspaces", argNames: ["sink"]); @protected AnyhowException dco_decode_AnyhowException(dynamic raw) { @@ -160,12 +156,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return (raw as List).map(dco_decode_workspace).toList(); } - @protected - String? dco_decode_opt_String(dynamic raw) { - // Codec=Dco (DartCObject based), see doc to use other codecs - return raw == null ? null : dco_decode_String(raw); - } - @protected int dco_decode_u_8(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -182,13 +172,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { Workspace dco_decode_workspace(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs final arr = raw as List; - if (arr.length != 3) - throw Exception('unexpected arr length: expect 3 but see ${arr.length}'); - return Workspace( - id: dco_decode_opt_String(arr[0]), - name: dco_decode_String(arr[1]), - active: dco_decode_bool(arr[2]), - ); + if (arr.length != 1) + throw Exception('unexpected arr length: expect 1 but see ${arr.length}'); + return Workspace(activated: dco_decode_bool(arr[0])); } @protected @@ -238,17 +224,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return ans_; } - @protected - String? sse_decode_opt_String(SseDeserializer deserializer) { - // Codec=Sse (Serialization based), see doc to use other codecs - - if (sse_decode_bool(deserializer)) { - return (sse_decode_String(deserializer)); - } else { - return null; - } - } - @protected int sse_decode_u_8(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -263,10 +238,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @protected Workspace sse_decode_workspace(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs - var var_id = sse_decode_opt_String(deserializer); - var var_name = sse_decode_String(deserializer); - var var_active = sse_decode_bool(deserializer); - return Workspace(id: var_id, name: var_name, active: var_active); + var var_activated = sse_decode_bool(deserializer); + return Workspace(activated: var_activated); } @protected @@ -335,16 +308,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } - @protected - void sse_encode_opt_String(String? self, SseSerializer serializer) { - // Codec=Sse (Serialization based), see doc to use other codecs - - sse_encode_bool(self != null, serializer); - if (self != null) { - sse_encode_String(self, serializer); - } - } - @protected void sse_encode_u_8(int self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -359,9 +322,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { @protected void sse_encode_workspace(Workspace self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs - sse_encode_opt_String(self.id, serializer); - sse_encode_String(self.name, serializer); - sse_encode_bool(self.active, serializer); + sse_encode_bool(self.activated, serializer); } @protected diff --git a/lib/src/rust/frb_generated.io.dart b/lib/src/rust/frb_generated.io.dart index c8fe5a3..7e5fcc7 100644 --- a/lib/src/rust/frb_generated.io.dart +++ b/lib/src/rust/frb_generated.io.dart @@ -3,7 +3,6 @@ // ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field -import 'api/model.dart'; import 'api/workspace_api.dart'; import 'dart:async'; import 'dart:convert'; @@ -39,9 +38,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected List dco_decode_list_workspace(dynamic raw); - @protected - String? dco_decode_opt_String(dynamic raw); - @protected int dco_decode_u_8(dynamic raw); @@ -71,9 +67,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected List sse_decode_list_workspace(SseDeserializer deserializer); - @protected - String? sse_decode_opt_String(SseDeserializer deserializer); - @protected int sse_decode_u_8(SseDeserializer deserializer); @@ -116,9 +109,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_opt_String(String? self, SseSerializer serializer); - @protected void sse_encode_u_8(int self, SseSerializer serializer); diff --git a/lib/src/rust/frb_generated.web.dart b/lib/src/rust/frb_generated.web.dart index 2ac7a6d..48a5e47 100644 --- a/lib/src/rust/frb_generated.web.dart +++ b/lib/src/rust/frb_generated.web.dart @@ -6,7 +6,6 @@ // Static analysis wrongly picks the IO variant, thus ignore this // ignore_for_file: argument_type_not_assignable -import 'api/model.dart'; import 'api/workspace_api.dart'; import 'dart:async'; import 'dart:convert'; @@ -41,9 +40,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected List dco_decode_list_workspace(dynamic raw); - @protected - String? dco_decode_opt_String(dynamic raw); - @protected int dco_decode_u_8(dynamic raw); @@ -73,9 +69,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected List sse_decode_list_workspace(SseDeserializer deserializer); - @protected - String? sse_decode_opt_String(SseDeserializer deserializer); - @protected int sse_decode_u_8(SseDeserializer deserializer); @@ -118,9 +111,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { SseSerializer serializer, ); - @protected - void sse_encode_opt_String(String? self, SseSerializer serializer); - @protected void sse_encode_u_8(int self, SseSerializer serializer); diff --git a/lib/widgets/bar.dart b/lib/widgets/bar.dart index f6e8507..4db9ba2 100644 --- a/lib/widgets/bar.dart +++ b/lib/widgets/bar.dart @@ -1,5 +1,8 @@ +import 'dart:developer'; + import 'package:flight/controllers/time_controller.dart'; import 'package:flight/controllers/workspaces_controller.dart'; +import 'package:flight/widgets/loading.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; @@ -24,18 +27,24 @@ class Bar extends ConsumerWidget { ref .watch(WorkspacesController.provider) .whenOrNull( - data: (value) => value - .map( - (element) => IconButton( - onPressed: () {}, - icon: Icon( - element.active - ? Icons.circle - : Icons.circle_outlined, + error: (error, stackTrace) => [ + Text(error.toString()), + ], + loading: () => [Text("loading")], + data: (value) { + return value + .map( + (element) => IconButton( + onPressed: () {}, + icon: Icon( + element.activated + ? Icons.circle + : Icons.circle_outlined, + ), ), - ), - ) - .toList(), + ) + .toList(); + }, ) ?? [], [ diff --git a/linux/nix/devshell.nix b/linux/nix/devshell.nix index 54a8b06..b65e322 100644 --- a/linux/nix/devshell.nix +++ b/linux/nix/devshell.nix @@ -7,6 +7,7 @@ pkgs.mkShell { gtk-layer-shell cargo + rustfmt flutter_rust_bridge_codegen (pkgs.writeShellScriptBin "rustup" (builtins.readFile ./fake-rustup.sh)) diff --git a/rust/Cargo.toml b/rust/Cargo.toml index ade4174..55ec7a9 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -7,12 +7,11 @@ edition = "2021" crate-type = ["cdylib", "staticlib"] [dependencies] +wayland-scanner = "0.31" flutter_rust_bridge = "=2.11.1" tokio = { version = "1", features = ["rt-multi-thread", "macros"] } futures = "0.3" - wayland-client = "0.31" -wayland-scanner = "0.31" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/rust/src/api/mod.rs b/rust/src/api/mod.rs index 4b88929..7ed5f32 100644 --- a/rust/src/api/mod.rs +++ b/rust/src/api/mod.rs @@ -1,2 +1 @@ -pub mod model; -pub mod workspace_api; \ No newline at end of file +pub mod workspace_api; diff --git a/rust/src/api/model.rs b/rust/src/api/model.rs deleted file mode 100644 index 3f9f965..0000000 --- a/rust/src/api/model.rs +++ /dev/null @@ -1,8 +0,0 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Workspace { - pub id: Option, - pub name: String, - pub active: bool, -} \ No newline at end of file diff --git a/rust/src/api/workspace_api.rs b/rust/src/api/workspace_api.rs index 61fa2ba..5104589 100644 --- a/rust/src/api/workspace_api.rs +++ b/rust/src/api/workspace_api.rs @@ -1,15 +1,38 @@ -use crate::frb_generated::StreamSink; -use crate::api::model::Workspace; +use serde_json::Result; +use wayland_client::{Connection, EventQueue}; +use std::collections::HashMap; +use crate::{frb_generated::StreamSink, internal::wayland::AppState}; -pub fn start_workspace_stream(sink: StreamSink>) { + +#[derive(Clone)] +pub struct Workspace { + pub activated: bool, +} + +pub fn listen_workspaces(sink: StreamSink>) -> Result<()> { std::thread::spawn(move || { + // Connect to Wayland + let conn = Connection::connect_to_env().expect("Failed to connect to Wayland"); + + let mut event_queue: EventQueue = conn.new_event_queue(); + let qh = event_queue.handle(); + + // Initialize state + let mut state = AppState { + workspaces: HashMap::new(), + sink, + }; + + // Get registry (this triggers wl_registry events → binds manager) + conn.display().get_registry(&qh, ()); + + // Main event loop loop { - // Replace with real shared state later - let data = vec![]; - - sink.add(data).ok(); - - std::thread::sleep(std::time::Duration::from_millis(500)); + event_queue + .blocking_dispatch(&mut state) + .expect("Wayland dispatch failed"); } }); + + Ok(()) } \ No newline at end of file diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index 6b656ca..94a03fc 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -37,7 +37,7 @@ flutter_rust_bridge::frb_generated_boilerplate!( 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 = 804335101; + pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1397669831; // Section: executor @@ -46,13 +46,13 @@ flutter_rust_bridge::frb_generated_default_handler!(); // Section: wire_funcs -fn wire__crate__api__workspace_api__start_workspace_stream_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: "start_workspace_stream", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { +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::<_, ()>((move || { - let output_ok = Result::<_,()>::Ok({ crate::api::workspace_api::start_workspace_stream(api_sink); })?; Ok(output_ok) + 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) })()) } }) } @@ -66,7 +66,7 @@ fn wire__crate__api__workspace_api__start_workspace_stream_impl(port_: flutter_r return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);} } - impl SseDecode for StreamSink,flutter_rust_bridge::for_generated::SseCodec> { + 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);} @@ -91,23 +91,14 @@ fn wire__crate__api__workspace_api__start_workspace_stream_impl(port_: flutter_r return ans_;} } - impl SseDecode for Vec { + 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)); } + for idx_ in 0..len_ { ans_.push(::sse_decode(deserializer)); } return ans_;} } - impl SseDecode for Option { - // Codec=Sse (Serialization based), see doc to use other codecs - fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {if (::sse_decode(deserializer)) { - return Some(::sse_decode(deserializer)); - } else { - return None; - }} - } - 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()} @@ -118,12 +109,10 @@ fn wire__crate__api__workspace_api__start_workspace_stream_impl(port_: flutter_r fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {} } - impl SseDecode for crate::api::model::Workspace { + 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_id = >::sse_decode(deserializer); -let mut var_name = ::sse_decode(deserializer); -let mut var_active = ::sse_decode(deserializer); -return crate::api::model::Workspace{id: var_id, name: var_name, active: var_active};} + 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 { @@ -139,7 +128,7 @@ return crate::api::model::Workspace{id: var_id, name: var_name, active: var_acti ) { // Codec=Pde (Serialization + dispatch), see doc to use other codecs match func_id { - 1 => wire__crate__api__workspace_api__start_workspace_stream_impl(port, ptr, rust_vec_len, data_len), + 1 => wire__crate__api__workspace_api__listen_workspaces_impl(port, ptr, rust_vec_len, data_len), _ => unreachable!(), } } @@ -161,18 +150,16 @@ return crate::api::model::Workspace{id: var_id, name: var_name, active: var_acti // Section: rust2dart // Codec=Dco (DartCObject based), see doc to use other codecs - impl flutter_rust_bridge::IntoDart for crate::api::model::Workspace { + impl flutter_rust_bridge::IntoDart for crate::api::workspace_api::Workspace { fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi { [ - self.id.into_into_dart().into_dart(), -self.name.into_into_dart().into_dart(), -self.active.into_into_dart().into_dart() + self.activated.into_into_dart().into_dart() ].into_dart() } } - impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::model::Workspace {} -impl flutter_rust_bridge::IntoIntoDart for crate::api::model::Workspace { - fn into_into_dart(self) -> crate::api::model::Workspace { + 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 } } @@ -182,7 +169,7 @@ impl flutter_rust_bridge::IntoIntoDart for crate:: 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> { + 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!("")} } @@ -203,18 +190,10 @@ impl flutter_rust_bridge::IntoIntoDart for crate:: for item in self { ::sse_encode(item, serializer); }} } - impl SseEncode for Vec { + 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 Option { - // 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.is_some(), serializer); - if let Some(value) = self { - ::sse_encode(value, serializer); - }} + for item in self { ::sse_encode(item, serializer); }} } impl SseEncode for u8 { @@ -227,11 +206,9 @@ impl flutter_rust_bridge::IntoIntoDart for crate:: fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} } - impl SseEncode for crate::api::model::Workspace { + 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.id, serializer); -::sse_encode(self.name, serializer); -::sse_encode(self.active, serializer);} + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {::sse_encode(self.activated, serializer);} } impl SseEncode for i32 { diff --git a/rust/src/internal/mod.rs b/rust/src/internal/mod.rs index 796f838..d41cd3d 100644 --- a/rust/src/internal/mod.rs +++ b/rust/src/internal/mod.rs @@ -1,2 +1 @@ -pub mod state; -pub mod wayland; \ No newline at end of file +pub mod wayland; diff --git a/rust/src/internal/state.rs b/rust/src/internal/state.rs deleted file mode 100644 index 79afe38..0000000 --- a/rust/src/internal/state.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::collections::HashMap; -use crate::api::model::Workspace; - -pub struct AppState { - pub workspaces: HashMap, -} - -impl AppState { - pub fn new() -> Self { - Self { - workspaces: HashMap::new(), - } - } -} \ No newline at end of file diff --git a/rust/src/internal/wayland.rs b/rust/src/internal/wayland.rs new file mode 100644 index 0000000..dda561f --- /dev/null +++ b/rust/src/internal/wayland.rs @@ -0,0 +1,122 @@ +use crate::{frb_generated::StreamSink, workspace_api::Workspace}; + +use std::collections::HashMap; +use wayland_client::{self, Connection, Dispatch, QueueHandle, event_created_child, protocol::{__interfaces::{WL_OUTPUT_INTERFACE, wl_output_interface}, wl_output, wl_registry}}; + + +wayland_scanner::generate_interfaces!("protocols/ext-workspace-v1.xml"); +wayland_scanner::generate_client_code!("protocols/ext-workspace-v1.xml"); + + +pub struct AppState { + pub workspaces: HashMap, + pub sink: StreamSink>, +} + +impl AppState { + fn emit(&self) { + let _ = self.sink.add(self.workspaces.values().cloned().collect()); + } +} + +// ------------------------ +// wl_registry +// ------------------------ +impl Dispatch for AppState { + fn event( + _state: &mut Self, + registry: &wl_registry::WlRegistry, + event: wl_registry::Event, + _data: &(), + _conn: &Connection, + qh: &QueueHandle, + ) { + if let wl_registry::Event::Global { + name, + interface, + version, + } = event + { + if interface == "ext_workspace_manager_v1" { + registry.bind::( + name, + version.min(1), + qh, + (), + ); + } + } + } +} + + + +impl Dispatch for AppState { + fn event( + _state: &mut Self, + _proxy: &ext_workspace_manager_v1::ExtWorkspaceManagerV1, + _event: ext_workspace_manager_v1::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle, + ) { + // unused for now + } + + event_created_child!( + AppState, + ext_workspace_manager_v1::ExtWorkspaceManagerV1, + [ + _workspace => ( + ext_workspace_handle_v1::ExtWorkspaceHandleV1, + () + ) + ] + ); +} + +// ------------------------ +// workspace handle +// ------------------------ +impl Dispatch for AppState { + fn event( + state: &mut Self, + _proxy: &ext_workspace_handle_v1::ExtWorkspaceHandleV1, + event: ext_workspace_handle_v1::Event, + _data: &(), + _conn: &Connection, + _qh: &QueueHandle, + ) { + match event { + ext_workspace_handle_v1::Event::Id { id } => { + let id: u32 = id.parse().unwrap_or(0); + + state.workspaces.insert(id, Workspace { activated: false }); + + state.emit(); + } + + ext_workspace_handle_v1::Event::State { state: flags } => { + let active = matches!( + flags, + wayland_client::WEnum::Value(ext_workspace_handle_v1::State::Active) + ); + + for ws in state.workspaces.values_mut() { + ws.activated = active; + } + + state.emit(); + } + +// ext_workspace_handle_v1::Event::Removed => { +// let id: u32 = id.parse().unwrap_or(0); + +// state.workspaces.remove(&id); +// state.emit(); +// } + + _ => {} + } + } +} \ No newline at end of file diff --git a/rust/src/internal/wayland/connection.rs b/rust/src/internal/wayland/connection.rs deleted file mode 100644 index f70068a..0000000 --- a/rust/src/internal/wayland/connection.rs +++ /dev/null @@ -1,19 +0,0 @@ -use wayland_client::{Connection, EventQueue}; - -use crate::internal::state::AppState; - -pub fn start_wayland() -> AppState { - let conn = Connection::connect_to_env().unwrap(); - let _ = conn.display(); - - let mut event_queue: EventQueue = conn.new_event_queue(); - let _ = event_queue.handle(); - - let mut state = AppState::new(); - - // attach globals here (workspace manager bind happens via registry in real impl) - - loop { - event_queue.blocking_dispatch(&mut state).unwrap(); - } -} \ No newline at end of file diff --git a/rust/src/internal/wayland/events.rs b/rust/src/internal/wayland/events.rs deleted file mode 100644 index 51f9021..0000000 --- a/rust/src/internal/wayland/events.rs +++ /dev/null @@ -1,63 +0,0 @@ -use wayland_client::{Dispatch, QueueHandle}; -use crate::internal::wayland::ext_workspace::ext_workspace_handle_v1::State; -use crate::internal::state::AppState; -use crate::api::model::Workspace; -use wayland_client::Proxy; -use wayland_client::WEnum; -use crate::internal::wayland::ext_workspace::{ - ext_workspace_manager_v1, - ext_workspace_handle_v1, -}; - -impl Dispatch for AppState { - fn event( - state: &mut Self, - _: &ext_workspace_manager_v1::ExtWorkspaceManagerV1, - event: ext_workspace_manager_v1::Event, - _: &(), - _: &wayland_client::Connection, - _: &QueueHandle, - ) { - match event { - ext_workspace_manager_v1::Event::Workspace { workspace } => { - state.workspaces.insert( - workspace.id().to_string(), - Workspace { - id: None, - name: String::new(), - active: false, - }, - ); - } - _ => {} - } - } -} - -impl Dispatch for AppState { - fn event( - state: &mut Self, - proxy: &ext_workspace_handle_v1::ExtWorkspaceHandleV1, - event: ext_workspace_handle_v1::Event, - _: &(), - _: &wayland_client::Connection, - _: &QueueHandle, - ) { - let ws = state.workspaces.get_mut(&proxy.id().to_string()); - - if let Some(ws) = ws { - match event { - ext_workspace_handle_v1::Event::Name { name } => { - ws.name = name; - } - ext_workspace_handle_v1::Event::Id { id } => { - ws.id = Some(id); - } - ext_workspace_handle_v1::Event::State { state: flags } => { - ws.active = matches!(flags, WEnum::Value(State::Active)); - } - _ => {} - } - } - } -} \ No newline at end of file diff --git a/rust/src/internal/wayland/ext_workspace.rs b/rust/src/internal/wayland/ext_workspace.rs deleted file mode 100644 index da84c79..0000000 --- a/rust/src/internal/wayland/ext_workspace.rs +++ /dev/null @@ -1,16 +0,0 @@ -use wayland_client; -use wayland_client::protocol::wl_output; - -pub mod __interfaces { - use wayland_client::protocol::__interfaces::*; - - wayland_scanner::generate_interfaces!( - "./protocols/ext-workspace-v1.xml" - ); -} - -use self::__interfaces::*; - -wayland_scanner::generate_client_code!( - "./protocols/ext-workspace-v1.xml" -); \ No newline at end of file diff --git a/rust/src/internal/wayland/mod.rs b/rust/src/internal/wayland/mod.rs deleted file mode 100644 index 94b66ff..0000000 --- a/rust/src/internal/wayland/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod connection; -pub mod events; -pub mod ext_workspace; \ No newline at end of file