mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-17 09:16:11 +03:00
gtk: update URLWidget to use zig-gobject
Also move URLWidget to a separate file to cut down on the size of Surface.zig.
This commit is contained in:
@ -4,6 +4,7 @@
|
||||
const Surface = @This();
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
const adw = @import("adw");
|
||||
const gtk = @import("gtk");
|
||||
const gio = @import("gio");
|
||||
@ -28,6 +29,7 @@ const Window = @import("Window.zig");
|
||||
const Menu = @import("menu.zig").Menu;
|
||||
const ClipboardConfirmationWindow = @import("ClipboardConfirmationWindow.zig");
|
||||
const ResizeOverlay = @import("ResizeOverlay.zig");
|
||||
const URLWidget = @import("URLWidget.zig");
|
||||
const inspector = @import("inspector.zig");
|
||||
const gtk_key = @import("key.zig");
|
||||
const c = @import("c.zig").c;
|
||||
@ -219,99 +221,6 @@ pub const Container = union(enum) {
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents the URL hover widgets that show the hovered URL.
|
||||
/// To explain a bit how this all works since its split across a few places:
|
||||
/// We create a left/right pair of labels. The left label is shown by default,
|
||||
/// and the right label is hidden. When the mouse enters the left label, we
|
||||
/// show the right label. When the mouse leaves the left label, we hide the
|
||||
/// right label.
|
||||
///
|
||||
/// The hover and styling is done with a combination of GTK event controllers
|
||||
/// and CSS in style.css.
|
||||
pub const URLWidget = struct {
|
||||
left: *c.GtkWidget,
|
||||
right: *c.GtkWidget,
|
||||
|
||||
pub fn init(surface: *const Surface, str: [:0]const u8) URLWidget {
|
||||
// Create the left
|
||||
const left = c.gtk_label_new(str.ptr);
|
||||
c.gtk_label_set_ellipsize(@ptrCast(left), c.PANGO_ELLIPSIZE_MIDDLE);
|
||||
c.gtk_widget_add_css_class(@ptrCast(left), "view");
|
||||
c.gtk_widget_add_css_class(@ptrCast(left), "url-overlay");
|
||||
c.gtk_widget_add_css_class(@ptrCast(left), "left");
|
||||
c.gtk_widget_set_halign(left, c.GTK_ALIGN_START);
|
||||
c.gtk_widget_set_valign(left, c.GTK_ALIGN_END);
|
||||
|
||||
// Create the right
|
||||
const right = c.gtk_label_new(str.ptr);
|
||||
c.gtk_label_set_ellipsize(@ptrCast(right), c.PANGO_ELLIPSIZE_MIDDLE);
|
||||
c.gtk_widget_add_css_class(@ptrCast(right), "hidden");
|
||||
c.gtk_widget_add_css_class(@ptrCast(right), "view");
|
||||
c.gtk_widget_add_css_class(@ptrCast(right), "url-overlay");
|
||||
c.gtk_widget_add_css_class(@ptrCast(right), "right");
|
||||
c.gtk_widget_set_halign(right, c.GTK_ALIGN_END);
|
||||
c.gtk_widget_set_valign(right, c.GTK_ALIGN_END);
|
||||
|
||||
// Setup our mouse hover event for the left
|
||||
const ec_motion = c.gtk_event_controller_motion_new();
|
||||
errdefer c.g_object_unref(ec_motion);
|
||||
c.gtk_widget_add_controller(@ptrCast(left), ec_motion);
|
||||
_ = c.g_signal_connect_data(
|
||||
ec_motion,
|
||||
"enter",
|
||||
c.G_CALLBACK(>kLeftEnter),
|
||||
right,
|
||||
null,
|
||||
c.G_CONNECT_DEFAULT,
|
||||
);
|
||||
_ = c.g_signal_connect_data(
|
||||
ec_motion,
|
||||
"leave",
|
||||
c.G_CALLBACK(>kLeftLeave),
|
||||
right,
|
||||
null,
|
||||
c.G_CONNECT_DEFAULT,
|
||||
);
|
||||
|
||||
// Show it
|
||||
c.gtk_overlay_add_overlay(surface.overlay, left);
|
||||
c.gtk_overlay_add_overlay(surface.overlay, right);
|
||||
|
||||
return .{
|
||||
.left = left,
|
||||
.right = right,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: *URLWidget, overlay: *c.GtkOverlay) void {
|
||||
c.gtk_overlay_remove_overlay(overlay, @ptrCast(self.left));
|
||||
c.gtk_overlay_remove_overlay(overlay, @ptrCast(self.right));
|
||||
}
|
||||
|
||||
pub fn setText(self: *const URLWidget, str: [:0]const u8) void {
|
||||
c.gtk_label_set_text(@ptrCast(self.left), str.ptr);
|
||||
c.gtk_label_set_text(@ptrCast(self.right), str.ptr);
|
||||
}
|
||||
|
||||
fn gtkLeftEnter(
|
||||
_: *c.GtkEventControllerMotion,
|
||||
_: c.gdouble,
|
||||
_: c.gdouble,
|
||||
ud: ?*anyopaque,
|
||||
) callconv(.C) void {
|
||||
const right: *c.GtkWidget = @ptrCast(@alignCast(ud orelse return));
|
||||
c.gtk_widget_remove_css_class(@ptrCast(right), "hidden");
|
||||
}
|
||||
|
||||
fn gtkLeftLeave(
|
||||
_: *c.GtkEventControllerMotion,
|
||||
ud: ?*anyopaque,
|
||||
) callconv(.C) void {
|
||||
const right: *c.GtkWidget = @ptrCast(@alignCast(ud orelse return));
|
||||
c.gtk_widget_add_css_class(@ptrCast(right), "hidden");
|
||||
}
|
||||
};
|
||||
|
||||
/// Whether the surface has been realized or not yet. When a surface is
|
||||
/// "realized" it means that the OpenGL context is ready and the core
|
||||
/// surface has been initialized.
|
||||
@ -1169,7 +1078,8 @@ pub fn setMouseVisibility(self: *Surface, visible: bool) void {
|
||||
pub fn mouseOverLink(self: *Surface, uri_: ?[]const u8) void {
|
||||
const uri = uri_ orelse {
|
||||
if (self.url_widget) |*widget| {
|
||||
widget.deinit(self.overlay);
|
||||
// FIXME: when Surface gets converted to zig-gobject
|
||||
widget.deinit(@ptrCast(@alignCast(self.overlay)));
|
||||
self.url_widget = null;
|
||||
}
|
||||
|
||||
@ -1187,7 +1097,8 @@ pub fn mouseOverLink(self: *Surface, uri_: ?[]const u8) void {
|
||||
return;
|
||||
}
|
||||
|
||||
self.url_widget = URLWidget.init(self, uriZ);
|
||||
// FIXME: when Surface gets converted to zig-gobject
|
||||
self.url_widget = URLWidget.init(@ptrCast(@alignCast(self.overlay)), uriZ);
|
||||
}
|
||||
|
||||
pub fn supportsClipboard(
|
||||
|
115
src/apprt/gtk/URLWidget.zig
Normal file
115
src/apprt/gtk/URLWidget.zig
Normal file
@ -0,0 +1,115 @@
|
||||
//! Represents the URL hover widgets that show the hovered URL.
|
||||
//!
|
||||
//! To explain a bit how this all works since its split across a few places:
|
||||
//! We create a left/right pair of labels. The left label is shown by default,
|
||||
//! and the right label is hidden. When the mouse enters the left label, we
|
||||
//! show the right label. When the mouse leaves the left label, we hide the
|
||||
//! right label.
|
||||
//!
|
||||
//! The hover and styling is done with a combination of GTK event controllers
|
||||
//! and CSS in style.css.
|
||||
const URLWidget = @This();
|
||||
|
||||
const gtk = @import("gtk");
|
||||
|
||||
/// The label that appears on the bottom left.
|
||||
left: *gtk.Label,
|
||||
|
||||
/// The label that appears on the bottom right.
|
||||
right: *gtk.Label,
|
||||
|
||||
pub fn init(
|
||||
/// The overlay that we will attach our labels to.
|
||||
overlay: *gtk.Overlay,
|
||||
/// The URL to display.
|
||||
str: [:0]const u8,
|
||||
) URLWidget {
|
||||
// Create the left
|
||||
const left = left: {
|
||||
const left = gtk.Label.new(str.ptr);
|
||||
left.setEllipsize(.middle);
|
||||
const widget = left.as(gtk.Widget);
|
||||
widget.addCssClass("view");
|
||||
widget.addCssClass("url-overlay");
|
||||
widget.addCssClass("left");
|
||||
widget.setHalign(.start);
|
||||
widget.setValign(.end);
|
||||
break :left left;
|
||||
};
|
||||
|
||||
// Create the right
|
||||
const right = right: {
|
||||
const right = gtk.Label.new(str.ptr);
|
||||
right.setEllipsize(.middle);
|
||||
const widget = right.as(gtk.Widget);
|
||||
widget.addCssClass("hidden");
|
||||
widget.addCssClass("view");
|
||||
widget.addCssClass("url-overlay");
|
||||
widget.addCssClass("right");
|
||||
widget.setHalign(.end);
|
||||
widget.setValign(.end);
|
||||
break :right right;
|
||||
};
|
||||
|
||||
// Setup our mouse hover event controller for the left label.
|
||||
const ec_motion = gtk.EventControllerMotion.new();
|
||||
errdefer ec_motion.unref();
|
||||
|
||||
left.as(gtk.Widget).addController(ec_motion.as(gtk.EventController));
|
||||
|
||||
_ = gtk.EventControllerMotion.signals.enter.connect(
|
||||
ec_motion,
|
||||
*gtk.Label,
|
||||
gtkLeftEnter,
|
||||
right,
|
||||
.{},
|
||||
);
|
||||
_ = gtk.EventControllerMotion.signals.leave.connect(
|
||||
ec_motion,
|
||||
*gtk.Label,
|
||||
gtkLeftLeave,
|
||||
right,
|
||||
.{},
|
||||
);
|
||||
|
||||
// Show it
|
||||
overlay.addOverlay(left.as(gtk.Widget));
|
||||
overlay.addOverlay(right.as(gtk.Widget));
|
||||
|
||||
return .{
|
||||
.left = left,
|
||||
.right = right,
|
||||
};
|
||||
}
|
||||
|
||||
/// Remove our labels from the overlay.
|
||||
pub fn deinit(self: *URLWidget, overlay: *gtk.Overlay) void {
|
||||
overlay.removeOverlay(self.left.as(gtk.Widget));
|
||||
overlay.removeOverlay(self.right.as(gtk.Widget));
|
||||
}
|
||||
|
||||
/// Change the URL that is displayed.
|
||||
pub fn setText(self: *const URLWidget, str: [:0]const u8) void {
|
||||
self.left.setText(str.ptr);
|
||||
self.right.setText(str.ptr);
|
||||
}
|
||||
|
||||
/// Callback for when the mouse enters the left label. That means that we should
|
||||
/// show the right label. CSS will handle hiding the left label.
|
||||
fn gtkLeftEnter(
|
||||
_: *gtk.EventControllerMotion,
|
||||
_: f64,
|
||||
_: f64,
|
||||
right: *gtk.Label,
|
||||
) callconv(.C) void {
|
||||
right.as(gtk.Widget).removeCssClass("hidden");
|
||||
}
|
||||
|
||||
/// Callback for when the mouse leaves the left label. That means that we should
|
||||
/// hide the right label. CSS will handle showing the left label.
|
||||
fn gtkLeftLeave(
|
||||
_: *gtk.EventControllerMotion,
|
||||
right: *gtk.Label,
|
||||
) callconv(.C) void {
|
||||
right.as(gtk.Widget).addCssClass("hidden");
|
||||
}
|
Reference in New Issue
Block a user