gtk: use GtkDrawingArea to dim unfocused split

Refactor the GTK unfocused split code to use a GtkDrawingArea widget to
dim the unfocused split. The GtkDrawingArea is added to the overlay and
a CSS style is used to give it a background color and opacity. This
aligns with the macOS design of drawing on top of the surface. In GTK,
we don't need to actually draw a rectangle because we can apply CSS
directly to the widget.
This commit is contained in:
Tim Culverhouse
2024-07-11 08:28:47 -05:00
parent f04fe01ac6
commit 11c2ae1007
2 changed files with 21 additions and 8 deletions

View File

@ -392,10 +392,8 @@ fn loadRuntimeCss(config: *const Config, provider: *c.GtkCssProvider) !void {
const fmt =
\\widget.unfocused-split {{
\\ opacity: {d:.2};
\\}}
\\.ghostty-surface>stack {{
\\ background-color: rgb({d},{d},{d});
\\}}"
\\}}
;
// The length required is always less than the length of the pre-formatted string:
// -> '{d:.2}' gets replaced with max 4 bytes (0.00)
@ -413,7 +411,7 @@ fn loadRuntimeCss(config: *const Config, provider: *c.GtkCssProvider) !void {
},
);
// Clears any previously loaded CSS from this provider
c.gtk_css_provider_load_from_string(provider, css);
c.gtk_css_provider_load_from_data(provider, css, @intCast(css.len));
}
/// Called by CoreApp to wake up the event loop.

View File

@ -325,6 +325,9 @@ gl_area: *c.GtkGLArea,
/// If non-null this is the widget on the overlay that shows the URL.
url_widget: ?URLWidget = null,
/// If non-null this is the widget on the overlay which dims the surface when it is unfocused
unfocused_widget: ?*c.GtkWidget = null,
/// Any active cursor we may have
cursor: ?*c.GdkCursor = null,
@ -590,6 +593,10 @@ pub fn deinit(self: *Surface) void {
// Free all our GTK stuff
c.g_object_unref(self.im_context);
if (self.cursor) |cursor| c.g_object_unref(cursor);
if (self.unfocused_widget) |widget| {
c.gtk_overlay_remove_overlay(self.overlay, widget);
self.unfocused_widget = null;
}
}
// unref removes the long-held reference to the gl_area and kicks off the
@ -1809,8 +1816,11 @@ fn gtkFocusEnter(_: *c.GtkEventControllerFocus, ud: ?*anyopaque) callconv(.C) vo
// Notify our IM context
c.gtk_im_context_focus_in(self.im_context);
// Unconditionally remove the unfocused split css class
c.gtk_widget_remove_css_class(@ptrCast(@alignCast(self.gl_area)), "unfocused-split");
// Remove the unfocused widget overlay, if we have one
if (self.unfocused_widget) |widget| {
c.gtk_overlay_remove_overlay(self.overlay, widget);
self.unfocused_widget = null;
}
// Notify our surface
self.core_surface.focusCallback(true) catch |err| {
@ -1826,11 +1836,16 @@ fn gtkFocusLeave(_: *c.GtkEventControllerFocus, ud: ?*anyopaque) callconv(.C) vo
// Notify our IM context
c.gtk_im_context_focus_out(self.im_context);
// We only add the unfocused-split class if we are actually a split
// We only add the unfocused-split widget if we are actually a split
switch (self.container) {
.split_br,
.split_tl,
=> c.gtk_widget_add_css_class(@ptrCast(@alignCast(self.gl_area)), "unfocused-split"),
=> blk: {
if (self.unfocused_widget != null) break :blk;
self.unfocused_widget = c.gtk_drawing_area_new();
c.gtk_widget_add_css_class(self.unfocused_widget.?, "unfocused-split");
c.gtk_overlay_add_overlay(self.overlay, self.unfocused_widget.?);
},
else => {},
}