问题描述
我不知道如何设置 wayland
窗口在屏幕上的位置。
它似乎是以某种方式设置的,因为在我的 PC 上,窗口似乎位于重复的位置。
我在 How to set position of a Wayland client's surface in Weston background?
中尝试了解决方案但它使我的 Ubuntu 18.04 崩溃(让我退出)。
我写了一个在窗口中显示图像的例子。图像已显示,但我希望能够以编程方式在屏幕上设置其位置。原始图像为 here。
使用 gcc wayland_example.cpp -lwayland-client -o wayland_example
编译
用./wayland_example <path_to_image>
运行
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <memory.h>
#include <wayland-client.h>
static struct wl_display *display = nullptr;
static struct wl_compositor *compositor = nullptr;
static struct wl_surface *surface;
static struct wl_shell *shell;
static struct wl_shell_surface *shell_surface;
static struct wl_shm *shm;
static struct wl_buffer *buffer;
static struct wl_callback *frame_callback;
static struct wl_registry *registry;
void *shm_data;
uint32_t *im_ptr;
static int w = 0;
static int h = 0;
static void handle_ping(__attribute__((unused)) void *data,struct wl_shell_surface *in_shell_surface,uint32_t serial) {
wl_shell_surface_pong(in_shell_surface,serial);
}
static void handle_configure(__attribute__((unused)) void *data,__attribute__((unused)) struct wl_shell_surface *in_shell_surface,__attribute__((unused)) uint32_t edges,__attribute__((unused)) int width,__attribute__((unused)) int height) {}
static void handle_popup_done(__attribute__((unused)) void *data,__attribute__((unused)) struct wl_shell_surface *in_shell_surface) {}
static const struct wl_shell_surface_listener kShellSurfaceListener = {
handle_ping,handle_configure,handle_popup_done};
static int set_cloexec_or_close(int fd) {
int flags;
if (fd == -1) {
return -1;
}
flags = fcntl(fd,F_GETFD);
if (flags == -1) {
goto err;
}
if (fcntl(fd,F_SETFD,flags | FD_CLOEXEC) == -1) {
goto err;
}
return fd;
err:
close(fd);
return -1;
}
static int create_tmpfile_cloexec(char *tmpname) {
int fd;
#ifdef HAVE_MKOstemP
fd = mkostemp(tmpname,O_CLOEXEC);
if (fd >= 0) {
unlink(tmpname);
}
#else /* HAVE_MKOstemP */
fd = mkstemp(tmpname);
if (fd >= 0) {
fd = set_cloexec_or_close(fd);
unlink(tmpname);
}
#endif /* WAYLAND */
return fd;
}
/*
* Create a new,unique,anonymous file of the given size,and
* return the file descriptor for it. The file descriptor is set
* CLOEXEC. The file is immediately suitable for mmap()'ing
* the given size at offset zero.
*
* The file should not have a permanent backing store like a disk,* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
*
* The file name is deleted from the file system.
*
* The file is suitable for buffer sharing between processes by
* transmitting the file descriptor over Unix sockets using the
* SCM_RIGHTS methods.
*/
static int os_create_anonymous_file(off_t size) {
static const char kTemplate1[] = "/weston-shared-XXXXXX";
const char *path = getenv("XDG_RUNTIME_DIR");
if (!path) {
errno = ENOENT;
return -1;
}
size_t total_len = strlen(path) + sizeof(kTemplate1);
char *name = reinterpret_cast<char *>(malloc(total_len));
if (!name) {
return -1;
}
snprintf(name,total_len,"%s%s",path,kTemplate1);
int fd = create_tmpfile_cloexec(name);
free(name);
if (fd < 0) {
return -1;
}
if (ftruncate(fd,size) < 0) {
close(fd);
return -1;
}
return fd;
}
static void paint_pixels() {
uint32_t *pixel = reinterpret_cast<uint32_t *>(shm_data);
memcpy(pixel,im_ptr,w * h * 4);
}
static void redraw(__attribute__((unused)) void *data,__attribute__((unused)) struct wl_callback *callback,__attribute__((unused)) uint32_t time);
static const struct wl_callback_listener kFrameListener = {redraw};
static void redraw(__attribute__((unused)) void *data,__attribute__((unused)) uint32_t time) {
wl_callback_destroy(frame_callback);
wl_surface_damage(surface,w,h);
paint_pixels();
frame_callback = wl_surface_frame(surface);
wl_surface_attach(surface,buffer,0);
wl_callback_add_listener(frame_callback,&kFrameListener,nullptr);
wl_surface_commit(surface);
}
static struct wl_buffer *create_buffer() {
struct wl_shm_pool *pool;
int stride = w * 4; // 4 bytes per pixel
int size = stride * h;
int fd;
struct wl_buffer *buff;
fd = os_create_anonymous_file(size);
if (fd < 0) {
printf("creating a buffer file for %d B Failed\n",size);
exit(1);
}
shm_data = mmap(nullptr,size,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if (shm_data == MAP_Failed) {
printf("mmap Failed\n");
close(fd);
exit(1);
}
pool = wl_shm_create_pool(shm,size);
buff = wl_shm_pool_create_buffer(pool,h,stride,WL_SHM_FORMAT_XRGB8888);
wl_shm_pool_destroy(pool);
return buff;
}
static void create_window() {
buffer = create_buffer();
wl_surface_attach(surface,0);
// wl_surface_damage(surface,WIDTH,HEIGHT);
wl_surface_commit(surface);
}
static void shm_format(__attribute__((unused)) void *data,__attribute__((unused)) struct wl_shm *wl_shm,__attribute__((unused)) uint32_t format) {}
struct wl_shm_listener shm_listener = {shm_format};
static void global_registry_handler(__attribute__((unused)) void *data,struct wl_registry *in_registry,uint32_t id,const char *interface,__attribute__((unused)) uint32_t version) {
if (strcmp(interface,"wl_compositor") == 0) {
compositor =
(struct wl_compositor *)wl_registry_bind(in_registry,id,&wl_compositor_interface,1);
} else if (strcmp(interface,"wl_shell") == 0) {
shell = (struct wl_shell *)wl_registry_bind(in_registry,&wl_shell_interface,"wl_shm") == 0) {
shm = (struct wl_shm *)wl_registry_bind(in_registry,&wl_shm_interface,1);
wl_shm_add_listener(shm,&shm_listener,nullptr);
}
}
static void global_registry_remover(__attribute__((unused)) void *data,__attribute__((unused)) struct wl_registry *in_registry,__attribute__((unused)) uint32_t id) {}
static const struct wl_registry_listener registry_listener = {global_registry_handler,global_registry_remover};
int main(int argc,char **argv) {
w = 640;
h = 480;
im_ptr = (uint32_t *)malloc(w * h * 4);
FILE *f = fopen(argv[1],"rb");
fread(im_ptr,w * h * 4,1,f);
fclose(f);
display = wl_display_connect(nullptr);
if (nullptr == display) {
printf("Can't connect to display\n");
exit(1);
}
printf("connected to display\n");
registry = wl_display_get_registry(display);
wl_registry_add_listener(registry,®istry_listener,nullptr);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (nullptr == compositor) {
printf("Can't find compositor\n");
exit(1);
} else {
printf("Found compositor\n");
}
surface = wl_compositor_create_surface(compositor);
if (nullptr == surface) {
printf("Can't create surface\n");
exit(1);
} else {
printf("Created surface\n");
}
shell_surface = wl_shell_get_shell_surface(shell,surface);
if (nullptr == shell_surface) {
printf("Can't create shell surface\n");
exit(1);
} else {
printf("Created shell surface\n");
}
wl_shell_surface_set_toplevel(shell_surface);
wl_shell_surface_add_listener(shell_surface,&kShellSurfaceListener,nullptr);
frame_callback = wl_surface_frame(surface);
wl_callback_add_listener(frame_callback,nullptr);
create_window();
redraw(nullptr,nullptr,0);
if (wl_display_dispatch(display) == -1) {
return 1;
}
getchar();
wl_display_disconnect(display);
free(registry);
registry = nullptr;
free(im_ptr);
return 0;
}
解决方法
根据this,顶层窗口不能在Wayland中移动,只能移动次表面。所以:你想要做的事情是不可能的。如果你真的需要移动窗口,你必须切换到 Xlib,或者更好的是使用 GUI 框架,如 Qt5 或 Gtk+ 3。Wayland 唯一的选择是使顶层与屏幕一样大,用图像创建一个子表面并在顶层移动该子表面,因为 在 Wayland 中是可能的。您可以在 this GitHub code 中找到有关如何创建次表面的示例。