decompose wl_stubs.c: move wl_frame_paint_button + wl_netwm_update_opacity to wl_framebuf.c

This commit is contained in:
Window Maker 2026-06-02 17:02:11 +02:00
parent c635fcd3fa
commit 75a4224370
2 changed files with 146 additions and 148 deletions

View File

@ -10,6 +10,8 @@
#include <wlr/types/wlr_output.h>
#include <libdrm/drm_fourcc.h>
#include <pixman.h>
#include <X11/Xlib.h>
#include "../../def_pixmaps.h"
#include "../../screen.h"
#include "../../framewin.h"
#include "../../texture.h"
@ -727,3 +729,145 @@ wl_frame_paint(struct WFrameWindow *fwin)
return 1;
}
void
wl_frame_paint_button(WCoreWindow *button, WTexture *texture,
unsigned long color, WPixmap *image, int pushed)
{
(void)texture; (void)image;
WFrameWindow *fwin = (WFrameWindow *)button->descriptor.parent;
if (!fwin || !fwin->core)
return;
struct wl_frame_buf *btn_fb = frame_buf_find(button->window);
if (!btn_fb || !btn_fb->image)
return;
int bw = btn_fb->width;
int bh = btn_fb->height;
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;
struct wl_frame_buf *tb_fb = fwin->titlebar ? frame_buf_find(fwin->titlebar->window) : NULL;
uint32_t bg_pixel = 0xFF333333;
if (tb_fb && tb_fb->image) {
uint32_t *tb_data = pixman_image_get_data(tb_fb->image);
int tb_stride = pixman_image_get_stride(tb_fb->image) / 4;
int sample_y = btn_fb->rel_y + bh / 2;
int sample_x = btn_fb->rel_x + bw / 2;
if (sample_y >= 0 && sample_y < tb_fb->height &&
sample_x >= 0 && sample_x < tb_fb->width)
bg_pixel = tb_data[sample_y * tb_stride + sample_x];
}
uint32_t fg_pixel = 0xFF000000 | ((color >> 16 & 0xFF) << 16) |
((color >> 8 & 0xFF) << 8) | (color & 0xFF);
uint32_t fill_bg = pushed ? fg_pixel : bg_pixel;
uint32_t fill_fg = pushed ? bg_pixel : fg_pixel;
uint32_t *dst = pixman_image_get_data(btn_fb->image);
int dst_stride = pixman_image_get_stride(btn_fb->image) / 4;
for (int y = 0; y < bh; y++)
for (int x = 0; x < bw; x++)
dst[y * dst_stride + x] = fill_bg;
unsigned char bg_r = (bg_pixel >> 16) & 0xFF;
unsigned char bg_g = (bg_pixel >> 8) & 0xFF;
unsigned char bg_b = bg_pixel & 0xFF;
uint32_t hi_c = 0xFF000000 | ((uint32_t)(bg_r + (255-bg_r)/3) << 16) |
((uint32_t)(bg_g + (255-bg_g)/3) << 8) | (bg_b + (255-bg_b)/3);
uint32_t lo_c = 0xFF000000 | ((uint32_t)(bg_r * 2/3) << 16) |
((uint32_t)(bg_g * 2/3) << 8) | (bg_b * 2/3);
uint32_t hi = pushed ? lo_c : hi_c;
uint32_t lo = pushed ? hi_c : lo_c;
for (int x = 0; x < bw; x++) { dst[x] = hi; dst[(bh-1) * dst_stride + x] = lo; }
for (int y = 0; y < bh; y++) { dst[y * dst_stride] = hi; dst[y * dst_stride + bw - 1] = lo; }
int ix = (bw - icon->width) / 2 + (pushed ? 1 : 0);
int iy = (bh - icon->height) / 2 + (pushed ? 1 : 0);
for (int y = 0; y < icon->height; y++) {
int dy = iy + y;
if (dy < 0 || dy >= bh) 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 >= bw) continue;
unsigned char a;
if (icon->format == RRGBAFormat)
a = icon->data[(y * icon->width + x) * 4 + 3];
else
a = 255;
if (a == 0) continue;
dst_row[dx] = fill_fg;
}
}
wlr_scene_buffer_set_buffer_with_damage(btn_fb->scene_buf, &btn_fb->base, NULL);
wlr_scene_node_set_enabled(&btn_fb->scene_buf->node, true);
wlr_scene_node_raise_to_top(&btn_fb->scene_buf->node);
}
void
wl_netwm_update_opacity(WWindow *wwin)
{
if (!wwin->frame)
return;
struct wl_frame_buf *fb = frame_buf_find(wwin->frame->core->window);
if (!fb || !fb->scene_buf)
return;
float alpha = 1.0f;
if (wl_state.x_display && wwin->client_win) {
WMNativeAtom type;
int format;
unsigned long items, rest;
unsigned char *prop = NULL;
WMNativeAtom opacity_atom = XInternAtom(wl_state.x_display,
"_NET_WM_WINDOW_OPACITY", False);
if (XGetWindowProperty(wl_state.x_display, (WNativeWindow)wwin->client_win,
opacity_atom, 0L, 1L, False, AnyPropertyType,
&type, &format, &items, &rest, &prop) == Success
&& format == 32 && items == 1 && prop) {
unsigned long val = *(unsigned long *)prop;
alpha = (float)val / (float)0xFFFFFFFF;
}
if (prop)
XFree(prop);
}
wlr_scene_buffer_set_opacity(fb->scene_buf, alpha);
struct wl_frame_buf *child;
wl_list_for_each(child, &wl_state.frame_list, link) {
if (child->parent_id == fb->id && child->scene_buf)
wlr_scene_buffer_set_opacity(child->scene_buf, alpha);
}
struct wl_toplevel_view *v;
wl_list_for_each(v, &wl_state.toplevel_list, link) {
if (v->frame_id == fb->id && v->scene_node) {
struct wlr_scene_node *node;
wl_list_for_each(node, &v->scene_node->children, link) {
if (node->type == WLR_SCENE_NODE_BUFFER)
wlr_scene_buffer_set_opacity(
wlr_scene_buffer_from_node(node), alpha);
}
}
}
}

View File

@ -39,6 +39,8 @@
/* Forward declarations */
struct wl_toplevel_view *wl_find_view_by_id(WNativeWindow id);
void wl_set_cursor_image(const char *name);
void wl_frame_paint_button(WCoreWindow *button, WTexture *texture, unsigned long color, WPixmap *image, int pushed);
void wl_netwm_update_opacity(WWindow *wwin);
extern void *W_RegisterBacking(unsigned long id, void *img);
extern void W_UnregisterBacking(unsigned long id);
@ -51,158 +53,10 @@ void wl_noop_frame_alloc_border_pixel(unsigned long colormap,
void wl_noop_frame_update_texture(struct WFrameWindow *fwin) { (void)fwin; }
void wl_frame_paint_button(WCoreWindow *button, WTexture *texture,
unsigned long color, WPixmap *image, int pushed)
{
(void)texture; (void)image;
WFrameWindow *fwin = (WFrameWindow *)button->descriptor.parent;
if (!fwin || !fwin->core)
return;
struct wl_frame_buf *btn_fb = frame_buf_find(button->window);
if (!btn_fb || !btn_fb->image)
return;
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;
/* Get titlebar background color */
struct wl_frame_buf *tb_fb = fwin->titlebar ? frame_buf_find(fwin->titlebar->window) : NULL;
uint32_t bg_pixel = 0xFF333333;
if (tb_fb && tb_fb->image) {
uint32_t *tb_data = pixman_image_get_data(tb_fb->image);
int tb_stride = pixman_image_get_stride(tb_fb->image) / 4;
int sample_y = btn_fb->rel_y + bh / 2;
int sample_x = btn_fb->rel_x + bw / 2;
if (sample_y >= 0 && sample_y < tb_fb->height &&
sample_x >= 0 && sample_x < tb_fb->width)
bg_pixel = tb_data[sample_y * tb_stride + sample_x];
}
/* Foreground = title text color; when pushed, swap fg/bg */
uint32_t fg_pixel = 0xFF000000 | ((color >> 16 & 0xFF) << 16) |
((color >> 8 & 0xFF) << 8) | (color & 0xFF);
uint32_t fill_bg = pushed ? fg_pixel : bg_pixel;
uint32_t fill_fg = pushed ? bg_pixel : fg_pixel;
uint32_t *dst = pixman_image_get_data(btn_fb->image);
int dst_stride = pixman_image_get_stride(btn_fb->image) / 4;
/* Fill background */
for (int y = 0; y < bh; y++)
for (int x = 0; x < bw; x++)
dst[y * dst_stride + x] = fill_bg;
/* Draw border bevel derived from bg color (raised normal, sunken pushed) */
unsigned char bg_r = (bg_pixel >> 16) & 0xFF;
unsigned char bg_g = (bg_pixel >> 8) & 0xFF;
unsigned char bg_b = bg_pixel & 0xFF;
uint32_t hi_c = 0xFF000000 | ((uint32_t)(bg_r + (255-bg_r)/3) << 16) |
((uint32_t)(bg_g + (255-bg_g)/3) << 8) | (bg_b + (255-bg_b)/3);
uint32_t lo_c = 0xFF000000 | ((uint32_t)(bg_r * 2/3) << 16) |
((uint32_t)(bg_g * 2/3) << 8) | (bg_b * 2/3);
uint32_t hi = pushed ? lo_c : hi_c;
uint32_t lo = pushed ? hi_c : lo_c;
for (int x = 0; x < bw; x++) { dst[x] = hi; dst[(bh-1) * dst_stride + x] = lo; }
for (int y = 0; y < bh; y++) { dst[y * dst_stride] = hi; dst[y * dst_stride + bw - 1] = lo; }
/* Blit icon centered, using fill_fg color for opaque pixels */
int ix = (bw - icon->width) / 2 + (pushed ? 1 : 0);
int iy = (bh - icon->height) / 2 + (pushed ? 1 : 0);
for (int y = 0; y < icon->height; y++) {
int dy = iy + y;
if (dy < 0 || dy >= bh) 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 >= bw) continue;
unsigned char a;
if (icon->format == RRGBAFormat)
a = icon->data[(y * icon->width + x) * 4 + 3];
else
a = 255;
if (a == 0) continue;
dst_row[dx] = fill_fg;
}
}
/* Enable and commit the button's own scene_buf */
wlr_scene_buffer_set_buffer_with_damage(btn_fb->scene_buf, &btn_fb->base, NULL);
wlr_scene_node_set_enabled(&btn_fb->scene_buf->node, true);
wlr_scene_node_raise_to_top(&btn_fb->scene_buf->node);
}
void wl_noop_netwm_init(WScreen *scr) { (void)scr; }
void wl_noop_netwm_cleanup(WScreen *scr) { (void)scr; }
void wl_noop_netwm_update_desktop(WScreen *scr) { (void)scr; }
int wl_noop_netwm_get_current_desktop(WScreen *scr) { (void)scr; return -1; }
void wl_netwm_update_opacity(WWindow *wwin)
{
if (!wwin->frame)
return;
struct wl_frame_buf *fb = frame_buf_find(wwin->frame->core->window);
if (!fb || !fb->scene_buf)
return;
float alpha = 1.0f;
if (wl_state.x_display && wwin->client_win) {
WMNativeAtom type;
int format;
unsigned long items, rest;
unsigned char *prop = NULL;
WMNativeAtom opacity_atom = XInternAtom(wl_state.x_display,
"_NET_WM_WINDOW_OPACITY", False);
if (XGetWindowProperty(wl_state.x_display, (WNativeWindow)wwin->client_win,
opacity_atom, 0L, 1L, False, AnyPropertyType,
&type, &format, &items, &rest, &prop) == Success
&& format == 32 && items == 1 && prop) {
unsigned long val = *(unsigned long *)prop;
alpha = (float)val / (float)0xFFFFFFFF;
}
if (prop)
XFree(prop);
}
wlr_scene_buffer_set_opacity(fb->scene_buf, alpha);
/* Apply to all child frame_bufs (titlebar buttons, resizebar) */
struct wl_frame_buf *child;
wl_list_for_each(child, &wl_state.frame_list, link) {
if (child->parent_id == fb->id && child->scene_buf)
wlr_scene_buffer_set_opacity(child->scene_buf, alpha);
}
/* Apply to the client surface */
struct wl_toplevel_view *v;
wl_list_for_each(v, &wl_state.toplevel_list, link) {
if (v->frame_id == fb->id && v->scene_node) {
struct wlr_scene_node *node;
wl_list_for_each(node, &v->scene_node->children, link) {
if (node->type == WLR_SCENE_NODE_BUFFER)
wlr_scene_buffer_set_opacity(
wlr_scene_buffer_from_node(node), alpha);
}
}
}
}
void wl_noop_netwm_update_actions(WWindow *wwin, int del) { (void)wwin; (void)del; }
void wl_noop_netwm_check_client_hints(WWindow *wwin, int *layer, int *workspace)
{ (void)wwin; (void)layer; (void)workspace; }