mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
apprt/gtk: move url hover bar when its under the mouse
This commit is contained in:
@ -208,6 +208,92 @@ 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(overlay: *c.GtkOverlay, str: [:0]const u8) URLWidget {
|
||||||
|
// Create the left
|
||||||
|
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), "url-overlay");
|
||||||
|
c.gtk_widget_set_halign(left, c.GTK_ALIGN_START);
|
||||||
|
c.gtk_widget_set_valign(left, c.GTK_ALIGN_END);
|
||||||
|
c.gtk_widget_set_margin_bottom(left, 2);
|
||||||
|
|
||||||
|
// Create the right
|
||||||
|
const right = c.gtk_label_new(str.ptr);
|
||||||
|
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_set_halign(right, c.GTK_ALIGN_END);
|
||||||
|
c.gtk_widget_set_valign(right, c.GTK_ALIGN_END);
|
||||||
|
c.gtk_widget_set_margin_bottom(right, 2);
|
||||||
|
|
||||||
|
// 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(@ptrCast(overlay), left);
|
||||||
|
c.gtk_overlay_add_overlay(@ptrCast(overlay), right);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
.left = left,
|
||||||
|
.right = 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
|
/// 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
|
/// "realized" it means that the OpenGL context is ready and the core
|
||||||
/// surface has been initialized.
|
/// surface has been initialized.
|
||||||
@ -230,7 +316,7 @@ overlay: *c.GtkOverlay,
|
|||||||
gl_area: *c.GtkGLArea,
|
gl_area: *c.GtkGLArea,
|
||||||
|
|
||||||
/// If non-null this is the widget on the overlay that shows the URL.
|
/// If non-null this is the widget on the overlay that shows the URL.
|
||||||
url_widget: ?*c.GtkWidget = null,
|
url_widget: ?URLWidget = null,
|
||||||
|
|
||||||
/// Any active cursor we may have
|
/// Any active cursor we may have
|
||||||
cursor: ?*c.GdkCursor = null,
|
cursor: ?*c.GdkCursor = null,
|
||||||
@ -896,8 +982,9 @@ pub fn setMouseVisibility(self: *Surface, visible: bool) void {
|
|||||||
|
|
||||||
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| {
|
||||||
c.gtk_overlay_remove_overlay(@ptrCast(self.overlay), widget);
|
widget.deinit(self.overlay);
|
||||||
self.url_widget = null;
|
self.url_widget = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -911,19 +998,11 @@ pub fn mouseOverLink(self: *Surface, uri_: ?[]const u8) void {
|
|||||||
|
|
||||||
// If we have a URL widget already just change the text.
|
// If we have a URL widget already just change the text.
|
||||||
if (self.url_widget) |widget| {
|
if (self.url_widget) |widget| {
|
||||||
c.gtk_label_set_text(@ptrCast(widget), uriZ.ptr);
|
widget.setText(uriZ);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the widget
|
self.url_widget = URLWidget.init(self.overlay, uriZ);
|
||||||
const label = c.gtk_label_new(uriZ.ptr);
|
|
||||||
c.gtk_widget_add_css_class(@ptrCast(label), "view");
|
|
||||||
c.gtk_widget_add_css_class(@ptrCast(label), "url-overlay");
|
|
||||||
c.gtk_widget_set_halign(label, c.GTK_ALIGN_START);
|
|
||||||
c.gtk_widget_set_valign(label, c.GTK_ALIGN_END);
|
|
||||||
c.gtk_widget_set_margin_bottom(label, 2);
|
|
||||||
c.gtk_overlay_add_overlay(@ptrCast(self.overlay), label);
|
|
||||||
self.url_widget = label;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clipboardRequest(
|
pub fn clipboardRequest(
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
label.url-overlay {
|
label.url-overlay {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
label.url-overlay:hover {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
label.url-overlay.hidden {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user