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

Oph*_*rmi 8 c wayland

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

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

我尝试了如何在 Weston 背景中设置 Wayland 客户端表面的位置?

但它使我的 Ubuntu 18.04 崩溃(让我退出)。

我写了一个在窗口中显示图像的示例。图像已显示,但我希望能够以编程方式设置其在屏幕上的位置。原始图像在这里

编译用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;
}

Run Code Online (Sandbox Code Playgroud)

小智 6

这应该可行(至少在 Centos 上可行,在 Centos Stream 8 和 9 上进行了测试)。您可以在脚本中简单地编写这些步骤,甚至可以将其绑定到一个键,以防您将其移动到给定位置(左上角、右上角、\xe2\x80\xa6,就像我一样):

\n
    \n
  1. 安装 gnome 扩展“Window Calls”(可以通过 Web 浏览器完成)

    \n
  2. \n
  3. 找到焦点下的windowId并将其存储在$wid变量中,例如:

    \n
    window_list=$(gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell/Extensions/Windows --method org.gnome.Shell.Extensions.Windows.List)\nwid=$(echo "${window_list:2:-3}" | jq -c \'.[] | select (.focus == true) | .id \')\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
  5. 现在将窗口移动到任何所需位置,如下所示(示例):

    \n
    x=500\ny=275\ngdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell/Extensions/Windows --method org.gnome.Shell.Extensions.Windows.Move ${wid} $x $y\n
    Run Code Online (Sandbox Code Playgroud)\n
  6. \n
\n


Pro*_*mer 4

据此 Wayland 中的顶层窗口不能移动,只能移动次表面。所以:你想做的事是不可能的。如果您确实必须移动窗口,则必须切换到 Xlib,或者更好的是,使用 Qt5 或 Gtk+ 3 等 GUI 框架。 Wayland 的唯一选择是使顶层与屏幕一样大,使用图像创建一个地下表面,并将该地下表面移动到顶层, 在 Wayland 中是可能的。您可以在Weston 合成器的 subsurface-test.c 文件中找到有关如何创建次表面的示例。