如何在屏幕上设置航路窗口的位置?

问题描述

我不知道如何设置 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,&registry_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 中找到有关如何创建次表面的示例。