wayland: implement kaboom animation for dock icon removal
Splits icon into PIECE_SIZE tiles, animates them falling with gravity using a wl_event_loop timer and a single scene buffer.
This commit is contained in:
parent
976bcce34c
commit
146f41008d
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,210 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/interfaces/wlr_buffer.h>
|
||||
#include <pixman.h>
|
||||
#include <drm_fourcc.h>
|
||||
#include "../../wconfig.h"
|
||||
#include "../../screen.h"
|
||||
#include "../../window.h"
|
||||
#include "wl_types.h"
|
||||
|
||||
#ifdef NORMAL_ICON_KABOOM
|
||||
|
||||
#define PIECE_SIZE ICON_KABOOM_PIECE_SIZE
|
||||
#define ANIM_FRAMES 12
|
||||
#define ANIM_INTERVAL_MS 30
|
||||
#define GRAVITY 2
|
||||
|
||||
struct kaboom_piece {
|
||||
int x, y;
|
||||
int vx, vy;
|
||||
uint32_t pixels[PIECE_SIZE * PIECE_SIZE];
|
||||
};
|
||||
|
||||
struct kaboom_state {
|
||||
struct wlr_scene_tree *tree;
|
||||
struct wlr_scene_buffer *scene_buf;
|
||||
struct wlr_buffer base;
|
||||
pixman_image_t *image;
|
||||
struct wl_event_source *timer;
|
||||
struct kaboom_piece *pieces;
|
||||
int npieces;
|
||||
int width, height;
|
||||
int frame;
|
||||
};
|
||||
|
||||
static void kaboom_destroy(struct kaboom_state *state)
|
||||
{
|
||||
if (state->timer)
|
||||
wl_event_source_remove(state->timer);
|
||||
if (state->tree)
|
||||
wlr_scene_node_destroy(&state->tree->node);
|
||||
if (state->image)
|
||||
pixman_image_unref(state->image);
|
||||
wlr_buffer_drop(&state->base);
|
||||
free(state->pieces);
|
||||
free(state);
|
||||
}
|
||||
|
||||
static bool kaboom_buf_begin_data_ptr_access(struct wlr_buffer *buf,
|
||||
uint32_t flags, void **data, uint32_t *format, size_t *stride)
|
||||
{
|
||||
struct kaboom_state *state = wl_container_of(buf, state, base);
|
||||
(void)flags;
|
||||
*data = pixman_image_get_data(state->image);
|
||||
*format = DRM_FORMAT_ARGB8888;
|
||||
*stride = pixman_image_get_stride(state->image);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void kaboom_buf_end_data_ptr_access(struct wlr_buffer *buf)
|
||||
{
|
||||
(void)buf;
|
||||
}
|
||||
|
||||
static void kaboom_buf_destroy(struct wlr_buffer *buf)
|
||||
{
|
||||
(void)buf;
|
||||
}
|
||||
|
||||
static const struct wlr_buffer_impl kaboom_buf_impl = {
|
||||
.destroy = kaboom_buf_destroy,
|
||||
.begin_data_ptr_access = kaboom_buf_begin_data_ptr_access,
|
||||
.end_data_ptr_access = kaboom_buf_end_data_ptr_access,
|
||||
};
|
||||
|
||||
static void kaboom_render(struct kaboom_state *state)
|
||||
{
|
||||
/* Clear to transparent */
|
||||
uint32_t *dst = pixman_image_get_data(state->image);
|
||||
int stride = pixman_image_get_stride(state->image) / 4;
|
||||
memset(dst, 0, stride * 4 * state->height);
|
||||
|
||||
/* Draw each piece at its current position */
|
||||
for (int i = 0; i < state->npieces; i++) {
|
||||
struct kaboom_piece *p = &state->pieces[i];
|
||||
for (int py = 0; py < PIECE_SIZE; py++) {
|
||||
int dy = p->y + py;
|
||||
if (dy < 0 || dy >= state->height) continue;
|
||||
for (int px = 0; px < PIECE_SIZE; px++) {
|
||||
int dx = p->x + px;
|
||||
if (dx < 0 || dx >= state->width) continue;
|
||||
dst[dy * stride + dx] = p->pixels[py * PIECE_SIZE + px];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int kaboom_timer_cb(void *data)
|
||||
{
|
||||
struct kaboom_state *state = data;
|
||||
state->frame++;
|
||||
|
||||
if (state->frame >= ANIM_FRAMES) {
|
||||
kaboom_destroy(state);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Update piece positions */
|
||||
for (int i = 0; i < state->npieces; i++) {
|
||||
struct kaboom_piece *p = &state->pieces[i];
|
||||
p->vy += GRAVITY;
|
||||
p->x += p->vx;
|
||||
p->y += p->vy;
|
||||
}
|
||||
|
||||
kaboom_render(state);
|
||||
wlr_scene_buffer_set_buffer_with_damage(state->scene_buf, &state->base, NULL);
|
||||
wl_event_source_timer_update(state->timer, ANIM_INTERVAL_MS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void wl_do_kaboom(WScreen *scr, WNativeWindow win, int x, int y)
|
||||
{
|
||||
(void)scr;
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (!fb || !fb->image || !wl_state.scene)
|
||||
return;
|
||||
|
||||
int w = fb->width;
|
||||
int h = fb->height;
|
||||
int cols = w / PIECE_SIZE;
|
||||
int rows = h / PIECE_SIZE;
|
||||
int npieces = cols * rows;
|
||||
if (npieces <= 0)
|
||||
return;
|
||||
|
||||
struct kaboom_state *state = calloc(1, sizeof(*state));
|
||||
if (!state) return;
|
||||
|
||||
state->pieces = calloc(npieces, sizeof(struct kaboom_piece));
|
||||
if (!state->pieces) { free(state); return; }
|
||||
state->npieces = npieces;
|
||||
state->width = w;
|
||||
state->height = h;
|
||||
state->frame = 0;
|
||||
|
||||
/* Copy pixel data from icon into pieces */
|
||||
uint32_t *src = pixman_image_get_data(fb->image);
|
||||
int src_stride = pixman_image_get_stride(fb->image) / 4;
|
||||
for (int r = 0; r < rows; r++) {
|
||||
for (int c = 0; c < cols; c++) {
|
||||
struct kaboom_piece *p = &state->pieces[r * cols + c];
|
||||
p->x = c * PIECE_SIZE;
|
||||
p->y = r * PIECE_SIZE;
|
||||
/* Random velocity: horizontal spread, slight upward */
|
||||
p->vx = (rand() % 7) - 3;
|
||||
p->vy = -(rand() % 4) - 1;
|
||||
for (int py = 0; py < PIECE_SIZE; py++) {
|
||||
for (int px = 0; px < PIECE_SIZE; px++) {
|
||||
int sx = c * PIECE_SIZE + px;
|
||||
int sy = r * PIECE_SIZE + py;
|
||||
if (sx < w && sy < h)
|
||||
p->pixels[py * PIECE_SIZE + px] = src[sy * src_stride + sx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Create scene buffer for animation */
|
||||
state->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0);
|
||||
if (!state->image) { free(state->pieces); free(state); return; }
|
||||
|
||||
wlr_buffer_init(&state->base, &kaboom_buf_impl, w, h);
|
||||
|
||||
struct wlr_scene_tree *parent = wl_state.level_trees[WL_LAYER_OVERLAY]
|
||||
? wl_state.level_trees[WL_LAYER_OVERLAY] : &wl_state.scene->tree;
|
||||
state->tree = wlr_scene_tree_create(parent);
|
||||
if (!state->tree) { kaboom_destroy(state); return; }
|
||||
wlr_scene_node_set_position(&state->tree->node, x, y);
|
||||
|
||||
state->scene_buf = wlr_scene_buffer_create(state->tree, &state->base);
|
||||
if (!state->scene_buf) { kaboom_destroy(state); return; }
|
||||
|
||||
/* Render first frame (original positions) and hide original icon */
|
||||
kaboom_render(state);
|
||||
wlr_scene_buffer_set_buffer_with_damage(state->scene_buf, &state->base, NULL);
|
||||
if (fb->tree)
|
||||
wlr_scene_node_set_enabled(&fb->tree->node, false);
|
||||
else if (fb->scene_buf)
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
||||
|
||||
/* Start animation timer */
|
||||
struct wl_event_loop *loop = wl_display_get_event_loop(wl_state.display);
|
||||
state->timer = wl_event_loop_add_timer(loop, kaboom_timer_cb, state);
|
||||
wl_event_source_timer_update(state->timer, ANIM_INTERVAL_MS);
|
||||
}
|
||||
|
||||
#else /* !NORMAL_ICON_KABOOM */
|
||||
|
||||
void wl_do_kaboom(WScreen *scr, WNativeWindow win, int x, int y)
|
||||
{
|
||||
(void)scr; (void)win; (void)x; (void)y;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -490,7 +490,7 @@ const WMBackend wl_backend = {
|
|||
.clip_icon_paint = wl_clip_icon_paint,
|
||||
.drawer_icon_paint = wl_drawer_icon_paint,
|
||||
.balloon_init = wl_balloon_init,
|
||||
.do_kaboom = wl_noop_do_kaboom,
|
||||
.do_kaboom = wl_do_kaboom,
|
||||
.menu_paint_entry = wl_menu_paint_entry,
|
||||
.menu_draw_frame = wl_menu_draw_frame,
|
||||
.draw_bevel = wl_noop_draw_bevel,
|
||||
|
|
|
|||
|
|
@ -521,6 +521,7 @@ void fb_attach_tree_listener(struct wl_frame_buf *fb);
|
|||
void fb_attach_scene_buf_listener(struct wl_frame_buf *fb);
|
||||
void wl_frame_paint_button(WCoreWindow *button, WTexture *texture, unsigned long color, WPixmap *image, int pushed);
|
||||
unsigned long wl_atom_intern(const char *name);
|
||||
void wl_do_kaboom(WScreen *scr, WNativeWindow win, int x, int y);
|
||||
|
||||
/* Signalfd module declarations (extracted to wl_signalfd.c) */
|
||||
int wl_signalfd_handler(int fd, uint32_t mask, void *data);
|
||||
|
|
|
|||
Loading…
Reference in New Issue