mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
when losing focus, show hollow box
This commit is contained in:
@ -7,12 +7,23 @@ flat in uint mode;
|
|||||||
// background color. Otherwise, this is the foreground color.
|
// background color. Otherwise, this is the foreground color.
|
||||||
flat in vec4 color;
|
flat in vec4 color;
|
||||||
|
|
||||||
|
// The position of the cells top-left corner.
|
||||||
|
flat in vec2 screen_cell_pos;
|
||||||
|
|
||||||
|
// Position the fragment coordinate to the upper left
|
||||||
|
layout(origin_upper_left) in vec4 gl_FragCoord;
|
||||||
|
|
||||||
// Font texture
|
// Font texture
|
||||||
uniform sampler2D text;
|
uniform sampler2D text;
|
||||||
|
|
||||||
|
// Dimensions of the cell
|
||||||
|
uniform vec2 cell_size;
|
||||||
|
|
||||||
// See fragment shader
|
// See fragment shader
|
||||||
const uint MODE_BG = 1u;
|
const uint MODE_BG = 1u;
|
||||||
const uint MODE_FG = 2u;
|
const uint MODE_FG = 2u;
|
||||||
|
const uint MODE_CURSOR_RECT = 3u;
|
||||||
|
const uint MODE_CURSOR_RECT_HOLLOW = 4u;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
@ -24,5 +35,45 @@ void main() {
|
|||||||
float a = texture(text, glyph_tex_coords).r;
|
float a = texture(text, glyph_tex_coords).r;
|
||||||
gl_FragColor = vec4(color.rgb, color.a*a);
|
gl_FragColor = vec4(color.rgb, color.a*a);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MODE_CURSOR_RECT:
|
||||||
|
gl_FragColor = color;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_CURSOR_RECT_HOLLOW:
|
||||||
|
// Okay so yeah this is probably horrendously slow and a shader
|
||||||
|
// should never do this, but we only ever render a cursor for ONE
|
||||||
|
// rectangle so we take the slowdown for that one.
|
||||||
|
|
||||||
|
// Default to no color.
|
||||||
|
gl_FragColor = vec4(0., 0., 0, 0.0);
|
||||||
|
|
||||||
|
// We subtracted one from cell size because our coordinates start at 0.
|
||||||
|
// So a width of 50 means max pixel of 49.
|
||||||
|
vec2 cell_size_coords = cell_size - 1;
|
||||||
|
|
||||||
|
// Apply padding
|
||||||
|
vec2 padding = vec2(1.,1.);
|
||||||
|
cell_size_coords = cell_size_coords - (padding * 2);
|
||||||
|
vec2 screen_cell_pos_padded = screen_cell_pos + padding;
|
||||||
|
|
||||||
|
// Convert our frag coord to offset of this cell. We have to subtract
|
||||||
|
// 0.5 because the frag coord is in center pixels.
|
||||||
|
vec2 cell_frag_coord = gl_FragCoord.xy - screen_cell_pos_padded - 0.5;
|
||||||
|
|
||||||
|
// If the frag coords are in the bounds, then we color it.
|
||||||
|
const float eps = 0.1;
|
||||||
|
if (cell_frag_coord.x >= 0 && cell_frag_coord.y >= 0 &&
|
||||||
|
cell_frag_coord.x <= cell_size_coords.x &&
|
||||||
|
cell_frag_coord.y <= cell_size_coords.y) {
|
||||||
|
if (abs(cell_frag_coord.x) < eps ||
|
||||||
|
abs(cell_frag_coord.x - cell_size_coords.x) < eps ||
|
||||||
|
abs(cell_frag_coord.y) < eps ||
|
||||||
|
abs(cell_frag_coord.y - cell_size_coords.y) < eps) {
|
||||||
|
gl_FragColor = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
// NOTE: this must be kept in sync with the fragment shader
|
// NOTE: this must be kept in sync with the fragment shader
|
||||||
const uint MODE_BG = 1u;
|
const uint MODE_BG = 1u;
|
||||||
const uint MODE_FG = 2u;
|
const uint MODE_FG = 2u;
|
||||||
|
const uint MODE_CURSOR_RECT = 3u;
|
||||||
|
const uint MODE_CURSOR_RECT_HOLLOW = 4u;
|
||||||
|
|
||||||
// The grid coordinates (x, y) where x < columns and y < rows
|
// The grid coordinates (x, y) where x < columns and y < rows
|
||||||
layout (location = 0) in vec2 grid_coord;
|
layout (location = 0) in vec2 grid_coord;
|
||||||
@ -38,6 +40,10 @@ flat out vec4 color;
|
|||||||
// The x/y coordinate for the glyph representing the font.
|
// The x/y coordinate for the glyph representing the font.
|
||||||
out vec2 glyph_tex_coords;
|
out vec2 glyph_tex_coords;
|
||||||
|
|
||||||
|
// The position of the cell top-left corner in screen cords. z and w
|
||||||
|
// are width and height.
|
||||||
|
flat out vec2 screen_cell_pos;
|
||||||
|
|
||||||
// Pass the mode forward to the fragment shader.
|
// Pass the mode forward to the fragment shader.
|
||||||
flat out uint mode;
|
flat out uint mode;
|
||||||
|
|
||||||
@ -121,5 +127,24 @@ void main() {
|
|||||||
// Set our foreground color output
|
// Set our foreground color output
|
||||||
color = fg_color_in / 255.;
|
color = fg_color_in / 255.;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case MODE_CURSOR_RECT:
|
||||||
|
// Same as background since we're taking up the whole cell.
|
||||||
|
cell_pos = cell_pos + cell_size * position;
|
||||||
|
|
||||||
|
gl_Position = projection * vec4(cell_pos, 0.0, 1.0);
|
||||||
|
color = bg_color_in / 255.0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MODE_CURSOR_RECT_HOLLOW:
|
||||||
|
// Top-left position of this cell is needed for the hollow rect.
|
||||||
|
screen_cell_pos = cell_pos;
|
||||||
|
|
||||||
|
// Same as background since we're taking up the whole cell.
|
||||||
|
cell_pos = cell_pos + cell_size * position;
|
||||||
|
|
||||||
|
gl_Position = projection * vec4(cell_pos, 0.0, 1.0);
|
||||||
|
color = bg_color_in / 255.0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,6 +37,12 @@ font_atlas: FontAtlas,
|
|||||||
/// Whether the cursor is visible or not. This is used to control cursor
|
/// Whether the cursor is visible or not. This is used to control cursor
|
||||||
/// blinking.
|
/// blinking.
|
||||||
cursor_visible: bool,
|
cursor_visible: bool,
|
||||||
|
cursor_style: CursorStyle,
|
||||||
|
|
||||||
|
const CursorStyle = enum(u8) {
|
||||||
|
box = 3,
|
||||||
|
box_hollow = 4,
|
||||||
|
};
|
||||||
|
|
||||||
/// The raw structure that maps directly to the buffer sent to the vertex shader.
|
/// The raw structure that maps directly to the buffer sent to the vertex shader.
|
||||||
const GPUCell = struct {
|
const GPUCell = struct {
|
||||||
@ -211,6 +217,7 @@ pub fn init(alloc: Allocator) !Grid {
|
|||||||
.texture = tex,
|
.texture = tex,
|
||||||
.font_atlas = font,
|
.font_atlas = font,
|
||||||
.cursor_visible = true,
|
.cursor_visible = true,
|
||||||
|
.cursor_style = .box,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,7 +302,7 @@ pub fn updateCells(self: *Grid, term: Terminal) !void {
|
|||||||
// Draw the cursor
|
// Draw the cursor
|
||||||
if (self.cursor_visible) {
|
if (self.cursor_visible) {
|
||||||
self.cells.appendAssumeCapacity(.{
|
self.cells.appendAssumeCapacity(.{
|
||||||
.mode = 1,
|
.mode = @enumToInt(self.cursor_style),
|
||||||
.grid_col = @intCast(u16, term.cursor.x),
|
.grid_col = @intCast(u16, term.cursor.x),
|
||||||
.grid_row = @intCast(u16, term.cursor.y),
|
.grid_row = @intCast(u16, term.cursor.y),
|
||||||
.fg_r = 0,
|
.fg_r = 0,
|
||||||
|
@ -221,10 +221,13 @@ fn keyCallback(
|
|||||||
fn focusCallback(window: glfw.Window, focused: bool) void {
|
fn focusCallback(window: glfw.Window, focused: bool) void {
|
||||||
const win = window.getUserPointer(Window) orelse return;
|
const win = window.getUserPointer(Window) orelse return;
|
||||||
if (focused) {
|
if (focused) {
|
||||||
win.cursor_timer.start(cursorTimerCallback, 800, 800) catch unreachable;
|
|
||||||
win.wakeup = true;
|
win.wakeup = true;
|
||||||
} else {
|
win.cursor_timer.start(cursorTimerCallback, 0, 800) catch unreachable;
|
||||||
|
win.grid.cursor_style = .box;
|
||||||
win.grid.cursor_visible = false;
|
win.grid.cursor_visible = false;
|
||||||
|
} else {
|
||||||
|
win.grid.cursor_visible = true;
|
||||||
|
win.grid.cursor_style = .box_hollow;
|
||||||
win.grid.updateCells(win.terminal) catch unreachable;
|
win.grid.updateCells(win.terminal) catch unreachable;
|
||||||
win.cursor_timer.stop() catch unreachable;
|
win.cursor_timer.stop() catch unreachable;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user