decompose wl_stubs.c: move wl_icon_paint + wl_appicon_paint to wl_icon.c

This commit is contained in:
Window Maker 2026-06-02 17:04:20 +02:00
parent 75a4224370
commit d376eec495
4 changed files with 174 additions and 322 deletions

View File

@ -198,6 +198,8 @@ wmaker_SOURCES += \
backend/wayland/wl_xwayland.c \
backend/wayland/wl_dock.c \
backend/wayland/wl_layer_shell.c \
backend/wayland/wl_handlers.c \
backend/wayland/wl_icon.c \
backend/wayland/wl_virtual_pointer.c \
backend/wayland/wl_input_fwd.c
endif

View File

@ -1644,26 +1644,6 @@ handle_idle_new_inhibitor(struct wl_listener *listener, void *data)
* to the seat so the focused Wayland client receives wl_pointer.axis events.
* Without this, scrolling is silently dropped in every Wayland client.
*/
void
handle_pointer_axis(struct wl_listener *listener, void *data)
{
(void)listener;
struct wlr_pointer_axis_event *ev = data;
if (!wl_state.seat)
return;
/* Drop axis events during a compositor grab so the grabbed window
* does not receive unexpected scroll events mid-move/resize. */
if (wl_state.grab_type)
return;
wlr_seat_pointer_notify_axis(wl_state.seat,
ev->time_msec,
ev->orientation,
ev->delta,
ev->delta_discrete,
ev->source,
ev->relative_direction);
}
/*
* Phase 30: new pointer constraint — a client requested pointer lock or
* pointer confinement (e.g. a game locking the cursor to its window).
@ -1892,158 +1872,6 @@ handle_layer_shell_new_surface(struct wl_listener *listener, void *data)
}
/* ------------------------------------------------------------------ */
void
handle_pointer_button(struct wl_listener *listener, void *data)
{
(void)listener;
struct wlr_pointer_button_event *ev = data;
if (!wl_state.seat)
return;
/* Phase 22: any button release ends an active compositor grab (move/resize).
* Type 3 (WM policy grab) is NOT ended here — the policy code calls
* pointer_ungrab itself after processing the button release event. */
if (wl_state.grab_type && wl_state.grab_type != 3 &&
ev->state == WLR_BUTTON_RELEASED) {
wwarning("wl_backend: grab ended (button release) grab_type=%d", wl_state.grab_type);
wl_grab_end();
wl_update_pointer_focus(ev->time_msec);
return;
}
/* Phase 24: click-to-focus — on button press, find the view under the
* pointer and focus + raise it via the WM policy layer.
* This mirrors what the X11 backend does via ButtonPress on frame windows. */
if (ev->state == WLR_BUTTON_PRESSED) {
double sx, sy;
struct wl_toplevel_view *view = NULL;
view_surface_at(wl_state.pointer_x, wl_state.pointer_y,
&sx, &sy, &view);
if (view) {
WObjDescriptor *desc =
wm_backend->context_find(view->id, WM_CTX_CLIENT_WIN);
if (desc && desc->parent_type == WCLASS_WINDOW) {
WWindow *wwin = (WWindow *)desc->parent;
WScreen *scr = wScreenWithNumber(0);
wSetFocusTo(scr, wwin);
/* Raise entire window assembly via tree */
if (view->frame_id) {
struct wl_frame_buf *fb = frame_buf_find(view->frame_id);
if (fb && fb->tree)
wlr_scene_node_raise_to_top(&fb->tree->node);
} else if (view->scene_node) {
wlr_scene_node_raise_to_top(&view->scene_node->node);
}
/* Also raise it in our toplevel list so view_surface_at()
* returns it first on subsequent hits. */
wl_list_remove(&view->link);
wl_list_insert(&wl_state.toplevel_list, &view->link);
}
} else {
/* No toplevel surface — check if a WINGs dialog frame_buf was clicked */
struct wl_frame_buf *hit = frame_buf_hit(wl_state.pointer_x,
wl_state.pointer_y);
if (hit) {
/* Walk up to the parent frame to find the WWindow */
WNativeWindow lookup = hit->parent_id ? hit->parent_id : hit->id;
WObjDescriptor *desc =
wm_backend->context_find(lookup, WM_CTX_CLIENT_WIN);
if (desc && desc->parent_type == WCLASS_WINDOW) {
WWindow *wwin = (WWindow *)desc->parent;
WScreen *scr = wScreenWithNumber(0);
wSetFocusTo(scr, wwin);
}
}
}
}
/* Phase A: enqueue native WMEvent for WINGs */
WMScreen *wmscr = wl_get_wmscreen();
if (wmscr) {
WMEvent wev;
memset(&wev, 0, sizeof(wev));
wev.type = (ev->state == WLR_BUTTON_PRESSED)
? WME_BUTTON_PRESS : WME_BUTTON_RELEASE;
/* Hit-test: determine which WM window was clicked.
* Use frame_buf_hit so button sub-windows (invisible to the scene
* graph because their pixels are composited into the titlebar buffer)
* are resolved to their own window IDs, letting handleButtonPress
* route the event to buttonMouseDown instead of titlebarMouseDown. */
struct wl_frame_buf *fb = frame_buf_hit(wl_state.pointer_x,
wl_state.pointer_y);
if (fb) {
wev.window = fb->id;
wev.u.button.window = fb->id;
wev.u.button.x = wl_state.pointer_x - fb->x;
wev.u.button.y = wl_state.pointer_y - fb->y;
} else {
WScreen *scr0 = wScreenWithNumber(0);
WNativeWindow root = scr0 ? scr0->root_win : (WNativeWindow)0x0FFFFFFF;
wev.window = root;
wev.u.button.window = root;
wev.u.button.x = wl_state.pointer_x;
wev.u.button.y = wl_state.pointer_y;
}
wev.u.button.time = ev->time_msec;
wev.u.button.x_root = wl_state.pointer_x;
wev.u.button.y_root = wl_state.pointer_y;
/* Linux evdev BTN_LEFT=0x110, BTN_RIGHT=0x111, BTN_MIDDLE=0x112
* Button1=1(left), Button2=2(middle), Button3=3(right) */
switch (ev->button) {
case 0x110: wev.u.button.button = 1; break;
case 0x111: wev.u.button.button = 3; break;
case 0x112: wev.u.button.button = 2; break;
default: wev.u.button.button = (ev->button - 0x110) + 1; break;
}
/* For WINGs views, resolve the child widget at click coordinates */
struct W_View *target = NULL;
if (fb && fb->id >= 0x20000000) {
extern W_View *W_GetViewForWindow(unsigned long id);
extern struct W_View *W_FindViewAtPoint(struct W_View *parent, int x, int y);
W_View *toplevel = W_GetViewForWindow((unsigned long)fb->id);
if (toplevel) {
target = W_FindViewAtPoint(toplevel,
wev.u.button.x, wev.u.button.y);
if (!target)
target = toplevel;
/* Adjust event coordinates to target view's local space */
if (target != toplevel) {
W_View *p = target;
int ox = 0, oy = 0;
while (p && p != toplevel) {
ox += p->pos.x;
oy += p->pos.y;
p = p->parent;
}
wev.u.button.x -= ox;
wev.u.button.y -= oy;
}
}
}
W_WL_EnqueueEvent(wmscr, &wev, target);
}
/* Refresh pointer focus before delivering button event.
* The last wl_update_pointer_focus call was during the most recent
* motion event. If no motion happened since then, the XWayland
* surface might not have pointer focus, causing
* wlr_seat_pointer_notify_button to be a no-op. */
wl_update_pointer_focus(ev->time_msec);
wlr_seat_pointer_notify_button(wl_state.seat, ev->time_msec,
ev->button, ev->state);
wlr_seat_pointer_notify_frame(wl_state.seat);
}
void
handle_pointer_frame(struct wl_listener *listener, void *data)
{
(void)listener; (void)data;
if (wl_state.seat)
wlr_seat_pointer_notify_frame(wl_state.seat);
}
/* ------------------------------------------------------------------ */
/* Keyboard grabs */
@ -2055,7 +1883,6 @@ handle_pointer_frame(struct wl_listener *listener, void *data)
/* Screen internals */
/* ------------------------------------------------------------------ */
int wl_screen_replace_wm(WScreen *scr) { (void)scr; return 1; }
int wl_screen_select_input(WScreen *scr, long mask) { (void)scr; (void)mask; return 1; }
void wl_screen_set_root_cursor(WScreen *scr, int cursor_id) { (void)scr; (void)cursor_id; }
void wl_screen_set_icon_sizes(WScreen *scr, int min_size, int max_size) { (void)scr; (void)min_size; (void)max_size; }

View File

@ -0,0 +1,169 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/interfaces/wlr_buffer.h>
#include <pixman.h>
#include "../../screen.h"
#include "../../framewin.h"
#include "../../window.h"
#include "../../icon.h"
#include "../../texture.h"
#include "../../misc.h"
#include "../../defaults.h"
#include "../../def_pixmaps.h"
#include "wl_types.h"
#include <WINGs/WINGsP.h>
/* Forward declarations */
struct wl_frame_buf *frame_buf_find(WNativeWindow id);
void
wl_icon_paint(WIcon *icon)
{
if (!icon || !icon->core) return;
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)icon->core->window);
if (!fb || !fb->image) return;
WScreen *scr = icon->core->screen_ptr;
if (!scr) return;
int size = wPreferences.icon_size;
RImage *tile = scr->icon_tile ? RCloneImage(scr->icon_tile) : NULL;
if (!tile) {
tile = RCreateImage(size, size, 1);
if (!tile) return;
RColor grey = {0xAE, 0xAA, 0xAE, 0xFF};
RClearImage(tile, &grey);
}
RImage *img = icon->file_image;
if (img) {
int theight = icon->show_title ? WMFontHeight(scr->icon_title_font) : 0;
unsigned w = ((unsigned)img->width > (unsigned)size) ? (unsigned)size : (unsigned)img->width;
unsigned h = ((unsigned)img->height + (unsigned)theight > (unsigned)size)
? (unsigned)(size - theight) : (unsigned)img->height;
int x = (size - (int)w) / 2;
int y = theight + (size - theight - (int)h) / 2;
int sx = ((int)img->width - (int)w) / 2;
int sy = ((int)img->height - (int)h) / 2;
RCombineArea(tile, img, sx, sy, w, h, x, y);
}
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
int stride = pixman_image_get_stride(fb->image) / 4;
unsigned char *tsrc = tile->data;
int has_alpha = (tile->format == RRGBAFormat);
for (int row = 0; row < size && row < fb->height; row++) {
for (int col = 0; col < size && col < fb->width; col++) {
int si = (row * tile->width + col) * (has_alpha ? 4 : 3);
unsigned char r = tsrc[si], g = tsrc[si+1], b = tsrc[si+2];
unsigned char a = has_alpha ? tsrc[si+3] : 0xFF;
dst[row * stride + col] = ((uint32_t)a << 24) | ((uint32_t)r << 16)
| ((uint32_t)g << 8) | (uint32_t)b;
}
}
RReleaseImage(tile);
if (icon->show_title && icon->icon_name && scr->icon_title_font) {
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
int tw = WMWidthOfString(scr->icon_title_font, icon->icon_name,
strlen(icon->icon_name));
int tx = (size - tw) / 2;
if (tx < 2) tx = 2;
WMColor *color = scr->icon_title_color;
if (color)
WMDrawString(scr->wmscreen, d, color, scr->icon_title_font,
tx, 0, icon->icon_name, strlen(icon->icon_name));
}
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
if (fb->tree)
wlr_scene_node_set_enabled(&fb->tree->node, true);
}
void
wl_appicon_show(WApplication *wapp)
{
extern void paint_app_icon(WApplication *wapp);
paint_app_icon(wapp);
}
void
wl_appicon_paint(WAppIcon *aicon)
{
WIcon *icon = aicon->icon;
if (!icon || !icon->core)
return;
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)icon->core->window);
if (!fb || !fb->image)
return;
WScreen *scr = icon->core->screen_ptr;
int size = wPreferences.icon_size;
RImage *tile = NULL;
switch (icon->tile_type) {
case TILE_CLIP: tile = scr->clip_tile ? RCloneImage(scr->clip_tile) : NULL; break;
case TILE_DRAWER: tile = scr->drawer_tile ? RCloneImage(scr->drawer_tile) : NULL; break;
default: tile = scr->icon_tile ? RCloneImage(scr->icon_tile) : NULL; break;
}
if (!tile) {
tile = RCreateImage(size, size, 1);
if (!tile) return;
RColor grey = {0xAE, 0xAA, 0xAE, 0xFF};
RClearImage(tile, &grey);
}
if (icon->file_image) {
RImage *img = icon->file_image;
int theight = icon->show_title ? WMFontHeight(scr->icon_title_font) : 0;
unsigned w = (img->width > size) ? size : img->width;
unsigned h = (img->height + theight > size) ? size - theight : img->height;
int x = (size - (int)w) / 2;
int y = theight + (size - theight - (int)h) / 2;
int sx = ((int)img->width - (int)w) / 2;
int sy = ((int)img->height - (int)h) / 2;
RCombineArea(tile, img, sx, sy, w, h, x, y);
}
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
int stride = pixman_image_get_stride(fb->image) / 4;
unsigned char *src = tile->data;
int has_alpha = (tile->format == RRGBAFormat);
for (int row = 0; row < size && row < fb->height; row++) {
for (int col = 0; col < size && col < fb->width; col++) {
int si = (row * tile->width + col) * (has_alpha ? 4 : 3);
unsigned char r = src[si], g = src[si+1], b = src[si+2];
unsigned char a = has_alpha ? src[si+3] : 0xFF;
dst[row * stride + col] = ((uint32_t)a << 24) | ((uint32_t)r << 16) |
((uint32_t)g << 8) | (uint32_t)b;
}
}
if (icon->show_title && icon->icon_name && scr->icon_title_font) {
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
int fh = WMFontHeight(scr->icon_title_font);
int tw = WMWidthOfString(scr->icon_title_font, icon->icon_name,
strlen(icon->icon_name));
int tx = (size - tw) / 2;
if (tx < 2) tx = 2;
int ty = 0;
WMColor *color = scr->icon_title_color;
if (color)
WMDrawString(scr->wmscreen, d, color, scr->icon_title_font,
tx, ty, icon->icon_name, strlen(icon->icon_name));
}
RReleaseImage(tile);
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
}

View File

@ -41,6 +41,9 @@ 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);
void wl_icon_paint(WIcon *icon);
void wl_appicon_show(WApplication *wapp);
void wl_appicon_paint(WAppIcon *aicon);
extern void *W_RegisterBacking(unsigned long id, void *img);
extern void W_UnregisterBacking(unsigned long id);
@ -167,155 +170,6 @@ void wl_noop_icon_update_pixmap(WIcon *icon) { (void)icon; }
* Called at the end of wIconPaint() in icon.c so the backend finalises the
* surface after the policy layer has set up icon->file_image etc.
*/
void
wl_icon_paint(WIcon *icon)
{
if (!icon || !icon->core) return;
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)icon->core->window);
if (!fb || !fb->image) return;
WScreen *scr = icon->core->screen_ptr;
if (!scr) return;
int size = wPreferences.icon_size;
/* --- Tile background --- */
RImage *tile = scr->icon_tile ? RCloneImage(scr->icon_tile) : NULL;
if (!tile) {
tile = RCreateImage(size, size, 1);
if (!tile) return;
RColor grey = {0xAE, 0xAA, 0xAE, 0xFF};
RClearImage(tile, &grey);
}
/* --- Composite icon image (file_image from database / NET_WM_ICON) --- */
RImage *img = icon->file_image;
if (img) {
int theight = icon->show_title ? WMFontHeight(scr->icon_title_font) : 0;
unsigned w = ((unsigned)img->width > (unsigned)size) ? (unsigned)size : (unsigned)img->width;
unsigned h = ((unsigned)img->height + (unsigned)theight > (unsigned)size)
? (unsigned)(size - theight) : (unsigned)img->height;
int x = (size - (int)w) / 2;
int y = theight + (size - theight - (int)h) / 2;
int sx = ((int)img->width - (int)w) / 2;
int sy = ((int)img->height - (int)h) / 2;
RCombineArea(tile, img, sx, sy, w, h, x, y);
}
/* --- Blit RImage (RGBA/RGB) -> pixman ARGB32 --- */
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
int stride = pixman_image_get_stride(fb->image) / 4;
unsigned char *tsrc = tile->data;
int has_alpha = (tile->format == RRGBAFormat);
for (int row = 0; row < size && row < fb->height; row++) {
for (int col = 0; col < size && col < fb->width; col++) {
int si = (row * tile->width + col) * (has_alpha ? 4 : 3);
unsigned char r = tsrc[si], g = tsrc[si+1], b = tsrc[si+2];
unsigned char a = has_alpha ? tsrc[si+3] : 0xFF;
dst[row * stride + col] = ((uint32_t)a << 24) | ((uint32_t)r << 16)
| ((uint32_t)g << 8) | (uint32_t)b;
}
}
RReleaseImage(tile);
/* --- Title text --- */
if (icon->show_title && icon->icon_name && scr->icon_title_font) {
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
int tw = WMWidthOfString(scr->icon_title_font, icon->icon_name,
strlen(icon->icon_name));
int tx = (size - tw) / 2;
if (tx < 2) tx = 2;
WMColor *color = scr->icon_title_color;
if (color)
WMDrawString(scr->wmscreen, d, color, scr->icon_title_font,
tx, 0, icon->icon_name, strlen(icon->icon_name));
}
/* --- Commit to scene graph --- */
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
if (fb->tree)
wlr_scene_node_set_enabled(&fb->tree->node, true);
}
void wl_appicon_show(WApplication *wapp) { paint_app_icon(wapp); }
void wl_appicon_paint(WAppIcon *aicon)
{
WIcon *icon = aicon->icon;
if (!icon || !icon->core)
return;
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)icon->core->window);
if (!fb || !fb->image)
return;
WScreen *scr = icon->core->screen_ptr;
int size = wPreferences.icon_size;
/* Compose the tile image */
RImage *tile = NULL;
switch (icon->tile_type) {
case TILE_CLIP: tile = scr->clip_tile ? RCloneImage(scr->clip_tile) : NULL; break;
case TILE_DRAWER: tile = scr->drawer_tile ? RCloneImage(scr->drawer_tile) : NULL; break;
default: tile = scr->icon_tile ? RCloneImage(scr->icon_tile) : NULL; break;
}
if (!tile) {
/* Fallback: solid grey */
tile = RCreateImage(size, size, 1);
if (!tile) return;
RColor grey = {0xAE, 0xAA, 0xAE, 0xFF};
RClearImage(tile, &grey);
}
/* Composite the app image on top */
if (icon->file_image) {
RImage *img = icon->file_image;
int theight = icon->show_title ? WMFontHeight(scr->icon_title_font) : 0;
unsigned w = (img->width > size) ? size : img->width;
unsigned h = (img->height + theight > size) ? size - theight : img->height;
int x = (size - (int)w) / 2;
int y = theight + (size - theight - (int)h) / 2;
int sx = ((int)img->width - (int)w) / 2;
int sy = ((int)img->height - (int)h) / 2;
RCombineArea(tile, img, sx, sy, w, h, x, y);
}
/* Blit RImage (RGBA) → pixman ARGB32 buffer */
uint32_t *dst = (uint32_t *)pixman_image_get_data(fb->image);
int stride = pixman_image_get_stride(fb->image) / 4;
unsigned char *src = tile->data;
int has_alpha = (tile->format == RRGBAFormat);
for (int row = 0; row < size && row < fb->height; row++) {
for (int col = 0; col < size && col < fb->width; col++) {
int si = (row * tile->width + col) * (has_alpha ? 4 : 3);
unsigned char r = src[si], g = src[si+1], b = src[si+2];
unsigned char a = has_alpha ? src[si+3] : 0xFF;
dst[row * stride + col] = ((uint32_t)a << 24) | ((uint32_t)r << 16) |
((uint32_t)g << 8) | (uint32_t)b;
}
}
/* Draw title text */
if (icon->show_title && icon->icon_name && scr->icon_title_font) {
WMDrawable d = (WMDrawable)(uintptr_t)fb->image;
int fh = WMFontHeight(scr->icon_title_font);
int tw = WMWidthOfString(scr->icon_title_font, icon->icon_name,
strlen(icon->icon_name));
int tx = (size - tw) / 2;
if (tx < 2) tx = 2;
int ty = 0; /* top of text area */
WMColor *color = scr->icon_title_color;
if (color)
WMDrawString(scr->wmscreen, d, color, scr->icon_title_font,
tx, ty, icon->icon_name, strlen(icon->icon_name));
}
RReleaseImage(tile);
/* Commit to scene graph */
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
}
void wl_noop_restore_desktop(WScreen *scr) { (void)scr; }
void wl_noop_wipe_desktop(WScreen *scr) { (void)scr; }