【问题标题】:How to set the position of a wayland window on the screen?如何设置 Wayland 窗口在屏幕上的位置?
【发布时间】:2021-04-29 13:26:30
【问题描述】:

我不知道如何设置wayland窗口在屏幕上的位置。

它似乎被以某种方式设置,因为在我的电脑上,窗口似乎位于重复的位置。

我尝试了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)) struct wl_callback *callback,
                   __attribute__((unused)) uint32_t time) {
  wl_callback_destroy(frame_callback);
  wl_surface_damage(surface, 0, 0, w, h);
  paint_pixels();
  frame_callback = wl_surface_frame(surface);
  wl_surface_attach(surface, buffer, 0, 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, fd, size);
  buff = wl_shm_pool_create_buffer(pool, 0, w, h, stride, WL_SHM_FORMAT_XRGB8888);
  wl_shm_pool_destroy(pool);
  return buff;
}

static void create_window() {
  buffer = create_buffer();

  wl_surface_attach(surface, buffer, 0, 0);
  // wl_surface_damage(surface, 0, 0, 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, id, &wl_shell_interface, 1);
  } else if (strcmp(interface, "wl_shm") == 0) {
    shm = (struct wl_shm *)wl_registry_bind(in_registry, id, &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, &kFrameListener, 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;
}

【问题讨论】:

  • 我按照你写的编译运行;但它给了我Can't connect to display ?!
  • 请澄清:标题说你想移动一个窗口,但在你的帖子中你说你想移动一个图像
  • 您需要使用 Wayland 作为屏幕管理器。如果您使用的是 ubuntu,则需要注销,登录时,请在设置中选择 wayland。
  • 我想移动一个窗口。图像在窗口中。这只是一个例子。
  • 好吧,还不是很清楚……

标签: c wayland


【解决方案1】:

根据this,顶层窗口不能在 Wayland 中移动,只能移动次表面。所以:你想做的事情是不可能的。如果你真的需要移动窗口,你将不得不切换到 Xlib,或者更好的是,使用 Qt5 或 Gtk+ 3 等 GUI 框架。Wayland 的唯一选择是让顶层与屏幕一样大,使用图像创建一个次表面并在顶层移动该次表面,因为 在 Wayland 中是可能的。您可以在this GitHub code 中找到有关如何创建次表面的示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-10
    • 2013-01-20
    • 2010-10-17
    相关资源
    最近更新 更多