Skip to content

Commit

Permalink
feat: add Window.visible and add safety checks to monitor API
Browse files Browse the repository at this point in the history
  • Loading branch information
zenith391 committed Dec 31, 2024
1 parent 9f037eb commit 857363d
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 12 deletions.
14 changes: 11 additions & 3 deletions examples/balls.zig
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,17 @@ var totalEnergy = capy.Atom(f32).of(0);
const BALL_DIAMETER = 20;
const BALL_RADIUS = BALL_DIAMETER / 2;

//var gpa = std.heap.GeneralPurposeAllocator(.{}) {};
//pub const capy_allocator = gpa.allocator();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
pub const capy_allocator = gpa.allocator();

pub fn main() !void {
defer _ = gpa.deinit();
try capy.init();
defer capy.deinit();

defer totalEnergy.deinit();
balls = std.ArrayList(Ball).init(capy.internal.lasting_allocator);
defer balls.deinit();

// Generate random balls
var prng = std.Random.DefaultPrng.init(@as(u64, @bitCast(std.time.milliTimestamp())));
Expand All @@ -39,6 +44,8 @@ pub fn main() !void {
});
}

// the canvas isn't referenced (canvas.ref()) so it will get deinitialized whenever the window
// is deinitialized
var canvas = capy.canvas(.{
.preferredSize = capy.Size.init(500, 500),
.ondraw = @as(*const fn (*anyopaque, *capy.DrawContext) anyerror!void, @ptrCast(&onDraw)),
Expand All @@ -51,6 +58,7 @@ pub fn main() !void {
defer totalEnergyFormat.deinit();

var window = try capy.Window.init();
defer window.deinit();
try window.set(capy.column(.{}, .{
capy.label(.{ .text = "Balls with attraction and friction" }),
capy.label(.{})
Expand Down Expand Up @@ -129,7 +137,7 @@ fn simulationThread(window: *capy.Window) !void {
const root = window.getChild().?.as(capy.Container);
const canvas = root.getChild("ball-canvas").?.as(capy.Canvas);

while (true) {
while (window.visible.get()) {
const delta = 1.0 / 60.0;
for (balls.items, 0..) |*ball, i| {
// Moving
Expand Down
19 changes: 19 additions & 0 deletions src/backends/gtk/Window.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub fn create() common.BackendError!Window {

const surface = c.gtk_native_get_surface(@ptrCast(window));
_ = c.g_signal_connect_data(surface, "layout", @ptrCast(&gtkLayout), window, null, c.G_CONNECT_AFTER);
_ = c.g_signal_connect_data(window, "close-request", @as(c.GCallback, @ptrCast(&gtkCloseRequest)), null, null, c.G_CONNECT_AFTER);
return Window{ .peer = window, .wbin = wbin, .vbox = vbox };
}

Expand Down Expand Up @@ -79,6 +80,18 @@ fn gtkLayout(peer: *c.GdkSurface, width: c.gint, height: c.gint, userdata: ?*any
return 0;
}

fn gtkCloseRequest(peer: *c.GtkWindow, userdata: ?*anyopaque) callconv(.C) c.gint {
_ = userdata;
const data = common.getEventUserData(@ptrCast(peer));
const value_bool: bool = false;
if (data.class.propertyChangeHandler) |handler|
handler("visible", &value_bool, data.userdata);
if (data.user.propertyChangeHandler) |handler|
handler("visible", &value_bool, data.userdata);

return 0;
}

pub fn resize(self: *Window, width: c_int, height: c_int) void {
c.gtk_window_set_default_size(@ptrCast(self.peer), width, height);
}
Expand Down Expand Up @@ -162,6 +175,12 @@ pub fn unfullscreen(self: *Window) void {

pub fn show(self: *Window) void {
c.gtk_widget_show(self.peer);
const data = common.getEventUserData(self.peer);
const value_bool: bool = true;
if (data.class.propertyChangeHandler) |handler|
handler("visible", &value_bool, data.userdata);
if (data.user.propertyChangeHandler) |handler|
handler("visible", &value_bool, data.userdata);
}

pub fn registerTickCallback(self: *Window) void {
Expand Down
12 changes: 6 additions & 6 deletions src/monitor.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ const ListAtom = @import("data.zig").ListAtom;
// TODO: when a monitor is removed, monitor.peer.deinit should be called
pub const Monitors = struct {
/// List of all monitors that are connected
pub var list = ListAtom(Monitor).init(internal.lasting_allocator);
pub var list: ListAtom(Monitor) = undefined;
/// Lock used to ensure the backend is initialized only once (at least in debug mode)
var initialized: std.debug.SafetyLock = .{};

/// Init the subsystem by filling the monitor list and by listening to events indicating
/// that a monitor is being added or removed.
/// This function is called by `capy.init()`, so it doesn't need to be called manually.
pub fn init() void {
initialized.lock();
Monitors.list = ListAtom(Monitor).init(internal.lasting_allocator);
const peer_list = backend.Monitor.getList();
for (peer_list) |*monitor_peer| {
list.append(Monitor.init(monitor_peer)) catch @panic("OOM");
Expand All @@ -25,6 +29,7 @@ pub const Monitors = struct {

/// This function is called by `capy.deinit()`, so it doesn't need to be called manually.
pub fn deinit() void {
initialized.unlock();
{
var iterator = Monitors.list.iterate();
defer iterator.deinit();
Expand All @@ -33,7 +38,6 @@ pub const Monitors = struct {
}
}
Monitors.list.deinit();
Monitors.list = ListAtom(Monitor).init(internal.lasting_allocator);
backend.Monitor.deinitAllPeers();
}
};
Expand Down Expand Up @@ -129,10 +133,6 @@ pub const Monitor = struct {
const monitor = Monitors.list.get(0);
const width, const height = monitor.getSize();
std.log.info("Monitor pixels: {d} px x {d} px", .{ width, height });

// Alternate usage to only retrieve the monitor's height
_, const h = monitor.getSize();
_ = h;
}
};

Expand Down
11 changes: 8 additions & 3 deletions src/window.zig
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ pub const Window = struct {
/// This can be used for synchronizing animations to the window's monitor's sync rate.
on_frame: *EventSource,
animation_controller: *AnimationController,
visible: Atom(bool) = Atom(bool).of(false),

pub const Feature = enum {
Title,
Expand Down Expand Up @@ -68,11 +69,13 @@ pub const Window = struct {

pub fn show(self: *Window) void {
self.peer.setUserData(self);
return self.peer.show();
self.peer.show();
self.visible.set(true);
}

pub fn close(self: *Window) void {
return self.peer.close();
self.peer.close();
self.visible.set(false);
}

/// wrappedContainer can be an error union, a pointer to the container or the container itself.
Expand Down Expand Up @@ -129,8 +132,10 @@ pub const Window = struct {
fn propertyChanged(name: []const u8, value: *const anyopaque, data: usize) void {
const self: *Window = @ptrFromInt(data);
if (std.mem.eql(u8, name, "tick_id")) {
_ = value;
self.on_frame.callListeners();
} else if (std.mem.eql(u8, name, "visible")) {
const bool_ptr: *const bool = @ptrCast(value);
self.visible.set(bool_ptr.*);
}
}

Expand Down

0 comments on commit 857363d

Please sign in to comment.