mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-25 13:16:11 +03:00
apprt/gtk: add all event handlers to the overlay so both receive
This commit is contained in:
@ -221,7 +221,7 @@ pub const URLWidget = struct {
|
|||||||
left: *c.GtkWidget,
|
left: *c.GtkWidget,
|
||||||
right: *c.GtkWidget,
|
right: *c.GtkWidget,
|
||||||
|
|
||||||
pub fn init(overlay: *c.GtkOverlay, str: [:0]const u8) URLWidget {
|
pub fn init(surface: *const Surface, str: [:0]const u8) URLWidget {
|
||||||
// Create the left
|
// Create the left
|
||||||
const left = c.gtk_label_new(str.ptr);
|
const left = c.gtk_label_new(str.ptr);
|
||||||
c.gtk_widget_add_css_class(@ptrCast(left), "view");
|
c.gtk_widget_add_css_class(@ptrCast(left), "view");
|
||||||
@ -261,8 +261,8 @@ pub const URLWidget = struct {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Show it
|
// Show it
|
||||||
c.gtk_overlay_add_overlay(@ptrCast(overlay), left);
|
c.gtk_overlay_add_overlay(@ptrCast(surface.overlay), left);
|
||||||
c.gtk_overlay_add_overlay(@ptrCast(overlay), right);
|
c.gtk_overlay_add_overlay(@ptrCast(surface.overlay), right);
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.left = left,
|
.left = left,
|
||||||
@ -365,12 +365,15 @@ pub fn create(alloc: Allocator, app: *App, opts: Options) !*Surface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
||||||
const widget: *c.GtkWidget = c.gtk_gl_area_new();
|
const gl_area = c.gtk_gl_area_new();
|
||||||
const gl_area: *c.GtkGLArea = @ptrCast(widget);
|
|
||||||
|
|
||||||
// Create an overlay so we can layer the GL area with other widgets.
|
// Create an overlay so we can layer the GL area with other widgets.
|
||||||
const overlay: *c.GtkOverlay = @ptrCast(c.gtk_overlay_new());
|
const overlay = c.gtk_overlay_new();
|
||||||
c.gtk_overlay_set_child(@ptrCast(overlay), widget);
|
c.gtk_overlay_set_child(@ptrCast(overlay), gl_area);
|
||||||
|
|
||||||
|
// Overlay is not focusable, but the GL area is.
|
||||||
|
c.gtk_widget_set_focusable(@ptrCast(overlay), 0);
|
||||||
|
c.gtk_widget_set_focus_on_click(@ptrCast(overlay), 0);
|
||||||
|
|
||||||
// We grab the floating reference to the primary widget. This allows the
|
// We grab the floating reference to the primary widget. This allows the
|
||||||
// widget tree to be moved around i.e. between a split, a tab, etc.
|
// widget tree to be moved around i.e. between a split, a tab, etc.
|
||||||
@ -383,45 +386,45 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
|||||||
errdefer c.g_object_unref(@ptrCast(overlay));
|
errdefer c.g_object_unref(@ptrCast(overlay));
|
||||||
|
|
||||||
// We want the gl area to expand to fill the parent container.
|
// We want the gl area to expand to fill the parent container.
|
||||||
c.gtk_widget_set_hexpand(widget, 1);
|
c.gtk_widget_set_hexpand(gl_area, 1);
|
||||||
c.gtk_widget_set_vexpand(widget, 1);
|
c.gtk_widget_set_vexpand(gl_area, 1);
|
||||||
|
|
||||||
// Various other GL properties
|
// Various other GL properties
|
||||||
c.gtk_widget_set_cursor_from_name(@ptrCast(gl_area), "text");
|
c.gtk_widget_set_cursor_from_name(@ptrCast(overlay), "text");
|
||||||
c.gtk_gl_area_set_required_version(gl_area, 3, 3);
|
c.gtk_gl_area_set_required_version(@ptrCast(gl_area), 3, 3);
|
||||||
c.gtk_gl_area_set_has_stencil_buffer(gl_area, 0);
|
c.gtk_gl_area_set_has_stencil_buffer(@ptrCast(gl_area), 0);
|
||||||
c.gtk_gl_area_set_has_depth_buffer(gl_area, 0);
|
c.gtk_gl_area_set_has_depth_buffer(@ptrCast(gl_area), 0);
|
||||||
c.gtk_gl_area_set_use_es(gl_area, 0);
|
c.gtk_gl_area_set_use_es(@ptrCast(gl_area), 0);
|
||||||
|
|
||||||
// Key event controller will tell us about raw keypress events.
|
// Key event controller will tell us about raw keypress events.
|
||||||
const ec_key = c.gtk_event_controller_key_new();
|
const ec_key = c.gtk_event_controller_key_new();
|
||||||
errdefer c.g_object_unref(ec_key);
|
errdefer c.g_object_unref(ec_key);
|
||||||
c.gtk_widget_add_controller(widget, ec_key);
|
c.gtk_widget_add_controller(@ptrCast(overlay), ec_key);
|
||||||
errdefer c.gtk_widget_remove_controller(widget, ec_key);
|
errdefer c.gtk_widget_remove_controller(@ptrCast(overlay), ec_key);
|
||||||
|
|
||||||
// Focus controller will tell us about focus enter/exit events
|
// Focus controller will tell us about focus enter/exit events
|
||||||
const ec_focus = c.gtk_event_controller_focus_new();
|
const ec_focus = c.gtk_event_controller_focus_new();
|
||||||
errdefer c.g_object_unref(ec_focus);
|
errdefer c.g_object_unref(ec_focus);
|
||||||
c.gtk_widget_add_controller(widget, ec_focus);
|
c.gtk_widget_add_controller(@ptrCast(overlay), ec_focus);
|
||||||
errdefer c.gtk_widget_remove_controller(widget, ec_focus);
|
errdefer c.gtk_widget_remove_controller(@ptrCast(overlay), ec_focus);
|
||||||
|
|
||||||
// Create a second key controller so we can receive the raw
|
// Create a second key controller so we can receive the raw
|
||||||
// key-press events BEFORE the input method gets them.
|
// key-press events BEFORE the input method gets them.
|
||||||
const ec_key_press = c.gtk_event_controller_key_new();
|
const ec_key_press = c.gtk_event_controller_key_new();
|
||||||
errdefer c.g_object_unref(ec_key_press);
|
errdefer c.g_object_unref(ec_key_press);
|
||||||
c.gtk_widget_add_controller(widget, ec_key_press);
|
c.gtk_widget_add_controller(@ptrCast(overlay), ec_key_press);
|
||||||
errdefer c.gtk_widget_remove_controller(widget, ec_key_press);
|
errdefer c.gtk_widget_remove_controller(@ptrCast(overlay), ec_key_press);
|
||||||
|
|
||||||
// Clicks
|
// Clicks
|
||||||
const gesture_click = c.gtk_gesture_click_new();
|
const gesture_click = c.gtk_gesture_click_new();
|
||||||
errdefer c.g_object_unref(gesture_click);
|
errdefer c.g_object_unref(gesture_click);
|
||||||
c.gtk_gesture_single_set_button(@ptrCast(gesture_click), 0);
|
c.gtk_gesture_single_set_button(@ptrCast(gesture_click), 0);
|
||||||
c.gtk_widget_add_controller(widget, @ptrCast(gesture_click));
|
c.gtk_widget_add_controller(@ptrCast(@alignCast(overlay)), @ptrCast(gesture_click));
|
||||||
|
|
||||||
// Mouse movement
|
// Mouse movement
|
||||||
const ec_motion = c.gtk_event_controller_motion_new();
|
const ec_motion = c.gtk_event_controller_motion_new();
|
||||||
errdefer c.g_object_unref(ec_motion);
|
errdefer c.g_object_unref(ec_motion);
|
||||||
c.gtk_widget_add_controller(widget, ec_motion);
|
c.gtk_widget_add_controller(@ptrCast(@alignCast(overlay)), ec_motion);
|
||||||
|
|
||||||
// Scroll events
|
// Scroll events
|
||||||
const ec_scroll = c.gtk_event_controller_scroll_new(
|
const ec_scroll = c.gtk_event_controller_scroll_new(
|
||||||
@ -429,7 +432,7 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
|||||||
c.GTK_EVENT_CONTROLLER_SCROLL_DISCRETE,
|
c.GTK_EVENT_CONTROLLER_SCROLL_DISCRETE,
|
||||||
);
|
);
|
||||||
errdefer c.g_object_unref(ec_scroll);
|
errdefer c.g_object_unref(ec_scroll);
|
||||||
c.gtk_widget_add_controller(widget, ec_scroll);
|
c.gtk_widget_add_controller(@ptrCast(overlay), ec_scroll);
|
||||||
|
|
||||||
// The input method context that we use to translate key events into
|
// The input method context that we use to translate key events into
|
||||||
// characters. This doesn't have an event key controller attached because
|
// characters. This doesn't have an event key controller attached because
|
||||||
@ -438,8 +441,8 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
|||||||
errdefer c.g_object_unref(im_context);
|
errdefer c.g_object_unref(im_context);
|
||||||
|
|
||||||
// The GL area has to be focusable so that it can receive events
|
// The GL area has to be focusable so that it can receive events
|
||||||
c.gtk_widget_set_focusable(widget, 1);
|
c.gtk_widget_set_focusable(gl_area, 1);
|
||||||
c.gtk_widget_set_focus_on_click(widget, 1);
|
c.gtk_widget_set_focus_on_click(gl_area, 1);
|
||||||
|
|
||||||
// Inherit the parent's font size if we have a parent.
|
// Inherit the parent's font size if we have a parent.
|
||||||
const font_size: ?font.face.DesiredSize = font_size: {
|
const font_size: ?font.face.DesiredSize = font_size: {
|
||||||
@ -482,8 +485,8 @@ pub fn init(self: *Surface, app: *App, opts: Options) !void {
|
|||||||
self.* = .{
|
self.* = .{
|
||||||
.app = app,
|
.app = app,
|
||||||
.container = .{ .none = {} },
|
.container = .{ .none = {} },
|
||||||
.overlay = overlay,
|
.overlay = @ptrCast(overlay),
|
||||||
.gl_area = gl_area,
|
.gl_area = @ptrCast(gl_area),
|
||||||
.title_text = null,
|
.title_text = null,
|
||||||
.core_surface = undefined,
|
.core_surface = undefined,
|
||||||
.font_size = font_size,
|
.font_size = font_size,
|
||||||
@ -961,8 +964,9 @@ pub fn setMouseShape(
|
|||||||
// Set our new cursor. We only do this if the cursor we currently
|
// Set our new cursor. We only do this if the cursor we currently
|
||||||
// have is NOT set to "none" because setting the cursor causes it
|
// have is NOT set to "none" because setting the cursor causes it
|
||||||
// to become visible again.
|
// to become visible again.
|
||||||
if (c.gtk_widget_get_cursor(@ptrCast(self.gl_area)) != self.app.cursor_none) {
|
const overlay_widget: *c.GtkWidget = @ptrCast(@alignCast(self.overlay));
|
||||||
c.gtk_widget_set_cursor(@ptrCast(self.gl_area), cursor);
|
if (c.gtk_widget_get_cursor(overlay_widget) != self.app.cursor_none) {
|
||||||
|
c.gtk_widget_set_cursor(overlay_widget, cursor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Free our existing cursor
|
// Free our existing cursor
|
||||||
@ -975,18 +979,20 @@ pub fn setMouseVisibility(self: *Surface, visible: bool) void {
|
|||||||
// Note in there that self.cursor or cursor_none may be null. That's
|
// Note in there that self.cursor or cursor_none may be null. That's
|
||||||
// not a problem because NULL is a valid argument for set cursor
|
// not a problem because NULL is a valid argument for set cursor
|
||||||
// which means to just use the parent value.
|
// which means to just use the parent value.
|
||||||
|
const overlay_widget: *c.GtkWidget = @ptrCast(@alignCast(self.overlay));
|
||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
c.gtk_widget_set_cursor(@ptrCast(self.gl_area), self.cursor);
|
c.gtk_widget_set_cursor(overlay_widget, self.cursor);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set our new cursor to the app "none" cursor
|
// Set our new cursor to the app "none" cursor
|
||||||
c.gtk_widget_set_cursor(@ptrCast(self.gl_area), self.app.cursor_none);
|
c.gtk_widget_set_cursor(overlay_widget, self.app.cursor_none);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouseOverLink(self: *Surface, uri_: ?[]const u8) void {
|
pub fn mouseOverLink(self: *Surface, uri_: ?[]const u8) void {
|
||||||
const uri = uri_ orelse {
|
const uri = uri_ orelse {
|
||||||
|
if (true) return;
|
||||||
if (self.url_widget) |*widget| {
|
if (self.url_widget) |*widget| {
|
||||||
widget.deinit(self.overlay);
|
widget.deinit(self.overlay);
|
||||||
self.url_widget = null;
|
self.url_widget = null;
|
||||||
@ -1006,7 +1012,7 @@ pub fn mouseOverLink(self: *Surface, uri_: ?[]const u8) void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.url_widget = URLWidget.init(self.overlay, uriZ);
|
self.url_widget = URLWidget.init(self, uriZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clipboardRequest(
|
pub fn clipboardRequest(
|
||||||
@ -1166,7 +1172,7 @@ fn gtkRealize(area: *c.GtkGLArea, ud: ?*anyopaque) callconv(.C) void {
|
|||||||
// When we have a realized surface, we also attach our input method context.
|
// When we have a realized surface, we also attach our input method context.
|
||||||
// We do this here instead of init because this allows us to relase the ref
|
// We do this here instead of init because this allows us to relase the ref
|
||||||
// to the GLArea when we unrealized.
|
// to the GLArea when we unrealized.
|
||||||
c.gtk_im_context_set_client_widget(self.im_context, @ptrCast(self.gl_area));
|
c.gtk_im_context_set_client_widget(self.im_context, @ptrCast(@alignCast(self.overlay)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is called when the underlying OpenGL resources must be released.
|
/// This is called when the underlying OpenGL resources must be released.
|
||||||
|
Reference in New Issue
Block a user