Implement WINGs dialog rendering infrastructure

- wl_client_reparent: create child frame_buf for WINGs views, connect
  backing pixman image so widgets paint into the scene graph
- View lookup table: map synthetic IDs to W_View* for event dispatch
- render_wl_pixmap_copy: detect view IDs and copy into backing image
- W_ViewCommitBacking callback: commit frame_buf after WINGs paint
- WMHandleEvent: use view table in Wayland mode (was always NULL)
- wtextfield.c paintCursor: use render backend draw_line instead of
  XDrawLine (crash fix for Run dialog)
This commit is contained in:
Levi Neely 2026-05-13 19:33:26 +02:00
parent 531dcf8235
commit 1d0b82eed5
5 changed files with 180 additions and 5 deletions

View File

@ -212,7 +212,8 @@ int WMHandleEvent(WMEvent * event)
XEvent *xev = (XEvent *)event->_x11_raw;
view = W_GetViewForXWindow(xev->xany.display, (Window)window);
} else {
view = NULL;
extern W_View *W_GetViewForWindow(Window id);
view = W_GetViewForWindow((Window)window);
}
if (!view) {

View File

@ -45,7 +45,16 @@ render_wl_pixmap_copy(void *rctx, WMDrawable src, WMDrawable dst,
{
(void)rctx;
pixman_image_t *s = (pixman_image_t *)src;
pixman_image_t *d = (pixman_image_t *)dst;
pixman_image_t *d;
/* If dst is a WINGs view ID, look up its backing image */
if ((unsigned long)dst >= 0x20000000 && (unsigned long)dst < 0x30000000) {
extern void *W_GetViewBacking(unsigned long id);
d = (pixman_image_t *)W_GetViewBacking((unsigned long)dst);
if (!d) return; /* no backing store yet */
} else {
d = (pixman_image_t *)dst;
}
pixman_image_composite32(PIXMAN_OP_SRC, s, NULL, d,
sx, sy, 0, 0, dx, dy, w, h);
}

View File

@ -716,8 +716,13 @@ static void paintCursor(TextField * tPtr)
printf("%d %d\n",cx,tPtr->cursorPosition);
*/
XDrawLine(screen->display, tPtr->view->window, screen->xorGC,
cx, tPtr->offsetWidth, cx, tPtr->view->size.height - tPtr->offsetWidth - 1);
{
const W_RenderBackend *R = screen->renderBackend;
void *rctx = screen->renderBackendCtx;
R->draw_line(rctx, (WMDrawable)tPtr->view->window, screen->black,
cx, tPtr->offsetWidth, cx,
tPtr->view->size.height - tPtr->offsetWidth - 1);
}
W_SetPreeditPositon(tPtr->view, cx, 0);

View File

@ -11,6 +11,83 @@
#define WL_VIEW_ID_BASE 0x20000000
static unsigned int wl_view_next_id = WL_VIEW_ID_BASE;
/* Callback set by WM backend to commit frame_buf after paint */
void (*W_ViewCommitBackingFn)(unsigned long id) = NULL;
/* Simple view lookup table (ID → W_View*) */
#define VIEW_TABLE_SIZE 256
static struct { Window id; W_View *view; void *backing; } view_table[VIEW_TABLE_SIZE];
static void view_table_put(Window id, W_View *view)
{
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
if (view_table[slot].id == 0 || view_table[slot].id == id) {
view_table[slot].id = id;
view_table[slot].view = view;
return;
}
}
}
W_View *W_GetViewForWindow(Window id)
{
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
if (view_table[slot].id == id)
return view_table[slot].view;
if (view_table[slot].id == 0)
return NULL;
}
return NULL;
}
/* Get/set backing pixman image for a view ID */
void *W_GetViewBacking(Window id)
{
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
if (view_table[slot].id == id)
return view_table[slot].backing;
if (view_table[slot].id == 0)
return NULL;
}
return NULL;
}
void W_SetViewBacking(Window id, void *img)
{
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
if (view_table[slot].id == id) {
view_table[slot].backing = img;
return;
}
if (view_table[slot].id == 0)
return;
}
}
static void view_table_remove(Window id)
{
unsigned idx = ((unsigned)id) % VIEW_TABLE_SIZE;
for (int i = 0; i < VIEW_TABLE_SIZE; i++) {
unsigned slot = (idx + i) % VIEW_TABLE_SIZE;
if (view_table[slot].id == id) {
view_table[slot].id = 0;
view_table[slot].view = NULL;
view_table[slot].backing = NULL;
return;
}
if (view_table[slot].id == 0)
return;
}
}
static void *wl_screen_init(W_Screen *scr)
{
(void)scr;
@ -27,6 +104,7 @@ static void wl_create_root(void *vctx, W_View *view)
(void)vctx;
view->window = (Window)wl_view_next_id++;
view_table_put(view->window, view);
/* Default screen size — the WM backend will update this */
view->size.width = 1920;
view->size.height = 1080;
@ -38,6 +116,7 @@ static void wl_realize(void *vctx, W_View *view)
/* Assign a synthetic ID so W_DispatchMessage doesn't skip this view */
view->window = (Window)wl_view_next_id++;
view_table_put(view->window, view);
}
static void wl_noop(void *vctx, W_View *view)
@ -117,6 +196,11 @@ static void wl_redisplay(void *vctx, W_View *view)
ev._x11_raw = NULL;
WMHandleEvent(&ev);
/* Notify WM backend to commit the view's backing buffer */
extern void (*W_ViewCommitBackingFn)(unsigned long id);
if (W_ViewCommitBackingFn)
W_ViewCommitBackingFn((unsigned long)view->window);
}
static WMPoint wl_get_screen_position(void *vctx, W_View *view)

View File

@ -2071,6 +2071,12 @@ wl_display_open(const char *name)
* when the output fires (for nested Wayland, new_output fires during
* wlr_backend_start via the host compositor roundtrip). */
wl_state.scene = wlr_scene_create();
/* Register commit callback for WINGs views (defined later in file) */
{
extern void (*W_ViewCommitBackingFn)(unsigned long id);
extern void wl_view_commit_backing_impl(unsigned long id);
W_ViewCommitBackingFn = wl_view_commit_backing_impl;
}
if (wl_state.scene)
wwarning("wl_backend: scene graph created");
else
@ -5707,7 +5713,77 @@ wl_client_adopt_attributes(WNativeWindow win, unsigned long event_mask)
static void
wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y)
{ (void)client; (void)new_parent; (void)x; (void)y; }
{
/* For WINGs internal windows: create a child frame_buf so the dialog
* content is visible in the scene graph. */
if (client >= 0x20000000 && new_parent >= 0x10000000) {
/* client is a WINGs view ID, new_parent is a frame_buf */
struct wl_frame_buf *parent_fb = frame_buf_find(new_parent);
if (!parent_fb) return;
/* Check if we already have a frame_buf for this client */
struct wl_frame_buf *existing = frame_buf_find(client);
if (existing) {
/* Just update parent and position */
existing->parent_id = new_parent;
existing->rel_x = x;
existing->rel_y = y;
existing->x = parent_fb->x + x;
existing->y = parent_fb->y + y;
if (existing->scene_buf)
wlr_scene_node_set_position(&existing->scene_buf->node,
existing->x, existing->y);
return;
}
/* Create a new frame_buf for this WINGs view.
* We don't know the size yet — use parent's content area. */
int w = parent_fb->width;
int h = parent_fb->height - y;
if (w <= 0) w = 1;
if (h <= 0) h = 1;
struct wl_frame_buf *fb = wmalloc(sizeof(*fb));
memset(fb, 0, sizeof(*fb));
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0);
if (!fb->image) { wfree(fb); return; }
wlr_buffer_init(&fb->base, &frame_buf_impl, w, h);
fb->id = client; /* use the WINGs view ID directly */
fb->parent_id = new_parent;
fb->rel_x = x;
fb->rel_y = y;
fb->x = parent_fb->x + x;
fb->y = parent_fb->y + y;
fb->width = w;
fb->height = h;
if (wl_state.scene) {
fb->scene_buf = wlr_scene_buffer_create(&wl_state.scene->tree,
&fb->base);
if (fb->scene_buf) {
wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y);
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
}
}
wl_list_insert(&wl_state.frame_list, &fb->link);
/* Connect the WINGs view's backing store to this frame_buf's image */
extern void W_SetViewBacking(unsigned long id, void *img);
W_SetViewBacking((unsigned long)client, fb->image);
}
}
/* Called by WINGs after a view repaints — commit its frame_buf to scene graph */
void wl_view_commit_backing_impl(unsigned long id)
{
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)id);
if (fb && fb->scene_buf)
wlr_scene_buffer_set_buffer(fb->scene_buf, &fb->base);
}
static void
wl_client_synth_configure(WNativeWindow client_win,