-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Basic WM #14
base: master
Are you sure you want to change the base?
[WIP] Basic WM #14
Changes from 4 commits
772920e
7171f26
edcb00f
8045de6
d5f59fc
5fcf6f9
fd9fdee
7d23a40
cd07c96
c348f7c
f053820
a5805dd
b3d8cd6
2d16c6f
d5ac87d
478aa92
8f5c450
45eab9e
a2c7e1b
01565e0
0358c32
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
// ignore_for_file: public_member_api_docs, sort_constructors_first | ||
library compositor_dart; | ||
|
||
import 'dart:async'; | ||
|
@@ -20,16 +21,45 @@ class Surface { | |
final int pid; | ||
final int gid; | ||
final int uid; | ||
|
||
final Compositor compositor; | ||
final bool isPopup; | ||
final int parentHandle; | ||
|
||
Surface({ | ||
required this.handle, | ||
required this.pid, | ||
required this.gid, | ||
required this.uid, | ||
required this.compositor, | ||
required this.isPopup, | ||
required this.parentHandle, | ||
}); | ||
|
||
@override | ||
bool operator ==(Object other) { | ||
if (identical(this, other)) return true; | ||
|
||
return other is Surface && | ||
other.handle == handle && | ||
other.pid == pid && | ||
other.gid == gid && | ||
other.uid == uid && | ||
other.isPopup == isPopup && | ||
other.parentHandle == parentHandle; | ||
} | ||
|
||
@override | ||
int get hashCode { | ||
return handle.hashCode ^ | ||
pid.hashCode ^ | ||
gid.hashCode ^ | ||
uid.hashCode ^ | ||
isPopup.hashCode ^ | ||
parentHandle.hashCode; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If everything else is functioning as it should, there should be one and only one Surface class instance for every handle on the native side. It should be safe to compare Surface classes by identity, so we probably don't need these implementations. |
||
|
||
@override | ||
String toString() { | ||
return 'Surface(handle: $handle, pid: $pid, gid: $gid, uid: $uid, isPopup: $isPopup, parentHandle: $parentHandle)'; | ||
} | ||
} | ||
|
||
class _CompositorPlatform { | ||
|
@@ -79,9 +109,11 @@ class _CompositorPlatform { | |
], | ||
); | ||
} | ||
} | ||
|
||
final Compositor compositor = Compositor(); | ||
Future<void> surfaceFocusViewWithHandle(int handle) async { | ||
await channel.invokeMethod("surface_focus_from_handle", [handle]); | ||
} | ||
} | ||
|
||
class Compositor { | ||
static void initLogger() { | ||
|
@@ -111,17 +143,21 @@ class Compositor { | |
pid: call.arguments["client_pid"], | ||
gid: call.arguments["client_gid"], | ||
uid: call.arguments["client_uid"], | ||
compositor: this, | ||
isPopup: call.arguments["is_popup"], | ||
parentHandle: call.arguments["parent_handle"], | ||
); | ||
surfaces[surface.handle] = surface; | ||
surfaces.putIfAbsent(surface.handle, () => surface); | ||
|
||
surfaceMapped.add(surface); | ||
}); | ||
|
||
platform.addHandler("surface_unmap", (call) async { | ||
int handle = call.arguments["handle"]; | ||
Surface surface = surfaces[handle]!; | ||
surfaces.remove(handle); | ||
surfaceUnmapped.add(surface); | ||
if (surfaces.containsKey(handle)) { | ||
Surface surface = surfaces[handle]!; | ||
surfaces.remove(handle); | ||
surfaceUnmapped.add(surface); | ||
} | ||
Comment on lines
-128
to
+197
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For any given surface, I believe
This should mean that:
We should likely add assertions for this, if this assumption is broken it would be a bug in the native code There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if the fact that things fail here on multiple surfaces means there is an error somewhere in my code where multiple surfaces get the same handle id? I think there are some debug prints for when a surface is mapped with its handle id, are those different? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From what I've checked, handles were different but I think it was the way we managed compositor - now it's created in and managed in main. |
||
}); | ||
|
||
platform.addHandler("flutter/keyevent", (call) async {}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import 'package:flutter/material.dart'; | ||
|
||
final systemBorderRadius = BorderRadius.circular(6); | ||
|
||
const double windowWidth = 400; | ||
const double windowHeight = 500; | ||
const double initialPositionX = 200; | ||
const double initialPositionY = 70; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we keep a reference to
Compositor
fromSurface
s or not?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's not necassry. Compositor will be created in main, and probably main should keep track of it. Is there actually any use case where we might have more than 1 compositor ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There will never be more than one compositor at a time in a given isolate, but the
Compositor
it belongs to is still part of the state conceptually in my mind.At the very least it prevents us from having to pass it around everywhere along with the surface. Most times you have a
Surface
you need access to the compositor as well.In my mind we have a few options:
Compositor
object within each surface. Only downside I can think of here is memory, but that's only a pointer.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about providing the compositor using an
InheritedWidget
?the app in order to use the compositor will need to use as root a
Compositor
widget of some sort which will then be used to create, maintain and dispose the compositor instance and also expose it to descendants usingCompositor.of(context)
.This way a
Surface
won't need to hold a compositor instance but instead only theSurfaceView
will need to get it, using theof
method indeed.It would also be possible to detect if the app is running with the compositor or not because of
Compositor.maybeOf(context)
returning null if no compositor is available for exampleThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer not using the widget tree to pass around the compositor instance.
The main reason for this is that the compositor instance inherently has another lifetime compared to something in the widget tree.
It creates a platform channel and uses this to communicate with native code on the other side for the lifetime of the isolate. It also accumulates and maintains state for its whole lifetime, something conceptually incompatible with being maintained as part of the widget tree. It is analogous to the various
Binding
s in the flutter framework. (WidgetBinding
for instance)It's just inherently a singleton with a global lifetime, and I think we would save ourselves some pain and complexity in the long run by just treating it as such from the beginning.
That being said, whether we should pass it around as a part of the surface objects or access it as a global every time is still an open question for me. Having written this out and thought through it a bit more I'm leaning towards the global route.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point then, i'm more leaning towards the global approach myself too