feat(electrobun): native C resize library (Wails pattern)
New: agor-pty/native/agor_resize.c — C shared library that: - Connects button-press-event on GtkWindow + WebView children in C - Stores mouseButton, xroot, yroot, dragTime from real GTK events - Exports agor_resize_start(edge) for Bun FFI Build: gcc -shared -fPIC -o libagor-resize.so agor_resize.c $(pkg-config --cflags --libs gtk+-3.0) New: ui-electrobun/src/bun/native-resize.ts — Bun FFI wrapper App.svelte: simplified to just edge detection + RPC call
This commit is contained in:
parent
de40bcbcac
commit
178e560068
5 changed files with 244 additions and 62 deletions
134
agor-pty/native/agor_resize.c
Normal file
134
agor-pty/native/agor_resize.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/**
|
||||
* libagor-resize.so — Native GTK resize handler for Electrobun.
|
||||
*
|
||||
* Connects button-press-event on the GtkWindow in C (not JSCallback).
|
||||
* Stores mouse state from the real GTK event. Exports start_resize(edge)
|
||||
* for Bun FFI to call — uses the stored event data for begin_resize_drag.
|
||||
*
|
||||
* This is the Wails pattern adapted for Electrobun/Bun.
|
||||
*
|
||||
* Build: gcc -shared -fPIC -o libagor-resize.so agor_resize.c \
|
||||
* $(pkg-config --cflags --libs gtk+-3.0)
|
||||
*/
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Stored mouse state from the last button-press event */
|
||||
static gdouble stored_xroot = 0.0;
|
||||
static gdouble stored_yroot = 0.0;
|
||||
static guint32 stored_time = 0;
|
||||
static guint stored_button = 1;
|
||||
static GtkWindow *stored_window = NULL;
|
||||
|
||||
/* Border width for hit-test (pixels) */
|
||||
static int border_width = 8;
|
||||
|
||||
/**
|
||||
* GTK button-press-event handler — stores mouse state for later use.
|
||||
* Connected directly in C — no JSCallback boundary crossing.
|
||||
* Returns FALSE to let the event propagate to WebKitGTK normally.
|
||||
*/
|
||||
static gboolean
|
||||
on_button_press(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
|
||||
{
|
||||
if (event == NULL) return FALSE;
|
||||
if (event->button == 3) return FALSE; /* Skip right-click */
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
|
||||
stored_xroot = event->x_root;
|
||||
stored_yroot = event->y_root;
|
||||
stored_time = event->time;
|
||||
stored_button = event->button;
|
||||
}
|
||||
return FALSE; /* Propagate — WebKitGTK still processes the event */
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize: connect button-press-event on the GtkWindow.
|
||||
* Call ONCE after window creation from Bun FFI.
|
||||
*
|
||||
* @param window_ptr GtkWindow* (from Electrobun's mainWindow.ptr)
|
||||
* @param border Border width in pixels for edge detection
|
||||
*/
|
||||
void agor_resize_init(void *window_ptr, int border)
|
||||
{
|
||||
if (!GTK_IS_WINDOW(window_ptr)) {
|
||||
fprintf(stderr, "[agor-resize] ERROR: not a GtkWindow: %p\n", window_ptr);
|
||||
return;
|
||||
}
|
||||
|
||||
stored_window = GTK_WINDOW(window_ptr);
|
||||
border_width = border > 0 ? border : 8;
|
||||
|
||||
/* Add event masks */
|
||||
gtk_widget_add_events(GTK_WIDGET(stored_window),
|
||||
GDK_POINTER_MOTION_MASK |
|
||||
GDK_BUTTON_PRESS_MASK |
|
||||
GDK_BUTTON1_MOTION_MASK);
|
||||
|
||||
/* Connect button-press on the window — fires even when WebView covers everything
|
||||
because we also connect on the WebView child below */
|
||||
g_signal_connect(stored_window, "button-press-event",
|
||||
G_CALLBACK(on_button_press), NULL);
|
||||
|
||||
/* Walk down to find the WebView and connect there too */
|
||||
GtkWidget *child = gtk_bin_get_child(GTK_BIN(stored_window));
|
||||
while (child && GTK_IS_BIN(child)) {
|
||||
g_signal_connect(child, "button-press-event",
|
||||
G_CALLBACK(on_button_press), NULL);
|
||||
child = gtk_bin_get_child(GTK_BIN(child));
|
||||
}
|
||||
|
||||
fprintf(stderr, "[agor-resize] Initialized: window=%p border=%d\n",
|
||||
window_ptr, border_width);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a resize drag using the stored mouse state.
|
||||
* Call from Bun FFI when JS detects a mousedown in the border zone.
|
||||
*
|
||||
* @param edge GdkWindowEdge value (0=NW, 1=N, 2=NE, 3=W, 4=E, 5=SW, 6=S, 7=SE)
|
||||
* @return 1 on success, 0 on failure
|
||||
*/
|
||||
int agor_resize_start(int edge)
|
||||
{
|
||||
if (!stored_window) {
|
||||
fprintf(stderr, "[agor-resize] ERROR: not initialized\n");
|
||||
return 0;
|
||||
}
|
||||
if (edge < 0 || edge > 7) {
|
||||
fprintf(stderr, "[agor-resize] ERROR: invalid edge %d\n", edge);
|
||||
return 0;
|
||||
}
|
||||
if (stored_time == 0) {
|
||||
fprintf(stderr, "[agor-resize] ERROR: no stored event (click first)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "[agor-resize] begin_resize_drag edge=%d btn=%u xy=(%.0f,%.0f) t=%u\n",
|
||||
edge, stored_button, stored_xroot, stored_yroot, stored_time);
|
||||
|
||||
gtk_window_begin_resize_drag(
|
||||
stored_window,
|
||||
(GdkWindowEdge)edge,
|
||||
stored_button,
|
||||
(gint)stored_xroot,
|
||||
(gint)stored_yroot,
|
||||
stored_time
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stored mouse position (for debugging).
|
||||
*/
|
||||
void agor_resize_get_state(double *out_x, double *out_y, unsigned int *out_time, unsigned int *out_button)
|
||||
{
|
||||
if (out_x) *out_x = stored_xroot;
|
||||
if (out_y) *out_y = stored_yroot;
|
||||
if (out_time) *out_time = stored_time;
|
||||
if (out_button) *out_button = stored_button;
|
||||
}
|
||||
BIN
agor-pty/native/libagor-resize.so
Executable file
BIN
agor-pty/native/libagor-resize.so
Executable file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue