diff --git a/build.zig b/build.zig index 0f9f7e7..f00c30c 100644 --- a/build.zig +++ b/build.zig @@ -1,73 +1,66 @@ const std = @import("std"); -const builtin = @import("builtin"); -const Builder = std.build.Builder; - -pub fn build(b: *Builder) void { - const gtk4_enabled = b.option(bool, "gtk4", "use GTK4 [default: false]") orelse false; +// Although this function looks imperative, note that its job is to +// declaratively construct a build graph that will be executed by an external +// runner. +pub fn build(b: *std.Build) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. const target = b.standardTargetOptions(.{}); - const exe = b.addExecutable(.{ - .name = "init-exe", - .root_source_file = .{ .path = "src/main.zig" }, - .target = target, - }); - exe.linkLibC(); - exe.addIncludePath(.{ .path = "." }); - const cflags = [_][]const u8{}; - exe.addCSourceFile(.{ .file = .{ .path = "ragel/lang.c" }, .flags = &cflags }); - if (gtk4_enabled) { - // gtk4 - // exe.addIncludeDir("/usr/include/gtk-4.0"); - // exe.addIncludeDir("/usr/include/graphene-1.0"); - // exe.addIncludeDir("/usr/lib/x86_64-linux-gnu/graphene-1.0/include"); - exe.linkSystemLibrary("gtk-4"); - // exe.addIncludeDir("/usr/include/gdk-pixbuf-2.0"); - exe.linkSystemLibrary("gdk"); // does not add extra include path (see below) - } else { - // gtk3 - exe.linkSystemLibrary("gtk-3"); - exe.linkSystemLibrary("gdk-3.0"); // add include path /usr/include/gtk-3.0 - } - - // gtk - exe.linkSystemLibrary("glib-2.0"); - exe.linkSystemLibrary("gdk_pixbuf-2.0"); - exe.linkSystemLibrary("gobject-2.0"); - exe.linkSystemLibrary("gmodule-2.0"); - exe.linkSystemLibrary("pango-1.0"); - exe.linkSystemLibrary("atk-1.0"); - exe.linkSystemLibrary("gio-2.0"); + // Standard optimization options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. Here we do not + // set a preferred release mode, allowing the user to decide how to optimize. + const optimize = b.standardOptimizeOption(.{}); - // html - exe.linkSystemLibrary("gumbo"); + const lib = b.addStaticLibrary(.{ + .name = "zootdeck", + // In this case the main source file is merely a path, however, in more + // complicated build scripts, this could be a generated file. + .root_source_file = .{ .src_path = .{ .sub_path = "src/root.zig", .owner = b } }, + .target = target, + .optimize = optimize, + }); - // qt5 - //exe.addIncludeDir("/usr/include/x86_64-linux-gnu/qt5"); + // This declares intent for the library to be installed into the standard + // location when the user invokes the "install" step (the default step when + // running `zig build`). + b.installArtifact(lib); - // libui (local) - // exe.addIncludeDir("../libui"); - // exe.linkSystemLibrary("ui"); - // exe.addLibPath("../libui/build/out"); + const exe = b.addExecutable(.{ + .name = "zootdeck", + .root_source_file = .{ .src_path = .{ .sub_path = "src/main.zig", .owner = b } }, + .target = target, + .optimize = optimize, + }); - // glfw (local) - // exe.addIncludeDir("../glfw/include"); - // exe.addIncludeDir("../glfw/deps"); - // exe.addIncludeDir("../nanovg/src"); - exe.linkSystemLibrary("glfw3"); - exe.addLibraryPath(.{ .path = "../glfw/build/src" }); + // This declares intent for the executable to be installed into the + // standard location when the user invokes the "install" step (the default + // step when running `zig build`). + b.installArtifact(exe); - // opengl - //exe.addObjectFile("ext/glad.o"); // build glad.c by hand for now - exe.linkSystemLibrary("dl"); - exe.linkSystemLibrary("X11"); - exe.linkSystemLibrary("pthread"); + // This *creates* a Run step in the build graph, to be executed when another + // step is evaluated that depends on it. The next line below will establish + // such a dependency. + const run_cmd = b.addRunArtifact(exe); - // net - exe.linkSystemLibrary("curl"); + // By making the run step depend on the install step, it will be run from the + // installation directory rather than directly from within the cache directory. + // This is not necessary, however, if the application depends on other installed + // files, this ensures they will be present and in the expected location. + run_cmd.step.dependOn(b.getInstallStep()); - // lmdb - exe.linkSystemLibrary("lmdb"); + // This allows the user to pass arguments to the application in the build + // command itself, like this: `zig build run -- arg1 arg2 etc` + if (b.args) |args| { + run_cmd.addArgs(args); + } - b.installArtifact(exe); + // This creates a build step. It will be visible in the `zig build --help` menu, + // and can be selected like this: `zig build run` + // This will evaluate the `run` step rather than the default, which is "install". + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); } diff --git a/src/config.zig b/src/config.zig index a7aa25e..7c6cf54 100644 --- a/src/config.zig +++ b/src/config.zig @@ -59,7 +59,7 @@ pub const ColumnInfo = struct { } else { addon = "_"; } - out = std.fmt.allocPrint(allocator, "{s}@{s}", .{ addon, column.filter.host() }) catch unreachable; + out = "Z"; //std.fmt.allocPrint(allocator, "{s}@{s}", .{ addon, column.filter.host() }) catch unreachable; } return out; } diff --git a/src/db/file.zig b/src/db/file.zig index e170a22..9f0e8fb 100644 --- a/src/db/file.zig +++ b/src/db/file.zig @@ -12,7 +12,11 @@ pub fn init() !void { } pub fn has(namespace: []const u8, key: []const u8, allocator: Allocator) bool { - var keypath = std.fmt.allocPrint(allocator, "{s}/{s}/{s}", .{ cache_dir, namespace, key }) catch unreachable; + _ = cache_dir; + _ = namespace; + _ = key; + _ = allocator; + var keypath = "Z"; //std.fmt.allocPrint(allocator, "{s}/{s}/{s}", .{ cache_dir, namespace, key }) catch unreachable; var found = false; if (std.fs.cwd().access(keypath, .{ .mode = .read_only })) { found = true; @@ -23,7 +27,10 @@ pub fn has(namespace: []const u8, key: []const u8, allocator: Allocator) bool { } pub fn write(namespace: []const u8, key: []const u8, value: []const u8, allocator: Allocator) !void { - var dirpath = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ cache_dir, namespace }); + _ = cache_dir; + _ = namespace; + _ = allocator; + var dirpath = "Z"; //try std.fmt.allocPrint(allocator, "{s}/{s}", .{ cache_dir, namespace }); warn("MKDIR {s}\n", .{dirpath}); var dir = std.fs.Dir.makeOpenPath(std.fs.cwd(), dirpath, .{}) catch unreachable; defer dir.close(); diff --git a/src/db/lmdb.zig b/src/db/lmdb.zig index 684756c..a02e63d 100644 --- a/src/db/lmdb.zig +++ b/src/db/lmdb.zig @@ -48,7 +48,10 @@ pub fn write(namespace: []const u8, key: []const u8, value: []const u8, allocato ret = c.mdb_dbi_open(txnptr.*, null, c.MDB_CREATE, dbiptr); if (ret == 0) { // TODO: seperator issue. perhaps 2 byte invalid utf8 sequence - var fullkey = std.fmt.allocPrint(allocator, "{s}:{s}", .{ namespace, key }) catch unreachable; + var fullkey = "Z"; + _ = key; + _ = namespace; + //std.fmt.allocPrint(allocator, "{s}:{s}", .{ namespace, key }) catch unreachable; var mdb_key = mdbVal(fullkey, allocator); var mdb_value = mdbVal(value, allocator); ret = c.mdb_put(txnptr.*, dbiptr.*, mdb_key, mdb_value, 0); diff --git a/src/gui.zig b/src/gui.zig index 3044a30..b8c5b79 100644 --- a/src/gui.zig +++ b/src/gui.zig @@ -8,10 +8,8 @@ const config = @import("./config.zig"); const toot_lib = @import("./toot.zig"); const thread = @import("./thread.zig"); -const guilib = @import("./gui/gtk3.zig"); - const GUIError = error{Init}; -const Column = guilib.Column; +const Column = u32; var columns: std.ArrayList(*Column) = undefined; var allocator: Allocator = undefined; var settings: *config.Settings = undefined; @@ -21,72 +19,67 @@ pub fn init(alloca: Allocator, set: *config.Settings) !void { settings = set; allocator = alloca; columns = std.ArrayList(*Column).init(allocator); - try guilib.init(alloca, set); } var myActor: *thread.Actor = undefined; var stop = false; pub fn go(data: ?*anyopaque) callconv(.C) ?*anyopaque { - warn("GUI {s} mainloop thread.self()={}\n", .{ guilib.libname(), thread.self() }); + warn("GUI {s} mainloop thread.self()={}\n", .{ "none", thread.self() }); myActor = @as(*thread.Actor, @ptrCast(@alignCast(data))); - if (guilib.gui_setup(myActor)) { - // mainloop - var then = std.time.milliTimestamp(); - while (!stop) { - stop = guilib.mainloop(); - var now = std.time.milliTimestamp(); - //warn("{}ms pause gui mainloop\n", .{now - then}); - then = now; - } - warn("final mainloop {}\n", .{guilib.mainloop()}); - guilib.gui_end(); - } else |err| { - warn("gui error {}\n", .{err}); - } return null; } pub fn schedule(func: ?*const fn (?*anyopaque) callconv(.C) c_int, param: ?*anyopaque) void { - guilib.schedule(func, param); + _ = func; + _ = param; } pub fn show_main_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.show_main_schedule(in); + _ = in; + return 0; } pub fn add_column_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.add_column_schedule(in); + _ = in; + return 0; } pub fn column_remove_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.column_remove_schedule(in); + _ = in; + return 0; } pub fn column_config_oauth_url_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.column_config_oauth_url_schedule(in); + _ = in; + return 0; } pub fn update_column_config_oauth_finalize_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.update_column_config_oauth_finalize_schedule(in); + _ = in; + return 0; } pub fn update_column_ui_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.update_column_ui_schedule(in); + _ = in; + return 0; } pub fn update_column_netstatus_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.update_column_netstatus_schedule(in); + _ = in; + return 0; } pub fn update_column_toots_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.update_column_toots_schedule(in); + _ = in; + return 0; } pub fn update_author_photo_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.update_author_photo_schedule(in); + _ = in; + return 0; } -pub const TootPic = guilib.TootPic; pub fn toot_media_schedule(in: ?*anyopaque) callconv(.C) c_int { - return guilib.toot_media_schedule(in); + _ = in; + return 0; } diff --git a/src/gui/gtk3.zig b/src/gui/gtk3.zig index 573c41e..e4908a3 100644 --- a/src/gui/gtk3.zig +++ b/src/gui/gtk3.zig @@ -316,9 +316,6 @@ pub fn update_column_toots(column: *Column) void { } const column_footer_count_label = builder_get_widget(column.builder, "column_footer_count"); const tootword = if (column.main.config.img_only) "images" else "toots"; - const countStr = std.fmt.allocPrint(allocator, "{} {s}", .{ column.main.toots.count(), tootword }) catch unreachable; - const cCountStr = util.sliceToCstr(allocator, countStr); - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_count_label)), cCountStr); } pub fn update_netstatus_column(http: *config.HttpInfo, column: *Column) void { @@ -440,9 +437,6 @@ pub fn makeTootBox(toot: *toot_lib.Type, column: *Column) *c.GtkBuilder { fn photo_refresh(acct: []const u8, builder: *c.GtkBuilder) void { const avatar = builder_get_widget(builder, "toot_author_avatar"); - const avatar_path = std.fmt.allocPrint(allocator, "./cache/{s}/photo", .{acct}) catch unreachable; - var pixbuf = c.gdk_pixbuf_new_from_file_at_scale(util.sliceToCstr(allocator, avatar_path), 50, -1, 1, null); - c.gtk_image_set_from_pixbuf(@as(*c.GtkImage, @ptrCast(avatar)), pixbuf); } fn toot_media(column: *Column, builder: *c.GtkBuilder, toot: *toot_lib.Type, pic: []const u8) void { @@ -521,9 +515,6 @@ fn escapeGtkString(str: []const u8) []const u8 { pub fn labelBufPrint(label: *c.GtkWidget, comptime fmt: []const u8, args: anytype) void { const buf = allocator.alloc(u8, 256) catch unreachable; - const str = std.fmt.bufPrint(buf, fmt, args) catch unreachable; - const cStr = util.sliceToCstr(allocator, str); - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(label)), cStr); } fn column_config_btn(columnptr: ?*anyopaque) callconv(.C) void { @@ -709,9 +700,6 @@ pub fn column_config_oauth_url(colInfo: *config.ColumnInfo) void { oauth_url_buf.append("&response_type=code") catch unreachable; oauth_url_buf.append("&redirect_uri=urn:ietf:wg:oauth:2.0:oob") catch unreachable; var markupBuf = allocator.alloc(u8, 512) catch unreachable; - var markup = std.fmt.bufPrint(markupBuf, "{s} oauth", .{ oauth_url_buf.toSliceConst(), column.main.filter.host() }) catch unreachable; - var cLabel = util.sliceToCstr(allocator, markup); - c.gtk_label_set_markup(@as(*c.GtkLabel, @ptrCast(oauth_label)), cLabel); } fn column_config_oauth_activate(selfptr: *anyopaque) callconv(.C) void { diff --git a/src/gui/gtk4.zig b/src/gui/gtk4.zig deleted file mode 100644 index b4960b6..0000000 --- a/src/gui/gtk4.zig +++ /dev/null @@ -1,869 +0,0 @@ -// GTK+ -const std = @import("std"); -const Allocator = std.mem.Allocator; -const util = @import("../util.zig"); -const warn = util.log; -const config = @import("../config.zig"); -const simple_buffer = @import("../simple_buffer.zig"); -const toot_lib = @import("../toot.zig"); -const thread = @import("../thread.zig"); -const filter_lib = @import("../filter.zig"); - -const c = @cImport({ - @cInclude("gtk/gtk.h"); -}); - -const GUIError = error{ - GtkInit, - GladeLoad, -}; - -var allocator: Allocator = undefined; -var settings: *config.Settings = undefined; -pub const queue = std.ArrayList(u8).init(allocator); -var myActor: *thread.Actor = undefined; -var myAllocation = c.GtkAllocation{ .x = -1, .y = -1, .width = 0, .height = 0 }; - -pub const Column = struct { - builder: *c.GtkBuilder, - columnbox: *c.GtkWidget, - config_window: *c.GtkWidget, - main: *config.ColumnInfo, - guitoots: std.StringHashMap(*c.GtkBuilder), -}; - -var columns: std.ArrayList(*Column) = undefined; -var myBuilder: ?*c.GtkBuilder = undefined; -var myCssProvider: *c.GtkCssProvider = undefined; - -pub fn libname() []const u8 { - return "GTK4"; -} - -pub fn init(alloca: Allocator, set: *config.Settings) !void { - warn("{s} init()", .{libname()}); - settings = set; - allocator = alloca; - columns = std.ArrayList(*Column).init(allocator); - var tf = c.gtk_init_check(); - if (tf != 1) return GUIError.GtkInit; -} - -pub fn gui_setup(actor: *thread.Actor) !void { - myActor = actor; - // GtkCssProvider *cssProvider = gtk_css_provider_new(); - myCssProvider = c.gtk_css_provider_new(); - c.gtk_css_provider_load_from_path(myCssProvider, "theme.css"); - c.gtk_style_context_add_provider_for_display(c.gdk_display_get_default(), @as(*c.GtkStyleProvider, @ptrCast(myCssProvider)), c.GTK_STYLE_PROVIDER_PRIORITY_USER); - - myBuilder = c.gtk_builder_new(); - var ret = c.gtk_builder_add_from_file(myBuilder, "glade/zootdeck.glade", @as([*c][*c]c._GError, @ptrFromInt(0))); - if (ret == 0) { - warn("builder file fail", .{}); - return GUIError.GladeLoad; - } - - // Callbacks - _ = c.gtk_builder_add_callback_symbol(myBuilder, "actionbar.add", actionbar_add); - _ = c.gtk_builder_add_callback_symbol(myBuilder, "zoot_drag", zoot_drag); - // captures all keys oh no - // _ = c.gtk_builder_add_callback_symbol(myBuilder, "zoot.keypress", - // @ptrCast(?extern fn() void, zoot_keypress)); - _ = c.gtk_builder_add_callback_symbol(myBuilder, "main_check_resize", @as(?fn () callconv(.C) void, @ptrCast(main_check_resize))); - _ = c.gtk_builder_connect_signals(myBuilder, null); - - // set main size before resize callback happens - var main_window = builder_get_widget(myBuilder, "main"); - var w = @as(c.gint, @intCast(settings.win_x)); - var h = @as(c.gint, @intCast(settings.win_y)); - // c.gtk_widget_set_size_request(main_window, w, h); - c.gtk_window_resize(@as(*c.GtkWindow, @ptrCast(main_window)), w, h); - _ = g_signal_connect(main_window, "destroy", gtk_quit, null); -} - -fn builder_get_widget(builder: *c.GtkBuilder, name: [*]const u8) *c.GtkWidget { - var gobject = @as(*c.GTypeInstance, @ptrCast(c.gtk_builder_get_object(builder, name))); - var gwidget = @as(*c.GtkWidget, @ptrCast(c.g_type_check_instance_cast(gobject, c.gtk_widget_get_type()))); - return gwidget; -} - -pub fn schedule(func: ?fn (?*anyopaque) callconv(.C) c_int, param: ?*anyopaque) void { - _ = c.gdk_threads_add_idle(func, param); -} - -fn hide_column_config(column: *Column) void { - c.gtk_widget_hide(column.config_window); -} - -pub fn show_login_schedule(in: *anyopaque) callconv(.C) c_int { - _ = in; - var login_window = builder_get_widget(myBuilder, "login"); - c.gtk_widget_show(login_window); - return 0; -} - -pub fn show_main_schedule(in: ?*anyopaque) callconv(.C) c_int { - _ = in; - var main_window = builder_get_widget(myBuilder, "main"); - c.gtk_widget_show(main_window); - return 0; -} - -pub fn column_config_oauth_url_schedule(in: ?*anyopaque) callconv(.C) c_int { - const column = @as(*config.ColumnInfo, @ptrCast(@alignCast(8, in))); - column_config_oauth_url(column); - return 0; -} - -pub fn update_author_photo_schedule(in: ?*anyopaque) callconv(.C) c_int { - const cAcct = @as(*const u8, @ptrCast(@alignCast(8, in))); - const acct = util.cstrToSliceCopy(allocator, cAcct); - update_author_photo(acct); - return 0; -} - -pub fn update_column_ui_schedule(in: ?*anyopaque) callconv(.C) c_int { - const columnInfo = @as(*config.ColumnInfo, @ptrCast(@alignCast(8, in))); - const column = findColumnByInfo(columnInfo); - update_column_ui(column); - return 0; -} - -pub const TootPic = struct { - toot: *toot_lib.Type, - pic: []const u8, -}; -pub fn toot_media_schedule(in: ?*anyopaque) callconv(.C) c_int { - const tootpic = @as(*TootPic, @ptrCast(@alignCast(8, in))); - const toot = tootpic.toot; - if (findColumnByTootId(toot.id())) |column| { - const builder = column.guitoots.get(toot.id()).?; - toot_media(column, builder, toot, tootpic.pic); - } - return 0; -} - -pub fn add_column_schedule(in: ?*anyopaque) callconv(.C) c_int { - const column = @as(*config.ColumnInfo, @ptrCast(@alignCast(8, in))); - add_column(column); - return 0; -} - -pub fn add_column(colInfo: *config.ColumnInfo) void { - const container = builder_get_widget(myBuilder, "ZootColumns"); - const column = allocator.create(Column) catch unreachable; - column.builder = c.gtk_builder_new_from_file("glade/column.glade"); - column.columnbox = builder_get_widget(column.builder, "column"); - column.main = colInfo; - //var line_buf: []u8 = allocator.alloc(u8, 255) catch unreachable; - column.config_window = builder_get_widget(column.builder, "column_config"); - c.gtk_window_resize(@as(*c.GtkWindow, @ptrCast(column.config_window)), 600, 200); - column.guitoots = std.StringHashMap(*c.GtkBuilder).init(allocator); - columns.append(column) catch unreachable; - columns_resize(); - warn("column added {s}\n", .{column.main.makeTitle()}); - const filter = builder_get_widget(column.builder, "column_filter"); - const cFilter = util.sliceToCstr(allocator, column.main.config.filter); - c.gtk_entry_set_text(@as(*c.GtkEntry, @ptrCast(filter)), cFilter); - //const footer = builder_get_widget(column.builder, "column_footer"); - const config_icon = builder_get_widget(column.builder, "column_config_icon"); - c.gtk_misc_set_alignment(@as(*c.GtkMisc, @ptrCast(config_icon)), 1, 0); - - update_column_ui(column); - - c.gtk_grid_attach_next_to(@as(*c.GtkGrid, @ptrCast(container)), column.columnbox, null, c.GTK_POS_RIGHT, 1, 1); - - _ = c.gtk_builder_add_callback_symbol(column.builder, "column.title", @as(?fn () callconv(.C) void, @ptrCast(column_top_label_title))); - _ = c.gtk_builder_add_callback_symbol(column.builder, "column.config", @as(?fn () callconv(.C) void, @ptrCast(column_config_btn))); - _ = c.gtk_builder_add_callback_symbol(column.builder, "column.reload", @as(?fn () callconv(.C) void, @ptrCast(column_reload))); - _ = c.gtk_builder_add_callback_symbol(column.builder, "column.imgonly", @as(?fn () callconv(.C) void, @ptrCast(column_imgonly))); - _ = c.gtk_builder_add_callback_symbol(column.builder, "column.filter_done", @as(?fn () callconv(.C) void, @ptrCast(column_filter_done))); - _ = c.gtk_builder_add_callback_symbol(column.builder, "column_config.done", @as(?fn () callconv(.C) void, @ptrCast(column_config_done))); - _ = c.gtk_builder_add_callback_symbol(column.builder, "column_config.remove", @as(?fn () callconv(.C) void, @ptrCast(column_remove_btn))); - _ = c.gtk_builder_add_callback_symbol(column.builder, "column_config.oauth_btn", @as(?fn () callconv(.C) void, @ptrCast(column_config_oauth_btn))); - _ = c.gtk_builder_add_callback_symbol(column.builder, "column_config.oauth_auth_enter", @as(?fn () callconv(.C) void, @ptrCast(column_config_oauth_activate))); - _ = c.gtk_builder_add_callback_symbol(column.builder, "zoot_drag", zoot_drag); - _ = c.gtk_builder_connect_signals(column.builder, null); - c.gtk_widget_show_all(container); -} - -pub fn update_author_photo(acct: []const u8) void { - warn("Update_author_photo {s}\n", .{acct}); - // all toots in all columns :O - for (columns.items) |column| { - const toots = column.main.toots.author(acct, allocator); - for (toots) |toot| { - warn("update_author_photo {s} {s} {s}\n", .{ column.main.filter.host(), acct, toot.id() }); - var tootbuilderMaybe = column.guitoots.get(toot.id()); - if (tootbuilderMaybe) |kv| { - photo_refresh(acct, kv); - } - } - } -} - -pub fn columns_resize() void { - if (columns.items.len > 0) { - const container = builder_get_widget(myBuilder, "ZootColumns"); - var app_width = c.gtk_widget_get_allocated_width(container); - var avg_col_width = @divTrunc(app_width, @as(c_int, @intCast(columns.items.len))); - warn("columns_resize app_width {} col_width {} columns {}\n", .{ app_width, avg_col_width, columns.items.len }); - for (columns.items) |col| { - c.gtk_widget_get_allocation(col.columnbox, &myAllocation); - } - } -} - -pub fn update_column_ui(column: *Column) void { - const label = builder_get_widget(column.builder, "column_top_label"); - //var topline_null: []u8 = undefined; - const title_null = util.sliceAddNull(allocator, column.main.makeTitle()); - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(label)), title_null.ptr); -} - -pub fn column_remove_schedule(in: ?*anyopaque) callconv(.C) c_int { - column_remove(@as(*config.ColumnInfo, @ptrCast(@alignCast(8, in)))); - return 0; -} - -pub fn column_remove(colInfo: *config.ColumnInfo) void { - warn("gui.column_remove {s}\n", .{colInfo.config.title}); - const container = builder_get_widget(myBuilder, "ZootColumns"); - const column = findColumnByInfo(colInfo); - hide_column_config(column); - c.gtk_container_remove(@as(*c.GtkContainer, @ptrCast(container)), column.columnbox); -} - -//pub const GCallback = ?extern fn() void; -fn column_top_label_title(p: *anyopaque) callconv(.C) void { - warn("column_top_label_title {}\n", .{p}); -} - -pub fn update_column_toots_schedule(in: ?*anyopaque) callconv(.C) c_int { - const c_column = @as(*config.ColumnInfo, @ptrCast(@alignCast(8, in))); - var columnMaybe = find_gui_column(c_column); - if (columnMaybe) |column| { - update_column_toots(column); - } - return 0; -} - -pub fn update_column_config_oauth_finalize_schedule(in: ?*anyopaque) callconv(.C) c_int { - const c_column = @as(*config.ColumnInfo, @ptrCast(@alignCast(8, in))); - var columnMaybe = find_gui_column(c_column); - if (columnMaybe) |column| { - column_config_oauth_finalize(column); - } - return 0; -} - -pub fn update_column_netstatus_schedule(in: ?*anyopaque) callconv(.C) c_int { - const http = @as(*config.HttpInfo, @ptrCast(@alignCast(8, in))); - var columnMaybe = find_gui_column(http.column); - if (columnMaybe) |column| { - update_netstatus_column(http, column); - } - return 0; -} - -fn find_gui_column(c_column: *config.ColumnInfo) ?*Column { - //var column: *Column = undefined; - for (columns.items) |col| { - if (col.main == c_column) return col; - } - return null; -} - -pub fn update_column_toots(column: *Column) void { - warn("update_column {s} {} toots {s}\n", .{ - column.main.config.title, - column.main.toots.count(), - if (column.main.inError) @as([]const u8, "ERROR") else @as([]const u8, ""), - }); - const column_toot_zone = builder_get_widget(column.builder, "toot_zone"); - var current = column.main.toots.first(); - var idx: c_int = 0; - if (current != null) { - while (current) |node| { - const toot = node.data; - var tootbuilderMaybe = column.guitoots.get(toot.id()); - if (column.main.filter.match(toot)) { - if (tootbuilderMaybe) |kv| { - const builder = kv; - destroyTootBox(builder); - warn("update_column_toots destroyTootBox toot #{s} {*} {*}\n", .{ toot.id(), toot, builder }); - } - const tootbuilder = makeTootBox(toot, column); - var tootbox = builder_get_widget(tootbuilder, "tootbox"); - _ = column.guitoots.put(toot.id(), tootbuilder) catch unreachable; - c.gtk_box_pack_start(@as(*c.GtkBox, @ptrCast(column_toot_zone)), tootbox, c.gtk_true(), c.gtk_true(), 0); - c.gtk_box_reorder_child(@as(*c.GtkBox, @ptrCast(column_toot_zone)), tootbox, idx); - } else { - if (tootbuilderMaybe) |kv| { - const builder = kv; - var tootbox = builder_get_widget(builder, "tootbox"); - c.gtk_widget_hide(tootbox); - warn("update_column_toots hide toot #{s} {*} {*}\n", .{ toot.id(), toot, builder }); - } - } - - current = node.next; - idx += 1; - } - } else { - // help? logo? - } - const column_footer_count_label = builder_get_widget(column.builder, "column_footer_count"); - const tootword = if (column.main.config.img_only) "images" else "toots"; - const countStr = std.fmt.allocPrint(allocator, "{} {s}", .{ column.main.toots.count(), tootword }) catch unreachable; - const cCountStr = util.sliceToCstr(allocator, countStr); - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_count_label)), cCountStr); -} - -pub fn update_netstatus_column(http: *config.HttpInfo, column: *Column) void { - warn("update_netstatus_column {s} {}\n", .{ http.url, http.response_code }); - const column_footer_netstatus = builder_get_widget(column.builder, "column_footer_netstatus"); - var gtk_context_netstatus = c.gtk_widget_get_style_context(column_footer_netstatus); - //var netmsg: *const u8 = undefined; - if (http.response_code == 0) { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "GET"); - c.gtk_style_context_add_class(gtk_context_netstatus, "net_active"); - } else if (http.response_code >= 200 and http.response_code < 300) { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "OK"); - c.gtk_style_context_remove_class(gtk_context_netstatus, "net_active"); - } else if (http.response_code >= 300 and http.response_code < 400) { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "redirect"); - } else if (http.response_code >= 400 and http.response_code < 500) { - if (http.response_code == 401) { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "token bad"); - } else if (http.response_code == 404) { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "404 err"); - } else { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "4xx err"); - } - } else if (http.response_code >= 500 and http.response_code < 600) { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "5xx err"); - } else if (http.response_code >= 1000 and http.response_code < 1100) { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "json err"); - } else if (http.response_code == 2100) { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "DNS err"); - } else if (http.response_code == 2200) { - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(column_footer_netstatus)), "timeout err"); - } - if (column.main.inError) { - c.gtk_style_context_add_class(gtk_context_netstatus, "net_error"); - } else { - c.gtk_style_context_remove_class(gtk_context_netstatus, "net_error"); - } -} - -fn widget_destroy(widget: *c.GtkWidget, userdata: ?*anyopaque) callconv(.C) void { - //warn("destroying {*}\n", widget); - _ = userdata; - c.gtk_widget_destroy(widget); -} - -pub fn destroyTootBox(builder: *c.GtkBuilder) void { - const tootbox = builder_get_widget(builder, "tootbox"); - c.gtk_widget_destroy(tootbox); - c.g_object_unref(builder); -} - -pub fn makeTootBox(toot: *toot_lib.Type, column: *Column) *c.GtkBuilder { - warn("maketootbox toot #{s} {*} gui building {} images\n", .{ toot.id(), toot, toot.imgList.items.len }); - const builder = c.gtk_builder_new_from_file("glade/toot.glade"); - //const tootbox = builder_get_widget(builder, "tootbox"); - - //const id = toot.get("id").?.String; - const account = toot.get("account").?.Object; - const author_acct = account.get("acct").?.String; - - const author_name = account.get("display_name").?.String; - const author_url = account.get("url").?.String; - const created_at = toot.get("created_at").?.String; - - const name_label = builder_get_widget(builder, "toot_author_name"); - labelBufPrint(name_label, "{s}", .{author_name}); - const url_label = builder_get_widget(builder, "toot_author_url"); - labelBufPrint(url_label, "{s}", .{author_url}); - const author_url_minimode_label = builder_get_widget(builder, "toot_author_url_minimode"); - labelBufPrint(author_url_minimode_label, "{s}", .{author_url}); - const date_label = builder_get_widget(builder, "toot_date"); - labelBufPrint(date_label, "{s}", .{created_at}); - photo_refresh(author_acct, builder); - - var hDecode = util.htmlEntityDecode(toot.content(), allocator) catch unreachable; - const html_trim = util.htmlTagStrip(hDecode, allocator) catch unreachable; - //var line_limit = 50 / columns.items.len; - //const html_wrapped = hardWrap(html_trim, line_limit) catch unreachable; - var cText = util.sliceToCstr(allocator, html_trim); - - const toottext_label = builder_get_widget(builder, "toot_text"); - c.gtk_label_set_line_wrap_mode(@as(*c.GtkLabel, @ptrCast(toottext_label)), c.PANGO_WRAP_WORD_CHAR); - c.gtk_label_set_line_wrap(@as(*c.GtkLabel, @ptrCast(toottext_label)), 1); - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(toottext_label)), cText); - - const tagBox = builder_get_widget(builder, "tag_flowbox"); - //var tagidx: usize = 0; - for (toot.tagList.items) |tag| { - const cTag = util.sliceToCstr(allocator, tag); - const tagLabel = c.gtk_label_new(cTag); - const labelContext = c.gtk_widget_get_style_context(tagLabel); - c.gtk_style_context_add_class(labelContext, "toot_tag"); - c.gtk_container_add(@as(*c.GtkContainer, @ptrCast(tagBox)), tagLabel); - c.gtk_widget_show(tagLabel); - } - - // show/hide parts to put widget into full or imgonly display - const id_row = builder_get_widget(builder, "toot_id_row"); - const toot_separator = builder_get_widget(builder, "toot_separator"); - if (column.main.config.img_only) { - c.gtk_widget_hide(toottext_label); - c.gtk_widget_hide(id_row); - if (toot.imgCount() == 0) { - c.gtk_widget_hide(date_label); - c.gtk_widget_hide(toot_separator); - } else { - c.gtk_widget_show(author_url_minimode_label); - c.gtk_widget_show(date_label); - } - } - - for (toot.imgList.items) |imgdata| { - warn("toot #{s} rebuilding with img\n", .{toot.id()}); - toot_media(column, builder, toot, imgdata); - } - - return builder; -} - -fn photo_refresh(acct: []const u8, builder: *c.GtkBuilder) void { - const avatar = builder_get_widget(builder, "toot_author_avatar"); - const avatar_path = std.fmt.allocPrint(allocator, "./cache/{s}/photo", .{acct}) catch unreachable; - var pixbuf = c.gdk_pixbuf_new_from_file_at_scale(util.sliceToCstr(allocator, avatar_path), 50, -1, 1, null); - c.gtk_image_set_from_pixbuf(@as(*c.GtkImage, @ptrCast(avatar)), pixbuf); -} - -fn toot_media(column: *Column, builder: *c.GtkBuilder, toot: *toot_lib.Type, pic: []const u8) void { - const tootBox = builder_get_widget(builder, "tootbox"); - const imageBox = builder_get_widget(builder, "image_box"); - c.gtk_widget_get_allocation(column.columnbox, &myAllocation); - var loader = c.gdk_pixbuf_loader_new(); - // todo: size-prepared signal - var colWidth = @as(c_int, @intFromFloat(@as(f32, @floatFromInt(myAllocation.width)) / @as(f32, @floatFromInt(columns.items.len)) * 0.9)); - var colHeight: c_int = -1; // seems to work - const colWidth_ptr = allocator.create(c_int) catch unreachable; - colWidth_ptr.* = colWidth; - _ = g_signal_connect(loader, "size-prepared", pixloaderSizePrepared, colWidth_ptr); - const loadYN = c.gdk_pixbuf_loader_write(loader, pic.ptr, pic.len, null); - if (loadYN == c.gtk_true()) { - var pixbuf = c.gdk_pixbuf_loader_get_pixbuf(loader); - //const account = toot.get("account").?.Object; - //const acct = account.get("acct").?.String; - var pixbufWidth = c.gdk_pixbuf_get_width(pixbuf); - warn("toot_media #{s} {*} {*} {} images. win {}x{} col {}x{}px pixbuf {}px\n", .{ - toot.id(), - toot, - tootBox, - toot.imgCount(), - myAllocation.width, - myAllocation.height, - colWidth, - colHeight, - pixbufWidth, - }); - _ = c.gdk_pixbuf_loader_close(loader, null); - if (pixbuf != null) { - var new_img = c.gtk_image_new_from_pixbuf(pixbuf); - c.gtk_box_pack_start(@as(*c.GtkBox, @ptrCast(imageBox)), new_img, c.gtk_false(), c.gtk_false(), 0); - c.gtk_widget_show(new_img); - } else { - warn("toot_media img from pixbuf FAILED\n", .{}); - } - } else { - warn("pixbuf load FAILED of {} bytes\n", .{pic.len}); - } -} - -fn pixloaderSizePrepared(loader: *c.GdkPixbufLoader, img_width: c.gint, img_height: c.gint, data_ptr: *anyopaque) void { - const colWidth = @as(*c_int, @ptrCast(@alignCast(4, data_ptr))).*; - var scaleWidth = img_width; - var scaleHeight = img_height; - if (img_width > colWidth) { - scaleWidth = colWidth; - //const scale_factor = @divFloor(img_width, colWidth); - const scale_factor = @as(f32, @floatFromInt(colWidth)) / @as(f32, @floatFromInt(img_width)); - scaleHeight = @as(c_int, @intFromFloat(@as(f32, @floatFromInt(img_height)) * scale_factor)); - } - warn("toot_media pixloaderSizePrepared col {}px img {}x{} scale {}x{}\n", .{ colWidth, img_width, img_height, scaleWidth, scaleHeight }); - c.gdk_pixbuf_loader_set_size(loader, scaleWidth, scaleHeight); -} - -fn hardWrap(str: []const u8, limit: usize) ![]const u8 { - var wrapped = try simple_buffer.SimpleU8.initSize(allocator, 0); - var short_lines = str.len / limit; - var extra_bytes = str.len % limit; - var idx: usize = 0; - while (idx < short_lines) : (idx += 1) { - try wrapped.append(str[limit * idx .. limit * (idx + 1)]); - try wrapped.append("\n"); - } - try wrapped.append(str[limit * idx .. (limit * idx) + extra_bytes]); - return wrapped.toSliceConst(); -} - -fn escapeGtkString(str: []const u8) []const u8 { - const str_esc_null = c.g_markup_escape_text(str.ptr, @as(c_long, @intCast(str.len))); - const str_esc = util.cstrToSlice(allocator, str_esc_null); - return str_esc; -} - -pub fn labelBufPrint(label: *c.GtkWidget, comptime fmt: []const u8, args: anytype) void { - const buf = allocator.alloc(u8, 256) catch unreachable; - const str = std.fmt.bufPrint(buf, fmt, args) catch unreachable; - const cStr = util.sliceToCstr(allocator, str); - c.gtk_label_set_text(@as(*c.GtkLabel, @ptrCast(label)), cStr); -} - -fn column_config_btn(columnptr: ?*anyopaque) callconv(.C) void { - var columnbox = @as(*c.GtkWidget, @ptrCast(@alignCast(8, columnptr))); - var column: *Column = findColumnByBox(columnbox); - - columnConfigWriteGui(column); - - c.gtk_widget_show(column.config_window); -} - -fn findColumnByTootId(toot_id: []const u8) ?*Column { - for (columns.items) |column| { - var kvMaybe = column.guitoots.get(toot_id); - if (kvMaybe) |_| { - return column; - } - } - return null; -} - -fn findColumnByInfo(info: *config.ColumnInfo) *Column { - for (columns.items) |col| { - if (col.main == info) { - return col; - } - } - unreachable; -} - -fn findColumnByBox(box: *c.GtkWidget) *Column { - for (columns.items) |col| { - if (col.columnbox == box) { - return col; - } - } - unreachable; -} - -fn findColumnByConfigWindow(widget: *c.GtkWidget) *Column { - const parent = c.gtk_widget_get_toplevel(widget); - for (columns.items) |col| { - if (col.config_window == parent) { - return col; - } - } - warn("Config window not found for widget {*} parent {*}\n", .{ widget, parent }); - unreachable; -} - -fn main_check_resize(selfptr: *anyopaque) callconv(.C) void { - var self = @as(*c.GtkWidget, @ptrCast(@alignCast(8, selfptr))); - var h: c.gint = undefined; - var w: c.gint = undefined; - c.gtk_window_get_size(@as(*c.GtkWindow, @ptrCast(self)), &w, &h); - if (w != settings.win_x) { - warn("main_check_resize() win_x {} != gtk_width {}\n", .{ settings.win_x, w }); - settings.win_x = w; - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.idle = undefined; - var command = allocator.create(thread.Command) catch unreachable; - command.id = 10; - command.verb = verb; - warn("main_check_resize() verb {*}\n", .{verb}); - thread.signal(myActor, command); - } - if (h != settings.win_y) { - warn("main_check_resize, win_y {} != gtk_height {}\n", .{ settings.win_x, w }); - settings.win_y = h; - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.idle = undefined; - var command = allocator.create(thread.Command) catch unreachable; - command.id = 10; - command.verb = verb; - thread.signal(myActor, command); - } -} - -fn actionbar_add() callconv(.C) void { - warn("actionbar_add()\n", .{}); - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.idle = undefined; - thread.signal(myActor, &thread.Command{ .actor = myActor, .id = 3, .verb = verb }); -} - -fn zoot_drag() callconv(.C) void { - warn("zoot_drag\n", .{}); -} - -// rebulid half of GdkEventKey, avoiding bitfield -const EventKey = packed struct { - _type: i32, - window: *c.GtkWindow, - send_event: i8, - time: u32, - state: u32, - keyval: u32, -}; - -fn zoot_keypress(widgetptr: *anyopaque, evtptr: *EventKey) callconv(.C) void { - _ = widgetptr; - warn("zoot_keypress {}\n", .{evtptr}); -} - -fn column_reload(columnptr: *anyopaque) callconv(.C) void { - var column_widget = @as(*c.GtkWidget, @ptrCast(@alignCast(8, columnptr))); - var column: *Column = findColumnByBox(column_widget); - warn("column reload found {s}\n", .{column.main.config.title}); - - // signal crazy - var command = allocator.create(thread.Command) catch unreachable; - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.column = column.main; - command.id = 2; - command.verb = verb; - thread.signal(myActor, command); -} - -fn column_imgonly(columnptr: *anyopaque) callconv(.C) void { - var column_widget = @as(*c.GtkWidget, @ptrCast(@alignCast(8, columnptr))); - var column: *Column = findColumnByBox(column_widget); - - // signal crazy - var command = allocator.create(thread.Command) catch unreachable; - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.column = column.main; - command.id = 9; //imgonly button press - command.verb = verb; - thread.signal(myActor, command); -} - -fn column_remove_btn(selfptr: *anyopaque) callconv(.C) void { - var self = @as(*c.GtkWidget, @ptrCast(@alignCast(8, selfptr))); - var column: *Column = findColumnByConfigWindow(self); - - // signal crazy - var command = allocator.create(thread.Command) catch unreachable; - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.column = column.main; - command.id = 5; // col remove button press - command.verb = verb; - thread.signal(myActor, command); -} - -fn column_config_oauth_btn(selfptr: *anyopaque) callconv(.C) void { - var self = @as(*c.GtkWidget, @ptrCast(@alignCast(8, selfptr))); - var column: *Column = findColumnByConfigWindow(self); - - var oauth_box = builder_get_widget(column.builder, "column_config_oauth_box"); - var host_box = builder_get_widget(column.builder, "column_config_host_box"); - c.gtk_box_pack_end(@as(*c.GtkBox, @ptrCast(host_box)), oauth_box, 1, 0, 0); - var oauth_label = builder_get_widget(column.builder, "column_config_oauth_label"); - c.gtk_label_set_markup(@as(*c.GtkLabel, @ptrCast(oauth_label)), "contacting server..."); - - columnConfigReadGui(column); - column.main.filter = filter_lib.parse(allocator, column.main.config.filter); - - // signal crazy - var command = allocator.create(thread.Command) catch unreachable; - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.column = column.main; - command.id = 6; - command.verb = verb; - warn("column_config_oauth_btn cmd vrb {*}\n", .{command.verb.column}); - thread.signal(myActor, command); -} - -pub fn column_config_oauth_url(colInfo: *config.ColumnInfo) void { - warn("gui.column_config_oauth_url {s}\n", .{colInfo.config.title}); - //const container = builder_get_widget(myBuilder, "ZootColumns"); - const column = findColumnByInfo(colInfo); - - //var oauth_box = builder_get_widget(column.builder, "column_config_oauth_box"); - - var oauth_label = builder_get_widget(column.builder, "column_config_oauth_label"); - var oauth_url_buf = simple_buffer.SimpleU8.initSize(allocator, 0) catch unreachable; - oauth_url_buf.append("https://") catch unreachable; - oauth_url_buf.append(column.main.filter.host()) catch unreachable; - oauth_url_buf.append("/oauth/authorize") catch unreachable; - oauth_url_buf.append("?client_id=") catch unreachable; - oauth_url_buf.append(column.main.oauthClientId.?) catch unreachable; - oauth_url_buf.append("&scope=read+write") catch unreachable; - oauth_url_buf.append("&response_type=code") catch unreachable; - oauth_url_buf.append("&redirect_uri=urn:ietf:wg:oauth:2.0:oob") catch unreachable; - var markupBuf = allocator.alloc(u8, 512) catch unreachable; - var markup = std.fmt.bufPrint(markupBuf, "{s} oauth", .{ oauth_url_buf.toSliceConst(), column.main.filter.host() }) catch unreachable; - var cLabel = util.sliceToCstr(allocator, markup); - c.gtk_label_set_markup(@as(*c.GtkLabel, @ptrCast(oauth_label)), cLabel); -} - -fn column_config_oauth_activate(selfptr: *anyopaque) callconv(.C) void { - var self = @as(*c.GtkWidget, @ptrCast(@alignCast(8, selfptr))); - var column: *Column = findColumnByConfigWindow(self); - - var token_entry = builder_get_widget(column.builder, "column_config_authorization_entry"); - const cAuthorization = c.gtk_entry_get_text(@as(*c.GtkEntry, @ptrCast(token_entry))); - const authorization = util.cstrToSliceCopy(allocator, cAuthorization); - - // signal crazy - var command = allocator.create(thread.Command) catch unreachable; - var verb = allocator.create(thread.CommandVerb) catch unreachable; - var auth = allocator.create(config.ColumnAuth) catch unreachable; - auth.code = authorization; - auth.column = column.main; - verb.auth = auth; - command.id = 7; - command.verb = verb; - thread.signal(myActor, command); -} - -pub fn column_config_oauth_finalize(column: *Column) void { - var oauth_box = builder_get_widget(column.builder, "column_config_oauth_box"); - var host_box = builder_get_widget(column.builder, "column_config_host_box"); - c.gtk_container_remove(@as(*c.GtkContainer, @ptrCast(host_box)), oauth_box); - columnConfigWriteGui(column); - update_column_ui(column); -} - -pub fn columnConfigWriteGui(column: *Column) void { - var url_entry = builder_get_widget(column.builder, "column_config_url_entry"); - var cUrl = util.sliceToCstr(allocator, column.main.filter.host()); - c.gtk_entry_set_text(@as(*c.GtkEntry, @ptrCast(url_entry)), cUrl); - - var token_image = builder_get_widget(column.builder, "column_config_token_image"); - var icon_name: []const u8 = undefined; - if (column.main.config.token) |_| { - icon_name = "gtk-apply"; - } else { - icon_name = "gtk-close"; - } - c.gtk_image_set_from_icon_name(@as(*c.GtkImage, @ptrCast(token_image)), util.sliceToCstr(allocator, icon_name), c.GTK_ICON_SIZE_BUTTON); -} - -pub fn columnReadFilter(column: *Column) []const u8 { - var filter_entry = builder_get_widget(column.builder, "column_filter"); - var cFilter = c.gtk_entry_get_text(@as(*c.GtkEntry, @ptrCast(filter_entry))); - const filter = util.cstrToSliceCopy(allocator, cFilter); // edit in guithread-- - warn("columnReadFilter: {s} {}\n", .{ filter, filter.len }); - return filter; -} - -pub fn columnConfigReadGui(column: *Column) void { - var url_entry = builder_get_widget(column.builder, "column_config_url_entry"); - var cUrl = c.gtk_entry_get_text(@as(*c.GtkEntry, @ptrCast(url_entry))); - const newFilter = util.cstrToSliceCopy(allocator, cUrl); // edit in guithread-- - column.main.filter = filter_lib.parse(allocator, newFilter); -} - -fn column_filter_done(selfptr: *anyopaque) callconv(.C) void { - var self = @as(*c.GtkWidget, @ptrCast(@alignCast(8, selfptr))); - var column: *Column = findColumnByBox(self); - - column.main.config.filter = columnReadFilter(column); - column.main.filter = filter_lib.parse(allocator, column.main.config.filter); - update_column_ui(column); - - // signal crazy - var command = allocator.create(thread.Command) catch unreachable; - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.column = column.main; - command.id = 4; // save config - command.verb = verb; - thread.signal(myActor, command); - - // signal crazy - command = allocator.create(thread.Command) catch unreachable; - verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.column = column.main; - command.id = 8; // update column UI - command.verb = verb; - thread.signal(myActor, command); -} - -fn column_config_done(selfptr: *anyopaque) callconv(.C) void { - var self = @as(*c.GtkWidget, @ptrCast(@alignCast(8, selfptr))); - var column: *Column = findColumnByConfigWindow(self); - - columnConfigReadGui(column); - column.main.filter = filter_lib.parse(allocator, column.main.config.filter); - hide_column_config(column); - - // signal crazy - var command = allocator.create(thread.Command) catch unreachable; - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.column = column.main; - command.id = 4; // save config - command.verb = verb; - thread.signal(myActor, command); - // signal crazy - command = allocator.create(thread.Command) catch unreachable; - verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.column = column.main; - command.id = 8; // update column UI - command.verb = verb; - thread.signal(myActor, command); -} - -fn g_signal_connect(instance: anytype, signal_name: []const u8, callback: anytype, data: anytype) c.gulong { - // pub extern fn g_signal_connect_data(instance: gpointer, - // detailed_signal: [*]const gchar, - // c_handler: GCallback, - // data: gpointer, - // destroy_data: GClosureNotify, - // connect_flags: GConnectFlags) gulong; - // connect_flags: GConnectFlags) gulong; - // typedef void* gpointer; - var signal_name_null: []u8 = util.sliceAddNull(allocator, signal_name) catch unreachable; - var data_ptr: ?*anyopaque = undefined; - if (@sizeOf(@TypeOf(data)) != 0) { - data_ptr = @as(?*anyopaque, @ptrCast(data)); - } else { - data_ptr = null; - } - var thing = @as(c.gpointer, @ptrCast(instance)); - return c.g_signal_connect_data(thing, signal_name_null.ptr, @as(c.GCallback, @ptrCast(callback)), data_ptr, null, c.G_CONNECT_AFTER); -} - -pub fn mainloop() bool { - var stop = false; - //warn("gtk pending {}\n", .{c.gtk_events_pending()}); - //warn("gtk main level {}\n", .{c.gtk_main_level()}); - var exitcode = c.gtk_main_iteration(); - //warn("gtk main interaction return {}\n", .{exitcode}); - //if(c.gtk_events_pending() != 0) { - if (exitcode == 0) { - stop = true; - } - return stop; -} - -pub fn gtk_quit() callconv(.C) void { - warn("gtk signal destroy called.\n", .{}); - c.g_object_unref(myBuilder); - var verb = allocator.create(thread.CommandVerb) catch unreachable; - verb.idle = undefined; - var command = allocator.create(thread.Command) catch unreachable; - command.id = 11; - command.verb = verb; - thread.signal(myActor, command); -} - -pub fn gui_end() void { - warn("gui ended\n", .{}); -} diff --git a/src/ipc/nng.zig b/src/ipc/nng.zig index 50c9fed..dc6f510 100644 --- a/src/ipc/nng.zig +++ b/src/ipc/nng.zig @@ -53,8 +53,6 @@ pub fn dial(socket: *sock, url: []u8) void { pub fn newClient(allocator: *Allocator) *Client { const client = allocator.create(Client) catch unreachable; var url_buf: [256]u8 = undefined; - const myUrl = std.fmt.bufPrint(url_buf[0..], "{}{*}", Url, client) catch unreachable; - warn("newClient {}\n", myUrl); const socket = allocator.create(sock) catch unreachable; client.srv = socket; var nng_ret = c.nng_pair0_open(client.srv); diff --git a/src/main.zig b/src/main.zig index b11f731..d76dd81 100644 --- a/src/main.zig +++ b/src/main.zig @@ -235,16 +235,16 @@ fn netback(command: *thread.Command) void { const item = jsonValue.Object; const toot = alloc.create(toot_lib.Type) catch unreachable; toot.* = toot_lib.Type.init(item, alloc); - var id = toot.id(); + const id = toot.id(); warn("netback json create toot #{s} {*}\n", .{ id, toot }); if (column.toots.contains(toot)) { // dupe } else { - var images = toot.get("media_attachments").?.Array; + const images = toot.get("media_attachments").?.Array; column.toots.sortedInsert(toot, alloc); - var html = toot.get("content").?.String; + const html = toot.get("content").?.String; //var html = json_lib.jsonStrDecode(jstr, allocator) catch unreachable; - var root = html_lib.parse(html); + const root = html_lib.parse(html); html_lib.search(root); cache_update(toot, alloc); @@ -341,7 +341,7 @@ fn guiback(command: *thread.Command) void { colInfo.toots = toot_list.TootList.init(); colInfo.last_check = 0; settings.columns.append(colInfo) catch unreachable; - var colConfig = alloc.create(config.ColumnConfig) catch unreachable; + const colConfig = alloc.create(config.ColumnConfig) catch unreachable; colInfo.config = colConfig; colInfo.config.title = ""[0..]; colInfo.config.filter = "mastodon.example.com"[0..]; @@ -415,7 +415,7 @@ fn heartback(command: *thread.Command) void { fn columns_net_freshen(allocator: std.mem.Allocator) void { for (settings.columns.items) |column| { - var now = config.now(); + const now = config.now(); const refresh = 60; const since = now - column.last_check; if (since > refresh) { diff --git a/src/net.zig b/src/net.zig index 64c6ef1..ba66df6 100644 --- a/src/net.zig +++ b/src/net.zig @@ -69,10 +69,6 @@ pub fn httpget(req: *config.HttpInfo) ![]const u8 { slist = c.curl_slist_append(slist, "Accept: application/json"); if (req.token) |token| { warn("Authorization: {s}\n", .{token}); - var authbuf = allocator.alloc(u8, 256) catch unreachable; - var authstr = std.fmt.bufPrint(authbuf, "Authorization: bearer {s}", .{token}) catch unreachable; - var cauthstr = util.sliceToCstr(allocator, authstr); - slist = c.curl_slist_append(slist, cauthstr); } _ = c.curl_easy_setopt(curl, c.CURLOPT_HTTPHEADER, slist); diff --git a/src/util.zig b/src/util.zig index 2d2450f..bc70aca 100644 --- a/src/util.zig +++ b/src/util.zig @@ -32,14 +32,12 @@ pub fn log(comptime msg: []const u8, args: anytype) void { //const tz = std.os.timezone.tz_minuteswest; var tz = std.os.timezone{ .tz_minuteswest = 0, .tz_dsttime = 0 }; std.os.gettimeofday(null, &tz); // does not set tz - const now_ms = std.time.milliTimestamp() + tz.tz_minuteswest * std.time.ms_per_hour; - const esec = std.time.epoch.EpochSeconds{ .secs = @as(u64, @intCast(@divTrunc(now_ms, std.time.ms_per_s))) }; - const eday = esec.getEpochDay(); - const yday = eday.calculateYearDay(); - const mday = yday.calculateMonthDay(); - const dsec = esec.getDaySeconds(); - const time_str = std.fmt.allocPrint(alloc, "{d}-{d:0>2}-{d:0>2} {d:0>2}:{d:0>2}:{d:0>2}", .{ yday.year, mday.month.numeric(), mday.day_index + 1, dsec.getHoursIntoDay(), dsec.getMinutesIntoHour(), dsec.getSecondsIntoMinute() }); - std.debug.print("{s}[tid#{d}/{s:9}] " ++ msg ++ "\n", .{ time_str, tid, tid_name } ++ args); + const time_str = "Z"; //std.fmt.allocPrint(alloc, "{d}-{d:0>2}-{d:0>2} {d:0>2}:{d:0>2}:{d:0>2}", .{ yday.year, mday.month.numeric(), mday.day_index + 1, dsec.getHoursIntoDay(), dsec.getMinutesIntoHour(), dsec.getSecondsIntoMinute() }) catch unreachable; + _ = time_str; + _ = tid_name; + _ = msg; + _ = args; + //std.debug.print("{s}[tid#{d}/{s:9}] " ++ msg ++ "\n", .{ time_str, tid, tid_name } ++ args); } pub fn hashIdSame(comptime T: type, a: T, b: T) bool {