Как установить положение окна wayland на экране?

Я не знаю, как установить положение окна wayland на экране.

Похоже, это как-то настраивается, потому что на моем ПК окно находится в повторяющемся месте.

Я попробовал решение в ​​Как установить положение поверхности клиента Wayland на фоне Weston?

Но это приводит к сбою моего 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;
}


person Ophir Carmi    schedule 29.04.2021    source источник
comment
Я скомпилировал и запустил, как вы написали; но это дает мне Can't connect to display ?!   -  person Programmer    schedule 01.05.2021
comment
Пожалуйста, уточните: в заголовке говорится, что вы хотите переместить окно, но в своем сообщении вы говорите, что хотите переместить изображение.   -  person Programmer    schedule 01.05.2021
comment
вам нужно использовать Wayland в качестве диспетчера экрана. если вы используете ubuntu, вам нужно выйти из системы, а при входе в систему выбрать wayland в настройках.   -  person Ophir Carmi    schedule 01.05.2021
comment
Я хочу переместить окно. Изображение находится в окне. Это просто пример.   -  person Ophir Carmi    schedule 01.05.2021
comment
Ладно, это было не так ясно…   -  person Programmer    schedule 01.05.2021
comment
Согласно этому должно быть достаточно изменить числа в wl_surface_attach(surface, buffer, 0, 0); : The x and y arguments specify the location of the new pending buffer's upper left corner, relative to the current buffer's upper left corner, in surface-local coordinates. Пожалуйста, посмотрите, поможет ли это (я не нашел способа проверить это на своей машине), если да, я сделаю это официальным ответом.   -  person Programmer    schedule 02.05.2021
comment
Куда мне его положить? Вы можете видеть, что он уже есть в моем коде. Я пробовал несколько мест, и ничего не изменилось.   -  person Ophir Carmi    schedule 02.05.2021
comment
Как вы сказали, он уже есть в вашей функции redraw. Я просто хочу, чтобы вы изменили wl_surface_attach(surface, buffer, 0, 0); на wl_surface_attach(surface, buffer, 100, 100); и посмотрели, будет ли это иметь какой-либо эффект. Если нет, попробуйте сделать то же самое в своей функции create_window.   -  person Programmer    schedule 02.05.2021
comment
это уже пробовал   -  person Ophir Carmi    schedule 02.05.2021
comment
Если вы можете заставить свое изображение быть нарисованным на подповерхности вместо поверхности верхнего уровня, вы можете использовать wl_subsurface_set_position   -  person Programmer    schedule 02.05.2021
comment
у вас есть рабочий код для этого подповерхностного решения?   -  person Ophir Carmi    schedule 02.05.2021
comment
Нет, извините, потому что я вообще не знаком с Wayland! покраснел Но я добавил ссылку на пример кода в свой ответ   -  person Programmer    schedule 02.05.2021


Ответы (1)


В соответствии с это, окна верхнего уровня не могут перемещаться в Wayland, можно перемещать только подповерхности. Итак: то, что вы пытаетесь сделать, невозможно. Если вам действительно нужно переместить окно, вам придется переключиться на Xlib или, что еще лучше, использовать фреймворк с графическим интерфейсом, такой как Qt5 или Gtk+ 3. Единственный вариант, который у вас есть с Wayland, — это сделать верхний уровень размером с экран. , создайте подповерхность с изображением и переместите эту подповерхность на верхний уровень, поскольку это возможно в Wayland. Вы можете найти пример создания подповерхностей в этот код GitHub.

person Programmer    schedule 02.05.2021