mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-19 10:16:12 +03:00
Merge pull request #2163 from jcollie/gtk-desktop-notification-fix
GTK: Fix clicking on desktop notifications
This commit is contained in:
@ -816,6 +816,8 @@ pub fn handleMessage(self: *Surface, msg: Message) !void {
|
||||
.renderer_health => |health| self.updateRendererHealth(health),
|
||||
|
||||
.report_color_scheme => try self.reportColorScheme(),
|
||||
|
||||
.present_surface => try self.presentSurface(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -4158,6 +4160,14 @@ fn crashThreadState(self: *Surface) crash.sentry.ThreadState {
|
||||
};
|
||||
}
|
||||
|
||||
/// Tell the surface to present itself to the user. This may involve raising the
|
||||
/// window and switching tabs.
|
||||
fn presentSurface(self: *Surface) !void {
|
||||
if (@hasDecl(apprt.Surface, "presentSurface")) {
|
||||
self.rt_surface.presentSurface();
|
||||
} else log.warn("runtime doesn't support presentSurface", .{});
|
||||
}
|
||||
|
||||
pub const face_ttf = @embedFile("font/res/JetBrainsMono-Regular.ttf");
|
||||
pub const face_bold_ttf = @embedFile("font/res/JetBrainsMono-Bold.ttf");
|
||||
pub const face_emoji_ttf = @embedFile("font/res/NotoColorEmoji.ttf");
|
||||
|
@ -382,8 +382,8 @@ fn updateConfigErrors(self: *App) !void {
|
||||
|
||||
fn syncActionAccelerators(self: *App) !void {
|
||||
try self.syncActionAccelerator("app.quit", .{ .quit = {} });
|
||||
try self.syncActionAccelerator("app.open_config", .{ .open_config = {} });
|
||||
try self.syncActionAccelerator("app.reload_config", .{ .reload_config = {} });
|
||||
try self.syncActionAccelerator("app.open-config", .{ .open_config = {} });
|
||||
try self.syncActionAccelerator("app.reload-config", .{ .reload_config = {} });
|
||||
try self.syncActionAccelerator("win.toggle_inspector", .{ .inspector = .toggle });
|
||||
try self.syncActionAccelerator("win.close", .{ .close_surface = {} });
|
||||
try self.syncActionAccelerator("win.new_window", .{ .new_window = {} });
|
||||
@ -825,17 +825,58 @@ fn gtkActionQuit(
|
||||
};
|
||||
}
|
||||
|
||||
/// Action sent by the window manager asking us to present a specific surface to
|
||||
/// the user. Usually because the user clicked on a desktop notification.
|
||||
fn gtkActionPresentSurface(
|
||||
_: *c.GSimpleAction,
|
||||
parameter: *c.GVariant,
|
||||
ud: ?*anyopaque,
|
||||
) callconv(.C) void {
|
||||
const self: *App = @ptrCast(@alignCast(ud orelse return));
|
||||
|
||||
// Make sure that we've receiived a u64 from the system.
|
||||
if (c.g_variant_is_of_type(parameter, c.G_VARIANT_TYPE("t")) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert that u64 to pointer to a core surface.
|
||||
const surface: *CoreSurface = @ptrFromInt(c.g_variant_get_uint64(parameter));
|
||||
|
||||
// Send a message through the core app mailbox rather than presenting the
|
||||
// surface directly so that it can validate that the surface pointer is
|
||||
// valid. We could get an invalid pointer if a desktop notification outlives
|
||||
// a Ghostty instance and a new one starts up, or there are multiple Ghostty
|
||||
// instances running.
|
||||
_ = self.core_app.mailbox.push(
|
||||
.{
|
||||
.surface_message = .{
|
||||
.surface = surface,
|
||||
.message = .{ .present_surface = {} },
|
||||
},
|
||||
},
|
||||
.{ .forever = {} },
|
||||
);
|
||||
}
|
||||
|
||||
/// This is called to setup the action map that this application supports.
|
||||
/// This should be called only once on startup.
|
||||
fn initActions(self: *App) void {
|
||||
// The set of actions. Each action has (in order):
|
||||
// [0] The action name
|
||||
// [1] The callback function
|
||||
// [2] The GVariantType of the parameter
|
||||
//
|
||||
// For action names:
|
||||
// https://docs.gtk.org/gio/type_func.Action.name_is_valid.html
|
||||
const actions = .{
|
||||
.{ "quit", >kActionQuit },
|
||||
.{ "open_config", >kActionOpenConfig },
|
||||
.{ "reload_config", >kActionReloadConfig },
|
||||
.{ "quit", >kActionQuit, null },
|
||||
.{ "open-config", >kActionOpenConfig, null },
|
||||
.{ "reload-config", >kActionReloadConfig, null },
|
||||
.{ "present-surface", >kActionPresentSurface, c.G_VARIANT_TYPE("t") },
|
||||
};
|
||||
|
||||
inline for (actions) |entry| {
|
||||
const action = c.g_simple_action_new(entry[0], null);
|
||||
const action = c.g_simple_action_new(entry[0], entry[2]);
|
||||
defer c.g_object_unref(action);
|
||||
_ = c.g_signal_connect_data(
|
||||
action,
|
||||
@ -871,8 +912,8 @@ fn initMenu(self: *App) void {
|
||||
defer c.g_object_unref(section);
|
||||
c.g_menu_append_section(menu, null, @ptrCast(@alignCast(section)));
|
||||
c.g_menu_append(section, "Terminal Inspector", "win.toggle_inspector");
|
||||
c.g_menu_append(section, "Open Configuration", "app.open_config");
|
||||
c.g_menu_append(section, "Reload Configuration", "app.reload_config");
|
||||
c.g_menu_append(section, "Open Configuration", "app.open-config");
|
||||
c.g_menu_append(section, "Reload Configuration", "app.reload-config");
|
||||
c.g_menu_append(section, "About Ghostty", "win.about");
|
||||
}
|
||||
|
||||
|
@ -1144,19 +1144,26 @@ pub fn showDesktopNotification(
|
||||
else => title,
|
||||
};
|
||||
|
||||
const notif = c.g_notification_new(t.ptr);
|
||||
defer c.g_object_unref(notif);
|
||||
c.g_notification_set_body(notif, body.ptr);
|
||||
const notification = c.g_notification_new(t.ptr);
|
||||
defer c.g_object_unref(notification);
|
||||
c.g_notification_set_body(notification, body.ptr);
|
||||
|
||||
const icon = c.g_themed_icon_new("com.mitchellh.ghostty");
|
||||
defer c.g_object_unref(icon);
|
||||
c.g_notification_set_icon(notif, icon);
|
||||
c.g_notification_set_icon(notification, icon);
|
||||
|
||||
const pointer = c.g_variant_new_uint64(@intFromPtr(&self.core_surface));
|
||||
c.g_notification_set_default_action_and_target_value(
|
||||
notification,
|
||||
"app.present-surface",
|
||||
pointer,
|
||||
);
|
||||
|
||||
const g_app: *c.GApplication = @ptrCast(self.app.app);
|
||||
|
||||
// We set the notification ID to the body content. If the content is the
|
||||
// same, this notification may replace a previous notification
|
||||
c.g_application_send_notification(g_app, body.ptr, notif);
|
||||
c.g_application_send_notification(g_app, body.ptr, notification);
|
||||
}
|
||||
|
||||
fn showContextMenu(self: *Surface, x: f32, y: f32) void {
|
||||
@ -1967,3 +1974,14 @@ fn translateMods(state: c.GdkModifierType) input.Mods {
|
||||
if (state & c.GDK_LOCK_MASK != 0) mods.caps_lock = true;
|
||||
return mods;
|
||||
}
|
||||
|
||||
pub fn presentSurface(self: *Surface) void {
|
||||
if (self.container.window()) |window| {
|
||||
if (self.container.tab()) |tab| {
|
||||
if (window.notebook.getTabPosition(tab)) |position|
|
||||
window.notebook.gotoNthTab(position);
|
||||
}
|
||||
c.gtk_window_present(window.window);
|
||||
}
|
||||
self.grabFocus();
|
||||
}
|
||||
|
@ -61,6 +61,10 @@ pub const Message = union(enum) {
|
||||
/// Report the color scheme
|
||||
report_color_scheme: void,
|
||||
|
||||
/// Tell the surface to present itself to the user. This may require raising
|
||||
/// a window and switching tabs.
|
||||
present_surface: void,
|
||||
|
||||
pub const ReportTitleStyle = enum {
|
||||
csi_21_t,
|
||||
|
||||
|
Reference in New Issue
Block a user