Wayland入门15:个性化鼠标

系列索引地址:Wayland入门系列教程索引

上一篇:Wayland入门14:鼠标操作

运行一下上一篇的鼠标操作程序,会发现,如果之前鼠标是箭头那么进入wayland程序窗口后就是箭头,如果进入前是输入模式那么进入wayland程序窗口后也是输入模式鼠标图标。

现在我们来修改一下在wayland窗口中的鼠标图标

纯色

先来试试纯色,以下在上一篇鼠标操作的基础上修改

先将14的代码复制过来。

首先,窗口或者说纹理都是一层一层的图片叠加起来的,如果某个区域的图片更新了,就只更新此区域的图片。那么我们需要在最底层的窗口上添加一个surface用于显示鼠标图标。方法和创建基本窗口类似。

声明用到的变量

1
2
3
4
struct wl_surface *pointer_surface;
struct wl_buffer *pointer_buffer;

void *pointer_shm_data;

鼠标图标用到的buffer和surface,以及用来操作buffer的pointer_shm_data

创建鼠标图标缓冲区

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
static struct wl_buffer *
create_pointer_buffer()
{
struct wl_shm_pool *pool;
int stride = 40 * 4; // 4 bytes per pixel
int size = stride * 40;
int fd;
struct wl_buffer *buff;

fd = os_create_anonymous_file(size);
if (fd < 0)
{
fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size);
exit(1);
}

pointer_shm_data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (pointer_shm_data == MAP_FAILED)
{
fprintf(stderr, "mmap failed: %m\n");
close(fd);
exit(1);
}

pool = wl_shm_create_pool(shm, fd, size);
buff = wl_shm_pool_create_buffer(pool, 0,
40 ,40,
stride,
WL_SHM_FORMAT_XRGB8888);
//wl_buffer_add_listener(buffer, &buffer_listener, buffer);
wl_shm_pool_destroy(pool);
return buff;
}

鼠标图标大小为40 * 40,创建一个文件fd,将文件fd映射到pointer_shm_data上,然后通过文件fd和shm(和窗口用的是同一个)创建内存池

当鼠标进入到窗口范围时,设置鼠标图标

1
2
3
4
5
6
7
8
9
10
static void
pointer_handle_enter(void *data, struct wl_pointer *pointer,
uint32_t serial, struct wl_surface *surface,
wl_fixed_t sx, wl_fixed_t sy)
{
//fprintf(stderr, "Pointer entered surface %p at %f %f\n", surface, wl_fixed_to_double(sx), wl_fixed_to_double(sy));
wl_surface_attach(pointer_surface,pointer_buffer,0,0);
wl_surface_commit(pointer_surface);
wl_pointer_set_cursor(pointer,serial,pointer_surface,20,20);
}

wl_pointer_set_cursor的最后两个参数表示鼠标点在图片的位置,本文是将其位于图片的中心点,可以将鼠标移至窗口右下角,在鼠标离开窗口的一瞬间看看鼠标图标剩余在窗口的位置是不是中心点。

在main函数使用前调用函数,因为使用了主窗口的shm变量,所以至少要在变量初始化之后调用,否则会报错

1
2
3
4
5
6
pointer_buffer = create_pointer_buffer();

uint32_t *pixel = pointer_shm_data;
for(int i=0;i<40*40;i++){
*pixel++ = 0x00ff00;//绿色
}

如果每次进入窗口就创建新buffer,一旦处理不好就容易内容泄漏,所以只在main中创建一次。

效果为:

pure

点击换色

当鼠标点击时,更改鼠标图标的颜色

图片

将鼠标图标显示为图片

因为共享内存方式图片是以RGB格式数据使用的,我们要把图片转换为rgb格式

1
ffmpeg -i 1.png 1.rgb

经过测试,只能使用带alpha的图片。

然后打开图片,同时将代码中的尺寸相关变量修改一下。

1
2
3
4
5
6
7
fd = open("./1.rgb", O_RDWR);
if (fd < 0)
{
fprintf(stderr, "creating a buffer file for %d B failed: %m\n",
size);
exit(1);
}

效果为

icon

图标是我从阿里图标库偷来的。

EGL版本只是替换了窗口显示部分,其他的代码一样。

完整代码在Wayland_Freshman中的15.custom_pointer15.custom_pointer_EGL下。

下一篇:Wayland入门16:窗口操作