vtgl

terminal emulator implemented in OpenGL
git clone anongit@rnpnr.xyz:vtgl.git
Log | Files | Refs | Feed | LICENSE

Commit: 29dd100505556b43d27fd440fbee7e7201c88e67
Parent: fec440a921cd85c312ff0d1dfded51e45c4e6320
Author: Randy Palamar
Date:   Thu,  7 Nov 2024 08:09:28 -0700

platform_x11: support primary selection

Diffstat:
Mplatform_linux_x11.c | 53++++++++++++++++++++++++++++++++++++++++++++++-------
Mutil.c | 7+++++++
Mvtgl.c | 22++++++++++++++++++++++
Mvtgl.h | 9+++++++++
4 files changed, 84 insertions(+), 7 deletions(-)

diff --git a/platform_linux_x11.c b/platform_linux_x11.c @@ -2,6 +2,16 @@ #define GL_GLEXT_PROTOTYPES 1 #include <GLFW/glfw3.h> +/* TODO: fix glfw */ +typedef void *RROutput; +typedef void *RRCrtc; +typedef void *Display; +typedef void *Window; + +#define GLFW_EXPOSE_NATIVE_X11 +#define GLFW_NATIVE_INCLUDE_NONE +#include <GLFW/glfw3native.h> + #include "util.h" #include "vtgl.h" @@ -22,11 +32,12 @@ static void *libhandle; /* TODO: cleanup */ typedef void reset_terminal_fn(TerminalMemory *); -#define LIB_FNS \ - X(debug_begin_frame) \ - X(debug_end_frame) \ - X(reset_terminal) \ - X(vtgl_initialize) \ +#define LIB_FNS \ + X(debug_begin_frame) \ + X(debug_end_frame) \ + X(reset_terminal) \ + X(vtgl_active_selection) \ + X(vtgl_initialize) \ X(vtgl_frame_step) #define X(name) static name ## _fn *name; @@ -295,6 +306,22 @@ update_input(GLFWwindow *win, TerminalInput *input) input->mouse_buttons[i].transitions = 0; } +static PLATFORM_GET_SELECTION_FN(x11_get_selection) +{ + /* NOTE: this does a bunch of extra copying and other garbage. both GLFW and X11 are + * at fault. The API is designed to do what the terminal wants and not be constrained + * by GLFW and X11 garbage */ + b32 result = 0; + if (buffer) { + char *selection = (char *)glfwGetX11SelectionString(); + if (selection) { + stream_push_s8(buffer, c_str_to_s8(selection)); + result = !buffer->errors; + } + } + return result; +} + static void usage(char *argv0, Stream *err) { @@ -325,9 +352,10 @@ main(i32 argc, char *argv[], char *envp[]) term_memory.platform_api.read = posix_read; term_memory.platform_api.write = posix_write; term_memory.platform_api.allocate_ring_buffer = posix_allocate_ring_buffer; + term_memory.platform_api.get_selection = x11_get_selection; - Arena error_arena = os_new_arena(MEGABYTE / 4); - Stream error_stream = arena_stream(error_arena); + Arena platform_arena = os_new_arena(2 * MEGABYTE); + Stream error_stream = stream_alloc(&platform_arena, MEGABYTE / 4); iv2 cells = {.x = -1, .y = -1}; @@ -418,6 +446,7 @@ main(i32 argc, char *argv[], char *envp[]) reset_terminal(&term_memory); } + Range last_sel = {0}; f64 last_time = os_get_time(); while (!glfwWindowShouldClose(window)) { update_input(window, &input); @@ -445,6 +474,16 @@ main(i32 argc, char *argv[], char *envp[]) vtgl_frame_step(&term_memory, &input); + Range current_sel = vtgl_active_selection(&term_memory, 0); + if (is_valid_range(current_sel) && !equal_range(current_sel, last_sel)) { + Stream buf = arena_stream(platform_arena); + vtgl_active_selection(&term_memory, &buf); + stream_push_byte(&buf, 0); + if (!buf.errors) + glfwSetX11SelectionString((c8 *)buf.buf); + last_sel = current_sel; + } + debug_end_frame(&term_memory); glfwSwapBuffers(window); diff --git a/util.c b/util.c @@ -44,6 +44,13 @@ is_valid_range(Range r) } static b32 +equal_range(Range a, Range b) +{ + b32 result = equal_iv2(a.start, b.start) && equal_iv2(a.end, b.end); + return result; +} + +static b32 point_in_rect(v2 point, Rect rect) { v2 max = {.x = rect.pos.x + rect.size.w, .y = rect.pos.y + rect.size.h}; diff --git a/vtgl.c b/vtgl.c @@ -30,6 +30,14 @@ clear_colour(void) glClear(GL_COLOR_BUFFER_BIT); } +/* TODO: move this elsewhere */ +static b32 +pressed_this_frame(ButtonState *button) +{ + b32 result = button->ended_down && button->transitions; + return result; +} + static void set_projection_matrix(GLCtx *gl) { @@ -754,6 +762,12 @@ handle_keybindings(Term *t, TerminalInput *input, PlatformAPI *platform) scroll(t, a); } } + + if (pressed_this_frame(input->mouse_buttons + MOUSE_MIDDLE)) { + Stream buffer = arena_stream(t->arena_for_frame); + if (platform->get_selection(&buffer)) + platform->write(t->child, stream_to_s8(&buffer), 0); + } } static void @@ -913,6 +927,14 @@ DEBUG_EXPORT VTGL_INITIALIZE_FN(vtgl_initialize) return requested_size; } +DEBUG_EXPORT VTGL_ACTIVE_SELECTION_FN(vtgl_active_selection) +{ + Term *t = memory->memory; + Range result = t->selection.range; + if (out) stream_push_selection(out, t->views + t->view_idx, t->selection.range, t->size.w); + return result; +} + DEBUG_EXPORT VTGL_FRAME_STEP_FN(vtgl_frame_step) { BEGIN_TIMED_BLOCK(); diff --git a/vtgl.h b/vtgl.h @@ -11,10 +11,16 @@ typedef PLATFORM_WRITE_FN(platform_write_fn); #define PLATFORM_READ_FN(name) size name(iptr file, s8 buffer, size offset) typedef PLATFORM_READ_FN(platform_read_fn); +#define PLATFORM_GET_SELECTION_FN(name) b32 name(Stream *buffer) +typedef PLATFORM_GET_SELECTION_FN(platform_get_selection_fn); +PLATFORM_GET_SELECTION_FN(get_selection_stub) {return 0;}; + typedef struct { platform_allocate_ring_buffer_fn *allocate_ring_buffer; platform_read_fn *read; platform_write_fn *write; + + platform_get_selection_fn *get_selection; } PlatformAPI; enum mouse_buttons { @@ -71,4 +77,7 @@ typedef VTGL_INITIALIZE_FN(vtgl_initialize_fn); #define VTGL_FRAME_STEP_FN(name) void name(TerminalMemory *memory, TerminalInput *input) typedef VTGL_FRAME_STEP_FN(vtgl_frame_step_fn); +#define VTGL_ACTIVE_SELECTION_FN(name) Range name(TerminalMemory *memory, Stream *out) +typedef VTGL_ACTIVE_SELECTION_FN(vtgl_active_selection_fn); + #endif /*_VTGL_H_ */