Skip to content

Commit

Permalink
Rework signals to type check args
Browse files Browse the repository at this point in the history
  • Loading branch information
frmdstryr committed Jan 13, 2024
1 parent 8948868 commit ae69762
Show file tree
Hide file tree
Showing 428 changed files with 39,802 additions and 23,402 deletions.
15 changes: 8 additions & 7 deletions example/src/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ const gtk = @import("gtk");
const gio = @import("gio");


pub fn onHelloClicked(button: *gtk.Button, data: ?*anyopaque) callconv(.C) void {
_ = data;
pub fn onHelloClicked(button: *gtk.Button, data: ?*gtk.Application) callconv(.C) void {
const app = data.?;
_ = app;
_ = button;
std.debug.print("Hello!", .{});
}
Expand All @@ -22,11 +23,11 @@ pub fn activate(app: *gtk.Application, data: ?*anyopaque) callconv(.C) void {
window.setChild(box.asWidget());

var button = gtk.Button.newWithLabel("Hello World!").?;
_ = button.connectSignal(.clicked, anyopaque, &onHelloClicked, null);
_ = button.connectClicked(gtk.Application, &onHelloClicked, app, .Default);
box.append(button.asWidget());

var button2 = gtk.Button.newWithLabel("Quit").?;
_ = button2.connectSignalSwapped(.clicked, gtk.Window, &gtk.Window.destroy, window);
_ = button2.connectClickedSwapped(gtk.Window, &gtk.Window.destroy, window.asWindow(), .Default);
box.append(button2.asWidget());
box.setSpacing(2);
box.setHomogeneous(true);
Expand All @@ -44,12 +45,12 @@ pub fn main() !u8 {
defer _ = gpa.deinit();
const allocator = gpa.allocator();

var args = try std.process.argsAlloc(allocator);
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
var app = gtk.Application.new("zig.gtk.example", gio.ApplicationFlags.FlagsNone).?;
defer app.unref();

_ = app.connectSignal(.activate, anyopaque, &activate, null);
return @intCast(app.run(@intCast(args.len), @ptrCast(args[0..])));
_ = app.connectActivate(anyopaque, &activate, null, .Default);
return @intCast(app.run(@intCast(args.len), @ptrCast(args.ptr)));
}

142 changes: 66 additions & 76 deletions gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@

EXCLUDED_ENUMS = {"GTK_ALIGN_BASELINE_FILL"}


# Half of them start with G_ other start with GLIB_
GLIB_CONSTANTS = (
"MAJOR_VERSION",
Expand Down Expand Up @@ -116,65 +117,6 @@
}


SIGNAL_METHODS = """
// Signals
// Connect to a signal with no arguments and optional user data
pub inline fn connectSignal(
self: *Self,
signal: Signals,
comptime T: type,
callback: *const fn (self: *Self, data: ?*T) callconv(.C) void,
data: anytype
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, 0));
}
// Connect to a signal with a typed argument and optional user data
pub inline fn connectSignalWithArg(
self: *Self,
signal: Signals,
comptime ArgType: type,
comptime UserDataType: type,
callback: *const fn (self: *Self, value: ArgType, data: ?*UserDataType) callconv(.C) void,
data: anytype,
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, 0));
}
// Connect to a signal with no type validation
pub inline fn connectSignalAnytype(
self: *Self,
signal: Signals,
callback: anytype,
data: anytype,
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, 0));
}
// Connect to a signal with a no arguments and optional user data
pub inline fn connectSignalAfter(
self: *Self,
signal: Signals,
comptime T: type,
callback: *const fn (self: *Self, data: ?*T) callconv(.C) void,
data: anytype
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, c.G_CONNECT_AFTER));
}
pub inline fn connectSignalSwapped(
self: *Self,
signal: Signals,
comptime T: type,
callback: *const fn (data: *T) callconv(.C) void,
data: anytype
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, c.G_CONNECT_SWAPPED));
}
"""


PROPERTY_METHODS = """
// Connect to a signal with no type validation
pub inline fn connectProperty(
Expand Down Expand Up @@ -231,7 +173,14 @@
EXTRA_API_IMPORTS: dict[str, list[str]] = {}


REGISTER_TYPE = """
GOBJECT_EXTRA = """
// Converted from flag to make it easier to use
pub const ConnectFlags = enum(c_int) {
Default = 0,
After = c.G_CONNECT_AFTER,
};
pub fn registerType(comptime T: type, comptime type_name: [:0]const u8) type {
const CustomTypeClass = struct {
parent_class: ObjectClass,
Expand Down Expand Up @@ -360,7 +309,8 @@
"extern fn gtk_init() void;",
"pub const init = gtk_init;",
],
"GObject": REGISTER_TYPE.split("\n"),
"GObject": GOBJECT_EXTRA.split("\n"),

}


Expand Down Expand Up @@ -435,10 +385,10 @@ def generate_constants(ns: str, constants: list) -> list[str]:
return out


def camel_case(name: str) -> str:
def camel_case(name: str, sep="_") -> str:
first, *rest = [
v
for it in name.strip().split("_")
for it in name.strip().split(sep)
if (v := it.strip()) # Name may start with _ or have __
]
return first.lower() + "".join([it.title() for it in rest])
Expand Down Expand Up @@ -806,20 +756,58 @@ def generate_class(ns: str, Cls: type):
if signals:
out.append("")
out.append(" // Signals")
out.append(" pub const Signals = enum(u8) {")
for i, signal in enumerate(signals):
name = signal.get_name().replace("-", "_")
out.append(f" {name} = {i},")
out.append(" };")
out.append("")
out.append(" pub const SignalNames = [_][:0]const u8{")
for i, signal in enumerate(signals):
name = signal.get_name()
out.append(f' "{name}",')
out.append(" };")

if signals:
out.append(SIGNAL_METHODS)
signal_args = []
for arg in signal.get_arguments():
name = clean_zig_name(arg.get_name())
t = func_arg_type(signal, arg, imports)
signal_args.append(f"{name}: {t}")
args = ["self: *Self"] + signal_args + ["data: ?*T"]
fn_name = camel_case("connect-"+signal.get_name(), "-")
out.append(" pub inline fn %s(" % fn_name)
out.append(" self: *Self,")
out.append(" comptime T: type,")
out.append(" callback: %s," % f"*const fn ({', '.join(args)}) callconv(.C) void")
out.append(" data: ?*T,")
out.append(" flags: gobject.ConnectFlags")
out.append(" ) u64 {")
out.append(f" return c.g_signal_connect_data(self, \"{signal.get_name()}\", @ptrCast(callback), data, null, @intFromEnum(flags));")
out.append(" }")
out.append("")

swapped_args = ["data: *T"] + signal_args
out.append(" pub inline fn %sSwapped(" % fn_name)
out.append(" self: *Self,")
out.append(" comptime T: type,")
out.append(" callback: %s," % f"*const fn ({', '.join(swapped_args)}) callconv(.C) void")
out.append(" data: *T,")
out.append(" flags: gobject.ConnectFlags")
out.append(" ) u64 {")
out.append(f" return c.g_signal_connect_data(self, \"{signal.get_name()}\", @ptrCast(callback), data, null, @as(c.GConnectFlags, @intFromEnum(flags)) | c.G_CONNECT_SWAPPED);")
out.append(" }")
out.append("")


# out.append(" pub const Signals = enum(u8) {")
# for i, signal in enumerate(signals):
# name = signal.get_name().replace("-", "_")
# if sig_args := signal.get_arguments():
# args = []
# for arg in sig_args:
# t = func_arg_type(None, arg, set())
# args.append(f"{arg.get_name()}: {t}")
# out.append(f" // Args ({', '.join(args)})")
# out.append(f" {name} = {i},")
# out.append(" };")
# out.append("")
# out.append(" pub const SignalNames = [_][:0]const u8{")
# for i, signal in enumerate(signals):
# name = signal.get_name()
# out.append(f' "{name}",')
# out.append(" };")

#if signals:
# out.append(SIGNAL_METHODS)

if properties:
out.append("")
Expand Down Expand Up @@ -932,6 +920,8 @@ def resolve_namespace(name: str, module: type) -> dict:
elif issubclass(v, GObject.GEnum):
enums.append(v)
elif issubclass(v, GObject.GFlags):
if v is GObject.ConnectFlags:
continue # Hack: use an enum
flags.append(v)
elif issubclass(
v,
Expand Down
98 changes: 54 additions & 44 deletions src/gdk/app_launch_context.zig
Original file line number Diff line number Diff line change
Expand Up @@ -133,74 +133,84 @@ pub const AppLaunchContext = extern struct {


// Signals
pub const Signals = enum(u8) {
launch_failed = 0,
launch_started = 1,
launched = 2,
notify = 3,
};
pub inline fn connectLaunchFailed(
self: *Self,
comptime T: type,
callback: *const fn (self: *Self, startup_notify_id: [*c]const u8, data: ?*T) callconv(.C) void,
data: ?*T,
flags: gobject.ConnectFlags
) u64 {
return c.g_signal_connect_data(self, "launch-failed", @ptrCast(callback), data, null, @intFromEnum(flags));
}

pub const SignalNames = [_][:0]const u8{
"launch-failed",
"launch-started",
"launched",
"notify",
};
pub inline fn connectLaunchFailedSwapped(
self: *Self,
comptime T: type,
callback: *const fn (data: *T, startup_notify_id: [*c]const u8) callconv(.C) void,
data: *T,
flags: gobject.ConnectFlags
) u64 {
return c.g_signal_connect_data(self, "launch-failed", @ptrCast(callback), data, null, @as(c.GConnectFlags, @intFromEnum(flags)) | c.G_CONNECT_SWAPPED);
}

// Signals
pub inline fn connectLaunchStarted(
self: *Self,
comptime T: type,
callback: *const fn (self: *Self, info: gio.AppInfo, platform_data: glib.Variant, data: ?*T) callconv(.C) void,
data: ?*T,
flags: gobject.ConnectFlags
) u64 {
return c.g_signal_connect_data(self, "launch-started", @ptrCast(callback), data, null, @intFromEnum(flags));
}

// Connect to a signal with no arguments and optional user data
pub inline fn connectSignal(
pub inline fn connectLaunchStartedSwapped(
self: *Self,
signal: Signals,
comptime T: type,
callback: *const fn (self: *Self, data: ?*T) callconv(.C) void,
data: anytype
callback: *const fn (data: *T, info: gio.AppInfo, platform_data: glib.Variant) callconv(.C) void,
data: *T,
flags: gobject.ConnectFlags
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, 0));
return c.g_signal_connect_data(self, "launch-started", @ptrCast(callback), data, null, @as(c.GConnectFlags, @intFromEnum(flags)) | c.G_CONNECT_SWAPPED);
}

// Connect to a signal with a typed argument and optional user data
pub inline fn connectSignalWithArg(
pub inline fn connectLaunched(
self: *Self,
signal: Signals,
comptime ArgType: type,
comptime UserDataType: type,
callback: *const fn (self: *Self, value: ArgType, data: ?*UserDataType) callconv(.C) void,
data: anytype,
comptime T: type,
callback: *const fn (self: *Self, info: gio.AppInfo, platform_data: glib.Variant, data: ?*T) callconv(.C) void,
data: ?*T,
flags: gobject.ConnectFlags
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, 0));
return c.g_signal_connect_data(self, "launched", @ptrCast(callback), data, null, @intFromEnum(flags));
}

// Connect to a signal with no type validation
pub inline fn connectSignalAnytype(
pub inline fn connectLaunchedSwapped(
self: *Self,
signal: Signals,
callback: anytype,
data: anytype,
comptime T: type,
callback: *const fn (data: *T, info: gio.AppInfo, platform_data: glib.Variant) callconv(.C) void,
data: *T,
flags: gobject.ConnectFlags
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, 0));
return c.g_signal_connect_data(self, "launched", @ptrCast(callback), data, null, @as(c.GConnectFlags, @intFromEnum(flags)) | c.G_CONNECT_SWAPPED);
}

// Connect to a signal with a no arguments and optional user data
pub inline fn connectSignalAfter(
pub inline fn connectNotify(
self: *Self,
signal: Signals,
comptime T: type,
callback: *const fn (self: *Self, data: ?*T) callconv(.C) void,
data: anytype
callback: *const fn (self: *Self, pspec: gobject.ParamSpec, data: ?*T) callconv(.C) void,
data: ?*T,
flags: gobject.ConnectFlags
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, c.G_CONNECT_AFTER));
return c.g_signal_connect_data(self, "notify", @ptrCast(callback), data, null, @intFromEnum(flags));
}

pub inline fn connectSignalSwapped(
pub inline fn connectNotifySwapped(
self: *Self,
signal: Signals,
comptime T: type,
callback: *const fn (data: *T) callconv(.C) void,
data: anytype
callback: *const fn (data: *T, pspec: gobject.ParamSpec) callconv(.C) void,
data: *T,
flags: gobject.ConnectFlags
) u64 {
return c.g_signal_connect_data(self, SignalNames[@intFromEnum(signal)], @ptrCast(callback), data, null, @as(c.GConnectFlags, c.G_CONNECT_SWAPPED));
return c.g_signal_connect_data(self, "notify", @ptrCast(callback), data, null, @as(c.GConnectFlags, @intFromEnum(flags)) | c.G_CONNECT_SWAPPED);
}


Expand Down
Loading

0 comments on commit ae69762

Please sign in to comment.