semi working

This commit is contained in:
Henry Hiles 2026-04-19 11:22:40 -04:00
commit 440dc1a0f9
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
27 changed files with 500 additions and 301 deletions

View file

@ -1,3 +1,4 @@
rust_input: crate::api rust_input: crate::api
rust_root: rust/ rust_root: rust/
dart_output: lib/src/rust dart_output: lib/src/rust
enable_lifetime: true

View file

@ -1,10 +1,9 @@
import "package:flight/src/rust/api/model.dart";
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<Workspace>> {
@override @override
Stream<List<Workspace>> build() => startWorkspaceStream(); Stream<List<Workspace>> build() => listenWorkspaces();
static final provider = static final provider =
StreamNotifierProvider<WorkspacesController, List<Workspace>>( StreamNotifierProvider<WorkspacesController, List<Workspace>>(

View file

@ -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;
}

View file

@ -4,8 +4,25 @@
// ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import // ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import
import '../frb_generated.dart'; import '../frb_generated.dart';
import 'model.dart';
import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
Stream<List<Workspace>> startWorkspaceStream() => // 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`
RustLib.instance.api.crateApiWorkspaceApiStartWorkspaceStream();
Stream<List<Workspace>> 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;
}

View file

@ -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<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExtWorkspaceGroupHandleV1>>
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<void> 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<void> destroy();
}

View file

@ -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<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExtWorkspaceHandleV1>>
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<void> 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<void> assign({required ExtWorkspaceGroupHandleV1 workspaceGroup});
///deactivate the workspace
///
///Request that this workspace be deactivated.
///
///There is no guarantee the workspace will be actually deactivated.
Future<void> 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<void> destroy();
///remove the workspace
///
///Request that this workspace be removed.
///
///There is no guarantee the workspace will be actually removed.
Future<void> remove();
}

View file

@ -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<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Event < >>>
abstract class Event implements RustOpaqueInterface {
///Get the opcode number of this message
Future<int> opcode();
}
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExtWorkspaceManagerV1>>
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<void> 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<void> stop();
}
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Lifetimeable < Request < 'static > >>>
abstract class Request implements RustOpaqueInterface {
///Get the opcode number of this message
Future<int> opcode();
}

View file

@ -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<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExtWorkspaceGroupHandleV1>>
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<void> 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<void> destroy();
}

View file

@ -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<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExtWorkspaceHandleV1>>
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<void> 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<void> assign({required ExtWorkspaceGroupHandleV1 workspaceGroup});
///deactivate the workspace
///
///Request that this workspace be deactivated.
///
///There is no guarantee the workspace will be actually deactivated.
Future<void> 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<void> destroy();
///remove the workspace
///
///Request that this workspace be removed.
///
///There is no guarantee the workspace will be actually removed.
Future<void> remove();
}

View file

@ -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<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Event < >>>
abstract class Event implements RustOpaqueInterface {
///Get the opcode number of this message
Future<int> opcode();
}
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExtWorkspaceManagerV1>>
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<void> 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<void> stop();
}
// Rust type: RustOpaqueMoi<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<Lifetimeable < Request < 'static > >>>
abstract class Request implements RustOpaqueInterface {
///Get the opcode number of this message
Future<int> opcode();
}

View file

@ -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 // 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 'api/workspace_api.dart';
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
@ -65,7 +64,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
String get codegenVersion => '2.11.1'; String get codegenVersion => '2.11.1';
@override @override
int get rustContentHash => 804335101; int get rustContentHash => 1397669831;
static const kDefaultExternalLibraryLoaderConfig = static const kDefaultExternalLibraryLoaderConfig =
ExternalLibraryLoaderConfig( ExternalLibraryLoaderConfig(
@ -76,7 +75,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
} }
abstract class RustLibApi extends BaseApi { abstract class RustLibApi extends BaseApi {
Stream<List<Workspace>> crateApiWorkspaceApiStartWorkspaceStream(); Stream<List<Workspace>> crateApiWorkspaceApiListenWorkspaces();
} }
class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
@ -88,7 +87,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
}); });
@override @override
Stream<List<Workspace>> crateApiWorkspaceApiStartWorkspaceStream() { Stream<List<Workspace>> crateApiWorkspaceApiListenWorkspaces() {
final sink = RustStreamSink<List<Workspace>>(); final sink = RustStreamSink<List<Workspace>>();
unawaited( unawaited(
handler.executeNormal( handler.executeNormal(
@ -105,9 +104,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
}, },
codec: SseCodec( codec: SseCodec(
decodeSuccessData: sse_decode_unit, decodeSuccessData: sse_decode_unit,
decodeErrorData: null, decodeErrorData: sse_decode_AnyhowException,
), ),
constMeta: kCrateApiWorkspaceApiStartWorkspaceStreamConstMeta, constMeta: kCrateApiWorkspaceApiListenWorkspacesConstMeta,
argValues: [sink], argValues: [sink],
apiImpl: this, apiImpl: this,
), ),
@ -116,11 +115,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return sink.stream; return sink.stream;
} }
TaskConstMeta get kCrateApiWorkspaceApiStartWorkspaceStreamConstMeta => TaskConstMeta get kCrateApiWorkspaceApiListenWorkspacesConstMeta =>
const TaskConstMeta( const TaskConstMeta(debugName: "listen_workspaces", argNames: ["sink"]);
debugName: "start_workspace_stream",
argNames: ["sink"],
);
@protected @protected
AnyhowException dco_decode_AnyhowException(dynamic raw) { AnyhowException dco_decode_AnyhowException(dynamic raw) {
@ -160,12 +156,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return (raw as List<dynamic>).map(dco_decode_workspace).toList(); return (raw as List<dynamic>).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 @protected
int dco_decode_u_8(dynamic raw) { int dco_decode_u_8(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs // 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) { Workspace dco_decode_workspace(dynamic raw) {
// Codec=Dco (DartCObject based), see doc to use other codecs // Codec=Dco (DartCObject based), see doc to use other codecs
final arr = raw as List<dynamic>; final arr = raw as List<dynamic>;
if (arr.length != 3) if (arr.length != 1)
throw Exception('unexpected arr length: expect 3 but see ${arr.length}'); throw Exception('unexpected arr length: expect 1 but see ${arr.length}');
return Workspace( return Workspace(activated: dco_decode_bool(arr[0]));
id: dco_decode_opt_String(arr[0]),
name: dco_decode_String(arr[1]),
active: dco_decode_bool(arr[2]),
);
} }
@protected @protected
@ -238,17 +224,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
return ans_; 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 @protected
int sse_decode_u_8(SseDeserializer deserializer) { int sse_decode_u_8(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
@ -263,10 +238,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
@protected @protected
Workspace sse_decode_workspace(SseDeserializer deserializer) { Workspace sse_decode_workspace(SseDeserializer deserializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
var var_id = sse_decode_opt_String(deserializer); var var_activated = sse_decode_bool(deserializer);
var var_name = sse_decode_String(deserializer); return Workspace(activated: var_activated);
var var_active = sse_decode_bool(deserializer);
return Workspace(id: var_id, name: var_name, active: var_active);
} }
@protected @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 @protected
void sse_encode_u_8(int self, SseSerializer serializer) { void sse_encode_u_8(int self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
@ -359,9 +322,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
@protected @protected
void sse_encode_workspace(Workspace self, SseSerializer serializer) { void sse_encode_workspace(Workspace self, SseSerializer serializer) {
// Codec=Sse (Serialization based), see doc to use other codecs // Codec=Sse (Serialization based), see doc to use other codecs
sse_encode_opt_String(self.id, serializer); sse_encode_bool(self.activated, serializer);
sse_encode_String(self.name, serializer);
sse_encode_bool(self.active, serializer);
} }
@protected @protected

View file

@ -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 // 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 'api/workspace_api.dart';
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
@ -39,9 +38,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
List<Workspace> dco_decode_list_workspace(dynamic raw); List<Workspace> dco_decode_list_workspace(dynamic raw);
@protected
String? dco_decode_opt_String(dynamic raw);
@protected @protected
int dco_decode_u_8(dynamic raw); int dco_decode_u_8(dynamic raw);
@ -71,9 +67,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
List<Workspace> sse_decode_list_workspace(SseDeserializer deserializer); List<Workspace> sse_decode_list_workspace(SseDeserializer deserializer);
@protected
String? sse_decode_opt_String(SseDeserializer deserializer);
@protected @protected
int sse_decode_u_8(SseDeserializer deserializer); int sse_decode_u_8(SseDeserializer deserializer);
@ -116,9 +109,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
SseSerializer serializer, SseSerializer serializer,
); );
@protected
void sse_encode_opt_String(String? self, SseSerializer serializer);
@protected @protected
void sse_encode_u_8(int self, SseSerializer serializer); void sse_encode_u_8(int self, SseSerializer serializer);

View file

@ -6,7 +6,6 @@
// Static analysis wrongly picks the IO variant, thus ignore this // Static analysis wrongly picks the IO variant, thus ignore this
// ignore_for_file: argument_type_not_assignable // ignore_for_file: argument_type_not_assignable
import 'api/model.dart';
import 'api/workspace_api.dart'; import 'api/workspace_api.dart';
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
@ -41,9 +40,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
List<Workspace> dco_decode_list_workspace(dynamic raw); List<Workspace> dco_decode_list_workspace(dynamic raw);
@protected
String? dco_decode_opt_String(dynamic raw);
@protected @protected
int dco_decode_u_8(dynamic raw); int dco_decode_u_8(dynamic raw);
@ -73,9 +69,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
@protected @protected
List<Workspace> sse_decode_list_workspace(SseDeserializer deserializer); List<Workspace> sse_decode_list_workspace(SseDeserializer deserializer);
@protected
String? sse_decode_opt_String(SseDeserializer deserializer);
@protected @protected
int sse_decode_u_8(SseDeserializer deserializer); int sse_decode_u_8(SseDeserializer deserializer);
@ -118,9 +111,6 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
SseSerializer serializer, SseSerializer serializer,
); );
@protected
void sse_encode_opt_String(String? self, SseSerializer serializer);
@protected @protected
void sse_encode_u_8(int self, SseSerializer serializer); void sse_encode_u_8(int self, SseSerializer serializer);

View file

@ -1,5 +1,8 @@
import 'dart:developer';
import 'package:flight/controllers/time_controller.dart'; import 'package:flight/controllers/time_controller.dart';
import 'package:flight/controllers/workspaces_controller.dart'; import 'package:flight/controllers/workspaces_controller.dart';
import 'package:flight/widgets/loading.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
@ -24,18 +27,24 @@ class Bar extends ConsumerWidget {
ref ref
.watch(WorkspacesController.provider) .watch(WorkspacesController.provider)
.whenOrNull( .whenOrNull(
data: (value) => value error: (error, stackTrace) => [
Text(error.toString()),
],
loading: () => [Text("loading")],
data: (value) {
return value
.map( .map(
(element) => IconButton( (element) => IconButton(
onPressed: () {}, onPressed: () {},
icon: Icon( icon: Icon(
element.active element.activated
? Icons.circle ? Icons.circle
: Icons.circle_outlined, : Icons.circle_outlined,
), ),
), ),
) )
.toList(), .toList();
},
) ?? ) ??
[], [],
[ [

View file

@ -7,6 +7,7 @@ pkgs.mkShell {
gtk-layer-shell gtk-layer-shell
cargo cargo
rustfmt
flutter_rust_bridge_codegen flutter_rust_bridge_codegen
(pkgs.writeShellScriptBin "rustup" (builtins.readFile ./fake-rustup.sh)) (pkgs.writeShellScriptBin "rustup" (builtins.readFile ./fake-rustup.sh))

View file

@ -7,12 +7,11 @@ edition = "2021"
crate-type = ["cdylib", "staticlib"] crate-type = ["cdylib", "staticlib"]
[dependencies] [dependencies]
wayland-scanner = "0.31"
flutter_rust_bridge = "=2.11.1" flutter_rust_bridge = "=2.11.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] } tokio = { version = "1", features = ["rt-multi-thread", "macros"] }
futures = "0.3" futures = "0.3"
wayland-client = "0.31" wayland-client = "0.31"
wayland-scanner = "0.31"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"

View file

@ -1,2 +1 @@
pub mod model;
pub mod workspace_api; pub mod workspace_api;

View file

@ -1,8 +0,0 @@
use serde::{Serialize, Deserialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Workspace {
pub id: Option<String>,
pub name: String,
pub active: bool,
}

View file

@ -1,15 +1,38 @@
use crate::frb_generated::StreamSink; use serde_json::Result;
use crate::api::model::Workspace; use wayland_client::{Connection, EventQueue};
use std::collections::HashMap;
use crate::{frb_generated::StreamSink, internal::wayland::AppState};
pub fn start_workspace_stream(sink: StreamSink<Vec<Workspace>>) {
#[derive(Clone)]
pub struct Workspace {
pub activated: bool,
}
pub fn listen_workspaces(sink: StreamSink<Vec<Workspace>>) -> Result<()> {
std::thread::spawn(move || { std::thread::spawn(move || {
// Connect to Wayland
let conn = Connection::connect_to_env().expect("Failed to connect to Wayland");
let mut event_queue: EventQueue<AppState> = 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 { loop {
// Replace with real shared state later event_queue
let data = vec![]; .blocking_dispatch(&mut state)
.expect("Wayland dispatch failed");
sink.add(data).ok();
std::thread::sleep(std::time::Duration::from_millis(500));
} }
}); });
Ok(())
} }

View file

@ -37,7 +37,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
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 = 804335101; pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 1397669831;
// Section: executor // Section: executor
@ -46,13 +46,13 @@ flutter_rust_bridge::frb_generated_default_handler!();
// Section: wire_funcs // 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) { 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::SseCodec,_,_>(flutter_rust_bridge::for_generated::TaskInfo{ debug_name: "start_workspace_stream", port: Some(port_), mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal }, move || { 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 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 mut deserializer = flutter_rust_bridge::for_generated::SseDeserializer::new(message);
let api_sink = <StreamSink<Vec<crate::api::model::Workspace>,flutter_rust_bridge::for_generated::SseCodec>>::sse_decode(&mut deserializer);deserializer.end(); move |context| { let api_sink = <StreamSink<Vec<crate::api::workspace_api::Workspace>,flutter_rust_bridge::for_generated::SseCodec>>::sse_decode(&mut deserializer);deserializer.end(); move |context| {
transform_result_sse::<_, ()>((move || { transform_result_sse::<_, flutter_rust_bridge::for_generated::anyhow::Error>((move || {
let output_ok = Result::<_,()>::Ok({ crate::api::workspace_api::start_workspace_stream(api_sink); })?; Ok(output_ok) 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);} return flutter_rust_bridge::for_generated::anyhow::anyhow!("{}", inner);}
} }
impl SseDecode for StreamSink<Vec<crate::api::model::Workspace>,flutter_rust_bridge::for_generated::SseCodec> { impl SseDecode for StreamSink<Vec<crate::api::workspace_api::Workspace>,flutter_rust_bridge::for_generated::SseCodec> {
// 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 {let mut inner = <String>::sse_decode(deserializer);
return StreamSink::deserialize(inner);} return StreamSink::deserialize(inner);}
@ -91,23 +91,14 @@ fn wire__crate__api__workspace_api__start_workspace_stream_impl(port_: flutter_r
return ans_;} return ans_;}
} }
impl SseDecode for Vec<crate::api::model::Workspace> { 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 {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::model::Workspace>::sse_decode(deserializer)); } for idx_ in 0..len_ { ans_.push(<crate::api::workspace_api::Workspace>::sse_decode(deserializer)); }
return ans_;} return ans_;}
} }
impl SseDecode for Option<String> {
// Codec=Sse (Serialization based), see doc to use other codecs
fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {if (<bool>::sse_decode(deserializer)) {
return Some(<String>::sse_decode(deserializer));
} else {
return None;
}}
}
impl SseDecode for u8 { 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 {deserializer.cursor.read_u8().unwrap()} 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 {} 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 // 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 = <Option<String>>::sse_decode(deserializer); fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {let mut var_activated = <bool>::sse_decode(deserializer);
let mut var_name = <String>::sse_decode(deserializer); return crate::api::workspace_api::Workspace{activated: var_activated};}
let mut var_active = <bool>::sse_decode(deserializer);
return crate::api::model::Workspace{id: var_id, name: var_name, active: var_active};}
} }
impl SseDecode for i32 { 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 // Codec=Pde (Serialization + dispatch), see doc to use other codecs
match func_id { 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!(), _ => unreachable!(),
} }
} }
@ -161,18 +150,16 @@ return crate::api::model::Workspace{id: var_id, name: var_name, active: var_acti
// 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::model::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.id.into_into_dart().into_dart(), self.activated.into_into_dart().into_dart()
self.name.into_into_dart().into_dart(),
self.active.into_into_dart().into_dart()
].into_dart() ].into_dart()
} }
} }
impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::model::Workspace {} impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive for crate::api::workspace_api::Workspace {}
impl flutter_rust_bridge::IntoIntoDart<crate::api::model::Workspace> for crate::api::model::Workspace { impl flutter_rust_bridge::IntoIntoDart<crate::api::workspace_api::Workspace> for crate::api::workspace_api::Workspace {
fn into_into_dart(self) -> crate::api::model::Workspace { fn into_into_dart(self) -> crate::api::workspace_api::Workspace {
self self
} }
} }
@ -182,7 +169,7 @@ impl flutter_rust_bridge::IntoIntoDart<crate::api::model::Workspace> for crate::
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) {<String>::sse_encode(format!("{:?}", self), serializer);}
} }
impl SseEncode for StreamSink<Vec<crate::api::model::Workspace>,flutter_rust_bridge::for_generated::SseCodec> { impl SseEncode for StreamSink<Vec<crate::api::workspace_api::Workspace>,flutter_rust_bridge::for_generated::SseCodec> {
// 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) {unimplemented!("")} fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {unimplemented!("")}
} }
@ -203,18 +190,10 @@ impl flutter_rust_bridge::IntoIntoDart<crate::api::model::Workspace> for crate::
for item in self { <u8>::sse_encode(item, serializer); }} for item in self { <u8>::sse_encode(item, serializer); }}
} }
impl SseEncode for Vec<crate::api::model::Workspace> { impl SseEncode 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_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<i32>::sse_encode(self.len() as _, serializer); 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::model::Workspace>::sse_encode(item, serializer); }} for item in self { <crate::api::workspace_api::Workspace>::sse_encode(item, serializer); }}
}
impl SseEncode for Option<String> {
// 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.is_some(), serializer);
if let Some(value) = self {
<String>::sse_encode(value, serializer);
}}
} }
impl SseEncode for u8 { impl SseEncode for u8 {
@ -227,11 +206,9 @@ impl flutter_rust_bridge::IntoIntoDart<crate::api::model::Workspace> for crate::
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {} 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 // Codec=Sse (Serialization based), see doc to use other codecs
fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<Option<String>>::sse_encode(self.id, serializer); fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {<bool>::sse_encode(self.activated, serializer);}
<String>::sse_encode(self.name, serializer);
<bool>::sse_encode(self.active, serializer);}
} }
impl SseEncode for i32 { impl SseEncode for i32 {

View file

@ -1,2 +1 @@
pub mod state;
pub mod wayland; pub mod wayland;

View file

@ -1,14 +0,0 @@
use std::collections::HashMap;
use crate::api::model::Workspace;
pub struct AppState {
pub workspaces: HashMap<String, Workspace>,
}
impl AppState {
pub fn new() -> Self {
Self {
workspaces: HashMap::new(),
}
}
}

View file

@ -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<u32, Workspace>,
pub sink: StreamSink<Vec<Workspace>>,
}
impl AppState {
fn emit(&self) {
let _ = self.sink.add(self.workspaces.values().cloned().collect());
}
}
// ------------------------
// wl_registry
// ------------------------
impl Dispatch<wl_registry::WlRegistry, ()> for AppState {
fn event(
_state: &mut Self,
registry: &wl_registry::WlRegistry,
event: wl_registry::Event,
_data: &(),
_conn: &Connection,
qh: &QueueHandle<Self>,
) {
if let wl_registry::Event::Global {
name,
interface,
version,
} = event
{
if interface == "ext_workspace_manager_v1" {
registry.bind::<ext_workspace_manager_v1::ExtWorkspaceManagerV1, _, _>(
name,
version.min(1),
qh,
(),
);
}
}
}
}
impl Dispatch<ext_workspace_manager_v1::ExtWorkspaceManagerV1, ()> for AppState {
fn event(
_state: &mut Self,
_proxy: &ext_workspace_manager_v1::ExtWorkspaceManagerV1,
_event: ext_workspace_manager_v1::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Self>,
) {
// unused for now
}
event_created_child!(
AppState,
ext_workspace_manager_v1::ExtWorkspaceManagerV1,
[
_workspace => (
ext_workspace_handle_v1::ExtWorkspaceHandleV1,
()
)
]
);
}
// ------------------------
// workspace handle
// ------------------------
impl Dispatch<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
fn event(
state: &mut Self,
_proxy: &ext_workspace_handle_v1::ExtWorkspaceHandleV1,
event: ext_workspace_handle_v1::Event,
_data: &(),
_conn: &Connection,
_qh: &QueueHandle<Self>,
) {
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();
// }
_ => {}
}
}
}

View file

@ -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<AppState> = 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();
}
}

View file

@ -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<ext_workspace_manager_v1::ExtWorkspaceManagerV1, ()> for AppState {
fn event(
state: &mut Self,
_: &ext_workspace_manager_v1::ExtWorkspaceManagerV1,
event: ext_workspace_manager_v1::Event,
_: &(),
_: &wayland_client::Connection,
_: &QueueHandle<Self>,
) {
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<ext_workspace_handle_v1::ExtWorkspaceHandleV1, ()> for AppState {
fn event(
state: &mut Self,
proxy: &ext_workspace_handle_v1::ExtWorkspaceHandleV1,
event: ext_workspace_handle_v1::Event,
_: &(),
_: &wayland_client::Connection,
_: &QueueHandle<Self>,
) {
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));
}
_ => {}
}
}
}
}

View file

@ -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"
);

View file

@ -1,3 +0,0 @@
pub mod connection;
pub mod events;
pub mod ext_workspace;