From b631745273931d288b3a63ad8a4be508dcadca90 Mon Sep 17 00:00:00 2001 From: Maciej Bartczak <39600846+maciekbartczak@users.noreply.github.com> Date: Thu, 2 Jan 2025 12:51:42 +0100 Subject: [PATCH] GTK: implement banner informing about existing crash reports --- src/apprt/gtk/Window.zig | 86 ++++++++++++++++++++++++++++++++++++++++ src/apprt/gtk/style.css | 4 ++ src/crash/dir.zig | 2 +- 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/apprt/gtk/Window.zig b/src/apprt/gtk/Window.zig index 63ee57d95..f30c5cc3a 100644 --- a/src/apprt/gtk/Window.zig +++ b/src/apprt/gtk/Window.zig @@ -14,6 +14,7 @@ const configpkg = @import("../../config.zig"); const font = @import("../../font/main.zig"); const input = @import("../../input.zig"); const CoreSurface = @import("../../Surface.zig"); +const crash = @import("../../crash/main.zig"); const App = @import("App.zig"); const Color = configpkg.Config.Color; @@ -248,9 +249,94 @@ pub fn init(self: *Window, app: *App) !void { } c.gtk_widget_add_css_class(@ptrCast(gtk_window), "devel"); c.gtk_widget_add_css_class(@ptrCast(warning_box), "background"); + c.gtk_widget_add_css_class(@ptrCast(warning_box), "banner-box"); c.gtk_box_append(@ptrCast(box), warning_box); } + // Display a banner informing about crash reports if any exist + { + var crash_dir = try crash.defaultDir(self.app.core_app.alloc); + defer self.app.core_app.alloc.free(crash_dir.path); + var it = try crash_dir.iterator(); + defer it.deinit(); + + if (try it.next()) |_| { + const warning_text = try std.fmt.allocPrintZ( + self.app.core_app.alloc, + \\ There are existing crash reports located at {s}. + \\ If possible, report them to the developers to help improve the application. + , + .{crash_dir.path, crash_dir.path} + ); + defer self.app.core_app.alloc.free(warning_text); + const warning_box = c.gtk_box_new(c.GTK_ORIENTATION_VERTICAL, 0); + + if ((comptime adwaita.versionAtLeast(1, 3, 0)) and + adwaita.enabled(&app.config) and + adwaita.versionAtLeast(1, 3, 0)) + { + const banner = c.adw_banner_new(warning_text.ptr); + c.adw_banner_set_revealed(@ptrCast(banner), 1); + c.adw_banner_set_use_markup(@ptrCast(banner), 1); + + c.adw_banner_set_button_label(@ptrCast(banner), "Dismiss"); + const close_banner_callback = struct { + fn callback(_: ?*c.GtkWidget, data: ?*anyopaque) callconv(.C) void { + const widget: *c.AdwBanner = @ptrCast(data); + c.adw_banner_set_revealed(widget, c.FALSE); + } + }.callback; + _ = c.g_signal_connect_data( + banner, + "button-clicked", + c.G_CALLBACK(&close_banner_callback), + banner, + null, + c.G_CONNECT_DEFAULT, + ); + + c.gtk_box_append(@ptrCast(warning_box), @ptrCast(banner)); + } else { + const hbox = c.gtk_box_new(c.GTK_ORIENTATION_HORIZONTAL, 5); + c.gtk_widget_set_halign(@ptrCast(hbox), c.GTK_ALIGN_CENTER); + + const message = c.gtk_label_new(null); + c.gtk_label_set_markup(@ptrCast(message), warning_text.ptr); + c.gtk_label_set_use_markup(@ptrCast(message), 1); + c.gtk_widget_set_margin_top(@ptrCast(message), 10); + c.gtk_widget_set_margin_bottom(@ptrCast(message), 10); + + c.gtk_box_append(@ptrCast(hbox), message); + + const close_button = c.gtk_button_new_from_icon_name("window-close-symbolic"); + c.gtk_widget_set_margin_top(@ptrCast(close_button), 10); + c.gtk_widget_set_margin_bottom(@ptrCast(close_button), 10); + + const close_warning_callback = struct { + fn callback(_: ?*c.GtkWidget, data: ?*anyopaque) callconv(.C) void { + const widget: *c.GtkWidget = @ptrCast(@alignCast(data)); + c.gtk_widget_set_visible(widget, c.FALSE); + } + }.callback; + _ = c.g_signal_connect_data( + close_button, + "clicked", + c.G_CALLBACK(&close_warning_callback), + warning_box, + null, + 0 + ); + + c.gtk_box_append(@ptrCast(hbox), close_button); + c.gtk_box_append(@ptrCast(warning_box), @ptrCast(hbox)); + } + + c.gtk_widget_add_css_class(@ptrCast(warning_box), "background"); + c.gtk_widget_add_css_class(@ptrCast(warning_box), "banner-box"); + c.gtk_box_append(@ptrCast(box), warning_box); + } + } + // Setup our toast overlay if we have one self.toast_overlay = if (adwaita.enabled(&self.app.config)) toast: { const toast_overlay = c.adw_toast_overlay_new(); diff --git a/src/apprt/gtk/style.css b/src/apprt/gtk/style.css index bf0ee62f6..37eea515d 100644 --- a/src/apprt/gtk/style.css +++ b/src/apprt/gtk/style.css @@ -45,3 +45,7 @@ window.without-window-decoration-and-with-titlebar { background-color: rgba(250, 250, 250, 1); background-clip: content-box; } + +.banner-box:not(:first-child) { + border-top: 1px solid alpha(@borders, 0.2); +} diff --git a/src/crash/dir.zig b/src/crash/dir.zig index e5a8f8a0c..7a141b1bc 100644 --- a/src/crash/dir.zig +++ b/src/crash/dir.zig @@ -38,7 +38,7 @@ pub const ReportIterator = struct { it: std.fs.Dir.Iterator = undefined, pub fn deinit(self: *ReportIterator) void { - if (self.dir) |dir| dir.close(); + if (self.dir) |*dir| dir.close(); } pub fn next(self: *ReportIterator) !?Report {