wayland: implement appicon dock dots and launching stipple

Replace the no-op wl_noop_appicon_paint_dock_dots with a real
implementation that draws:
- 3 white dots with black shadow for docked+not-running icons
- Checkerboard dimming (stipple) for launching icons

Dot geometry matches the X11 backend: positioned at 4m/9m/14m
horizontally, icon_size-6m vertically (m = icon_size/64, min 1).
This commit is contained in:
lkn 2026-06-21 18:19:21 +02:00
parent 8f45001ffc
commit 6611dd4853
2 changed files with 64 additions and 3 deletions

View File

@ -249,6 +249,67 @@ void wl_clip_icon_paint(WAppIcon *aicon)
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
}
void wl_appicon_paint_dock_dots(WAppIcon *aicon, void *wapp_ptr)
{
WApplication *wapp = (WApplication *)wapp_ptr;
if (!aicon || !aicon->icon || !aicon->icon->core)
return;
struct wl_frame_buf *fb = frame_buf_find((WNativeWindow)aicon->icon->core->window);
if (!fb || !fb->image)
return;
int size = wPreferences.icon_size;
uint32_t *data = (uint32_t *)pixman_image_get_data(fb->image);
int stride = pixman_image_get_stride(fb->image) / 4;
int m = size / 64;
if (m < 1) m = 1;
/* Docked + not running + has command: draw 3 dots near bottom */
if (aicon->docked && !aicon->running && aicon->command != NULL) {
int dy = size - (6 * m);
int dots_x[3] = { 4*m, 9*m, 14*m };
for (int d = 0; d < 3; d++) {
int dx = dots_x[d];
/* Black shadow (offset +1,+1) */
for (int row = dy+1; row < dy+1 + 2*m && row < size; row++)
for (int col = dx+1; col < dx+1 + 3*m && col < size; col++)
data[row * stride + col] = 0xFF000000;
/* White dot */
for (int row = dy; row < dy + 2*m && row < size; row++)
for (int col = dx; col < dx + 3*m && col < size; col++)
data[row * stride + col] = 0xFFFFFFFF;
}
}
#ifdef HIDDENDOT
if (wapp && wapp->flags.hidden) {
int dy = size - (6 * m);
/* Draw only first dot (7px width) */
for (int row = dy; row < dy + 2*m && row < size; row++)
for (int col = 0; col < 7 && col < size; col++)
data[row * stride + col] = 0xFFFFFFFF;
}
#else
(void)wapp;
#endif
/* Launching: stipple (darken every other pixel) */
if (aicon->launching) {
for (int row = 0; row < size && row < fb->height; row++) {
for (int col = (row & 1); col < size && col < fb->width; col += 2) {
uint32_t px = data[row * stride + col];
uint32_t r = ((px >> 16) & 0xFF) >> 1;
uint32_t g = ((px >> 8) & 0xFF) >> 1;
uint32_t b = (px & 0xFF) >> 1;
data[row * stride + col] = (px & 0xFF000000) | (r << 16) | (g << 8) | b;
}
}
}
wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL);
}
void wl_drawer_icon_paint(WAppIcon *aicon)
{
if (!aicon || !aicon->icon || !aicon->icon->core)

View File

@ -219,8 +219,8 @@ WScreen *wl_noop_screen_for_window(WNativeWindow window)
const char *mask_path, WMNativeCursor *cursor_out)
{ (void)scr; (void)bitmap_path; (void)mask_path; (void)cursor_out; return 0; }
void wl_noop_cursor_free(WMNativeCursor cursor) { (void)cursor; }
void wl_noop_cursor_set(WNativeWindow window, WMNativeCursor cursor) { (void)window; (void)cursor; }void wl_noop_appicon_paint_dock_dots(WAppIcon *aicon, void *wapp)
{ (void)aicon; (void)wapp; }
void wl_noop_cursor_set(WNativeWindow window, WMNativeCursor cursor) { (void)window; (void)cursor; }
void wl_appicon_paint_dock_dots(WAppIcon *aicon, void *wapp);
int wl_noop_pixmap_get_size(unsigned long drawable, unsigned int *w, unsigned int *h, unsigned int *depth)
{ (void)drawable; *w = 0; *h = 0; *depth = 0; return 0; }
@ -497,7 +497,7 @@ const WMBackend wl_backend = {
.cursor_free = wl_noop_cursor_free,
.cursor_set = wl_noop_cursor_set,
.pointer_change_cursor = wl_pointer_change_cursor,
.appicon_paint_dock_dots = wl_noop_appicon_paint_dock_dots,
.appicon_paint_dock_dots = wl_appicon_paint_dock_dots,
.pixmap_get_size = wl_noop_pixmap_get_size,
.icon_paint_title_bg = wl_noop_icon_paint_title_bg,
.icon_select_paint = wl_noop_icon_select_paint,