diff --git a/src/Surface.zig b/src/Surface.zig index ac4991f5e..7e5e13a19 100644 --- a/src/Surface.zig +++ b/src/Surface.zig @@ -138,6 +138,9 @@ const Mouse = struct { /// True if the mouse is hidden hidden: bool = false, + + /// True if the mouse position is currently over a link. + over_link: bool = false, }; /// The configuration that a surface has, this is copied from the main @@ -2059,18 +2062,21 @@ pub fn cursorPosCallback( // Always show the mouse again if it is hidden if (self.mouse.hidden) self.showMouse(); + // The mouse position in the viewport + const pos_vp = self.posToViewport(pos.x, pos.y); + // We are reading/writing state for the remainder self.renderer_state.mutex.lock(); defer self.renderer_state.mutex.unlock(); + // Update our mouse state + self.renderer_state.mouse.point = pos_vp; + // If we have an inspector, we need to always record position information if (self.inspector) |insp| { insp.mouse.last_xpos = pos.x; insp.mouse.last_ypos = pos.y; - - const point = self.posToViewport(pos.x, pos.y); - insp.mouse.last_point = point.toScreen(&self.io.terminal.screen); - + insp.mouse.last_point = pos_vp.toScreen(&self.io.terminal.screen); try self.queueRender(); } @@ -2115,8 +2121,7 @@ pub fn cursorPosCallback( } // Convert to points - const viewport_point = self.posToViewport(pos.x, pos.y); - const screen_point = viewport_point.toScreen(&self.io.terminal.screen); + const screen_point = pos_vp.toScreen(&self.io.terminal.screen); // Handle dragging depending on click count switch (self.mouse.left_click_count) { @@ -2130,12 +2135,14 @@ pub fn cursorPosCallback( } // Handle link hovering - // TODO: update render state with mouse pos - // TODO: unsure if resetting cursor logic is correct if (try self.linkAtPos(pos)) |_| { + self.mouse.over_link = true; try self.rt_surface.setMouseShape(.pointer); - } else { + try self.queueRender(); + } else if (self.mouse.over_link) { + self.mouse.over_link = false; try self.rt_surface.setMouseShape(self.io.terminal.mouse_shape); + try self.queueRender(); } } diff --git a/src/renderer/Metal.zig b/src/renderer/Metal.zig index 76afaf459..205f7eafc 100644 --- a/src/renderer/Metal.zig +++ b/src/renderer/Metal.zig @@ -566,6 +566,7 @@ pub fn updateFrame( bg: terminal.color.RGB, selection: ?terminal.Selection, screen: terminal.Screen, + mouse: renderer.State.Mouse, preedit: ?renderer.State.Preedit, cursor_style: ?renderer.CursorStyle, }; @@ -633,6 +634,7 @@ pub fn updateFrame( .bg = self.background_color, .selection = selection, .screen = screen_copy, + .mouse = state.mouse, .preedit = if (cursor_style != null) state.preedit else null, .cursor_style = cursor_style, }; @@ -643,6 +645,7 @@ pub fn updateFrame( try self.rebuildCells( critical.selection, &critical.screen, + critical.mouse, critical.preedit, critical.cursor_style, ); @@ -1365,6 +1368,7 @@ fn rebuildCells( self: *Metal, term_selection: ?terminal.Selection, screen: *terminal.Screen, + mouse: renderer.State.Mouse, preedit: ?renderer.State.Preedit, cursor_style_: ?renderer.CursorStyle, ) !void { @@ -1391,7 +1395,7 @@ fn rebuildCells( var link_match_set = try self.config.links.matchSet( arena_alloc, screen, - .{}, // TODO: mouse hover point + mouse.point orelse .{}, ); // Determine our x/y range for preedit. We don't want to render anything diff --git a/src/renderer/State.zig b/src/renderer/State.zig index 55332c2d4..bde0f0f52 100644 --- a/src/renderer/State.zig +++ b/src/renderer/State.zig @@ -29,7 +29,12 @@ preedit: ?Preedit = null, /// need about the mouse. mouse: Mouse = .{}, -pub const Mouse = struct {}; +pub const Mouse = struct { + /// The point on the viewport where the mouse currently is. We use + /// viewport points to avoid the complexity of mapping the mouse to + /// the renderer state. + point: ?terminal.point.Viewport = null, +}; /// The pre-edit state. See Surface.preeditCallback for more information. pub const Preedit = struct {