Merge pull request #1512 from mitchellh/macos-occlusion

macOS: notify core of window occlusion state
This commit is contained in:
Mitchell Hashimoto
2024-02-12 14:04:06 -08:00
committed by GitHub
4 changed files with 422 additions and 339 deletions

View File

@ -24,10 +24,10 @@ extern "C" {
// Types
// Opaque types
typedef void *ghostty_app_t;
typedef void *ghostty_config_t;
typedef void *ghostty_surface_t;
typedef void *ghostty_inspector_t;
typedef void* ghostty_app_t;
typedef void* ghostty_config_t;
typedef void* ghostty_surface_t;
typedef void* ghostty_inspector_t;
// Enums are up top so we can reference them later.
typedef enum {
@ -326,7 +326,7 @@ typedef struct {
ghostty_input_action_e action;
ghostty_input_mods_e mods;
uint32_t keycode;
const char *text;
const char* text;
bool composing;
} ghostty_input_key_s;
@ -353,20 +353,20 @@ typedef enum {
// for all of these types is available in the Zig source.
typedef struct {
ghostty_build_mode_e build_mode;
const char *version;
const char* version;
uintptr_t version_len;
} ghostty_info_s;
typedef struct {
const char *message;
const char* message;
} ghostty_error_s;
typedef struct {
void *nsview;
void* nsview;
} ghostty_platform_macos_s;
typedef struct {
void *uiview;
void* uiview;
} ghostty_platform_ios_s;
typedef union {
@ -377,41 +377,65 @@ typedef union {
typedef struct {
ghostty_platform_e platform_tag;
ghostty_platform_u platform;
void *userdata;
void* userdata;
double scale_factor;
uint16_t font_size;
const char *working_directory;
const char *command;
const char* working_directory;
const char* command;
} ghostty_surface_config_s;
typedef void (*ghostty_runtime_wakeup_cb)(void *);
typedef const ghostty_config_t (*ghostty_runtime_reload_config_cb)(void *);
typedef void (*ghostty_runtime_open_config_cb)(void *);
typedef void (*ghostty_runtime_set_title_cb)(void *, const char *);
typedef void (*ghostty_runtime_set_mouse_shape_cb)(void *, ghostty_mouse_shape_e);
typedef void (*ghostty_runtime_set_mouse_visibility_cb)(void *, bool);
typedef void (*ghostty_runtime_read_clipboard_cb)(void *, ghostty_clipboard_e, void *);
typedef void (*ghostty_runtime_confirm_read_clipboard_cb)(void *, const char*, void *, ghostty_clipboard_request_e);
typedef void (*ghostty_runtime_write_clipboard_cb)(void *, const char *, ghostty_clipboard_e, bool);
typedef void (*ghostty_runtime_new_split_cb)(void *, ghostty_split_direction_e, ghostty_surface_config_s);
typedef void (*ghostty_runtime_new_tab_cb)(void *, ghostty_surface_config_s);
typedef void (*ghostty_runtime_new_window_cb)(void *, ghostty_surface_config_s);
typedef void (*ghostty_runtime_control_inspector_cb)(void *, ghostty_inspector_mode_e);
typedef void (*ghostty_runtime_close_surface_cb)(void *, bool);
typedef void (*ghostty_runtime_focus_split_cb)(void *, ghostty_split_focus_direction_e);
typedef void (*ghostty_runtime_resize_split_cb)(void *, ghostty_split_resize_direction_e, uint16_t);
typedef void (*ghostty_runtime_equalize_splits_cb)(void *);
typedef void (*ghostty_runtime_toggle_split_zoom_cb)(void *);
typedef void (*ghostty_runtime_goto_tab_cb)(void *, int32_t);
typedef void (*ghostty_runtime_toggle_fullscreen_cb)(void *, ghostty_non_native_fullscreen_e);
typedef void (*ghostty_runtime_set_initial_window_size_cb)(void *, uint32_t, uint32_t);
typedef void (*ghostty_runtime_render_inspector_cb)(void *);
typedef void (*ghostty_runtime_set_cell_size_cb)(void *, uint32_t, uint32_t);
typedef void (*ghostty_runtime_show_desktop_notification_cb)(void *, const char *, const char *);
typedef void (*ghostty_runtime_update_renderer_health)(void *, ghostty_renderer_health_e);
typedef void (*ghostty_runtime_wakeup_cb)(void*);
typedef const ghostty_config_t (*ghostty_runtime_reload_config_cb)(void*);
typedef void (*ghostty_runtime_open_config_cb)(void*);
typedef void (*ghostty_runtime_set_title_cb)(void*, const char*);
typedef void (*ghostty_runtime_set_mouse_shape_cb)(void*,
ghostty_mouse_shape_e);
typedef void (*ghostty_runtime_set_mouse_visibility_cb)(void*, bool);
typedef void (*ghostty_runtime_read_clipboard_cb)(void*,
ghostty_clipboard_e,
void*);
typedef void (*ghostty_runtime_confirm_read_clipboard_cb)(
void*,
const char*,
void*,
ghostty_clipboard_request_e);
typedef void (*ghostty_runtime_write_clipboard_cb)(void*,
const char*,
ghostty_clipboard_e,
bool);
typedef void (*ghostty_runtime_new_split_cb)(void*,
ghostty_split_direction_e,
ghostty_surface_config_s);
typedef void (*ghostty_runtime_new_tab_cb)(void*, ghostty_surface_config_s);
typedef void (*ghostty_runtime_new_window_cb)(void*, ghostty_surface_config_s);
typedef void (*ghostty_runtime_control_inspector_cb)(void*,
ghostty_inspector_mode_e);
typedef void (*ghostty_runtime_close_surface_cb)(void*, bool);
typedef void (*ghostty_runtime_focus_split_cb)(void*,
ghostty_split_focus_direction_e);
typedef void (*ghostty_runtime_resize_split_cb)(
void*,
ghostty_split_resize_direction_e,
uint16_t);
typedef void (*ghostty_runtime_equalize_splits_cb)(void*);
typedef void (*ghostty_runtime_toggle_split_zoom_cb)(void*);
typedef void (*ghostty_runtime_goto_tab_cb)(void*, int32_t);
typedef void (*ghostty_runtime_toggle_fullscreen_cb)(
void*,
ghostty_non_native_fullscreen_e);
typedef void (*ghostty_runtime_set_initial_window_size_cb)(void*,
uint32_t,
uint32_t);
typedef void (*ghostty_runtime_render_inspector_cb)(void*);
typedef void (*ghostty_runtime_set_cell_size_cb)(void*, uint32_t, uint32_t);
typedef void (*ghostty_runtime_show_desktop_notification_cb)(void*,
const char*,
const char*);
typedef void (
*ghostty_runtime_update_renderer_health)(void*, ghostty_renderer_health_e);
typedef struct {
void *userdata;
void* userdata;
bool supports_selection_clipboard;
ghostty_runtime_wakeup_cb wakeup_cb;
ghostty_runtime_reload_config_cb reload_config_cb;
@ -444,26 +468,29 @@ typedef struct {
// Published API
int ghostty_init(void);
void ghostty_cli_main(uintptr_t, char **);
void ghostty_cli_main(uintptr_t, char**);
ghostty_info_s ghostty_info(void);
ghostty_config_t ghostty_config_new();
void ghostty_config_free(ghostty_config_t);
void ghostty_config_load_cli_args(ghostty_config_t);
void ghostty_config_load_string(ghostty_config_t, const char *, uintptr_t);
void ghostty_config_load_string(ghostty_config_t, const char*, uintptr_t);
void ghostty_config_load_default_files(ghostty_config_t);
void ghostty_config_load_recursive_files(ghostty_config_t);
void ghostty_config_finalize(ghostty_config_t);
bool ghostty_config_get(ghostty_config_t, void *, const char *, uintptr_t);
ghostty_input_trigger_s ghostty_config_trigger(ghostty_config_t, const char *, uintptr_t);
bool ghostty_config_get(ghostty_config_t, void*, const char*, uintptr_t);
ghostty_input_trigger_s ghostty_config_trigger(ghostty_config_t,
const char*,
uintptr_t);
uint32_t ghostty_config_errors_count(ghostty_config_t);
ghostty_error_s ghostty_config_get_error(ghostty_config_t, uint32_t);
void ghostty_config_open();
ghostty_app_t ghostty_app_new(const ghostty_runtime_config_s *, ghostty_config_t);
ghostty_app_t ghostty_app_new(const ghostty_runtime_config_s*,
ghostty_config_t);
void ghostty_app_free(ghostty_app_t);
bool ghostty_app_tick(ghostty_app_t);
void *ghostty_app_userdata(ghostty_app_t);
void* ghostty_app_userdata(ghostty_app_t);
void ghostty_app_keyboard_changed(ghostty_app_t);
void ghostty_app_open_config(ghostty_app_t);
void ghostty_app_reload_config(ghostty_app_t);
@ -479,46 +506,70 @@ bool ghostty_surface_needs_confirm_quit(ghostty_surface_t);
void ghostty_surface_refresh(ghostty_surface_t);
void ghostty_surface_set_content_scale(ghostty_surface_t, double, double);
void ghostty_surface_set_focus(ghostty_surface_t, bool);
void ghostty_surface_set_occlusion(ghostty_surface_t, bool);
void ghostty_surface_set_size(ghostty_surface_t, uint32_t, uint32_t);
void ghostty_surface_set_color_scheme(ghostty_surface_t, ghostty_color_scheme_e);
ghostty_input_mods_e ghostty_surface_key_translation_mods(ghostty_surface_t, ghostty_input_mods_e);
void ghostty_surface_set_color_scheme(ghostty_surface_t,
ghostty_color_scheme_e);
ghostty_input_mods_e ghostty_surface_key_translation_mods(ghostty_surface_t,
ghostty_input_mods_e);
void ghostty_surface_key(ghostty_surface_t, ghostty_input_key_s);
void ghostty_surface_text(ghostty_surface_t, const char *, uintptr_t);
void ghostty_surface_mouse_button(ghostty_surface_t, ghostty_input_mouse_state_e, ghostty_input_mouse_button_e, ghostty_input_mods_e);
void ghostty_surface_text(ghostty_surface_t, const char*, uintptr_t);
void ghostty_surface_mouse_button(ghostty_surface_t,
ghostty_input_mouse_state_e,
ghostty_input_mouse_button_e,
ghostty_input_mods_e);
void ghostty_surface_mouse_pos(ghostty_surface_t, double, double);
void ghostty_surface_mouse_scroll(ghostty_surface_t, double, double, ghostty_input_scroll_mods_t);
void ghostty_surface_ime_point(ghostty_surface_t, double *, double *);
void ghostty_surface_mouse_scroll(ghostty_surface_t,
double,
double,
ghostty_input_scroll_mods_t);
void ghostty_surface_ime_point(ghostty_surface_t, double*, double*);
void ghostty_surface_request_close(ghostty_surface_t);
void ghostty_surface_split(ghostty_surface_t, ghostty_split_direction_e);
void ghostty_surface_split_focus(ghostty_surface_t, ghostty_split_focus_direction_e);
void ghostty_surface_split_resize(ghostty_surface_t, ghostty_split_resize_direction_e, uint16_t);
void ghostty_surface_split_focus(ghostty_surface_t,
ghostty_split_focus_direction_e);
void ghostty_surface_split_resize(ghostty_surface_t,
ghostty_split_resize_direction_e,
uint16_t);
void ghostty_surface_split_equalize(ghostty_surface_t);
bool ghostty_surface_binding_action(ghostty_surface_t, const char *, uintptr_t);
void ghostty_surface_complete_clipboard_request(ghostty_surface_t, const char *, void *, bool);
uintptr_t ghostty_surface_pwd(ghostty_surface_t, char *, uintptr_t);
bool ghostty_surface_binding_action(ghostty_surface_t, const char*, uintptr_t);
void ghostty_surface_complete_clipboard_request(ghostty_surface_t,
const char*,
void*,
bool);
uintptr_t ghostty_surface_pwd(ghostty_surface_t, char*, uintptr_t);
bool ghostty_surface_has_selection(ghostty_surface_t);
uintptr_t ghostty_surface_selection(ghostty_surface_t, char *, uintptr_t);
uintptr_t ghostty_surface_selection(ghostty_surface_t, char*, uintptr_t);
ghostty_inspector_t ghostty_surface_inspector(ghostty_surface_t);
void ghostty_inspector_free(ghostty_surface_t);
void ghostty_inspector_set_focus(ghostty_inspector_t, bool);
void ghostty_inspector_set_content_scale(ghostty_inspector_t, double, double);
void ghostty_inspector_set_size(ghostty_inspector_t, uint32_t, uint32_t);
void ghostty_inspector_mouse_button(ghostty_inspector_t, ghostty_input_mouse_state_e, ghostty_input_mouse_button_e, ghostty_input_mods_e);
void ghostty_inspector_mouse_button(ghostty_inspector_t,
ghostty_input_mouse_state_e,
ghostty_input_mouse_button_e,
ghostty_input_mods_e);
void ghostty_inspector_mouse_pos(ghostty_inspector_t, double, double);
void ghostty_inspector_mouse_scroll(ghostty_inspector_t, double, double, ghostty_input_scroll_mods_t);
void ghostty_inspector_key(ghostty_inspector_t, ghostty_input_action_e, ghostty_input_key_e, ghostty_input_mods_e);
void ghostty_inspector_text(ghostty_inspector_t, const char *);
void ghostty_inspector_mouse_scroll(ghostty_inspector_t,
double,
double,
ghostty_input_scroll_mods_t);
void ghostty_inspector_key(ghostty_inspector_t,
ghostty_input_action_e,
ghostty_input_key_e,
ghostty_input_mods_e);
void ghostty_inspector_text(ghostty_inspector_t, const char*);
#ifdef __APPLE__
bool ghostty_inspector_metal_init(ghostty_inspector_t, void *);
void ghostty_inspector_metal_render(ghostty_inspector_t, void *, void *);
bool ghostty_inspector_metal_init(ghostty_inspector_t, void*);
void ghostty_inspector_metal_render(ghostty_inspector_t, void*, void*);
bool ghostty_inspector_metal_shutdown(ghostty_inspector_t);
#endif
// APIs I'd like to get rid of eventually but are still needed for now.
// Don't use these unless you know what you're doing.
void ghostty_set_window_background_blur(ghostty_surface_t, void *);
void ghostty_set_window_background_blur(ghostty_surface_t, void*);
#ifdef __cplusplus
}

View File

@ -384,6 +384,16 @@ class TerminalController: NSWindowController, NSWindowDelegate,
self.fixTabBar()
}
func windowDidChangeOcclusionState(_ notification: Notification) {
guard let surfaceTree = self.surfaceTree else { return }
let visible = self.window?.occlusionState.contains(.visible) ?? false
for leaf in surfaceTree {
if let surface = leaf.surface.surface {
ghostty_surface_set_occlusion(surface, visible)
}
}
}
// Called when the window will be encoded. We handle the data encoding here in the
// window controller.
func window(_ window: NSWindow, willEncodeRestorableState state: NSCoder) {

View File

@ -1527,6 +1527,16 @@ pub fn textCallback(self: *Surface, text: []const u8) !void {
try self.completeClipboardPaste(text, true);
}
/// Callback for when the surface is fully visible or not, regardless
/// of focus state. This is used to pause rendering when the surface
/// is not visible, and also re-render when it becomes visible again.
pub fn occlusionCallback(self: *Surface, visible: bool) !void {
// If we became visible, then we queue a render. This helps scenarios
// where the apprt pauses rendering when the surface is not visible,
// i.e. macOS with Metal (see issue #1510).
if (visible) try self.queueRender();
}
pub fn focusCallback(self: *Surface, focused: bool) !void {
// Notify our render thread of the new state
_ = self.renderer_thread.mailbox.push(.{

View File

@ -945,6 +945,13 @@ pub const Surface = struct {
};
}
pub fn occlusionCallback(self: *Surface, visible: bool) void {
self.core_surface.occlusionCallback(visible) catch |err| {
log.err("error in occlusion callback err={}", .{err});
return;
};
}
pub fn gotoTab(self: *Surface, n: usize) void {
const func = self.app.opts.goto_tab orelse {
log.info("runtime embedder does not goto_tab", .{});
@ -1546,6 +1553,11 @@ pub const CAPI = struct {
surface.focusCallback(focused);
}
/// Update the occlusion state of a surface.
export fn ghostty_surface_set_occlusion(surface: *Surface, visible: bool) void {
surface.occlusionCallback(visible);
}
/// Filter the mods if necessary. This handles settings such as
/// `macos-option-as-alt`. The filtered mods should be used for
/// key translation but should NOT be sent back via the `_key`