Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

Commit

Permalink
feat: working on toplevel resizing
Browse files Browse the repository at this point in the history
  • Loading branch information
RossComputerGuy committed May 9, 2024
1 parent 52d64e2 commit ae95f6f
Show file tree
Hide file tree
Showing 8 changed files with 139 additions and 34 deletions.
6 changes: 5 additions & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,11 @@
mkShell = pkg: pkgs.mkShell {
inherit (pkg) pname version name;
inputsFrom = [ pkg ];
packages = [ pkgs.flutter pkgs.yq ];
packages = with pkgs; [
flutter yq cage
wayland-utils
mesa-demos
];
};
in {
default = mkShell self.packages.${system}.default;
Expand Down
34 changes: 30 additions & 4 deletions lib/logic/display.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class DisplayManager extends ChangeNotifier {

DisplayManager() {
channel.setMethodCallHandler((call) async {
print(call.arguments);
switch (call.method) {
case 'newToplevel':
final server = find(call.arguments['name']);
Expand All @@ -36,8 +37,9 @@ class DisplayManager extends ChangeNotifier {
case 'map':
toplevel.sync();
break;
case 'commit':
default:
toplevel.notifyListeners();
server.notifyListeners();
break;
}
break;
Expand Down Expand Up @@ -130,6 +132,23 @@ class DisplayServer extends ChangeNotifier {
}
}

class DisplayServerToplevelSize {
const DisplayServerToplevelSize({
this.width = 0,
this.height = 0,
});

final int width;
final int height;

dynamic toJSON() {
return <String, dynamic>{
'width': width,
'height': height,
};
}
}

class DisplayServerToplevel extends ChangeNotifier {
DisplayServerToplevel._(this._server, this.id);

Expand All @@ -146,6 +165,8 @@ class DisplayServerToplevel extends ChangeNotifier {
return _server._toplevels.firstWhere((item) => item.id == _parent);
}

DisplayServerToplevelSize? size;

Future<void> sync() async {
final data = await DisplayManager.channel.invokeMethod('getToplevel', <String, dynamic>{
'name': _server.name,
Expand All @@ -156,15 +177,20 @@ class DisplayServerToplevel extends ChangeNotifier {
title = data['title'];
texture = data['texture'];
_parent = data['parent'];
size = DisplayServerToplevelSize(
width: data['size']['width'],
height: data['size']['height'],
);
notifyListeners();
}

Future<void> setSize(int width, int height) async {
await DisplayManager.channel.invokeMethod('setToplevelSize', <String, dynamic>{
size = DisplayServerToplevelSize(width: width, height: height);
await DisplayManager.channel.invokeMethod('setToplevel', <String, dynamic>{
'name': _server.name,
'id': id,
'width': width,
'height': height,
'size': size!.toJSON(),
});
await sync();
}
}
2 changes: 2 additions & 0 deletions lib/widgets/system_layout.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class SystemLayout extends StatelessWidget {
frontLayer: body,
bottomSheet: bottomSheet,
bottomNavigationBar: bottomNavigationBar,
extendBody: true,
);

Widget _buildDesktop(BuildContext context) =>
Expand Down Expand Up @@ -141,6 +142,7 @@ class SystemLayout extends StatelessWidget {
body: body,
bottomSheet: bottomSheet,
bottomNavigationBar: bottomNavigationBar,
extendBody: true,
);

@override
Expand Down
47 changes: 34 additions & 13 deletions lib/widgets/toplevel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,29 +20,50 @@ class Toplevel extends StatefulWidget {
class _ToplevelState extends State<Toplevel> {
GlobalKey key = GlobalKey();

void _sendSize() {
if (key.currentContext != null && widget.toplevel.texture != null) {
final box = key.currentContext!.findRenderObject() as RenderBox;
widget.toplevel.setSize(box.size.width.toInt(), box.size.height.toInt());
}
}

@override
void initState() {
super.initState();

SchedulerBinding.instance.addPostFrameCallback((_) {
if (key.currentContext != null && widget.toplevel.texture != null) {
final box = key.currentContext!.findRenderObject() as RenderBox;
widget.toplevel.setSize(box.size.width.toInt(), box.size.height.toInt());
}
_sendSize();
});
}

@override
Widget buildContent(BuildContext context, DisplayServerToplevel toplevel) =>
toplevel.texture == null
? SizedBox() : Texture(
textureId: toplevel.texture!,
);

@override
Widget build(BuildContext context) =>
ChangeNotifierProvider(
key: key,
create: (_) => widget.toplevel,
child: Consumer<DisplayServerToplevel>(
builder: (context, toplevel, _) =>
toplevel.texture == null
? SizedBox() : Texture(
textureId: toplevel.texture!,
),
NotificationListener<SizeChangedLayoutNotification>(
onNotification: (notif) {
_sendSize();
return true;
},
child: SizeChangedLayoutNotifier(
child: ChangeNotifierProvider(
create: (_) => widget.toplevel,
child: Consumer<DisplayServerToplevel>(
key: key,
builder: (context, toplevel, _) =>
toplevel.size != null
? SizedBox(
width: toplevel.size!.width.toDouble(),
height: toplevel.size!.height.toDouble(),
child: buildContent(context, toplevel),
) : buildContent(context, toplevel),
),
),
),
);
}
28 changes: 26 additions & 2 deletions linux/channels/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ static FlValue* new_string(const gchar* str) {
return fl_value_new_string(g_strdup(str));
}

static void toplevel_decor_new(struct wl_listener* listener, void* data) {
DisplayChannelDisplay* self = wl_container_of(listener, self, toplevel_decor_new);
struct wlr_xdg_toplevel_decoration_v1* decor = data;
g_message("%p", decor->toplevel->base->data);
wlr_xdg_toplevel_decoration_v1_set_mode(decor, WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
}

static gboolean display_channel_wl_poll(GIOChannel* src, GIOCondition cond, gpointer user_data) {
DisplayChannelDisplay* self = (DisplayChannelDisplay*)user_data;
struct wl_display* wl_display = display_channel_backend_get_display(self->backend);
Expand Down Expand Up @@ -97,6 +104,11 @@ static void method_call_handler(FlMethodChannel* channel, FlMethodCall* method_c
disp->seat = wlr_seat_create(wl_display, session_name);
disp->xdg_shell = wlr_xdg_shell_create(wl_display, 3);

disp->xdg_decor = wlr_xdg_decoration_manager_v1_create(wl_display);

disp->toplevel_decor_new.notify = toplevel_decor_new;
wl_signal_add(&disp->xdg_decor->events.new_toplevel_decoration, &disp->toplevel_decor_new);

disp->xdg_surface_new.notify = xdg_surface_new;
wl_signal_add(&disp->xdg_shell->events.new_surface, &disp->xdg_surface_new);

Expand Down Expand Up @@ -206,8 +218,16 @@ static void method_call_handler(FlMethodChannel* channel, FlMethodCall* method_c
fl_value_set(value, fl_value_new_string("texture"), fl_value_new_null());
}

struct wlr_box geom;
wlr_xdg_surface_get_geometry(toplevel->xdg->base, &geom);

FlValue* value_size = fl_value_new_map();
fl_value_set(value_size, fl_value_new_string("width"), fl_value_new_int(geom.width));
fl_value_set(value_size, fl_value_new_string("height"), fl_value_new_int(geom.height));
fl_value_set(value, fl_value_new_string("size"), value_size);

response = FL_METHOD_RESPONSE(fl_method_success_response_new(value));
} else if (strcmp(fl_method_call_get_name(method_call), "setToplevelSize") == 0) {
} else if (strcmp(fl_method_call_get_name(method_call), "setToplevel") == 0) {
FlValue* args = fl_method_call_get_args(method_call);
const gchar* name = fl_value_get_string(fl_value_lookup_string(args, "name"));
int id = fl_value_get_int(fl_value_lookup_string(args, "id"));
Expand All @@ -227,7 +247,11 @@ static void method_call_handler(FlMethodChannel* channel, FlMethodCall* method_c
DisplayChannelToplevel* toplevel = g_hash_table_lookup(disp->toplevels, &id);
g_assert(toplevel->id == id);

wlr_xdg_toplevel_set_size(toplevel->xdg, fl_value_get_int(fl_value_lookup_string(args, "width")), fl_value_get_int(fl_value_lookup_string(args, "height")));
FlValue* value_size = fl_value_lookup_string(args, "size");
if (value_size != NULL) {
wlr_xdg_toplevel_set_size(toplevel->xdg, fl_value_get_int(fl_value_lookup_string(value_size, "width")), fl_value_get_int(fl_value_lookup_string(value_size, "height")));
}

response = FL_METHOD_RESPONSE(fl_method_success_response_new(NULL));
} else {
response = FL_METHOD_RESPONSE(fl_method_not_implemented_response_new());
Expand Down
3 changes: 3 additions & 0 deletions linux/channels/display.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ extern "C" {
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_shm.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_xdg_decoration_v1.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wayland-server.h>
#include <wayland-client.h>
Expand Down Expand Up @@ -66,12 +67,14 @@ typedef struct _DisplayChannelDisplay {
struct wlr_compositor* compositor;
struct wlr_seat* seat;
struct wlr_xdg_shell* xdg_shell;
struct wlr_xdg_decoration_manager_v1* xdg_decor;

const gchar* prev_wl_disp;
const char* socket;
struct _DisplayChannel* channel;

struct wl_listener xdg_surface_new;
struct wl_listener toplevel_decor_new;

GList* outputs;
GHashTable* toplevels;
Expand Down
12 changes: 12 additions & 0 deletions linux/channels/display/texture.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ typedef struct _DisplayChannelTexturePrivate {
uint32_t name;
uint32_t width;
uint32_t height;
bool has_init;
} DisplayChannelTexturePrivate;

enum {
PROP_0 = 0,
PROP_GL_CONTEXT,
PROP_HAS_INIT,
N_PROPERTIES,
};

Expand Down Expand Up @@ -42,6 +44,9 @@ static void display_channel_texture_get_property(GObject* obj, guint prop_id, GV
case PROP_GL_CONTEXT:
g_value_set_object(value, priv->gl_context);
break;
case PROP_HAS_INIT:
g_value_set_boolean(value, priv->has_init);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, prop_id, pspec);
break;
Expand Down Expand Up @@ -78,6 +83,7 @@ static void display_channel_texture_class_init(DisplayChannelTextureClass* klass
FL_TEXTURE_GL_CLASS(klass)->populate = display_channel_texture_populate;

obj_props[PROP_GL_CONTEXT] = g_param_spec_object("gl-context", "GL Context", "The OpenGL context in GDK to use", GDK_TYPE_GL_CONTEXT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
obj_props[PROP_HAS_INIT] = g_param_spec_boolean("has-init", "Has initial update", "Whether the texture has done an initial update", false, G_PARAM_READABLE);
g_object_class_install_properties(obj_class, N_PROPERTIES, obj_props);
}

Expand All @@ -92,6 +98,7 @@ DisplayChannelTexture* display_channel_texture_new(GdkGLContext* gl_context, str
glGenTextures(1, &priv->name);
gdk_gl_context_clear_current();

priv->has_init = false;
display_channel_texture_update(self, buffer);
return self;
}
Expand All @@ -106,7 +113,10 @@ void display_channel_texture_update(DisplayChannelTexture* self, struct wlr_buff
wlr_buffer_begin_data_ptr_access(buffer, WLR_BUFFER_DATA_PTR_ACCESS_READ, &data, &fmt, &stride);

const struct wlr_gles2_pixel_format* gles2_fmt = get_gles2_format_from_drm(fmt);
g_return_if_fail(gles2_fmt != NULL);

const struct wlr_pixel_format_info* drm_fmt = drm_get_pixel_format_info(fmt);
g_return_if_fail(drm_fmt != NULL);

glBindTexture(GL_TEXTURE_2D, priv->name);

Expand All @@ -127,4 +137,6 @@ void display_channel_texture_update(DisplayChannelTexture* self, struct wlr_buff
wlr_buffer_end_data_ptr_access(buffer);

gdk_gl_context_clear_current();

priv->has_init = true;
}
41 changes: 27 additions & 14 deletions linux/channels/display/toplevel.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ static void xdg_toplevel_destroy(struct wl_listener* listener, void* data) {

DisplayChannelToplevel* self = wl_container_of(listener, self, destroy);

g_autoptr(FlValue) value = fl_value_new_map();
fl_value_set(value, fl_value_new_string("name"), fl_value_new_string(self->display->socket));
fl_value_set(value, fl_value_new_string("id"), fl_value_new_int(self->id));
invoke_method(self->display->channel->channel, "removeToplevel", value);

wl_list_remove(&self->map.link);
wl_list_remove(&self->unmap.link);
wl_list_remove(&self->destroy.link);
Expand All @@ -63,19 +68,20 @@ static void xdg_toplevel_destroy(struct wl_listener* listener, void* data) {
g_hash_table_remove(self->display->toplevels, &self->id);

if (self->texture != NULL) {
GenesisShellApplication* app = wl_container_of(self->display->channel, app, display);
FlEngine* engine = fl_view_get_engine(app->view);
FlTextureRegistrar* tex_reg = fl_engine_get_texture_registrar(engine);
fl_texture_registrar_unregister_texture(tex_reg, FL_TEXTURE(self->texture));
bool has_init;
g_object_get(G_OBJECT(self->texture), "has-init", &has_init, NULL);

if (has_init) {
GenesisShellApplication* app = wl_container_of(self->display->channel, app, display);
FlEngine* engine = fl_view_get_engine(app->view);
FlTextureRegistrar* tex_reg = fl_engine_get_texture_registrar(engine);
// FIXME: Sometimes this causes a SIGSEV
fl_texture_registrar_unregister_texture(tex_reg, FL_TEXTURE(self->texture));
}
}

g_clear_object(&self->texture);

g_autoptr(FlValue) value = fl_value_new_map();
fl_value_set(value, fl_value_new_string("name"), fl_value_new_string(self->display->socket));
fl_value_set(value, fl_value_new_string("id"), fl_value_new_int(self->id));
invoke_method(self->display->channel->channel, "removeToplevel", value);

free(self);
}

Expand Down Expand Up @@ -109,13 +115,18 @@ static void xdg_toplevel_commit(struct wl_listener* listener, void* data) {
display_channel_texture_update(self->texture, buffer);
}

fl_texture_registrar_mark_texture_frame_available(tex_reg, FL_TEXTURE(self->texture));
bool has_init;
g_object_get(G_OBJECT(self->texture), "has-init", &has_init, NULL);

if (is_new) {
xdg_toplevel_emit_prop(self, "texture", fl_value_new_int((uintptr_t)FL_TEXTURE(self->texture)));
}
if (has_init) {
fl_texture_registrar_mark_texture_frame_available(tex_reg, FL_TEXTURE(self->texture));

xdg_toplevel_emit_request(self, "commit");
if (is_new) {
xdg_toplevel_emit_prop(self, "texture", fl_value_new_int((uintptr_t)FL_TEXTURE(self->texture)));
}

xdg_toplevel_emit_request(self, "commit");
}
}

static void xdg_toplevel_request_maximize(struct wl_listener* listener, void* data) {
Expand Down Expand Up @@ -195,6 +206,8 @@ void xdg_surface_new(struct wl_listener* listener, void* data) {
struct wlr_xdg_toplevel* xdg_toplevel = wlr_xdg_toplevel_try_from_wlr_surface(xdg_surface->surface);

DisplayChannelToplevel* toplevel = (DisplayChannelToplevel*)malloc(sizeof (DisplayChannelToplevel));
xdg_surface->data = toplevel;

toplevel->display = self;
toplevel->xdg = xdg_toplevel;
toplevel->id = self->toplevel_id++;
Expand Down

0 comments on commit ae95f6f

Please sign in to comment.