diff --git a/src/backend/wayland/wl_framebuf.c b/src/backend/wayland/wl_framebuf.c index de9c716..d52ee77 100644 --- a/src/backend/wayland/wl_framebuf.c +++ b/src/backend/wayland/wl_framebuf.c @@ -10,6 +10,8 @@ #include #include #include +#include +#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); + } + } + } +} diff --git a/src/backend/wayland/wl_stubs.c b/src/backend/wayland/wl_stubs.c index 5c504e9..a4d5dd2 100644 --- a/src/backend/wayland/wl_stubs.c +++ b/src/backend/wayland/wl_stubs.c @@ -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; }