Implement frame button rendering (close/iconify icons)

Add wl_frame_paint_button which renders button icons from XPM data
into the parent frame buffer. Called both from the vtable slot and
from wl_frame_paint during titlebar rendering. Uses PRED_CLOSE_XPM
and PRED_ICONIFY_XPM parsed lazily via RGetImageFromXPMData.

Also removes XEvent from all WFrameWindow callbacks (on_click_left,
on_click_right, on_dblclick_right, on_mousedown_resizebar) — they
now take WMEvent*.
This commit is contained in:
Levi Neely 2026-05-13 17:46:21 +02:00
parent 1af95d539f
commit 784fcfbfb2
1 changed files with 90 additions and 3 deletions

View File

@ -203,6 +203,7 @@
#include <WINGs/WINGsP.h>
/* ------------------------------------------------------------------ */
#include <WINGs/WMEvent.h>
#include "../../def_pixmaps.h"
struct W_Screen;
struct W_View;
void W_WL_EnqueueEvent(struct W_Screen *scr, const WMEvent *ev, struct W_View *target);
@ -495,6 +496,10 @@ struct wl_compositor_state {
* wl_event_loop_run() after the startup pump thread stops (to avoid racing
* with the pump thread's frame-timer callback on the scene graph). */
WScreen *dock_pending_scr;
/* Button icon RImages (parsed from XPM on first use) */
RImage *btn_close_img;
RImage *btn_iconify_img;
RImage *btn_kill_img;
};
static struct wl_compositor_state wl_state;
@ -3681,6 +3686,9 @@ wl_frame_configure(WNativeWindow win, int x, int y, int width, int height)
}
}
static void wl_frame_paint_button(WCoreWindow *button, WTexture *texture,
unsigned long color, WPixmap *image, int pushed);
/*
* wl_frame_paint — render the entire frame decoration into the pixman buffer.
*
@ -3781,6 +3789,22 @@ wl_frame_paint(struct WFrameWindow *fwin)
}
}
/* --- Titlebar buttons --- */
if (fwin->titlebar && fwin->top_width > 0) {
if (fwin->left_button && !fwin->flags.hide_left_button &&
!fwin->flags.lbutton_dont_fit)
wl_frame_paint_button(fwin->left_button,
fwin->title_texture[state],
WMColorPixel(fwin->title_color[state]),
fwin->lbutton_image, False);
if (fwin->right_button && !fwin->flags.hide_right_button &&
!fwin->flags.rbutton_dont_fit)
wl_frame_paint_button(fwin->right_button,
fwin->title_texture[state],
WMColorPixel(fwin->title_color[state]),
fwin->rbutton_image, False);
}
/* --- Resizebar --- */
if (fwin->resizebar && fwin->bottom_width > 0) {
int rb_y = total_h - fwin->bottom_width;
@ -6209,9 +6233,72 @@ static void wl_noop_frame_alloc_border_pixel(unsigned long colormap,
static void wl_noop_frame_update_texture(struct WFrameWindow *fwin) { (void)fwin; }
static void wl_noop_frame_paint_button(WCoreWindow *button, WTexture *texture,
static void wl_frame_paint_button(WCoreWindow *button, WTexture *texture,
unsigned long color, WPixmap *image, int pushed)
{ (void)button; (void)texture; (void)color; (void)image; (void)pushed; }
{
(void)texture; (void)color; (void)image;
WFrameWindow *fwin = (WFrameWindow *)button->descriptor.parent;
if (!fwin || !fwin->core)
return;
struct wl_frame_buf *frame_fb = frame_buf_find(fwin->core->window);
struct wl_frame_buf *btn_fb = frame_buf_find(button->window);
if (!frame_fb || !frame_fb->image || !btn_fb)
return;
int bx = btn_fb->rel_x;
int by = btn_fb->rel_y;
int bw = btn_fb->width;
int bh = btn_fb->height;
/* Determine which icon to use */
RImage *icon = NULL;
if (button == fwin->right_button) {
if (!wl_state.btn_close_img)
wl_state.btn_close_img = RGetImageFromXPMData(
button->screen_ptr->rcontext, PRED_CLOSE_XPM);
icon = wl_state.btn_close_img;
} else if (button == fwin->left_button) {
if (!wl_state.btn_iconify_img)
wl_state.btn_iconify_img = RGetImageFromXPMData(
button->screen_ptr->rcontext, PRED_ICONIFY_XPM);
icon = wl_state.btn_iconify_img;
}
if (!icon)
return;
/* Blit icon centered in button area */
uint32_t *dst = pixman_image_get_data(frame_fb->image);
int dst_stride = pixman_image_get_stride(frame_fb->image) / 4;
int ix = bx + (bw - icon->width) / 2 + (pushed ? 1 : 0);
int iy = by + (bh - icon->height) / 2 + (pushed ? 1 : 0);
for (int y = 0; y < icon->height; y++) {
int dy = iy + y;
if (dy < 0 || dy >= frame_fb->height) continue;
uint32_t *dst_row = dst + dy * dst_stride;
for (int x = 0; x < icon->width; x++) {
int dx = ix + x;
if (dx < 0 || dx >= frame_fb->width) continue;
unsigned char r, g, b, a;
if (icon->format == RRGBAFormat) {
int off = (y * icon->width + x) * 4;
r = icon->data[off]; g = icon->data[off+1];
b = icon->data[off+2]; a = icon->data[off+3];
} else {
int off = (y * icon->width + x) * 3;
r = icon->data[off]; g = icon->data[off+1];
b = icon->data[off+2]; a = 255;
}
if (a == 0) continue; /* transparent */
dst_row[dx] = ((uint32_t)a << 24) | ((uint32_t)r << 16) |
((uint32_t)g << 8) | (uint32_t)b;
}
}
if (frame_fb->scene_buf)
wlr_scene_buffer_set_buffer(frame_fb->scene_buf, &frame_fb->base);
}
static void wl_noop_netwm_init(WScreen *scr) { (void)scr; }
static void wl_noop_netwm_cleanup(WScreen *scr) { (void)scr; }
@ -6978,7 +7065,7 @@ const WMBackend wl_backend = {
.texture_free_gc = wl_texture_free_gc,
.frame_alloc_border_pixel = wl_noop_frame_alloc_border_pixel,
.frame_update_texture = wl_noop_frame_update_texture,
.frame_paint_button = wl_noop_frame_paint_button,
.frame_paint_button = wl_frame_paint_button,
.netwm_init = wl_noop_netwm_init,
.netwm_cleanup = wl_noop_netwm_cleanup,
.netwm_update_desktop = wl_noop_netwm_update_desktop,