Skip to content
This repository has been archived by the owner on Jan 1, 2025. It is now read-only.

Commit

Permalink
feat: adding window management
Browse files Browse the repository at this point in the history
  • Loading branch information
RossComputerGuy committed May 9, 2024
1 parent ddb8030 commit e3cfe9d
Show file tree
Hide file tree
Showing 6 changed files with 357 additions and 47 deletions.
55 changes: 54 additions & 1 deletion lib/logic/display.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ class DisplayManager extends ChangeNotifier {
final server = find(call.arguments['name']);
if (server == null) break;

server!._toplevels.add(DisplayServerToplevel._(server, call.arguments['id']));
final toplevel = DisplayServerToplevel._(server, call.arguments['id']);

server!._toplevelAddedCtrl.add(toplevel);
server!._toplevels.add(toplevel);
server!.notifyListeners();
break;
case 'removeToplevel':
final server = find(call.arguments['name']);
if (server == null) break;

final toplevel = server._toplevels.firstWhere((item) => item.id == call.arguments['id']);

server!._toplevelRemovedCtrl.add(toplevel);
server!._toplevels.removeWhere((item) => item.id == call.arguments['id']);
server!.notifyListeners();
break;
Expand All @@ -43,6 +49,8 @@ class DisplayManager extends ChangeNotifier {
server.notifyListeners();
break;
}

toplevel._reqCtrl.add(call.arguments['reqName']);
break;
case 'notifyToplevel':
final server = find(call.arguments['name']);
Expand Down Expand Up @@ -74,6 +82,11 @@ class DisplayManager extends ChangeNotifier {
default:
throw MissingPluginException();
}

toplevel._notifyCtrl.add(DisplayServerToplevelNotify(
propName: call.arguments['propName'],
propValue: call.arguments['propValue'],
));
break;
default:
throw MissingPluginException();
Expand All @@ -93,6 +106,12 @@ class DisplayManager extends ChangeNotifier {

List<DisplayServer> _servers = [];

StreamController<DisplayServer> _serverStartedCtrl = StreamController();
Stream<DisplayServer> get serverStarted => _serverStartedCtrl.stream;

StreamController<DisplayServer> _serverStoppedCtrl = StreamController();
Stream<DisplayServer> get serverStopped => _serverStoppedCtrl.stream;

DisplayServer? find(String name) {
for (final server in _servers) {
if (server.name == name) return server;
Expand All @@ -109,6 +128,7 @@ class DisplayManager extends ChangeNotifier {

final instance = DisplayServer._(this, name);
_servers.add(instance);
_serverStartedCtrl.add(instance);
notifyListeners();
return instance;
}
Expand All @@ -123,9 +143,16 @@ class DisplayServer extends ChangeNotifier {
List<DisplayServerToplevel> _toplevels = [];
UnmodifiableListView<DisplayServerToplevel> get toplevels => UnmodifiableListView(_toplevels);

StreamController<DisplayServerToplevel> _toplevelAddedCtrl = StreamController();
Stream<DisplayServerToplevel> get toplevelAdded => _toplevelAddedCtrl.stream;

StreamController<DisplayServerToplevel> _toplevelRemovedCtrl = StreamController();
Stream<DisplayServerToplevel> get toplevelRemoved => _toplevelRemovedCtrl.stream;

Future<void> stop() async {
await DisplayManager.channel.invokeMethod('stop', name);
_manager._servers.removeWhere((entry) => entry.name == name);
_manager._serverStoppedCtrl.add(this);
_manager.notifyListeners();
}

Expand All @@ -137,6 +164,16 @@ class DisplayServer extends ChangeNotifier {
}
}

class DisplayServerToplevelNotify {
const DisplayServerToplevelNotify({
required this.propName,
required this.propValue,
});

final String propName;
final String propValue;
}

class DisplayServerToplevelSize {
const DisplayServerToplevelSize({
this.width,
Expand Down Expand Up @@ -175,6 +212,12 @@ class DisplayServerToplevel extends ChangeNotifier {
final DisplayServer _server;
final int id;

StreamController<DisplayServerToplevelNotify> _notifyCtrl = StreamController();
Stream<DisplayServerToplevelNotify> get notify => _notifyCtrl.stream;

StreamController<String> _reqCtrl = StreamController();
Stream<String> get req => _reqCtrl.stream;

String? _appId;
String? get appId => _appId;

Expand Down Expand Up @@ -208,6 +251,16 @@ class DisplayServerToplevel extends ChangeNotifier {
bool _hasDecorations;
bool get hasDecorations => _hasDecorations;

Future<void> close() => sendRequest('close');

Future<void> sendRequest(String name) async {
await DisplayManager.channel.invokeMethod('requestToplevel', <String, dynamic>{
'name': _server.name,
'id': id,
'reqName': name,
});
}

Future<void> sync() async {
final data = await DisplayManager.channel.invokeMethod('getToplevel', <String, dynamic>{
'name': _server.name,
Expand Down
79 changes: 79 additions & 0 deletions lib/logic/wm.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import 'package:flutter/foundation.dart';

import 'display.dart';

enum WindowManagerMode {
tiling,
floating,
stacking,
}

class WindowManager extends ChangeNotifier {
WindowManager({
this.mode = WindowManagerMode.stacking,
});

final WindowManagerMode mode;
List<Window> _wins = [];

void dispose() {}

Window fromToplevel(DisplayServerToplevel toplevel) {
for (final win in _wins) {
if (win.toplevel == toplevel) return win;
}

final win = Window._(this, toplevel);
_wins.add(win);
notifyListeners();
return win;
}

void removeToplevel(DisplayServerToplevel toplevel) {
_wins.removeWhere((win) => win.toplevel == toplevel);
notifyListeners();
}
}

class Window extends ChangeNotifier {
Window._(this.manager, this.toplevel) :
_x = 0, _y = 0, _layer = 0, _minimized = false;

final WindowManager manager;
final DisplayServerToplevel toplevel;

@override
void notifyListeners() {
super.notifyListeners();
manager.notifyListeners();
}

double _x;
double get x => _x;
set x(double value) {
_x = value;
notifyListeners();
}

double _y;
double get y => _y;
set y(double value) {
_y = value;
notifyListeners();
}

int _layer;
int get layer => _layer;
set layer(int value) {
_layer = value;
notifyListeners();
}

bool _minimized;
bool get minimized => _minimized;

set minimized(bool value) {
_minimized = value;
notifyListeners();
}
}
38 changes: 5 additions & 33 deletions lib/views/desktop.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ import 'package:provider/provider.dart';
import '../logic/display.dart';
import '../logic/outputs.dart';
import '../logic/wallpaper.dart';
import '../logic/wm.dart';

import '../widgets/system_layout.dart';
import '../widgets/system_navbar.dart';
import '../widgets/toplevel.dart';
import '../widgets/wm.dart';

class DesktopView extends StatefulWidget {
const DesktopView({
Expand Down Expand Up @@ -115,38 +116,9 @@ class _DesktopViewState extends State<DesktopView> {
),
constraints: BoxConstraints.expand(),
child: _displayServer != null
? ChangeNotifierProvider.value(
value: _displayServer!,
child: Consumer<DisplayServer>(
builder: (context, server, _) =>
Stack(
children: server.toplevels.map(
(toplevel) =>
ToplevelView(
toplevel: toplevel,
buildDecor: (context, toplevel, content) =>
!Breakpoints.small.isActive(context)
? Container(
width: toplevel.size != null ? (toplevel.size!.width ?? 0).toDouble() : null,
child: Column(
children: [
ToplevelDecor(
toplevel: toplevel,
),
ClipRRect(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(12),
bottomRight: Radius.circular(12),
),
child: content,
),
],
),
) : null,
)
).toList(),
),
),
? WindowManagerView(
displayServer: _displayServer!,
mode: Breakpoints.small.isActive(context) ? WindowManagerMode.stacking : WindowManagerMode.floating,
) : null,
),
bottomNavigationBar: Breakpoints.small.isActive(context)
Expand Down
35 changes: 22 additions & 13 deletions lib/widgets/toplevel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,15 @@ class ToplevelDecor extends StatelessWidget {
const ToplevelDecor({
super.key,
required this.toplevel,
this.onMinimize,
this.onMaximize,
this.onClose,
});

final DisplayServerToplevel toplevel;
final VoidCallback? onMinimize;
final VoidCallback? onMaximize;
final VoidCallback? onClose;

@override
Widget build(BuildContext context) =>
Expand All @@ -27,19 +33,22 @@ class ToplevelDecor extends StatelessWidget {
),
),
actions: [
IconButton(
onPressed: () {},
icon: Icon(Icons.windowMinimize),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.windowMaximize),
),
IconButton(
onPressed: () {},
icon: Icon(Icons.circleXmark),
),
],
onMinimize != null
? IconButton(
onPressed: onMinimize!,
icon: Icon(Icons.windowMinimize),
) : null,
onMaximize != null
? IconButton(
onPressed: onMaximize!,
icon: Icon(Icons.windowMaximize),
) : null,
onClose != null
? IconButton(
onPressed: onClose!,
icon: Icon(Icons.circleXmark),
) : null,
].where((e) => e != null).toList().cast<Widget>(),
);
}

Expand Down
Loading

0 comments on commit e3cfe9d

Please sign in to comment.