wlroots 0.12.0

Antonin Décimo (3):
       Fix typos
       Fix incorrect format parameters
       xwayland: free server in error path
 
 Daniel De Graaf (1):
       wlr_virtual_keyboard: fix fd leak
 
 Daniel Kondor (2):
       foreign-toplevel-management: report parent toplevel
       foreign toplevel: send parent event only to clients that support it
 
 Devin J. Pohly (1):
       drm: fix uninitialized read
 
 Drew DeVault (1):
       Remove xdg-shell v6
 
 Guido Cella (1):
       render: Don't crash on 0 dimensions
 
 Ilia Bozhinov (9):
       xwayland: do not allow apps to change focus after wlroots request
       make sure to fail setting gamma on disabled outputs
       backend/wayland: destroy relative pointer when output is disconnected
       wayland: emit relative pointer events only for current pointer
       xwayland: disconnect display destroy listener even if xwayland didn't initialize
       xwayland: add set_geometry event
       backend/wayland: add touch support to the wayland backend
       xdg_shell: fix a typo
       xdg_shell: handle inert popups
 
 Isaac Freund (6):
       xdg-shell: split last-acked and current state
       layer-shell: add for_each_popup
       layer-shell: error on 0 dimension without anchors
       xdg_positioner: remove unused field
       wlr_drag: remove unused point_destroy field
       xwayland: remove unused listener
 
 Kenny Levinsen (2):
       session: Add libseat backend
       session: Add missing init to direct-freebsd
 
 Marten Ringwelski (1):
       backend/drm: Check if output is enabled before sending frame event
 
 Mykola Orliuk (5):
       backend/wayland: manage cursor for current pointer
       backend/wayland: factor out wlr_wl_seat
       backend/wayland: add error flow in create_wl_seat
       backend/wayland: fix input creation error handling
       backend/wayland: fix some keyboard/touch leaks
 
 Patrick Steinhardt (1):
       session: Don't refuse unprivileged creation of "direct" backend
 
 Roman Gilg (3):
       output-management-v1: add head identifying events
       output-management-v1: send head identifying information
       output-management-v1: send complete head state on enable change
 
 Ronan Pigott (1):
       virtual_pointer: remember current axis for axis events
 
 Rouven Czerwinski (2):
       examples: remove unnecessary gles2.h imports
       xwm: add loop detection for read_surface_parent
 
 Ryan Walklin (4):
       Implement logind session SetType method to change session type to wayland
       Also set XDG_SESSION_TYPE
       Don't set XDG_SESSION_TYPE unless logind SetType succeeds
       Quieten failure to set login session type
 
 Scott Moreau (2):
       xwm: Set _NET_WM_STATE_FOCUSED property for the focused surface
       foreign toplevel: Fix whitespace error
 
 Simon Ser (31):
       xwayland/xwm: don't insert surface in list on error
       xwayland/xwm: add prop count assert in xsurface_set_net_wm_state
       xwayland/xwm: use initializer for props in xsurface_set_wm_state
       render/gles2: make wlr_gles2_texture_from_* private
       render/gles2: keep ref to wlr_gles2_renderer in wlr_gles2_texture
       render/gles2: make push/pop debug functions take a wlr_renderer
       render/gles2: remove gles2_procs
       gamma-control-v1: fix use-after-free in gamma_control_handle_set_gamma
       examples/simple: use wlr_output_preferred_mode
       examples/simple: use wlr_renderer instead of GL
       Remove unnecessary wl_display_dispatch calls
       output: introduce wlr_output_event_commit
       output-power-management-v1: listen to output commit
       examples/dmabuf-capture: add extra roundtrip for wl_output listener
       backend/session/libseat: register log handler
       backend: remove check for _WAYLAND_DISPLAY
       backend/libinput: improve logger callback
       render: define EGL_NO_PLATFORM_SPECIFIC_TYPES (#2452)
       backend/drm: fix "a page-flip is already pending" errors on modeset
       xwayland: minor code style fixes
       xwayland: log unhandled NET_WM_STATE property changes
       gamma-control-v1: apply gamma LUT when output gets enabled
       screencopy: stop setting needs_frame flag
       backend/drm: export pending FB in export_dmabuf, if any
       output: update docs to reflect reality
       output: add when field to wlr_output_event_commit
       export-dmabuf: export DMA-BUF on output commit
       screencopy: perform DMA-BUF copy on output commit
       screencopy: send failed when copying a DMA-BUF with a region
       input-method: send modifiers in set_keyboard
       Update version to 0.12.0
 
 Tobias Langendorf (1):
       xwm: add support for xwayland minimize
 
 Tudor Brindus (11):
       examples: use `perror` instead of `fprintf` GNU %m `printf` extension
       xwayland: using %m in `wlr_log` is broken, use `wlr_log_errno` instead
       xwayland: fix use-after-free in selection handling
       xwayland: introduce WLR_XWAYLAND for specifying which Xwayland to use
       xwayland: remove stale transfers from the same requestor
       xwayland: notify requestor when we fail to respond to their request
       xwayland: fix minor typo in debug log
       types/wlr_keyboard: use bitmasks for wlr_keyboard_led and wlr_keyboard_modifier enums
       types/wlr_output_layout: use bitmask for wlr_direction
       util/edges: use bitmask for wlr_edges
       render/dmabuf: use bitmask for wlr_dmabuf_attributes_flags
 
 Valentin (2):
       Use fixed size integer type
       Fix undefined behavior
 
 nerdopolis (1):
       Accommodate for CONFIG_VT=0, all TTYs are in seat0, but not all seat0s have TTYs
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEENP+VJs/vDpejQOLkD9574OiPXkgFAl+n+t4ACgkQD9574OiP
 Xkg8TRAAopnm99XA7TE3w0UEDhXUBvlWB05fS6M4wiSNXjMp1ENW0O7PGtIbZt1Y
 /mbJQ8yAXbT0i5X7aE6iKTW8GjHoWpwaYCL3BrDb8A8Hl2s04pxSiLL2JMbHyb02
 KsCjZSbCBGldmgYOaJZl9SM5TDSyYo8xwGprkRiqK8Nz/SL75+sR4Jf/iMfaP1Rx
 qu2o87z3B1DEX+dvf0UaStJSmAb5sBmEW0X8sj8jf6Iubwsxy0BjI00AoTa2TS7k
 U1h3QuHqFy65pVg9Hwe5jPsoKVN5UqFzZNFja+91fXcjohm4gRkrnPZHCXijAl5E
 +sNSkY0SjO1ci4KSRXRTzD9X7HfA2f4yGjDEjoKorop7kUVAHQeKfFbbrKEjoYao
 aJLCFCNjT2ednZJhteYXKEodYfQov6AEirPJtw+UEDe8JgLSDZJZtXnBXKBXEeFa
 BgEzkoQiKqA4J3ToEj2fWrNMLkjfnc99vGn3tso9wfVB93sfg8lX1L9BI9CklGuD
 je6inBDRTa/RmALe1IGE4Y2PwrlmtQqHVjqDKv5MDpy65ffuYS3bH18fSLTW2cWY
 zYQmFOuj1VHxqT1noKAqTeowR691KC7JmAG2RjOZK2huP1xkijdaOVCA4bWlEqS3
 zld5pUUJ4k30UJmJIUK1Vp9eCStnPvxti1ngfuLHZ6WCe/jT8Os=
 =2poj
 -----END PGP SIGNATURE-----

Merge tag '0.12.0' into color-profiles

wlroots 0.12.0

Antonin Décimo (3):
      Fix typos
      Fix incorrect format parameters
      xwayland: free server in error path

Daniel De Graaf (1):
      wlr_virtual_keyboard: fix fd leak

Daniel Kondor (2):
      foreign-toplevel-management: report parent toplevel
      foreign toplevel: send parent event only to clients that support it

Devin J. Pohly (1):
      drm: fix uninitialized read

Drew DeVault (1):
      Remove xdg-shell v6

Guido Cella (1):
      render: Don't crash on 0 dimensions

Ilia Bozhinov (9):
      xwayland: do not allow apps to change focus after wlroots request
      make sure to fail setting gamma on disabled outputs
      backend/wayland: destroy relative pointer when output is disconnected
      wayland: emit relative pointer events only for current pointer
      xwayland: disconnect display destroy listener even if xwayland didn't initialize
      xwayland: add set_geometry event
      backend/wayland: add touch support to the wayland backend
      xdg_shell: fix a typo
      xdg_shell: handle inert popups

Isaac Freund (6):
      xdg-shell: split last-acked and current state
      layer-shell: add for_each_popup
      layer-shell: error on 0 dimension without anchors
      xdg_positioner: remove unused field
      wlr_drag: remove unused point_destroy field
      xwayland: remove unused listener

Kenny Levinsen (2):
      session: Add libseat backend
      session: Add missing init to direct-freebsd

Marten Ringwelski (1):
      backend/drm: Check if output is enabled before sending frame event

Mykola Orliuk (5):
      backend/wayland: manage cursor for current pointer
      backend/wayland: factor out wlr_wl_seat
      backend/wayland: add error flow in create_wl_seat
      backend/wayland: fix input creation error handling
      backend/wayland: fix some keyboard/touch leaks

Patrick Steinhardt (1):
      session: Don't refuse unprivileged creation of "direct" backend

Roman Gilg (3):
      output-management-v1: add head identifying events
      output-management-v1: send head identifying information
      output-management-v1: send complete head state on enable change

Ronan Pigott (1):
      virtual_pointer: remember current axis for axis events

Rouven Czerwinski (2):
      examples: remove unnecessary gles2.h imports
      xwm: add loop detection for read_surface_parent

Ryan Walklin (4):
      Implement logind session SetType method to change session type to wayland
      Also set XDG_SESSION_TYPE
      Don't set XDG_SESSION_TYPE unless logind SetType succeeds
      Quieten failure to set login session type

Scott Moreau (2):
      xwm: Set _NET_WM_STATE_FOCUSED property for the focused surface
      foreign toplevel: Fix whitespace error

Simon Ser (31):
      xwayland/xwm: don't insert surface in list on error
      xwayland/xwm: add prop count assert in xsurface_set_net_wm_state
      xwayland/xwm: use initializer for props in xsurface_set_wm_state
      render/gles2: make wlr_gles2_texture_from_* private
      render/gles2: keep ref to wlr_gles2_renderer in wlr_gles2_texture
      render/gles2: make push/pop debug functions take a wlr_renderer
      render/gles2: remove gles2_procs
      gamma-control-v1: fix use-after-free in gamma_control_handle_set_gamma
      examples/simple: use wlr_output_preferred_mode
      examples/simple: use wlr_renderer instead of GL
      Remove unnecessary wl_display_dispatch calls
      output: introduce wlr_output_event_commit
      output-power-management-v1: listen to output commit
      examples/dmabuf-capture: add extra roundtrip for wl_output listener
      backend/session/libseat: register log handler
      backend: remove check for _WAYLAND_DISPLAY
      backend/libinput: improve logger callback
      render: define EGL_NO_PLATFORM_SPECIFIC_TYPES (#2452)
      backend/drm: fix "a page-flip is already pending" errors on modeset
      xwayland: minor code style fixes
      xwayland: log unhandled NET_WM_STATE property changes
      gamma-control-v1: apply gamma LUT when output gets enabled
      screencopy: stop setting needs_frame flag
      backend/drm: export pending FB in export_dmabuf, if any
      output: update docs to reflect reality
      output: add when field to wlr_output_event_commit
      export-dmabuf: export DMA-BUF on output commit
      screencopy: perform DMA-BUF copy on output commit
      screencopy: send failed when copying a DMA-BUF with a region
      input-method: send modifiers in set_keyboard
      Update version to 0.12.0

Tobias Langendorf (1):
      xwm: add support for xwayland minimize

Tudor Brindus (11):
      examples: use `perror` instead of `fprintf` GNU %m `printf` extension
      xwayland: using %m in `wlr_log` is broken, use `wlr_log_errno` instead
      xwayland: fix use-after-free in selection handling
      xwayland: introduce WLR_XWAYLAND for specifying which Xwayland to use
      xwayland: remove stale transfers from the same requestor
      xwayland: notify requestor when we fail to respond to their request
      xwayland: fix minor typo in debug log
      types/wlr_keyboard: use bitmasks for wlr_keyboard_led and wlr_keyboard_modifier enums
      types/wlr_output_layout: use bitmask for wlr_direction
      util/edges: use bitmask for wlr_edges
      render/dmabuf: use bitmask for wlr_dmabuf_attributes_flags

Valentin (2):
      Use fixed size integer type
      Fix undefined behavior

nerdopolis (1):
      Accommodate for CONFIG_VT=0, all TTYs are in seat0, but not all seat0s have TTYs
This commit is contained in:
Devin Bayer 2021-01-21 17:39:54 +01:00
commit 9d76bca931
105 changed files with 1680 additions and 3182 deletions

View file

@ -16,7 +16,7 @@ sources:
tasks:
- setup: |
cd wlroots
meson build -Dauto_features=enabled -Dlogind=disabled -Dxcb-errors=disabled
meson build -Dauto_features=enabled -Dlogind=disabled -Dlibseat=disabled -Dxcb-errors=disabled
- build: |
cd wlroots
ninja -C build

View file

@ -12,6 +12,7 @@ packages:
- xcb-util-errors
- xcb-util-image
- xcb-util-wm
- seatd
sources:
- https://github.com/swaywm/wlroots
tasks:

View file

@ -18,6 +18,7 @@ packages:
- x11/pixman
- x11/xcb-util-errors
- x11/xcb-util-wm
- sysutils/seatd
sources:
- https://github.com/swaywm/wlroots
tasks:

View file

@ -254,8 +254,7 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display,
return backend;
}
if (getenv("WAYLAND_DISPLAY") || getenv("_WAYLAND_DISPLAY") ||
getenv("WAYLAND_SOCKET")) {
if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET")) {
struct wlr_backend *wl_backend = attempt_wl_backend(display,
create_renderer_func);
if (!wl_backend) {

View file

@ -373,6 +373,12 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) {
}
conn->pageflip_pending = true;
// wlr_output's API guarantees that submitting a buffer will schedule a
// frame event. However the DRM backend will also schedule a frame event
// when performing a modeset. Set frame_pending to true so that
// wlr_output_schedule_frame doesn't trigger a synthetic frame event.
conn->output.frame_pending = true;
return true;
}
@ -633,13 +639,15 @@ static bool drm_connector_export_dmabuf(struct wlr_output *output,
return false;
}
struct wlr_drm_plane *plane = crtc->primary;
if (plane->current_fb.type == WLR_DRM_FB_TYPE_NONE) {
struct wlr_drm_fb *fb = &crtc->primary->queued_fb;
if (fb->type == WLR_DRM_FB_TYPE_NONE) {
fb = &crtc->primary->current_fb;
}
if (fb->type == WLR_DRM_FB_TYPE_NONE) {
return false;
}
return export_drm_bo(plane->current_fb.bo, attribs);
return export_drm_bo(fb->bo, attribs);
}
struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane) {
@ -800,7 +808,7 @@ bool drm_connector_set_mode(struct wlr_drm_connector *conn,
return false;
}
wlr_log(WLR_INFO, "Modesetting '%s' with '%ux%u@%u mHz'",
wlr_log(WLR_INFO, "Modesetting '%s' with '%" PRId32 "x%" PRId32 "@%" PRId32 "mHz'",
conn->output.name, wlr_mode->width, wlr_mode->height,
wlr_mode->refresh);
@ -1398,7 +1406,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
bool is_mst = false;
char *path = get_drm_prop_blob(drm->fd, wlr_conn->id,
wlr_conn->props.path, &path_len);
if (path_len > 4 && path && strncmp(path, "mst:", 4) == 0) {
if (path && path_len > 4 && strncmp(path, "mst:", 4) == 0) {
is_mst = true;
}
free(path);
@ -1523,7 +1531,7 @@ static void page_flip_handler(int fd, unsigned seq,
};
wlr_output_send_present(&conn->output, &present_event);
if (drm->session->active) {
if (drm->session->active && conn->output.enabled) {
wlr_output_send_frame(&conn->output);
}
}

View file

@ -44,9 +44,24 @@ static int handle_libinput_readable(int fd, uint32_t mask, void *_backend) {
return 0;
}
static enum wlr_log_importance libinput_log_priority_to_wlr(
enum libinput_log_priority priority) {
switch (priority) {
case LIBINPUT_LOG_PRIORITY_ERROR:
return WLR_ERROR;
case LIBINPUT_LOG_PRIORITY_INFO:
return WLR_INFO;
default:
return WLR_DEBUG;
}
}
static void log_libinput(struct libinput *libinput_context,
enum libinput_log_priority priority, const char *fmt, va_list args) {
_wlr_vlog(WLR_ERROR, fmt, args);
enum wlr_log_importance importance = libinput_log_priority_to_wlr(priority);
static char wlr_fmt[1024];
snprintf(wlr_fmt, sizeof(wlr_fmt), "[libinput] %s", fmt);
_wlr_vlog(importance, wlr_fmt, args);
}
static bool backend_start(struct wlr_backend *wlr_backend) {

View file

@ -18,6 +18,7 @@
#include <wlr/util/log.h>
#include <xf86drm.h>
#include "backend/session/direct-ipc.h"
#include "backend/session/session.h"
#include "util/signal.h"
const struct session_impl session_direct;
@ -274,6 +275,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) {
return NULL;
}
session_init(&session->base);
session->sock = direct_ipc_init(&session->child);
if (session->sock == -1) {
goto error_session;
@ -297,6 +299,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) {
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat);
session->base.impl = &session_direct;
session->base.active = true;
return &session->base;
error_ipc:

View file

@ -24,16 +24,6 @@
enum { DRM_MAJOR = 226 };
static bool have_permissions(void) {
#ifdef __linux__
if (geteuid() != 0) {
wlr_log(WLR_ERROR, "Do not have root privileges; cannot become DRM master");
return false;
}
#endif
return true;
}
static void send_msg(int sock, int fd, void *buf, size_t buf_len) {
char control[CMSG_SPACE(sizeof(fd))] = {0};
struct iovec iovec = { .iov_base = buf, .iov_len = buf_len };
@ -223,10 +213,6 @@ void direct_ipc_finish(int sock, pid_t pid) {
}
int direct_ipc_init(pid_t *pid_out) {
if (!have_permissions()) {
return -1;
}
int sock[2];
if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sock) < 0) {
wlr_log_errno(WLR_ERROR, "Failed to create socket pair");

View file

@ -18,6 +18,7 @@
#include <wlr/backend/session/interface.h>
#include <wlr/util/log.h>
#include "backend/session/direct-ipc.h"
#include "backend/session/session.h"
#include "util/signal.h"
enum { DRM_MAJOR = 226 };
@ -246,6 +247,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) {
return NULL;
}
session_init(&session->base);
session->sock = direct_ipc_init(&session->child);
if (session->sock == -1) {
goto error_session;
@ -267,6 +269,7 @@ static struct wlr_session *direct_session_create(struct wl_display *disp) {
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat);
session->base.impl = &session_direct;
session->base.active = true;
wlr_log(WLR_INFO, "Successfully loaded direct session");
return &session->base;

215
backend/session/libseat.c Normal file
View file

@ -0,0 +1,215 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wayland-server-core.h>
#include <wlr/backend/session/interface.h>
#include <wlr/config.h>
#include <wlr/util/log.h>
#include "backend/session/session.h"
#include "util/signal.h"
#include <libseat.h>
const struct session_impl session_libseat;
struct libseat_device {
struct wl_list link;
int fd;
int device_id;
};
struct libseat_session {
struct wlr_session base;
struct libseat *seat;
struct wl_event_source *event;
struct wl_list devices;
};
static void handle_enable_seat(struct libseat *seat, void *data) {
struct libseat_session *session = data;
session->base.active = true;
wlr_signal_emit_safe(&session->base.session_signal, session);
}
static void handle_disable_seat(struct libseat *seat, void *data) {
struct libseat_session *session = data;
session->base.active = false;
wlr_signal_emit_safe(&session->base.session_signal, session);
libseat_disable_seat(session->seat);
}
static int libseat_event(int fd, uint32_t mask, void *data) {
struct libseat *seat = data;
libseat_dispatch(seat, 0);
return 1;
}
static struct libseat_seat_listener seat_listener = {
.enable_seat = handle_enable_seat,
.disable_seat = handle_disable_seat,
};
static struct libseat_session *libseat_session_from_session(
struct wlr_session *base) {
assert(base->impl == &session_libseat);
return (struct libseat_session *)base;
}
static enum wlr_log_importance libseat_log_level_to_wlr(
enum libseat_log_level level) {
switch (level) {
case LIBSEAT_LOG_LEVEL_ERROR:
return WLR_ERROR;
case LIBSEAT_LOG_LEVEL_INFO:
return WLR_INFO;
default:
return WLR_DEBUG;
}
}
static void log_libseat(enum libseat_log_level level,
const char *fmt, va_list args) {
enum wlr_log_importance importance = libseat_log_level_to_wlr(level);
static char wlr_fmt[1024];
snprintf(wlr_fmt, sizeof(wlr_fmt), "[libseat] %s", fmt);
_wlr_vlog(importance, wlr_fmt, args);
}
static struct wlr_session *libseat_session_create(struct wl_display *disp) {
struct libseat_session *session = calloc(1, sizeof(*session));
if (!session) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
return NULL;
}
session_init(&session->base);
wl_list_init(&session->devices);
libseat_set_log_handler(log_libseat);
libseat_set_log_level(LIBSEAT_LOG_LEVEL_ERROR);
session->seat = libseat_open_seat(&seat_listener, session);
if (session->seat == NULL) {
wlr_log_errno(WLR_ERROR, "Unable to create seat");
goto error;
}
const char *seat_name = libseat_seat_name(session->seat);
if (seat_name == NULL) {
wlr_log_errno(WLR_ERROR, "Unable to get seat info");
goto error;
}
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat_name);
struct wl_event_loop *event_loop = wl_display_get_event_loop(disp);
session->event = wl_event_loop_add_fd(event_loop, libseat_get_fd(session->seat),
WL_EVENT_READABLE, libseat_event, session->seat);
if (session->event == NULL) {
wlr_log(WLR_ERROR, "Failed to create libseat event source");
goto error;
}
// We may have received enable_seat immediately after the open_seat result,
// so, dispatch once without timeout to speed up activation.
if (libseat_dispatch(session->seat, 0) == -1) {
wlr_log_errno(WLR_ERROR, "libseat dispatch failed");
goto error;
}
wlr_log(WLR_INFO, "Successfully loaded libseat session");
session->base.impl = &session_libseat;
return &session->base;
error:
if (session->seat != NULL) {
libseat_close_seat(session->seat);
}
if (session->event != NULL) {
wl_event_source_remove(session->event);
}
free(session);
return NULL;
}
static void libseat_session_destroy(struct wlr_session *base) {
struct libseat_session *session = libseat_session_from_session(base);
libseat_close_seat(session->seat);
wl_event_source_remove(session->event);
free(session);
}
static struct libseat_device *find_device_by_fd(struct libseat_session *session, int fd) {
struct libseat_device *dev;
wl_list_for_each(dev, &session->devices, link) {
if (dev->fd == fd) {
return dev;
}
}
return NULL;
}
static int libseat_session_open_device(struct wlr_session *base, const char *path) {
struct libseat_session *session = libseat_session_from_session(base);
int fd;
int device_id = libseat_open_device(session->seat, path, &fd);
if (device_id == -1) {
wlr_log_errno(WLR_ERROR, "Failed to open device '%s'", path);
return -1;
}
struct libseat_device *dev = calloc(1, sizeof(struct libseat_device));
if (dev == NULL) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
libseat_close_device(session->seat, device_id);
return -1;
}
dev->fd = fd;
dev->device_id = device_id;
wl_list_insert(&session->devices, &dev->link);
return fd;
}
static void libseat_session_close_device(struct wlr_session *base, int fd) {
struct libseat_session *session = libseat_session_from_session(base);
struct libseat_device *dev = find_device_by_fd(session, fd);
if (dev == NULL) {
wlr_log(WLR_ERROR, "No device with fd %d found", fd);
close(fd);
return;
}
if (libseat_close_device(session->seat, dev->device_id) == -1) {
wlr_log_errno(WLR_ERROR, "Failed to close device %d", dev->device_id);
}
wl_list_remove(&dev->link);
free(dev);
close(fd);
}
static bool libseat_change_vt(struct wlr_session *base, unsigned vt) {
struct libseat_session *session = libseat_session_from_session(base);
return libseat_switch_session(session->seat, vt);
}
const struct session_impl session_libseat = {
.create = libseat_session_create,
.destroy = libseat_session_destroy,
.open = libseat_session_open_device,
.close = libseat_session_close_device,
.change_vt = libseat_change_vt,
};

View file

@ -13,6 +13,7 @@
#include <wlr/backend/session/interface.h>
#include <wlr/config.h>
#include <wlr/util/log.h>
#include "backend/session/session.h"
#include "util/signal.h"
#if WLR_HAS_SYSTEMD
@ -129,8 +130,8 @@ static void logind_release_device(struct wlr_session *base, int fd) {
static bool logind_change_vt(struct wlr_session *base, unsigned vt) {
struct logind_session *session = logind_session_from_session(base);
// Only seat0 has VTs associated with it
if (strcmp(session->base.seat, "seat0") != 0) {
// Only if seat has VTs associated with it
if (!sd_seat_can_tty(session->base.seat)) {
return true;
}
@ -142,7 +143,7 @@ static bool logind_change_vt(struct wlr_session *base, unsigned vt) {
"/org/freedesktop/login1/seat/seat0", "org.freedesktop.login1.Seat", "SwitchTo",
&error, &msg, "u", (uint32_t)vt);
if (ret < 0) {
wlr_log(WLR_ERROR, "Failed to change to vt '%d'", vt);
wlr_log(WLR_ERROR, "Failed to change to vt '%u'", vt);
}
sd_bus_error_free(&error);
@ -241,6 +242,32 @@ static bool take_control(struct logind_session *session) {
return ret >= 0;
}
static void set_type(struct logind_session *session) {
int ret;
sd_bus_message *msg = NULL;
sd_bus_error error = SD_BUS_ERROR_NULL;
ret = sd_bus_call_method(session->bus, "org.freedesktop.login1",
session->path, "org.freedesktop.login1.Session", "SetType",
&error, &msg, "s", "wayland");
if (ret < 0) {
wlr_log(WLR_DEBUG, "Failed to set logind session type for session: %s",
error.message);
}
sd_bus_error_free(&error);
sd_bus_message_unref(msg);
if (ret < 0) {
return;
}
ret = setenv("XDG_SESSION_TYPE", "wayland", 1);
if (ret < 0) {
wlr_log(WLR_ERROR, "Failed to set XDG_SESSION_TYPE for session");
}
}
static void release_control(struct logind_session *session) {
int ret;
sd_bus_message *msg = NULL;
@ -750,6 +777,8 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
return NULL;
}
session_init(&session->base);
if (!get_display_session(&session->id)) {
goto error;
}
@ -762,7 +791,7 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
}
snprintf(session->base.seat, sizeof(session->base.seat), "%s", seat);
if (strcmp(seat, "seat0") == 0) {
if (sd_seat_can_tty(seat)) {
ret = sd_session_get_vt(session->id, &session->base.vtnr);
if (ret < 0) {
wlr_log(WLR_ERROR, "Session not running in virtual terminal");
@ -819,9 +848,13 @@ static struct wlr_session *logind_session_create(struct wl_display *disp) {
}
}
set_type(session);
wlr_log(WLR_INFO, "Successfully loaded logind session");
session->base.impl = &session_logind;
session->base.active = true;
return &session->base;
error_bus:

View file

@ -62,3 +62,12 @@ if logind_found
wlr_files += files('logind.c')
wlr_deps += logind
endif
# libseat
libseat = dependency('libseat', required: get_option('libseat'), version: '>=0.2.0')
if libseat.found()
wlr_files += files('libseat.c')
wlr_deps += libseat
conf_data.set10('WLR_HAS_LIBSEAT', true)
endif

View file

@ -6,6 +6,7 @@
#include <wayland-server-core.h>
#include <wlr/backend/session/interface.h>
#include <wlr/util/log.h>
#include "backend/session/session.h"
#include "util/signal.h"
const struct session_impl session_noop;
@ -33,7 +34,9 @@ static struct wlr_session *noop_session_create(struct wl_display *disp) {
return NULL;
}
session_init(session);
session->impl = &session_noop;
session->active = true;
wlr_log(WLR_INFO, "Successfully initialized noop session");
return session;

View file

@ -13,13 +13,18 @@
#include <wlr/util/log.h>
#include <xf86drm.h>
#include <xf86drmMode.h>
#include "backend/session/session.h"
#include "util/signal.h"
extern const struct session_impl session_libseat;
extern const struct session_impl session_logind;
extern const struct session_impl session_direct;
extern const struct session_impl session_noop;
static const struct session_impl *impls[] = {
#if WLR_HAS_LIBSEAT
&session_libseat,
#endif
#if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND
&session_logind,
#endif
@ -65,12 +70,24 @@ static void handle_display_destroy(struct wl_listener *listener, void *data) {
wlr_session_destroy(session);
}
void session_init(struct wlr_session *session) {
wl_signal_init(&session->session_signal);
wl_signal_init(&session->events.destroy);
wl_list_init(&session->devices);
}
struct wlr_session *wlr_session_create(struct wl_display *disp) {
struct wlr_session *session = NULL;
const char *env_wlr_session = getenv("WLR_SESSION");
if (env_wlr_session) {
if (strcmp(env_wlr_session, "logind") == 0 ||
if (strcmp(env_wlr_session, "libseat") == 0) {
#if WLR_HAS_LIBSEAT
session = session_libseat.create(disp);
#else
wlr_log(WLR_ERROR, "wlroots is not compiled with libseat support");
#endif
} else if (strcmp(env_wlr_session, "logind") == 0 ||
strcmp(env_wlr_session, "systemd") == 0) {
#if WLR_HAS_SYSTEMD || WLR_HAS_ELOGIND
session = session_logind.create(disp);
@ -97,11 +114,6 @@ struct wlr_session *wlr_session_create(struct wl_display *disp) {
return NULL;
}
session->active = true;
wl_signal_init(&session->session_signal);
wl_signal_init(&session->events.destroy);
wl_list_init(&session->devices);
session->udev = udev_new();
if (!session->udev) {
wlr_log_errno(WLR_ERROR, "Failed to create udev context");

View file

@ -97,15 +97,17 @@ static void registry_global(void *data, struct wl_registry *registry,
uint32_t name, const char *iface, uint32_t version) {
struct wlr_wl_backend *wl = data;
wlr_log(WLR_DEBUG, "Remote wayland global: %s v%d", iface, version);
wlr_log(WLR_DEBUG, "Remote wayland global: %s v%" PRIu32, iface, version);
if (strcmp(iface, wl_compositor_interface.name) == 0) {
wl->compositor = wl_registry_bind(registry, name,
&wl_compositor_interface, 4);
} else if (strcmp(iface, wl_seat_interface.name) == 0) {
wl->seat = wl_registry_bind(registry, name,
struct wl_seat *wl_seat = wl_registry_bind(registry, name,
&wl_seat_interface, 5);
wl_seat_add_listener(wl->seat, &seat_listener, wl);
if (!create_wl_seat(wl_seat, wl)) {
wl_seat_destroy(wl_seat);
}
} else if (strcmp(iface, xdg_wm_base_interface.name) == 0) {
wl->xdg_wm_base = wl_registry_bind(registry, name,
&xdg_wm_base_interface, 1);
@ -155,13 +157,16 @@ static bool backend_start(struct wlr_backend *backend) {
wl->started = true;
if (wl->keyboard) {
create_wl_keyboard(wl->keyboard, wl);
}
struct wlr_wl_seat *seat = wl->seat;
if (seat != NULL) {
if (seat->keyboard) {
create_wl_keyboard(seat->keyboard, wl);
}
if (wl->tablet_manager && wl->seat) {
wl_add_tablet_seat(wl->tablet_manager,
wl->seat, wl);
if (wl->tablet_manager) {
wl_add_tablet_seat(wl->tablet_manager,
seat->wl_seat, wl);
}
}
for (size_t i = 0; i < wl->requested_outputs; ++i) {
@ -192,8 +197,6 @@ static void backend_destroy(struct wlr_backend *backend) {
wl_list_remove(&wl->local_display_destroy.link);
free(wl->seat_name);
wl_event_source_remove(wl->remote_display_src);
wlr_renderer_destroy(wl->renderer);
@ -201,12 +204,7 @@ static void backend_destroy(struct wlr_backend *backend) {
wlr_drm_format_set_finish(&wl->linux_dmabuf_v1_formats);
if (wl->pointer) {
wl_pointer_destroy(wl->pointer);
}
if (wl->seat) {
wl_seat_destroy(wl->seat);
}
destroy_wl_seats(wl);
if (wl->zxdg_decoration_manager_v1) {
zxdg_decoration_manager_v1_destroy(wl->zxdg_decoration_manager_v1);
}
@ -279,7 +277,6 @@ struct wlr_backend *wlr_wl_backend_create(struct wl_display *display,
}
wl_registry_add_listener(wl->registry, &registry_listener, wl);
wl_display_dispatch(wl->remote_display);
wl_display_roundtrip(wl->remote_display);
if (!wl->compositor) {

View file

@ -419,8 +419,9 @@ static void output_destroy(struct wlr_output *wlr_output) {
}
void update_wl_output_cursor(struct wlr_wl_output *output) {
if (output->backend->pointer && output->enter_serial) {
wl_pointer_set_cursor(output->backend->pointer, output->enter_serial,
struct wlr_wl_pointer *pointer = output->backend->current_pointer;
if (pointer && pointer->output == output && output->enter_serial) {
wl_pointer_set_cursor(pointer->wl_pointer, output->enter_serial,
output->cursor.surface, output->cursor.hotspot_x,
output->cursor.hotspot_y);
}
@ -585,8 +586,11 @@ struct wlr_output *wlr_wl_output_create(struct wlr_backend *wlr_backend) {
wlr_signal_emit_safe(&backend->backend.events.new_output, wlr_output);
if (backend->pointer != NULL) {
create_wl_pointer(backend->pointer, output);
struct wlr_wl_seat *seat = backend->seat;
if (seat != NULL) {
if (seat->pointer) {
create_wl_pointer(seat->pointer, output);
}
}
return wlr_output;

View file

@ -48,6 +48,7 @@ static void pointer_handle_enter(void *data, struct wl_pointer *wl_pointer,
struct wlr_wl_output *output = wl_surface_get_user_data(surface);
assert(output);
struct wlr_wl_pointer *pointer = output_get_pointer(output);
assert(!backend->current_pointer || backend->current_pointer == pointer);
output->enter_serial = serial;
backend->current_pointer = pointer;
@ -276,18 +277,156 @@ static struct wl_keyboard_listener keyboard_listener = {
.repeat_info = keyboard_handle_repeat_info
};
static void touch_coordinates_to_absolute(struct wlr_wl_input_device *device,
wl_fixed_t x, wl_fixed_t y, double *sx, double *sy) {
// TODO: each output needs its own touch
struct wlr_wl_output *output, *tmp;
wl_list_for_each_safe(output, tmp, &device->backend->outputs, link) {
*sx = wl_fixed_to_double(x) / output->wlr_output.width;
*sy = wl_fixed_to_double(y) / output->wlr_output.height;
return; // Choose the first output in the list
}
*sx = *sy = 0;
}
static void touch_handle_down(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, struct wl_surface *surface,
int32_t id, wl_fixed_t x, wl_fixed_t y) {
struct wlr_wl_input_device *device = data;
assert(device && device->wlr_input_device.touch);
double sx, sy;
touch_coordinates_to_absolute(device, x, y, &sx, &sy);
struct wlr_event_touch_down event = {
.device = &device->wlr_input_device,
.time_msec = time,
.touch_id = id,
.x = sx,
.y = sy
};
wlr_signal_emit_safe(&device->wlr_input_device.touch->events.down, &event);
}
static void touch_handle_up(void *data, struct wl_touch *wl_touch,
uint32_t serial, uint32_t time, int32_t id) {
struct wlr_wl_input_device *device = data;
assert(device && device->wlr_input_device.touch);
struct wlr_event_touch_up event = {
.device = &device->wlr_input_device,
.time_msec = time,
.touch_id = id,
};
wlr_signal_emit_safe(&device->wlr_input_device.touch->events.up, &event);
}
static void touch_handle_motion(void *data, struct wl_touch *wl_touch,
uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y) {
struct wlr_wl_input_device *device = data;
assert(device && device->wlr_input_device.touch);
double sx, sy;
touch_coordinates_to_absolute(device, x, y, &sx, &sy);
struct wlr_event_touch_motion event = {
.device = &device->wlr_input_device,
.time_msec = time,
.touch_id = id,
.x = sx,
.y = sy
};
wlr_signal_emit_safe(&device->wlr_input_device.touch->events.motion, &event);
}
static void touch_handle_frame(void *data, struct wl_touch *wl_touch) {
// no-op
}
static void touch_handle_cancel(void *data, struct wl_touch *wl_touch) {
// no-op
}
static void touch_handle_shape(void *data, struct wl_touch *wl_touch,
int32_t id, wl_fixed_t major, wl_fixed_t minor) {
// no-op
}
static void touch_handle_orientation(void *data, struct wl_touch *wl_touch,
int32_t id, wl_fixed_t orientation) {
// no-op
}
static struct wl_touch_listener touch_listener = {
.down = touch_handle_down,
.up = touch_handle_up,
.motion = touch_handle_motion,
.frame = touch_handle_frame,
.cancel = touch_handle_cancel,
.shape = touch_handle_shape,
.orientation = touch_handle_orientation,
};
static struct wlr_wl_input_device *get_wl_input_device_from_input_device(
struct wlr_input_device *wlr_dev) {
assert(wlr_input_device_is_wl(wlr_dev));
return (struct wlr_wl_input_device *)wlr_dev;
}
bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl) {
assert(!wl->seat); // only one seat supported at the moment
struct wlr_wl_seat *seat = calloc(1, sizeof(struct wlr_wl_seat));
if (!seat) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
return false;
}
seat->wl_seat = wl_seat;
wl->seat = seat;
wl_seat_add_listener(wl_seat, &seat_listener, wl);
return true;
}
void destroy_wl_seats(struct wlr_wl_backend *wl) {
struct wlr_wl_seat *seat = wl->seat;
if (!seat) {
return;
}
if (seat->touch) {
wl_touch_destroy(seat->touch);
}
if (seat->pointer) {
wl_pointer_destroy(seat->pointer);
}
if (seat->keyboard && !wl->started) {
// early termination will not be handled by input_device_destroy
wl_keyboard_destroy(seat->keyboard);
}
free(seat->name);
if (seat->wl_seat) {
wl_seat_destroy(seat->wl_seat);
}
free(seat);
}
static struct wlr_wl_seat *backend_get_seat(struct wlr_wl_backend *backend, struct wl_seat *wl_seat) {
assert(backend->seat && backend->seat->wl_seat == wl_seat);
return backend->seat;
}
static struct wlr_wl_seat *input_device_get_seat(struct wlr_input_device *wlr_dev) {
struct wlr_wl_input_device *dev =
get_wl_input_device_from_input_device(wlr_dev);
assert(dev->backend->seat);
return dev->backend->seat;
}
static void input_device_destroy(struct wlr_input_device *wlr_dev) {
struct wlr_wl_input_device *dev =
get_wl_input_device_from_input_device(wlr_dev);
if (dev->wlr_input_device.type == WLR_INPUT_DEVICE_KEYBOARD) {
wl_keyboard_release(dev->backend->keyboard);
dev->backend->keyboard = NULL;
struct wlr_wl_seat *seat = input_device_get_seat(wlr_dev);
wl_keyboard_release(seat->keyboard);
seat->keyboard = NULL;
}
wl_list_remove(&dev->wlr_input_device.link);
free(dev);
@ -450,6 +589,9 @@ static void relative_pointer_handle_relative_motion(void *data,
wl_fixed_t dy_unaccel) {
struct wlr_wl_input_device *input_device = data;
struct wlr_input_device *wlr_dev = &input_device->wlr_input_device;
if (pointer_get_wl(wlr_dev->pointer) != input_device->backend->current_pointer) {
return;
}
uint64_t time_usec = (uint64_t)utime_hi << 32 | utime_lo;
@ -473,6 +615,9 @@ static void pointer_handle_output_destroy(struct wl_listener *listener,
void *data) {
struct wlr_wl_pointer *pointer =
wl_container_of(listener, pointer, output_destroy);
if (pointer->relative_pointer) {
zwp_relative_pointer_v1_destroy(pointer->relative_pointer);
}
wlr_input_device_destroy(&pointer->input_device->wlr_input_device);
}
@ -498,9 +643,6 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp
pointer->wl_pointer = wl_pointer;
pointer->output = output;
wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy);
pointer->output_destroy.notify = pointer_handle_output_destroy;
struct wlr_wl_input_device *dev =
create_wl_input_device(backend, WLR_INPUT_DEVICE_POINTER);
if (dev == NULL) {
@ -510,6 +652,9 @@ void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *outp
}
pointer->input_device = dev;
wl_signal_add(&output->wlr_output.events.destroy, &pointer->output_destroy);
pointer->output_destroy.notify = pointer_handle_output_destroy;
wlr_dev = &dev->wlr_input_device;
wlr_dev->pointer = &pointer->wlr_pointer;
wlr_dev->output_name = strdup(output->wlr_output.name);
@ -548,7 +693,7 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *
wlr_dev->keyboard = calloc(1, sizeof(*wlr_dev->keyboard));
if (!wlr_dev->keyboard) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
free(dev);
wlr_input_device_destroy(wlr_dev);
return;
}
wlr_keyboard_init(wlr_dev->keyboard, NULL);
@ -557,23 +702,45 @@ void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *
wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev);
}
void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl) {
struct wlr_wl_input_device *dev =
create_wl_input_device(wl, WLR_INPUT_DEVICE_TOUCH);
if (!dev) {
return;
}
struct wlr_input_device *wlr_dev = &dev->wlr_input_device;
wlr_dev->touch = calloc(1, sizeof(*wlr_dev->touch));
if (!wlr_dev->touch) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
wlr_input_device_destroy(wlr_dev);
return;
}
wlr_touch_init(wlr_dev->touch, NULL);
wl_touch_add_listener(wl_touch, &touch_listener, dev);
wlr_signal_emit_safe(&wl->backend.events.new_input, wlr_dev);
}
static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
enum wl_seat_capability caps) {
struct wlr_wl_backend *backend = data;
assert(backend->seat == wl_seat);
struct wlr_wl_seat *seat = backend_get_seat(backend, wl_seat);
if ((caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer == NULL) {
if ((caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer == NULL) {
wlr_log(WLR_DEBUG, "seat %p offered pointer", (void *)wl_seat);
struct wl_pointer *wl_pointer = wl_seat_get_pointer(wl_seat);
backend->pointer = wl_pointer;
seat->pointer = wl_pointer;
struct wlr_wl_output *output;
wl_list_for_each(output, &backend->outputs, link) {
create_wl_pointer(wl_pointer, output);
}
}
if (!(caps & WL_SEAT_CAPABILITY_POINTER) && backend->pointer != NULL) {
if (!(caps & WL_SEAT_CAPABILITY_POINTER) && seat->pointer != NULL) {
wlr_log(WLR_DEBUG, "seat %p dropped pointer", (void *)wl_seat);
struct wlr_input_device *device, *tmp;
@ -583,21 +750,21 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
}
}
wl_pointer_release(backend->pointer);
backend->pointer = NULL;
wl_pointer_release(seat->pointer);
seat->pointer = NULL;
}
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard == NULL) {
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard == NULL) {
wlr_log(WLR_DEBUG, "seat %p offered keyboard", (void *)wl_seat);
struct wl_keyboard *wl_keyboard = wl_seat_get_keyboard(wl_seat);
backend->keyboard = wl_keyboard;
seat->keyboard = wl_keyboard;
if (backend->started) {
create_wl_keyboard(wl_keyboard, backend);
}
}
if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && backend->keyboard != NULL) {
if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && seat->keyboard != NULL) {
wlr_log(WLR_DEBUG, "seat %p dropped keyboard", (void *)wl_seat);
struct wlr_input_device *device, *tmp;
@ -606,17 +773,38 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat,
wlr_input_device_destroy(device);
}
}
assert(backend->keyboard == NULL); // free'ed by input_device_destroy
assert(seat->keyboard == NULL); // free'ed by input_device_destroy
}
if ((caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch == NULL) {
wlr_log(WLR_DEBUG, "seat %p offered touch", (void *)wl_seat);
seat->touch = wl_seat_get_touch(wl_seat);
if (backend->started) {
create_wl_touch(seat->touch, backend);
}
}
if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && seat->touch != NULL) {
wlr_log(WLR_DEBUG, "seat %p dropped touch", (void *)wl_seat);
struct wlr_input_device *device, *tmp;
wl_list_for_each_safe(device, tmp, &backend->devices, link) {
if (device->type == WLR_INPUT_DEVICE_TOUCH) {
wlr_input_device_destroy(device);
}
}
wl_touch_release(seat->touch);
seat->touch = NULL;
}
}
static void seat_handle_name(void *data, struct wl_seat *wl_seat,
const char *name) {
struct wlr_wl_backend *backend = data;
assert(backend->seat == wl_seat);
// Do we need to check if seatName was previously set for name change?
free(backend->seat_name);
backend->seat_name = strdup(name);
struct wlr_wl_seat *seat = backend_get_seat(backend, wl_seat);
free(seat->name);
seat->name = strdup(name);
}
const struct wl_seat_listener seat_listener = {
@ -625,7 +813,5 @@ const struct wl_seat_listener seat_listener = {
};
struct wl_seat *wlr_wl_input_device_get_seat(struct wlr_input_device *wlr_dev) {
struct wlr_wl_input_device *dev =
get_wl_input_device_from_input_device(wlr_dev);
return dev->backend->seat;
return input_device_get_seat(wlr_dev)->wl_seat;
}

View file

@ -9,6 +9,8 @@ wlroots reads these environment variables
* *WLR_SESSION*: specifies the wlr\_session to be used (available sessions:
logind/systemd, direct)
* *WLR_DIRECT_TTY*: specifies the tty to be used (instead of using /dev/tty)
* *WLR_XWAYLAND*: specifies the path to an Xwayland binary to be used (instead
of following shell search semantics for "Xwayland")
## DRM backend

View file

@ -753,8 +753,11 @@ static int init(struct capture_context *ctx) {
ctx->registry = wl_display_get_registry(ctx->display);
wl_registry_add_listener(ctx->registry, &registry_listener, ctx);
// First roundtrip to fetch globals
wl_display_roundtrip(ctx->display);
// Second roundtrip to fetch wl_output information
wl_display_roundtrip(ctx->display);
wl_display_dispatch(ctx->display);
if (!ctx->export_manager) {
av_log(ctx, AV_LOG_ERROR, "Compositor doesn't support %s!\n",

View file

@ -7,7 +7,7 @@
#include <wayland-client.h>
#include "wlr-foreign-toplevel-management-unstable-v1-client-protocol.h"
#define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 2
#define WLR_FOREIGN_TOPLEVEL_MANAGEMENT_VERSION 3
/**
* Usage:
@ -38,11 +38,14 @@ enum toplevel_state_field {
TOPLEVEL_STATE_INVALID = (1 << 4),
};
static const uint32_t no_parent = (uint32_t)-1;
struct toplevel_state {
char *title;
char *app_id;
uint32_t state;
uint32_t parent_id;
};
static void copy_state(struct toplevel_state *current,
@ -67,6 +70,8 @@ static void copy_state(struct toplevel_state *current,
current->state = pending->state;
}
current->parent_id = pending->parent_id;
pending->state = TOPLEVEL_STATE_INVALID;
}
@ -84,6 +89,12 @@ static void print_toplevel(struct toplevel_v1 *toplevel, bool print_endl) {
toplevel->current.title ?: "(nil)",
toplevel->current.app_id ?: "(nil)");
if (toplevel->current.parent_id != no_parent) {
printf(" parent=%u", toplevel->current.parent_id);
} else {
printf(" no parent");
}
if (print_endl) {
printf("\n");
}
@ -172,6 +183,28 @@ static void toplevel_handle_state(void *data,
toplevel->pending.state = array_to_state(state);
}
static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL;
static struct wl_list toplevel_list;
static void toplevel_handle_parent(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_parent) {
struct toplevel_v1 *toplevel = data;
toplevel->pending.parent_id = no_parent;
if (zwlr_parent) {
struct toplevel_v1 *toplevel_tmp;
wl_list_for_each(toplevel_tmp, &toplevel_list, link) {
if (toplevel_tmp->zwlr_toplevel == zwlr_parent) {
toplevel->pending.parent_id = toplevel_tmp->id;
break;
}
}
if (toplevel->pending.parent_id == no_parent) {
fprintf(stderr, "Cannot find parent toplevel!\n");
}
}
}
static void toplevel_handle_done(void *data,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
struct toplevel_v1 *toplevel = data;
@ -202,11 +235,9 @@ static const struct zwlr_foreign_toplevel_handle_v1_listener toplevel_impl = {
.state = toplevel_handle_state,
.done = toplevel_handle_done,
.closed = toplevel_handle_closed,
.parent = toplevel_handle_parent
};
static struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager = NULL;
static struct wl_list toplevel_list;
static void toplevel_manager_handle_toplevel(void *data,
struct zwlr_foreign_toplevel_manager_v1 *toplevel_manager,
struct zwlr_foreign_toplevel_handle_v1 *zwlr_toplevel) {
@ -218,6 +249,8 @@ static void toplevel_manager_handle_toplevel(void *data,
toplevel->id = global_id++;
toplevel->zwlr_toplevel = zwlr_toplevel;
toplevel->current.parent_id = no_parent;
toplevel->pending.parent_id = no_parent;
wl_list_insert(&toplevel_list, &toplevel->link);
zwlr_foreign_toplevel_handle_v1_add_listener(zwlr_toplevel, &toplevel_impl,
@ -332,7 +365,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (toplevel_manager == NULL) {

View file

@ -162,7 +162,6 @@ int main(int argc, char *argv[]) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (gamma_control_manager == NULL) {

View file

@ -177,7 +177,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (compositor == NULL) {

View file

@ -125,7 +125,6 @@ int main(int argc, char *argv[]) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
wl_registry_destroy(registry);

View file

@ -150,7 +150,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
assert(registry);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
assert(compositor && seat && wm_base && input_inhibit_manager);

View file

@ -191,7 +191,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (input_method_manager == NULL) {

View file

@ -324,7 +324,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (compositor == NULL) {

View file

@ -209,7 +209,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (compositor == NULL) {

View file

@ -10,7 +10,6 @@
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/backend/session.h>
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_keyboard.h>

View file

@ -109,12 +109,11 @@ int main(int argc, char *argv[]) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (output_power_manager == NULL) {
fprintf(stderr,
"compositor doesn't support wlr-output-power-managment-unstable-v1\n");
"compositor doesn't support wlr-output-power-management-unstable-v1\n");
return EXIT_FAILURE;
}

View file

@ -198,7 +198,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
struct wl_region *disjoint_region = wl_compositor_create_region(compositor);

View file

@ -9,7 +9,6 @@
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/backend/session.h>
#include <wlr/render/gles2.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_keyboard.h>

View file

@ -412,7 +412,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
/* Check that all the global interfaces were captured */

View file

@ -297,7 +297,7 @@ int main(int argc, char *argv[]) {
drm_fd = open(render_node, O_RDWR);
if (drm_fd < 0) {
fprintf(stderr, "Failed to open drm render node: %m\n");
perror("Failed to open drm render node");
return EXIT_FAILURE;
}
@ -309,13 +309,12 @@ int main(int argc, char *argv[]) {
struct wl_display *display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
perror("failed to create display");
return EXIT_FAILURE;
}
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (dmabuf == NULL) {
@ -344,7 +343,7 @@ int main(int argc, char *argv[]) {
void *data = gbm_bo_map(buffer.bo, 0, 0, buffer.width, buffer.height,
GBM_BO_TRANSFER_READ, &stride, &map_data);
if (!data) {
fprintf(stderr, "Failed to map gbm bo: %m\n");
perror("Failed to map gbm bo");
return EXIT_FAILURE;
}

View file

@ -90,7 +90,7 @@ static struct wl_buffer *create_shm_buffer(enum wl_shm_format fmt,
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (data == MAP_FAILED) {
fprintf(stderr, "mmap failed: %m\n");
perror("mmap failed");
close(fd);
return NULL;
}
@ -228,13 +228,12 @@ static void write_image(char *filename, enum wl_shm_format wl_fmt, int width,
int main(int argc, char *argv[]) {
struct wl_display * display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
perror("failed to create display");
return EXIT_FAILURE;
}
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (shm == NULL) {

View file

@ -1,5 +1,4 @@
#define _POSIX_C_SOURCE 200112L
#include <GLES2/gl2.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
@ -8,6 +7,7 @@
#include <wayland-server-core.h>
#include <wlr/backend.h>
#include <wlr/backend/session.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_input_device.h>
#include <wlr/util/log.h>
@ -18,7 +18,7 @@ struct sample_state {
struct wl_listener new_output;
struct wl_listener new_input;
struct timespec last_frame;
float color[3];
float color[4];
int dec;
};
@ -40,6 +40,8 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
struct sample_output *sample_output =
wl_container_of(listener, sample_output, frame);
struct sample_state *sample = sample_output->sample;
struct wlr_output *wlr_output = sample_output->output;
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@ -56,12 +58,15 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {
sample->dec = inc;
}
wlr_output_attach_render(sample_output->output, NULL);
wlr_output_attach_render(wlr_output, NULL);
glClearColor(sample->color[0], sample->color[1], sample->color[2], 1.0);
glClear(GL_COLOR_BUFFER_BIT);
struct wlr_renderer *renderer =
wlr_backend_get_renderer(wlr_output->backend);
wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
wlr_renderer_clear(renderer, sample->color);
wlr_renderer_end(renderer);
wlr_output_commit(sample_output->output);
wlr_output_commit(wlr_output);
sample->last_frame = now;
}
@ -80,9 +85,9 @@ static void new_output_notify(struct wl_listener *listener, void *data) {
wl_container_of(listener, sample, new_output);
struct sample_output *sample_output =
calloc(1, sizeof(struct sample_output));
if (!wl_list_empty(&output->modes)) {
struct wlr_output_mode *mode =
wl_container_of(output->modes.prev, mode, link);
struct wlr_output_mode *mode = wlr_output_preferred_mode(output);
if (mode != NULL) {
wlr_output_set_mode(output, mode);
}
sample_output->output = output;
@ -162,7 +167,7 @@ int main(void) {
wlr_log_init(WLR_DEBUG, NULL);
struct wl_display *display = wl_display_create();
struct sample_state state = {
.color = { 1.0, 0.0, 0.0 },
.color = { 1.0, 0.0, 0.0, 1.0 },
.dec = 0,
.last_frame = { 0 },
.display = display

View file

@ -344,7 +344,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (compositor == NULL) {

View file

@ -203,7 +203,6 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (compositor == NULL) {

View file

@ -61,13 +61,12 @@ int main(int argc, char *argv[]) {
}
struct wl_display * display = wl_display_connect(NULL);
if (display == NULL) {
fprintf(stderr, "failed to create display: %m\n");
perror("failed to create display");
return EXIT_FAILURE;
}
struct wl_registry *registry = wl_display_get_registry(display);
wl_registry_add_listener(registry, &registry_listener, NULL);
wl_display_dispatch(display);
wl_display_roundtrip(display);
if (pointer_manager == NULL) {
@ -132,7 +131,6 @@ int main(int argc, char *argv[]) {
zwlr_virtual_pointer_v1_frame(pointer);
zwlr_virtual_pointer_v1_destroy(pointer);
wl_display_dispatch(display);
return EXIT_SUCCESS;
}

View file

@ -134,7 +134,7 @@ struct wlr_drm_connector {
struct wl_list link;
/*
* We've asked for a state change in the kernel, and yet to recieve a
* We've asked for a state change in the kernel, and yet to receive a
* notification for its completion. Currently, the kernel only has a
* queue length of 1, and no way to modify your submissions after
* they're sent.

View file

@ -0,0 +1,8 @@
#ifndef BACKEND_SESSION_SESSION_H
#define BACKEND_SESSION_SESSION_H
struct wlr_session;
void session_init(struct wlr_session *session);
#endif

View file

@ -38,12 +38,9 @@ struct wlr_wl_backend {
struct wp_presentation *presentation;
struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf_v1;
struct zwp_relative_pointer_manager_v1 *zwp_relative_pointer_manager_v1;
struct wl_seat *seat;
struct wl_pointer *pointer;
struct wl_keyboard *keyboard;
struct wlr_wl_seat *seat;
struct wlr_wl_pointer *current_pointer;
struct zwp_tablet_manager_v2 *tablet_manager;
char *seat_name;
struct wlr_drm_format_set linux_dmabuf_v1_formats;
};
@ -107,13 +104,25 @@ struct wlr_wl_pointer {
struct wl_listener output_destroy;
};
struct wlr_wl_seat {
struct wl_seat *wl_seat;
char *name;
struct wl_touch *touch;
struct wl_pointer *pointer;
struct wl_keyboard *keyboard;
};
struct wlr_wl_backend *get_wl_backend_from_backend(struct wlr_backend *backend);
void update_wl_output_cursor(struct wlr_wl_output *output);
struct wlr_wl_pointer *pointer_get_wl(struct wlr_pointer *wlr_pointer);
void create_wl_pointer(struct wl_pointer *wl_pointer, struct wlr_wl_output *output);
void create_wl_keyboard(struct wl_keyboard *wl_keyboard, struct wlr_wl_backend *wl);
void create_wl_touch(struct wl_touch *wl_touch, struct wlr_wl_backend *wl);
struct wlr_wl_input_device *create_wl_input_device(
struct wlr_wl_backend *backend, enum wlr_input_device_type type);
bool create_wl_seat(struct wl_seat *wl_seat, struct wlr_wl_backend *wl);
void destroy_wl_seats(struct wlr_wl_backend *wl);
extern const struct wl_seat_listener seat_listener;

View file

@ -15,17 +15,6 @@
#include <wlr/render/wlr_texture.h>
#include <wlr/util/log.h>
struct wlr_gles2_procs {
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR;
PFNGLDEBUGMESSAGECONTROLKHRPROC glDebugMessageControlKHR;
PFNGLPOPDEBUGGROUPKHRPROC glPopDebugGroupKHR;
PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR;
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
};
extern struct wlr_gles2_procs gles2_procs;
struct wlr_gles2_pixel_format {
enum wl_shm_format wl_format;
GLint gl_format, gl_type;
@ -62,6 +51,15 @@ struct wlr_gles2_renderer {
bool egl_image_oes;
} exts;
struct {
PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES;
PFNGLDEBUGMESSAGECALLBACKKHRPROC glDebugMessageCallbackKHR;
PFNGLDEBUGMESSAGECONTROLKHRPROC glDebugMessageControlKHR;
PFNGLPOPDEBUGGROUPKHRPROC glPopDebugGroupKHR;
PFNGLPUSHDEBUGGROUPKHRPROC glPushDebugGroupKHR;
PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC glEGLImageTargetRenderbufferStorageOES;
} procs;
struct {
struct {
GLuint program;
@ -87,7 +85,7 @@ struct wlr_gles2_renderer {
struct wlr_gles2_texture {
struct wlr_texture wlr_texture;
struct wlr_egl *egl;
struct wlr_gles2_renderer *renderer;
// Basically:
// GL_TEXTURE_2D == mutable
@ -110,13 +108,23 @@ const struct wlr_gles2_pixel_format *get_gles2_format_from_gl(
GLint gl_format, GLint gl_type, bool alpha);
const enum wl_shm_format *get_gles2_wl_formats(size_t *len);
struct wlr_gles2_renderer *gles2_get_renderer(
struct wlr_renderer *wlr_renderer);
struct wlr_gles2_texture *gles2_get_texture(
struct wlr_texture *wlr_texture);
void push_gles2_marker(const char *file, const char *func);
void pop_gles2_marker(void);
#define PUSH_GLES2_DEBUG push_gles2_marker(_WLR_FILENAME, __func__)
#define POP_GLES2_DEBUG pop_gles2_marker()
struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height,
const void *data);
struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
struct wl_resource *data);
struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
struct wlr_dmabuf_attributes *attribs);
void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
const char *file, const char *func);
#define push_gles2_debug(renderer) push_gles2_debug_(renderer, _WLR_FILENAME, __func__)
void pop_gles2_debug(struct wlr_gles2_renderer *renderer);
// color engine

View file

@ -1,47 +0,0 @@
#ifndef TYPES_WLR_XDG_SHELL_V6_H
#define TYPES_WLR_XDG_SHELL_V6_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_xdg_shell_v6.h>
#include "xdg-shell-unstable-v6-protocol.h"
struct wlr_xdg_positioner_v6_resource {
struct wl_resource *resource;
struct wlr_xdg_positioner_v6 attrs;
};
extern const struct wlr_surface_role xdg_toplevel_v6_surface_role;
extern const struct wlr_surface_role xdg_popup_v6_surface_role;
uint32_t schedule_xdg_surface_v6_configure(struct wlr_xdg_surface_v6 *surface);
struct wlr_xdg_surface_v6 *create_xdg_surface_v6(
struct wlr_xdg_client_v6 *client, struct wlr_surface *surface,
uint32_t id);
void unmap_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface);
void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface);
void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface);
void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface);
void create_xdg_positioner_v6(struct wlr_xdg_client_v6 *client, uint32_t id);
struct wlr_xdg_positioner_v6_resource *get_xdg_positioner_v6_from_resource(
struct wl_resource *resource);
void create_xdg_popup_v6(struct wlr_xdg_surface_v6 *xdg_surface,
struct wlr_xdg_surface_v6 *parent,
struct wlr_xdg_positioner_v6_resource *positioner, int32_t id);
void handle_xdg_surface_v6_popup_committed(struct wlr_xdg_surface_v6 *surface);
struct wlr_xdg_popup_grab_v6 *get_xdg_shell_v6_popup_grab_from_seat(
struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat);
void destroy_xdg_popup_v6(struct wlr_xdg_surface_v6 *surface);
void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface,
uint32_t id);
void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface);
void send_xdg_toplevel_v6_configure(struct wlr_xdg_surface_v6 *surface,
struct wlr_xdg_surface_v6_configure *configure);
void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface,
struct wlr_xdg_surface_v6_configure *configure);
bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state);
void destroy_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *surface);
#endif

View file

@ -8,6 +8,8 @@
#mesondefine WLR_HAS_SYSTEMD
#mesondefine WLR_HAS_ELOGIND
#mesondefine WLR_HAS_LIBSEAT
#mesondefine WLR_HAS_X11_BACKEND
#mesondefine WLR_HAS_XWAYLAND

View file

@ -15,9 +15,9 @@
#define WLR_DMABUF_MAX_PLANES 4
enum wlr_dmabuf_attributes_flags {
WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1,
WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 2,
WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 4,
WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT = 1 << 0,
WLR_DMABUF_ATTRIBUTES_FLAGS_INTERLACED = 1 << 1,
WLR_DMABUF_ATTRIBUTES_FLAGS_BOTTOM_FIRST = 1 << 2,
};
struct wlr_dmabuf_attributes {

View file

@ -15,6 +15,9 @@
#ifndef EGL_NO_X11
#define EGL_NO_X11
#endif
#ifndef EGL_NO_PLATFORM_SPECIFIC_TYPES
#define EGL_NO_PLATFORM_SPECIFIC_TYPES
#endif
#include <wlr/config.h>

View file

@ -21,14 +21,6 @@ struct wlr_egl *wlr_gles2_renderer_get_egl(struct wlr_renderer *renderer);
bool wlr_gles2_renderer_check_ext(struct wlr_renderer *renderer,
const char *ext);
struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width, uint32_t height,
const void *data);
struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
struct wl_resource *data);
struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
struct wlr_dmabuf_attributes *attribs);
struct wlr_gles2_texture_attribs {
GLenum target; /* either GL_TEXTURE_2D or GL_TEXTURE_EXTERNAL_OES */
GLuint tex;

View file

@ -15,6 +15,9 @@
#ifndef EGL_NO_X11
#define EGL_NO_X11
#endif
#ifndef EGL_NO_PLATFORM_SPECIFIC_TYPES
#define EGL_NO_PLATFORM_SPECIFIC_TYPES
#endif
#include <EGL/egl.h>
#include <EGL/eglext.h>

View file

@ -136,7 +136,6 @@ struct wlr_drag {
struct wl_signal destroy;
} events;
struct wl_listener point_destroy;
struct wl_listener source_destroy;
struct wl_listener seat_client_destroy;
struct wl_listener icon_destroy;

View file

@ -29,12 +29,11 @@ struct wlr_export_dmabuf_frame_v1 {
struct wlr_export_dmabuf_manager_v1 *manager;
struct wl_list link; // wlr_export_dmabuf_manager_v1::frames
struct wlr_dmabuf_attributes attribs;
struct wlr_output *output;
bool cursor_locked;
struct wl_listener output_precommit;
struct wl_listener output_commit;
};
struct wlr_export_dmabuf_manager_v1 *wlr_export_dmabuf_manager_v1_create(

View file

@ -50,6 +50,7 @@ struct wlr_foreign_toplevel_handle_v1 {
char *title;
char *app_id;
struct wlr_foreign_toplevel_handle_v1 *parent;
struct wl_list outputs; // wlr_foreign_toplevel_v1_output
uint32_t state; // wlr_foreign_toplevel_v1_state
@ -104,6 +105,12 @@ struct wlr_foreign_toplevel_manager_v1 *wlr_foreign_toplevel_manager_v1_create(
struct wlr_foreign_toplevel_handle_v1 *wlr_foreign_toplevel_handle_v1_create(
struct wlr_foreign_toplevel_manager_v1 *manager);
/* Destroy the given toplevel handle, sending the closed event to any
* client. Also, if the destroyed toplevel is set as a parent of any
* other valid toplevel, clients still holding a handle to both are
* sent a parent signal with NULL parent. If this is not desired, the
* caller should ensure that any child toplevels are destroyed before
* the parent. */
void wlr_foreign_toplevel_handle_v1_destroy(
struct wlr_foreign_toplevel_handle_v1 *toplevel);
@ -126,4 +133,14 @@ void wlr_foreign_toplevel_handle_v1_set_activated(
void wlr_foreign_toplevel_handle_v1_set_fullscreen(
struct wlr_foreign_toplevel_handle_v1* toplevel, bool fullscreen);
/* Set the parent of a toplevel. If the parent changed from its previous
* value, also sends a parent event to all clients that hold handles to
* both toplevel and parent (no message is sent to clients that have
* previously destroyed their parent handle). NULL is allowed as the
* parent, meaning no parent exists. */
void wlr_foreign_toplevel_handle_v1_set_parent(
struct wlr_foreign_toplevel_handle_v1 *toplevel,
struct wlr_foreign_toplevel_handle_v1 *parent);
#endif

View file

@ -21,6 +21,10 @@ struct wlr_gamma_control_v1 {
struct wlr_output *output;
struct wl_list link;
uint16_t *table;
size_t ramp_size;
struct wl_listener output_commit_listener;
struct wl_listener output_destroy_listener;
void *data;

View file

@ -18,22 +18,22 @@
#define WLR_LED_COUNT 3
enum wlr_keyboard_led {
WLR_LED_NUM_LOCK = 1,
WLR_LED_CAPS_LOCK = 2,
WLR_LED_SCROLL_LOCK = 4,
WLR_LED_NUM_LOCK = 1 << 0,
WLR_LED_CAPS_LOCK = 1 << 1,
WLR_LED_SCROLL_LOCK = 1 << 2,
};
#define WLR_MODIFIER_COUNT 8
enum wlr_keyboard_modifier {
WLR_MODIFIER_SHIFT = 1,
WLR_MODIFIER_CAPS = 2,
WLR_MODIFIER_CTRL = 4,
WLR_MODIFIER_ALT = 8,
WLR_MODIFIER_MOD2 = 16,
WLR_MODIFIER_MOD3 = 32,
WLR_MODIFIER_LOGO = 64,
WLR_MODIFIER_MOD5 = 128,
WLR_MODIFIER_SHIFT = 1 << 0,
WLR_MODIFIER_CAPS = 1 << 1,
WLR_MODIFIER_CTRL = 1 << 2,
WLR_MODIFIER_ALT = 1 << 3,
WLR_MODIFIER_MOD2 = 1 << 4,
WLR_MODIFIER_MOD3 = 1 << 5,
WLR_MODIFIER_LOGO = 1 << 6,
WLR_MODIFIER_MOD5 = 1 << 7,
};
#define WLR_KEYBOARD_KEYS_CAP 32

View file

@ -138,6 +138,10 @@ struct wlr_layer_surface_v1 *wlr_layer_surface_v1_from_wlr_surface(
void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface,
wlr_surface_iterator_func_t iterator, void *user_data);
/* Calls the iterator function for each popup of this surface */
void wlr_layer_surface_v1_for_each_popup(struct wlr_layer_surface_v1 *surface,
wlr_surface_iterator_func_t iterator, void *user_data);
/**
* Find a surface within this layer-surface tree at the given surface-local
* coordinates. Returns the surface and coordinates in the leaf surface

View file

@ -163,7 +163,7 @@ struct wlr_output {
// Emitted right before commit
struct wl_signal precommit; // wlr_output_event_precommit
// Emitted right after commit
struct wl_signal commit;
struct wl_signal commit; // wlr_output_event_commit
// Emitted right after the buffer has been presented to the user
struct wl_signal present; // wlr_output_event_present
struct wl_signal enable;
@ -200,6 +200,12 @@ struct wlr_output_event_precommit {
struct timespec *when;
};
struct wlr_output_event_commit {
struct wlr_output *output;
uint32_t committed; // bitmask of enum wlr_output_state_field
struct timespec *when;
};
enum wlr_output_present_flag {
// The presentation was synchronized to the "vertical retrace" by the
// display hardware such that tearing does not happen.
@ -388,8 +394,7 @@ size_t wlr_output_get_gamma_size(struct wlr_output *output);
void wlr_output_set_gamma(struct wlr_output *output, size_t size,
const uint16_t *r, const uint16_t *g, const uint16_t *b);
/**
* Exports the output's current back-buffer as a DMA-BUF (ie. the buffer that
* will be displayed on next commit).
* Exports the last committed buffer as a DMA-BUF.
*
* The caller is responsible for cleaning up the DMA-BUF attributes.
*/

View file

@ -124,10 +124,10 @@ struct wlr_output *wlr_output_layout_get_center_output(
struct wlr_output_layout *layout);
enum wlr_direction {
WLR_DIRECTION_UP = 1,
WLR_DIRECTION_DOWN = 2,
WLR_DIRECTION_LEFT = 4,
WLR_DIRECTION_RIGHT = 8,
WLR_DIRECTION_UP = 1 << 0,
WLR_DIRECTION_DOWN = 1 << 1,
WLR_DIRECTION_LEFT = 1 << 2,
WLR_DIRECTION_RIGHT = 1 << 3,
};
/**

View file

@ -25,7 +25,7 @@ struct wlr_output_power_v1 {
struct wl_list link;
struct wl_listener output_destroy_listener;
struct wl_listener output_enable_listener;
struct wl_listener output_commit_listener;
void *data;
};

View file

@ -53,6 +53,7 @@ struct wlr_screencopy_frame_v1 {
struct wlr_output *output;
struct wl_listener output_precommit;
struct wl_listener output_commit;
struct wl_listener output_destroy;
struct wl_listener output_enable;

View file

@ -409,6 +409,12 @@ void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat,
*/
void wlr_seat_pointer_notify_clear_focus(struct wlr_seat *wlr_seat);
/**
* Warp the pointer of this seat to the given surface-local coordinates, without
* generating motion events.
*/
void wlr_seat_pointer_warp(struct wlr_seat *wlr_seat, double sx, double sy);
/**
* Notify the seat of motion over the given surface. Pass surface-local
* coordinates where the pointer motion occurred. Defers to any grab of the

View file

@ -48,8 +48,6 @@ struct wlr_xdg_client {
};
struct wlr_xdg_positioner {
struct wl_resource *resource;
struct wlr_box anchor_rect;
enum xdg_positioner_anchor anchor;
enum xdg_positioner_gravity gravity;
@ -124,6 +122,7 @@ struct wlr_xdg_toplevel {
struct wlr_xdg_toplevel_state client_pending;
struct wlr_xdg_toplevel_state server_pending;
struct wlr_xdg_toplevel_state last_acked;
struct wlr_xdg_toplevel_state current;
char *title;

View file

@ -1,374 +0,0 @@
/*
* This protocol is obsolete and will be removed in a future version. The
* recommended replacement is xdg-shell.
*/
/*
* This an unstable interface of wlroots. No guarantees are made regarding the
* future consistency of this API.
*/
#ifndef WLR_USE_UNSTABLE
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
#endif
#ifndef WLR_TYPES_WLR_XDG_SHELL_V6_H
#define WLR_TYPES_WLR_XDG_SHELL_V6_H
#include <wayland-server-core.h>
#include <wlr/types/wlr_box.h>
#include <wlr/types/wlr_seat.h>
#include "xdg-shell-unstable-v6-protocol.h"
/**
* An interface enabling clients to turn their wl_surfaces into windows in a
* desktop environment.
*/
struct wlr_xdg_shell_v6 {
struct wl_global *global;
struct wl_list clients;
struct wl_list popup_grabs;
uint32_t ping_timeout;
struct wl_listener display_destroy;
struct {
/**
* The `new_surface` event signals that a client has requested to
* create a new shell surface. At this point, the surface is ready to
* be configured but is not mapped or ready receive input events. The
* surface will be ready to be managed on the `map` event.
*/
struct wl_signal new_surface;
struct wl_signal destroy;
} events;
void *data;
};
struct wlr_xdg_client_v6 {
struct wlr_xdg_shell_v6 *shell;
struct wl_resource *resource;
struct wl_client *client;
struct wl_list surfaces;
struct wl_list link; // wlr_xdg_shell_v6::clients
uint32_t ping_serial;
struct wl_event_source *ping_timer;
};
struct wlr_xdg_positioner_v6 {
struct wlr_box anchor_rect;
enum zxdg_positioner_v6_anchor anchor;
enum zxdg_positioner_v6_gravity gravity;
enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment;
struct {
int32_t width, height;
} size;
struct {
int32_t x, y;
} offset;
};
struct wlr_xdg_popup_v6 {
struct wlr_xdg_surface_v6 *base;
struct wl_list link;
struct wl_resource *resource;
bool committed;
struct wlr_xdg_surface_v6 *parent;
struct wlr_seat *seat;
// Position of the popup relative to the upper left corner of the window
// geometry of the parent surface
struct wlr_box geometry;
struct wlr_xdg_positioner_v6 positioner;
struct wl_list grab_link; // wlr_xdg_popup_grab_v6::popups
};
// each seat gets a popup grab
struct wlr_xdg_popup_grab_v6 {
struct wl_client *client;
struct wlr_seat_pointer_grab pointer_grab;
struct wlr_seat_keyboard_grab keyboard_grab;
struct wlr_seat_touch_grab touch_grab;
struct wlr_seat *seat;
struct wl_list popups;
struct wl_list link; // wlr_xdg_shell_v6::popup_grabs
struct wl_listener seat_destroy;
};
enum wlr_xdg_surface_v6_role {
WLR_XDG_SURFACE_V6_ROLE_NONE,
WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL,
WLR_XDG_SURFACE_V6_ROLE_POPUP,
};
struct wlr_xdg_toplevel_v6_state {
bool maximized, fullscreen, resizing, activated;
uint32_t width, height;
uint32_t max_width, max_height;
uint32_t min_width, min_height;
// Since the fullscreen request may be made before the toplevel's surface
// is mapped, this is used to store the requested fullscreen output (if
// any) for wlr_xdg_toplevel_v6::client_pending.
struct wlr_output *fullscreen_output;
struct wl_listener fullscreen_output_destroy;
};
/**
* An xdg-surface is a user interface element requiring management by the
* compositor. An xdg-surface alone isn't useful, a role should be assigned to
* it in order to map it.
*
* When a surface has a role and is ready to be displayed, the `map` event is
* emitted. When a surface should no longer be displayed, the `unmap` event is
* emitted. The `unmap` event is guaranteed to be emitted before the `destroy`
* event if the view is destroyed when mapped.
*/
struct wlr_xdg_toplevel_v6 {
struct wl_resource *resource;
struct wlr_xdg_surface_v6 *base;
struct wlr_xdg_surface_v6 *parent;
bool added;
struct wlr_xdg_toplevel_v6_state client_pending;
struct wlr_xdg_toplevel_v6_state server_pending;
struct wlr_xdg_toplevel_v6_state current;
char *title;
char *app_id;
struct {
struct wl_signal request_maximize;
struct wl_signal request_fullscreen;
struct wl_signal request_minimize;
struct wl_signal request_move;
struct wl_signal request_resize;
struct wl_signal request_show_window_menu;
struct wl_signal set_parent;
struct wl_signal set_title;
struct wl_signal set_app_id;
} events;
};
struct wlr_xdg_surface_v6_configure {
struct wl_list link; // wlr_xdg_surface_v6::configure_list
uint32_t serial;
struct wlr_xdg_toplevel_v6_state *toplevel_state;
};
struct wlr_xdg_surface_v6 {
struct wlr_xdg_client_v6 *client;
struct wl_resource *resource;
struct wlr_surface *surface;
struct wl_list link; // wlr_xdg_client_v6::surfaces
enum wlr_xdg_surface_v6_role role;
union {
struct wlr_xdg_toplevel_v6 *toplevel;
struct wlr_xdg_popup_v6 *popup;
};
struct wl_list popups; // wlr_xdg_popup_v6::link
bool added, configured, mapped;
uint32_t configure_serial;
struct wl_event_source *configure_idle;
uint32_t configure_next_serial;
struct wl_list configure_list;
bool has_next_geometry;
struct wlr_box next_geometry;
struct wlr_box geometry;
struct wl_listener surface_destroy;
struct wl_listener surface_commit;
struct {
struct wl_signal destroy;
struct wl_signal ping_timeout;
struct wl_signal new_popup;
/**
* The `map` event signals that the shell surface is ready to be
* managed by the compositor and rendered on the screen. At this point,
* the surface has configured its properties, has had the opportunity
* to bind to the seat to receive input events, and has a buffer that
* is ready to be rendered. You can now safely add this surface to a
* list of views.
*/
struct wl_signal map;
/**
* The `unmap` event signals that the surface is no longer in a state
* where it should be shown on the screen. This might happen if the
* surface no longer has a displayable buffer because either the
* surface has been hidden or is about to be destroyed.
*/
struct wl_signal unmap;
} events;
void *data;
};
struct wlr_xdg_toplevel_v6_move_event {
struct wlr_xdg_surface_v6 *surface;
struct wlr_seat_client *seat;
uint32_t serial;
};
struct wlr_xdg_toplevel_v6_resize_event {
struct wlr_xdg_surface_v6 *surface;
struct wlr_seat_client *seat;
uint32_t serial;
uint32_t edges;
};
struct wlr_xdg_toplevel_v6_set_fullscreen_event {
struct wlr_xdg_surface_v6 *surface;
bool fullscreen;
struct wlr_output *output;
};
struct wlr_xdg_toplevel_v6_show_window_menu_event {
struct wlr_xdg_surface_v6 *surface;
struct wlr_seat_client *seat;
uint32_t serial;
uint32_t x, y;
};
struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display);
/**
* Send a ping to the surface. If the surface does not respond in a reasonable
* amount of time, the ping_timeout event will be emitted.
*/
void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface);
/**
* Request that this toplevel surface be the given size. Returns the associated
* configure serial.
*/
uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface,
uint32_t width, uint32_t height);
/**
* Request that this toplevel surface show itself in an activated or deactivated
* state. Returns the associated configure serial.
*/
uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface,
bool activated);
/**
* Request that this toplevel surface consider itself maximized or not
* maximized. Returns the associated configure serial.
*/
uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface,
bool maximized);
/**
* Request that this toplevel surface consider itself fullscreen or not
* fullscreen. Returns the associated configure serial.
*/
uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface,
bool fullscreen);
/**
* Request that this toplevel surface consider itself to be resizing or not
* resizing. Returns the associated configure serial.
*/
uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface,
bool resizing);
/**
* Request that this xdg surface closes.
*/
void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface);
/**
* Find a surface within this xdg-surface tree at the given surface-local
* coordinates. Returns the surface and coordinates in the leaf surface
* coordinate system or NULL if no surface is found at that location.
*/
struct wlr_surface *wlr_xdg_surface_v6_surface_at(
struct wlr_xdg_surface_v6 *surface, double sx, double sy,
double *sub_x, double *sub_y);
/**
* Get the geometry for this positioner based on the anchor rect, gravity, and
* size of this positioner.
*/
struct wlr_box wlr_xdg_positioner_v6_get_geometry(
struct wlr_xdg_positioner_v6 *positioner);
/**
* Get the anchor point for this popup in the toplevel parent's coordinate system.
*/
void wlr_xdg_popup_v6_get_anchor_point(struct wlr_xdg_popup_v6 *popup,
int *toplevel_sx, int *toplevel_sy);
/**
* Convert the given coordinates in the popup coordinate system to the toplevel
* surface coordinate system.
*/
void wlr_xdg_popup_v6_get_toplevel_coords(struct wlr_xdg_popup_v6 *popup,
int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy);
/**
* Set the geometry of this popup to unconstrain it according to its
* xdg-positioner rules. The box should be in the popup's root toplevel parent
* surface coordinate system.
*/
void wlr_xdg_popup_v6_unconstrain_from_box(struct wlr_xdg_popup_v6 *popup,
struct wlr_box *toplevel_sx_box);
/**
Invert the right/left anchor and gravity for this positioner. This can be
used to "flip" the positioner around the anchor rect in the x direction.
*/
void wlr_positioner_v6_invert_x(
struct wlr_xdg_positioner_v6 *positioner);
/**
Invert the top/bottom anchor and gravity for this positioner. This can be
used to "flip" the positioner around the anchor rect in the y direction.
*/
void wlr_positioner_v6_invert_y(
struct wlr_xdg_positioner_v6 *positioner);
bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface);
struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface(
struct wlr_surface *surface);
/**
* Get the surface geometry.
* This is either the geometry as set by the client, or defaulted to the bounds
* of the surface + the subsurfaces (as specified by the protocol).
*
* The x and y value can be <0
*/
void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box);
/**
* Call `iterator` on each surface and popup in the xdg-surface tree, with the
* surface's position relative to the root xdg-surface. The function is called
* from root to leaves (in rendering order).
*/
void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface,
wlr_surface_iterator_func_t iterator, void *user_data);
/**
* Call `iterator` on each popup in the xdg-surface tree, with the popup's
* position relative to the root xdg-surface. The function is called from root
* to leaves (in rendering order).
*/
void wlr_xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface,
wlr_surface_iterator_func_t iterator, void *user_data);
#endif

View file

@ -19,10 +19,10 @@
enum wlr_edges {
WLR_EDGE_NONE = 0,
WLR_EDGE_TOP = 1,
WLR_EDGE_BOTTOM = 2,
WLR_EDGE_LEFT = 4,
WLR_EDGE_RIGHT = 8,
WLR_EDGE_TOP = 1 << 0,
WLR_EDGE_BOTTOM = 1 << 1,
WLR_EDGE_LEFT = 1 << 2,
WLR_EDGE_RIGHT = 1 << 3,
};
#endif

View file

@ -84,7 +84,6 @@ struct wlr_xwayland {
struct wl_listener server_ready;
struct wl_listener server_destroy;
struct wl_listener client_destroy;
struct wl_listener seat_destroy;
void *data;
@ -173,6 +172,7 @@ struct wlr_xwayland_surface {
bool modal;
bool fullscreen;
bool maximized_vert, maximized_horz;
bool minimized;
bool has_alpha;
@ -181,6 +181,7 @@ struct wlr_xwayland_surface {
struct wl_signal request_configure;
struct wl_signal request_move;
struct wl_signal request_resize;
struct wl_signal request_minimize;
struct wl_signal request_maximize;
struct wl_signal request_fullscreen;
struct wl_signal request_activate;
@ -196,6 +197,7 @@ struct wlr_xwayland_surface {
struct wl_signal set_hints;
struct wl_signal set_decorations;
struct wl_signal set_override_redirect;
struct wl_signal set_geometry;
struct wl_signal ping_timeout;
} events;
@ -221,6 +223,11 @@ struct wlr_xwayland_resize_event {
uint32_t edges;
};
struct wlr_xwayland_minimize_event {
struct wlr_xwayland_surface *surface;
bool minimize;
};
struct wlr_xwayland_server *wlr_xwayland_server_create(
struct wl_display *display, struct wlr_xwayland_server_options *options);
void wlr_xwayland_server_destroy(struct wlr_xwayland_server *server);
@ -250,6 +257,9 @@ void wlr_xwayland_surface_configure(struct wlr_xwayland_surface *surface,
void wlr_xwayland_surface_close(struct wlr_xwayland_surface *surface);
void wlr_xwayland_surface_set_minimized(struct wlr_xwayland_surface *surface,
bool minimized);
void wlr_xwayland_surface_set_maximized(struct wlr_xwayland_surface *surface,
bool maximized);

View file

@ -26,8 +26,10 @@
#ifndef XCURSOR_H
#define XCURSOR_H
typedef int XcursorBool;
typedef unsigned int XcursorUInt;
#include <stdint.h>
typedef int XcursorBool;
typedef uint32_t XcursorUInt;
typedef XcursorUInt XcursorDim;
typedef XcursorUInt XcursorPixel;

View file

@ -40,11 +40,14 @@ enum atom_name {
NET_ACTIVE_WINDOW,
NET_WM_MOVERESIZE,
NET_SUPPORTING_WM_CHECK,
NET_WM_STATE_FOCUSED,
NET_WM_STATE_MODAL,
NET_WM_STATE_FULLSCREEN,
NET_WM_STATE_MAXIMIZED_VERT,
NET_WM_STATE_MAXIMIZED_HORZ,
NET_WM_STATE_HIDDEN,
NET_WM_PING,
WM_CHANGE_STATE,
WM_STATE,
CLIPBOARD,
PRIMARY,
@ -125,6 +128,7 @@ struct wlr_xwm {
#if WLR_HAS_XCB_ERRORS
xcb_errors_context_t *errors_context;
#endif
unsigned int last_focus_seq;
struct wl_listener compositor_new_surface;
struct wl_listener compositor_destroy;

View file

@ -1,7 +1,7 @@
project(
'wlroots',
'c',
version: '0.10.0',
version: '0.12.0',
license: 'MIT',
meson_version: '>=0.54.0',
default_options: [
@ -15,7 +15,7 @@ project(
# necessary for bugfix releases. Increasing soversion is required because
# wlroots never guarantees ABI stability -- only API stability is guaranteed
# between minor releases.
soversion = 5
soversion = 7
add_project_arguments([
'-DWLR_USE_UNSTABLE',
@ -82,6 +82,7 @@ endif
conf_data = configuration_data()
conf_data.set10('WLR_HAS_SYSTEMD', false)
conf_data.set10('WLR_HAS_ELOGIND', false)
conf_data.set10('WLR_HAS_LIBSEAT', false)
conf_data.set10('WLR_HAS_X11_BACKEND', false)
conf_data.set10('WLR_HAS_XWAYLAND', false)
conf_data.set10('WLR_HAS_XCB_ERRORS', false)
@ -178,6 +179,7 @@ meson.override_dependency('wlroots', wlroots)
summary({
'systemd': conf_data.get('WLR_HAS_SYSTEMD', 0),
'elogind': conf_data.get('WLR_HAS_ELOGIND', 0),
'libseat': conf_data.get('WLR_HAS_LIBSEAT', 0),
'xwayland': conf_data.get('WLR_HAS_XWAYLAND', 0),
'x11_backend': conf_data.get('WLR_HAS_X11_BACKEND', 0),
'xcb-icccm': conf_data.get('WLR_HAS_XCB_ICCCM', 0),

View file

@ -1,5 +1,6 @@
option('logind', type: 'feature', value: 'auto', description: 'Enable support for rootless session via logind')
option('logind-provider', type: 'combo', choices: ['auto', 'systemd', 'elogind'], value: 'auto', description: 'Provider of logind support library')
option('libseat', type: 'feature', value: 'auto', description: 'Enable support for rootless session via libseat')
option('xcb-errors', type: 'feature', value: 'auto', description: 'Use xcb-errors util library')
option('xcb-icccm', type: 'feature', value: 'auto', description: 'Use xcb-icccm util library')
option('xwayland', type: 'feature', value: 'auto', yield: true, description: 'Enable support for X11 applications')

View file

@ -28,7 +28,6 @@ protocols = {
'text-input-unstable-v3': wl_protocol_dir / 'unstable/text-input/text-input-unstable-v3.xml',
'xdg-decoration-unstable-v1': wl_protocol_dir / 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml',
'xdg-output-unstable-v1': wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
'xdg-shell-unstable-v6': wl_protocol_dir / 'unstable/xdg-shell/xdg-shell-unstable-v6.xml',
# Other protocols
'gtk-primary-selection': 'gtk-primary-selection.xml',
'kde-idle': 'idle.xml',

View file

@ -25,7 +25,7 @@
THIS SOFTWARE.
</copyright>
<interface name="zwlr_foreign_toplevel_manager_v1" version="2">
<interface name="zwlr_foreign_toplevel_manager_v1" version="3">
<description summary="list and control opened apps">
The purpose of this protocol is to enable the creation of taskbars
and docks by providing them with a list of opened applications and
@ -68,7 +68,7 @@
</event>
</interface>
<interface name="zwlr_foreign_toplevel_handle_v1" version="2">
<interface name="zwlr_foreign_toplevel_handle_v1" version="3">
<description summary="an opened toplevel">
A zwlr_foreign_toplevel_handle_v1 object represents an opened toplevel
window. Each app may have multiple opened toplevels.
@ -255,5 +255,16 @@
actually changes, this will be indicated by the state event.
</description>
</request>
<!-- Version 3 additions -->
<event name="parent" since="3">
<description summary="parent change">
This event is emitted whenever the parent of the toplevel changes.
No event is emitted when the parent handle is destroyed by the client.
</description>
<arg name="parent" type="object" interface="zwlr_foreign_toplevel_handle_v1" allow-null="true"/>
</event>
</interface>
</protocol>

View file

@ -39,7 +39,7 @@
interface version number is reset.
</description>
<interface name="zwlr_output_manager_v1" version="1">
<interface name="zwlr_output_manager_v1" version="2">
<description summary="output device configuration manager">
This interface is a manager that allows reading and writing the current
output device configuration.
@ -125,7 +125,7 @@
</event>
</interface>
<interface name="zwlr_output_head_v1" version="1">
<interface name="zwlr_output_head_v1" version="2">
<description summary="output device">
A head is an output device. The difference between a wl_output object and
a head is that heads are advertised even if they are turned off. A head
@ -257,9 +257,80 @@
resources associated with it.
</description>
</event>
<!-- Version 2 additions -->
<event name="make" since="2">
<description summary="head manufacturer">
This event describes the manufacturer of the head.
This must report the same make as the wl_output interface does in its
geometry event.
Together with the model and serial_number events the purpose is to
allow clients to recognize heads from previous sessions and for example
load head-specific configurations back.
It is not guaranteed this event will be ever sent. A reason for that
can be that the compositor does not have information about the make of
the head or the definition of a make is not sensible in the current
setup, for example in a virtual session. Clients can still try to
identify the head by available information from other events but should
be aware that there is an increased risk of false positives.
It is not recommended to display the make string in UI to users. For
that the string provided by the description event should be preferred.
</description>
<arg name="make" type="string"/>
</event>
<event name="model" since="2">
<description summary="head model">
This event describes the model of the head.
This must report the same model as the wl_output interface does in its
geometry event.
Together with the make and serial_number events the purpose is to
allow clients to recognize heads from previous sessions and for example
load head-specific configurations back.
It is not guaranteed this event will be ever sent. A reason for that
can be that the compositor does not have information about the model of
the head or the definition of a model is not sensible in the current
setup, for example in a virtual session. Clients can still try to
identify the head by available information from other events but should
be aware that there is an increased risk of false positives.
It is not recommended to display the model string in UI to users. For
that the string provided by the description event should be preferred.
</description>
<arg name="model" type="string"/>
</event>
<event name="serial_number" since="2">
<description summary="head serial number">
This event describes the serial number of the head.
Together with the make and model events the purpose is to allow clients
to recognize heads from previous sessions and for example load head-
specific configurations back.
It is not guaranteed this event will be ever sent. A reason for that
can be that the compositor does not have information about the serial
number of the head or the definition of a serial number is not sensible
in the current setup. Clients can still try to identify the head by
available information from other events but should be aware that there
is an increased risk of false positives.
It is not recommended to display the serial_number string in UI to
users. For that the string provided by the description event should be
preferred.
</description>
<arg name="serial_number" type="string"/>
</event>
</interface>
<interface name="zwlr_output_mode_v1" version="1">
<interface name="zwlr_output_mode_v1" version="2">
<description summary="output mode">
This object describes an output mode.
@ -305,7 +376,7 @@
</event>
</interface>
<interface name="zwlr_output_configuration_v1" version="1">
<interface name="zwlr_output_configuration_v1" version="2">
<description summary="output configuration">
This object is used by the client to describe a full output configuration.
@ -423,7 +494,7 @@
</request>
</interface>
<interface name="zwlr_output_configuration_head_v1" version="1">
<interface name="zwlr_output_configuration_head_v1" version="2">
<description summary="head configuration">
This object is used by the client to update a single head's configuration.

View file

@ -459,7 +459,20 @@ void wlr_egl_save_context(struct wlr_egl_context *context) {
}
bool wlr_egl_restore_context(struct wlr_egl_context *context) {
return eglMakeCurrent(context->display, context->draw_surface,
// If the saved context is a null-context, we must use the current
// display instead of the saved display because eglMakeCurrent() can't
// handle EGL_NO_DISPLAY.
EGLDisplay display = context->display == EGL_NO_DISPLAY ?
eglGetCurrentDisplay() : context->display;
// If the current display is also EGL_NO_DISPLAY, we assume that there
// is currently no context set and no action needs to be taken to unset
// the context.
if (display == EGL_NO_DISPLAY) {
return true;
}
return eglMakeCurrent(display, context->draw_surface,
context->read_surface, context->context);
}

View file

@ -21,11 +21,9 @@ static const GLfloat verts[] = {
0, 1, // bottom left
};
struct wlr_gles2_procs gles2_procs = {0};
static const struct wlr_renderer_impl renderer_impl;
static struct wlr_gles2_renderer *gles2_get_renderer(
struct wlr_gles2_renderer *gles2_get_renderer(
struct wlr_renderer *wlr_renderer) {
assert(wlr_renderer->impl == &renderer_impl);
return (struct wlr_gles2_renderer *)wlr_renderer;
@ -43,7 +41,7 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
struct wlr_gles2_renderer *renderer =
gles2_get_renderer_in_context(wlr_renderer);
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glViewport(0, 0, width, height);
renderer->viewport_width = width;
@ -58,7 +56,7 @@ static void gles2_begin(struct wlr_renderer *wlr_renderer, uint32_t width,
// XXX: maybe we should save output projection and remove some of the need
// for users to sling matricies themselves
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
}
static void gles2_end(struct wlr_renderer *wlr_renderer) {
@ -68,12 +66,13 @@ static void gles2_end(struct wlr_renderer *wlr_renderer) {
static void gles2_clear(struct wlr_renderer *wlr_renderer,
const float color[static 4]) {
gles2_get_renderer_in_context(wlr_renderer);
struct wlr_gles2_renderer *renderer =
gles2_get_renderer_in_context(wlr_renderer);
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glClearColor(color[0], color[1], color[2], color[3]);
glClear(GL_COLOR_BUFFER_BIT);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
}
static void gles2_scissor(struct wlr_renderer *wlr_renderer,
@ -81,7 +80,7 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer,
struct wlr_gles2_renderer *renderer =
gles2_get_renderer_in_context(wlr_renderer);
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
if (box != NULL) {
struct wlr_box gl_box;
wlr_box_transform(&gl_box, box, WL_OUTPUT_TRANSFORM_FLIPPED_180,
@ -92,7 +91,7 @@ static void gles2_scissor(struct wlr_renderer *wlr_renderer,
} else {
glDisable(GL_SCISSOR_TEST);
}
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
}
static void gles2_color_config(struct wlr_renderer *wlr_renderer, struct wlr_color_config *color) {
@ -139,7 +138,7 @@ static bool gles2_render_subtexture_with_matrix(
float transposition[9];
wlr_matrix_transpose(transposition, matrix);
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex);
@ -186,7 +185,7 @@ static bool gles2_render_subtexture_with_matrix(
glBindTexture(texture->target, 0);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
return true;
}
@ -203,7 +202,7 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer,
float converted[4];
color_convert(NULL, renderer->color, color, converted);
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glUseProgram(renderer->shaders.quad.program);
glUniformMatrix3fv(renderer->shaders.quad.proj, 1, GL_FALSE, transposition);
@ -218,7 +217,7 @@ static void gles2_render_quad_with_matrix(struct wlr_renderer *wlr_renderer,
glDisableVertexAttribArray(renderer->shaders.quad.pos_attrib);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
}
static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer,
@ -241,7 +240,7 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer,
float converted[4];
color_convert(NULL, renderer->color, color, converted);
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glUseProgram(renderer->shaders.ellipse.program);
glUniformMatrix3fv(renderer->shaders.ellipse.proj, 1, GL_FALSE, transposition);
@ -259,7 +258,7 @@ static void gles2_render_ellipse_with_matrix(struct wlr_renderer *wlr_renderer,
glDisableVertexAttribArray(renderer->shaders.ellipse.pos_attrib);
glDisableVertexAttribArray(renderer->shaders.ellipse.tex_attrib);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
}
static const enum wl_shm_format *gles2_renderer_formats(
@ -312,10 +311,10 @@ static enum wl_shm_format gles2_preferred_read_format(
gles2_get_renderer_in_context(wlr_renderer);
GLint gl_format = -1, gl_type = -1;
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_FORMAT, &gl_format);
glGetIntegerv(GL_IMPLEMENTATION_COLOR_READ_TYPE, &gl_type);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
EGLint alpha_size = -1;
eglGetConfigAttrib(renderer->egl->display, renderer->egl->config,
@ -352,7 +351,7 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,
return false;
}
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
// Make sure any pending drawing is finished before we try to read it
glFinish();
@ -379,7 +378,7 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,
}
}
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
return glGetError() == GL_NO_ERROR;
}
@ -387,7 +386,8 @@ static bool gles2_read_pixels(struct wlr_renderer *wlr_renderer,
static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer,
struct wlr_dmabuf_attributes *dst_attr,
struct wlr_dmabuf_attributes *src_attr) {
if (!gles2_procs.glEGLImageTargetRenderbufferStorageOES) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
if (!renderer->procs.glEGLImageTargetRenderbufferStorageOES) {
return false;
}
@ -412,15 +412,14 @@ static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer,
// texture.
gles2_src_tex->inverted_y = !(src_inverted_y ^ dst_inverted_y);
struct wlr_egl *egl = wlr_gles2_renderer_get_egl(wlr_renderer);
if (!wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL)) {
if (!wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL)) {
goto texture_destroy_out;
}
// TODO: The imported buffer should be checked with
// eglQueryDmaBufModifiersEXT to see if it may be modified.
bool external_only = false;
EGLImageKHR image = wlr_egl_create_image_from_dmabuf(egl, dst_attr,
EGLImageKHR image = wlr_egl_create_image_from_dmabuf(renderer->egl, dst_attr,
&external_only);
if (image == EGL_NO_IMAGE_KHR) {
goto texture_destroy_out;
@ -429,7 +428,7 @@ static bool gles2_blit_dmabuf(struct wlr_renderer *wlr_renderer,
GLuint rbo = 0;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
gles2_procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
renderer->procs.glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER,
image);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
@ -458,7 +457,7 @@ out:
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
glDeleteRenderbuffers(1, &rbo);
wlr_egl_destroy_image(egl, image);
wlr_egl_destroy_image(renderer->egl, image);
texture_destroy_out:
wlr_texture_destroy(src_tex);
restore_context_out:
@ -466,27 +465,6 @@ restore_context_out:
return r;
}
static struct wlr_texture *gles2_texture_from_pixels(
struct wlr_renderer *wlr_renderer, enum wl_shm_format wl_fmt,
uint32_t stride, uint32_t width, uint32_t height, const void *data) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
return wlr_gles2_texture_from_pixels(renderer->egl, wl_fmt, stride, width,
height, data);
}
static struct wlr_texture *gles2_texture_from_wl_drm(
struct wlr_renderer *wlr_renderer, struct wl_resource *data) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
return wlr_gles2_texture_from_wl_drm(renderer->egl, data);
}
static struct wlr_texture *gles2_texture_from_dmabuf(
struct wlr_renderer *wlr_renderer,
struct wlr_dmabuf_attributes *attribs) {
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
return wlr_gles2_texture_from_dmabuf(renderer->egl, attribs);
}
static bool gles2_init_wl_display(struct wlr_renderer *wlr_renderer,
struct wl_display *wl_display) {
struct wlr_gles2_renderer *renderer =
@ -523,17 +501,17 @@ static void gles2_destroy(struct wlr_renderer *wlr_renderer) {
wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL);
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glDeleteProgram(renderer->shaders.quad.program);
glDeleteProgram(renderer->shaders.ellipse.program);
glDeleteProgram(renderer->shaders.tex_rgba.program);
glDeleteProgram(renderer->shaders.tex_rgbx.program);
glDeleteProgram(renderer->shaders.tex_ext.program);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
if (renderer->exts.debug_khr) {
glDisable(GL_DEBUG_OUTPUT_KHR);
gles2_procs.glDebugMessageCallbackKHR(NULL, NULL);
renderer->procs.glDebugMessageCallbackKHR(NULL, NULL);
}
wlr_egl_unset_current(renderer->egl);
@ -565,20 +543,21 @@ static const struct wlr_renderer_impl renderer_impl = {
.blit_dmabuf = gles2_blit_dmabuf,
};
void push_gles2_marker(const char *file, const char *func) {
if (!gles2_procs.glPushDebugGroupKHR) {
void push_gles2_debug_(struct wlr_gles2_renderer *renderer,
const char *file, const char *func) {
if (!renderer->procs.glPushDebugGroupKHR) {
return;
}
int len = snprintf(NULL, 0, "%s:%s", file, func) + 1;
char str[len];
snprintf(str, len, "%s:%s", file, func);
gles2_procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str);
renderer->procs.glPushDebugGroupKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, 1, -1, str);
}
void pop_gles2_marker(void) {
if (gles2_procs.glPopDebugGroupKHR) {
gles2_procs.glPopDebugGroupKHR();
void pop_gles2_debug(struct wlr_gles2_renderer *renderer) {
if (renderer->procs.glPopDebugGroupKHR) {
renderer->procs.glPopDebugGroupKHR();
}
}
@ -602,8 +581,9 @@ static void gles2_log(GLenum src, GLenum type, GLuint id, GLenum severity,
_wlr_log(gles2_log_importance_to_wlr(type), "[GLES2] %s", msg);
}
static GLuint compile_shader(GLuint type, const GLchar *src) {
PUSH_GLES2_DEBUG;
static GLuint compile_shader(struct wlr_gles2_renderer *renderer,
GLuint type, const GLchar *src) {
push_gles2_debug(renderer);
GLuint shader = glCreateShader(type);
glShaderSource(shader, 1, &src, NULL);
@ -616,19 +596,20 @@ static GLuint compile_shader(GLuint type, const GLchar *src) {
shader = 0;
}
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
return shader;
}
static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) {
PUSH_GLES2_DEBUG;
static GLuint link_program(struct wlr_gles2_renderer *renderer,
const GLchar *vert_src, const GLchar *frag_src) {
push_gles2_debug(renderer);
GLuint vert = compile_shader(GL_VERTEX_SHADER, vert_src);
GLuint vert = compile_shader(renderer, GL_VERTEX_SHADER, vert_src);
if (!vert) {
goto error;
}
GLuint frag = compile_shader(GL_FRAGMENT_SHADER, frag_src);
GLuint frag = compile_shader(renderer, GL_FRAGMENT_SHADER, frag_src);
if (!frag) {
glDeleteShader(vert);
goto error;
@ -651,11 +632,11 @@ static GLuint link_program(const GLchar *vert_src, const GLchar *frag_src) {
goto error;
}
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
return prog;
error:
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
return 0;
}
@ -696,7 +677,7 @@ extern struct wlr_gles2_tex_shader
tex_fragment_src_external;
// return true on success
static bool build_tex_shader(struct wlr_gles2_tex_shader *shader)
static bool build_tex_shader(struct wlr_gles2_renderer *renderer, struct wlr_gles2_tex_shader *shader)
{
GLuint prog;
@ -708,7 +689,7 @@ static bool build_tex_shader(struct wlr_gles2_tex_shader *shader)
assert(n < (int)sizeof(fragsrc));
shader->program = prog = link_program(tex_vertex_src, fragsrc);
shader->program = prog = link_program(renderer, tex_vertex_src, fragsrc);
if (!prog) {
return false;
}
@ -765,41 +746,41 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) {
if (check_gl_ext(exts_str, "GL_KHR_debug")) {
renderer->exts.debug_khr = true;
load_gl_proc(&gles2_procs.glDebugMessageCallbackKHR,
load_gl_proc(&renderer->procs.glDebugMessageCallbackKHR,
"glDebugMessageCallbackKHR");
load_gl_proc(&gles2_procs.glDebugMessageControlKHR,
load_gl_proc(&renderer->procs.glDebugMessageControlKHR,
"glDebugMessageControlKHR");
}
if (check_gl_ext(exts_str, "GL_OES_EGL_image_external")) {
renderer->exts.egl_image_external_oes = true;
load_gl_proc(&gles2_procs.glEGLImageTargetTexture2DOES,
load_gl_proc(&renderer->procs.glEGLImageTargetTexture2DOES,
"glEGLImageTargetTexture2DOES");
}
if (check_gl_ext(exts_str, "GL_OES_EGL_image")) {
renderer->exts.egl_image_oes = true;
load_gl_proc(&gles2_procs.glEGLImageTargetRenderbufferStorageOES,
load_gl_proc(&renderer->procs.glEGLImageTargetRenderbufferStorageOES,
"glEGLImageTargetRenderbufferStorageOES");
}
if (renderer->exts.debug_khr) {
glEnable(GL_DEBUG_OUTPUT_KHR);
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_KHR);
gles2_procs.glDebugMessageCallbackKHR(gles2_log, NULL);
renderer->procs.glDebugMessageCallbackKHR(gles2_log, NULL);
// Silence unwanted message types
gles2_procs.glDebugMessageControlKHR(GL_DONT_CARE,
GL_DEBUG_TYPE_POP_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE);
gles2_procs.glDebugMessageControlKHR(GL_DONT_CARE,
GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE);
renderer->procs.glDebugMessageControlKHR(GL_DONT_CARE,
GL_DEBUG_TYPE_POP_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE);
renderer->procs.glDebugMessageControlKHR(GL_DONT_CARE,
GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE);
}
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
GLuint prog;
renderer->shaders.quad.program = prog =
link_program(quad_vertex_src, quad_fragment_src);
link_program(renderer, quad_vertex_src, quad_fragment_src);
if (!renderer->shaders.quad.program) {
goto error;
}
@ -808,7 +789,7 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) {
renderer->shaders.quad.pos_attrib = glGetAttribLocation(prog, "pos");
renderer->shaders.ellipse.program = prog =
link_program(quad_vertex_src, ellipse_fragment_src);
link_program(renderer, quad_vertex_src, ellipse_fragment_src);
if (!renderer->shaders.ellipse.program) {
goto error;
}
@ -818,23 +799,23 @@ struct wlr_renderer *wlr_gles2_renderer_create(struct wlr_egl *egl) {
renderer->shaders.ellipse.tex_attrib = glGetAttribLocation(prog, "texcoord");
renderer->shaders.tex_rgba = tex_fragment_src_rgba;
if(! build_tex_shader(&renderer->shaders.tex_rgba)) {
if(! build_tex_shader(renderer, &renderer->shaders.tex_rgba)) {
goto error;
}
renderer->shaders.tex_rgbx = tex_fragment_src_rgbx;
if(! build_tex_shader(&renderer->shaders.tex_rgbx)) {
if(! build_tex_shader(renderer, &renderer->shaders.tex_rgbx)) {
goto error;
}
if (renderer->exts.egl_image_external_oes) {
renderer->shaders.tex_ext = tex_fragment_src_external;
if(! build_tex_shader(&renderer->shaders.tex_ext)) {
if(! build_tex_shader(renderer, &renderer->shaders.tex_ext)) {
goto error;
}
}
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
wlr_egl_unset_current(renderer->egl);
@ -847,11 +828,11 @@ error:
glDeleteProgram(renderer->shaders.tex_rgbx.program);
glDeleteProgram(renderer->shaders.tex_ext.program);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
if (renderer->exts.debug_khr) {
glDisable(GL_DEBUG_OUTPUT_KHR);
gles2_procs.glDebugMessageCallbackKHR(NULL, NULL);
renderer->procs.glDebugMessageCallbackKHR(NULL, NULL);
}
wlr_egl_unset_current(renderer->egl);

View file

@ -29,7 +29,7 @@ struct wlr_gles2_texture *gles2_get_texture(
static struct wlr_gles2_texture *get_gles2_texture_in_context(
struct wlr_texture *wlr_texture) {
struct wlr_gles2_texture *texture = gles2_get_texture(wlr_texture);
wlr_egl_make_current(texture->egl, EGL_NO_SURFACE, NULL);
wlr_egl_make_current(texture->renderer->egl, EGL_NO_SURFACE, NULL);
return texture;
}
@ -47,7 +47,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
if (texture->target != GL_TEXTURE_2D) {
wlr_log(WLR_ERROR, "Cannot write pixels to immutable texture");
wlr_egl_unset_current(texture->egl);
wlr_egl_unset_current(texture->renderer->egl);
return false;
}
@ -56,7 +56,7 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
assert(fmt);
// TODO: what if the unpack subimage extension isn't supported?
PUSH_GLES2_DEBUG;
push_gles2_debug(texture->renderer);
glBindTexture(GL_TEXTURE_2D, texture->tex);
@ -73,9 +73,9 @@ static bool gles2_texture_write_pixels(struct wlr_texture *wlr_texture,
glBindTexture(GL_TEXTURE_2D, 0);
POP_GLES2_DEBUG;
pop_gles2_debug(texture->renderer);
wlr_egl_unset_current(texture->egl);
wlr_egl_unset_current(texture->renderer->egl);
return true;
}
@ -86,12 +86,12 @@ static bool gles2_texture_to_dmabuf(struct wlr_texture *wlr_texture,
if (!texture->image) {
assert(texture->target == GL_TEXTURE_2D);
if (!texture->egl->exts.image_base_khr) {
if (!texture->renderer->egl->exts.image_base_khr) {
return false;
}
texture->image = texture->egl->procs.eglCreateImageKHR(
texture->egl->display, texture->egl->context, EGL_GL_TEXTURE_2D_KHR,
texture->image = texture->renderer->egl->procs.eglCreateImageKHR(
texture->renderer->egl->display, texture->renderer->egl->context, EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)(uintptr_t)texture->tex, NULL);
if (texture->image == EGL_NO_IMAGE_KHR) {
return false;
@ -103,7 +103,7 @@ static bool gles2_texture_to_dmabuf(struct wlr_texture *wlr_texture,
flags |= WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT;
}
return wlr_egl_export_image_to_dmabuf(texture->egl, texture->image,
return wlr_egl_export_image_to_dmabuf(texture->renderer->egl, texture->image,
wlr_texture->width, wlr_texture->height, flags, attribs);
}
@ -115,14 +115,14 @@ static void gles2_texture_destroy(struct wlr_texture *wlr_texture) {
struct wlr_gles2_texture *texture =
get_gles2_texture_in_context(wlr_texture);
PUSH_GLES2_DEBUG;
push_gles2_debug(texture->renderer);
glDeleteTextures(1, &texture->tex);
wlr_egl_destroy_image(texture->egl, texture->image);
wlr_egl_destroy_image(texture->renderer->egl, texture->image);
POP_GLES2_DEBUG;
pop_gles2_debug(texture->renderer);
wlr_egl_unset_current(texture->egl);
wlr_egl_unset_current(texture->renderer->egl);
free(texture);
}
@ -134,11 +134,12 @@ static const struct wlr_texture_impl texture_impl = {
.destroy = gles2_texture_destroy,
};
struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
struct wlr_texture *gles2_texture_from_pixels(struct wlr_renderer *wlr_renderer,
enum wl_shm_format wl_fmt, uint32_t stride, uint32_t width,
uint32_t height, const void *data) {
wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL);
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL);
const struct wlr_gles2_pixel_format *fmt = get_gles2_format_from_wl(wl_fmt);
if (fmt == NULL) {
@ -153,12 +154,12 @@ struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
return NULL;
}
wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height);
texture->egl = egl;
texture->renderer = renderer;
texture->target = GL_TEXTURE_2D;
texture->has_alpha = fmt->has_alpha;
texture->wl_format = fmt->wl_format;
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glGenTextures(1, &texture->tex);
glBindTexture(GL_TEXTURE_2D, texture->tex);
@ -170,24 +171,26 @@ struct wlr_texture *wlr_gles2_texture_from_pixels(struct wlr_egl *egl,
glBindTexture(GL_TEXTURE_2D, 0);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
wlr_egl_unset_current(egl);
wlr_egl_unset_current(renderer->egl);
return &texture->wlr_texture;
}
struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
struct wlr_texture *gles2_texture_from_wl_drm(struct wlr_renderer *wlr_renderer,
struct wl_resource *resource) {
wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL);
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
if (!gles2_procs.glEGLImageTargetTexture2DOES) {
wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL);
if (!renderer->procs.glEGLImageTargetTexture2DOES) {
return NULL;
}
EGLint fmt;
int width, height;
bool inverted_y;
EGLImageKHR image = wlr_egl_create_image_from_wl_drm(egl, resource,
EGLImageKHR image = wlr_egl_create_image_from_wl_drm(renderer->egl, resource,
&fmt, &width, &height, &inverted_y);
if (image == EGL_NO_IMAGE_KHR) {
wlr_log(WLR_ERROR, "Failed to create EGL image from wl_drm resource");
@ -198,11 +201,11 @@ struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
calloc(1, sizeof(struct wlr_gles2_texture));
if (texture == NULL) {
wlr_log(WLR_ERROR, "Allocation failed");
wlr_egl_destroy_image(egl, image);
wlr_egl_destroy_image(renderer->egl, image);
return NULL;
}
wlr_texture_init(&texture->wlr_texture, &texture_impl, width, height);
texture->egl = egl;
texture->renderer = renderer;
texture->wl_format = 0xFFFFFFFF; // texture can't be written anyways
texture->image = image;
@ -218,36 +221,38 @@ struct wlr_texture *wlr_gles2_texture_from_wl_drm(struct wlr_egl *egl,
break;
default:
wlr_log(WLR_ERROR, "Invalid or unsupported EGL buffer format");
wlr_egl_destroy_image(egl, image);
wlr_egl_destroy_image(renderer->egl, image);
free(texture);
return NULL;
}
texture->target = GL_TEXTURE_EXTERNAL_OES;
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glGenTextures(1, &texture->tex);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture->tex);
gles2_procs.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES,
renderer->procs.glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES,
texture->image);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
wlr_egl_unset_current(egl);
wlr_egl_unset_current(renderer->egl);
return &texture->wlr_texture;
}
struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
struct wlr_texture *gles2_texture_from_dmabuf(struct wlr_renderer *wlr_renderer,
struct wlr_dmabuf_attributes *attribs) {
wlr_egl_make_current(egl, EGL_NO_SURFACE, NULL);
struct wlr_gles2_renderer *renderer = gles2_get_renderer(wlr_renderer);
if (!gles2_procs.glEGLImageTargetTexture2DOES) {
wlr_egl_make_current(renderer->egl, EGL_NO_SURFACE, NULL);
if (!renderer->procs.glEGLImageTargetTexture2DOES) {
return NULL;
}
if (!egl->exts.image_dmabuf_import_ext) {
if (!renderer->egl->exts.image_dmabuf_import_ext) {
wlr_log(WLR_ERROR, "Cannot create DMA-BUF texture: EGL extension "
"unavailable");
return NULL;
@ -273,7 +278,7 @@ struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
}
wlr_texture_init(&texture->wlr_texture, &texture_impl,
attribs->width, attribs->height);
texture->egl = egl;
texture->renderer = renderer;
texture->has_alpha = true;
texture->wl_format = 0xFFFFFFFF; // texture can't be written anyways
texture->inverted_y =
@ -281,7 +286,7 @@ struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
bool external_only;
texture->image =
wlr_egl_create_image_from_dmabuf(egl, attribs, &external_only);
wlr_egl_create_image_from_dmabuf(renderer->egl, attribs, &external_only);
if (texture->image == EGL_NO_IMAGE_KHR) {
wlr_log(WLR_ERROR, "Failed to create EGL image from DMA-BUF");
free(texture);
@ -290,16 +295,16 @@ struct wlr_texture *wlr_gles2_texture_from_dmabuf(struct wlr_egl *egl,
texture->target = external_only ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
PUSH_GLES2_DEBUG;
push_gles2_debug(renderer);
glGenTextures(1, &texture->tex);
glBindTexture(texture->target, texture->tex);
gles2_procs.glEGLImageTargetTexture2DOES(texture->target, texture->image);
renderer->procs.glEGLImageTargetTexture2DOES(texture->target, texture->image);
glBindTexture(texture->target, 0);
POP_GLES2_DEBUG;
pop_gles2_debug(renderer);
wlr_egl_unset_current(egl);
wlr_egl_unset_current(renderer->egl);
return &texture->wlr_texture;
}

View file

@ -104,6 +104,9 @@ bool wlr_render_subtexture_with_matrix(struct wlr_renderer *r,
void wlr_render_rect(struct wlr_renderer *r, const struct wlr_box *box,
const float color[static 4], const float projection[static 9]) {
if (box->width == 0 || box->height == 0) {
return;
}
assert(box->width > 0 && box->height > 0);
float matrix[9];
wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0,
@ -120,6 +123,9 @@ void wlr_render_quad_with_matrix(struct wlr_renderer *r,
void wlr_render_ellipse(struct wlr_renderer *r, const struct wlr_box *box,
const float color[static 4], const float projection[static 9]) {
if (box->width == 0 || box->height == 0) {
return;
}
assert(box->width > 0 && box->height > 0);
float matrix[9];
wlr_matrix_project_box(matrix, box, WL_OUTPUT_TRANSFORM_NORMAL, 0,

View file

@ -11,11 +11,6 @@ wlr_files += files(
'tablet_v2/wlr_tablet_v2_tablet.c',
'tablet_v2/wlr_tablet_v2_tool.c',
'tablet_v2/wlr_tablet_v2.c',
'xdg_shell_v6/wlr_xdg_popup_v6.c',
'xdg_shell_v6/wlr_xdg_positioner_v6.c',
'xdg_shell_v6/wlr_xdg_shell_v6.c',
'xdg_shell_v6/wlr_xdg_surface_v6.c',
'xdg_shell_v6/wlr_xdg_toplevel_v6.c',
'xdg_shell/wlr_xdg_popup.c',
'xdg_shell/wlr_xdg_positioner.c',
'xdg_shell/wlr_xdg_shell.c',

View file

@ -267,7 +267,7 @@ void wlr_seat_keyboard_enter(struct wlr_seat *seat,
for (size_t i = 0; i < num_keycodes; ++i) {
uint32_t *p = wl_array_add(&keys, sizeof(uint32_t));
if (!p) {
wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %d\n",
wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %" PRIu32 "\n",
keycodes[i]);
continue;
}
@ -449,7 +449,7 @@ void seat_client_create_keyboard(struct wlr_seat_client *seat_client,
for (size_t i = 0; i < num_keycodes; ++i) {
uint32_t *p = wl_array_add(&keys, sizeof(uint32_t));
if (!p) {
wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %d\n",
wlr_log(WLR_ERROR, "Cannot allocate memory, skipping keycode: %" PRIu32 "\n",
keycodes[i]);
continue;
}

View file

@ -199,11 +199,9 @@ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat,
wlr_seat->pointer_state.focused_client = client;
wlr_seat->pointer_state.focused_surface = surface;
if (surface != NULL) {
wlr_seat->pointer_state.sx = sx;
wlr_seat->pointer_state.sy = sy;
wlr_seat_pointer_warp(wlr_seat, sx, sy);
} else {
wlr_seat->pointer_state.sx = NAN;
wlr_seat->pointer_state.sy = NAN;
wlr_seat_pointer_warp(wlr_seat, NAN, NAN);
}
struct wlr_seat_pointer_focus_change_event event = {
@ -220,6 +218,11 @@ void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat) {
wlr_seat_pointer_enter(wlr_seat, NULL, 0, 0);
}
void wlr_seat_pointer_warp(struct wlr_seat *wlr_seat, double sx, double sy) {
wlr_seat->pointer_state.sx = sx;
wlr_seat->pointer_state.sy = sy;
}
void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time,
double sx, double sy) {
struct wlr_seat_client *client = wlr_seat->pointer_state.focused_client;
@ -241,8 +244,7 @@ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time,
wl_fixed_from_double(sy));
}
wlr_seat->pointer_state.sx = sx;
wlr_seat->pointer_state.sy = sy;
wlr_seat_pointer_warp(wlr_seat, sx, sy);
}
uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time,

View file

@ -39,7 +39,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client,
if (surface == parent) {
wl_resource_post_error(resource,
WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
"%s%d: wl_surface@%d cannot be its own parent",
"%s%" PRIu32 ": wl_surface@%" PRIu32 " cannot be its own parent",
msg, id, wl_resource_get_id(surface_resource));
return;
}
@ -48,7 +48,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client,
wlr_subsurface_from_wlr_surface(surface) != NULL) {
wl_resource_post_error(resource,
WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
"%s%d: wl_surface@%d is already a sub-surface",
"%s%" PRIu32 ": wl_surface@%" PRIu32 " is already a sub-surface",
msg, id, wl_resource_get_id(surface_resource));
return;
}
@ -56,7 +56,7 @@ static void subcompositor_handle_get_subsurface(struct wl_client *client,
if (wlr_surface_get_root_surface(parent) == surface) {
wl_resource_post_error(resource,
WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
"%s%d: wl_surface@%d is an ancestor of parent",
"%s%" PRIu32 ": wl_surface@%" PRIu32 " is an ancestor of parent",
msg, id, wl_resource_get_id(surface_resource));
return;
}

View file

@ -41,8 +41,7 @@ static void frame_destroy(struct wlr_export_dmabuf_frame_v1 *frame) {
}
}
wl_list_remove(&frame->link);
wl_list_remove(&frame->output_precommit.link);
wlr_dmabuf_attributes_finish(&frame->attribs);
wl_list_remove(&frame->output_commit.link);
// Make the frame resource inert
wl_resource_set_user_data(frame->resource, NULL);
free(frame);
@ -53,18 +52,41 @@ static void frame_handle_resource_destroy(struct wl_resource *resource) {
frame_destroy(frame);
}
static void frame_output_handle_precommit(struct wl_listener *listener,
static void frame_output_handle_commit(struct wl_listener *listener,
void *data) {
struct wlr_export_dmabuf_frame_v1 *frame =
wl_container_of(listener, frame, output_precommit);
struct wlr_output_event_precommit *event = data;
wl_container_of(listener, frame, output_commit);
struct wlr_output_event_commit *event = data;
if (!(event->output->pending.committed & WLR_OUTPUT_STATE_BUFFER)) {
if (!(event->committed & WLR_OUTPUT_STATE_BUFFER)) {
return;
}
wl_list_remove(&frame->output_precommit.link);
wl_list_init(&frame->output_precommit.link);
wl_list_remove(&frame->output_commit.link);
wl_list_init(&frame->output_commit.link);
struct wlr_dmabuf_attributes attribs = {0};
if (!wlr_output_export_dmabuf(frame->output, &attribs)) {
zwlr_export_dmabuf_frame_v1_send_cancel(frame->resource,
ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_TEMPORARY);
frame_destroy(frame);
return;
}
uint32_t frame_flags = ZWLR_EXPORT_DMABUF_FRAME_V1_FLAGS_TRANSIENT;
uint32_t mod_high = attribs.modifier >> 32;
uint32_t mod_low = attribs.modifier & 0xFFFFFFFF;
zwlr_export_dmabuf_frame_v1_send_frame(frame->resource,
attribs.width, attribs.height, 0, 0, attribs.flags, frame_flags,
attribs.format, mod_high, mod_low, attribs.n_planes);
for (int i = 0; i < attribs.n_planes; ++i) {
off_t size = lseek(attribs.fd[i], 0, SEEK_END);
zwlr_export_dmabuf_frame_v1_send_object(frame->resource, i,
attribs.fd[i], size, attribs.offset[i], attribs.stride[i], i);
}
wlr_dmabuf_attributes_finish(&attribs);
time_t tv_sec = event->when->tv_sec;
uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0;
@ -98,7 +120,7 @@ static void manager_handle_capture_output(struct wl_client *client,
return;
}
frame->manager = manager;
wl_list_init(&frame->output_precommit.link);
wl_list_init(&frame->output_commit.link);
uint32_t version = wl_resource_get_version(manager_resource);
frame->resource = wl_resource_create(client,
@ -120,14 +142,6 @@ static void manager_handle_capture_output(struct wl_client *client,
return;
}
struct wlr_dmabuf_attributes *attribs = &frame->attribs;
if (!wlr_output_export_dmabuf(output, attribs)) {
zwlr_export_dmabuf_frame_v1_send_cancel(frame->resource,
ZWLR_EXPORT_DMABUF_FRAME_V1_CANCEL_REASON_TEMPORARY);
frame_destroy(frame);
return;
}
frame->output = output;
wlr_output_lock_attach_render(frame->output, true);
@ -136,26 +150,11 @@ static void manager_handle_capture_output(struct wl_client *client,
frame->cursor_locked = true;
}
uint32_t frame_flags = ZWLR_EXPORT_DMABUF_FRAME_V1_FLAGS_TRANSIENT;
uint32_t mod_high = attribs->modifier >> 32;
uint32_t mod_low = attribs->modifier & 0xFFFFFFFF;
zwlr_export_dmabuf_frame_v1_send_frame(frame->resource,
output->width, output->height, 0, 0, attribs->flags, frame_flags,
attribs->format, mod_high, mod_low, attribs->n_planes);
for (int i = 0; i < attribs->n_planes; ++i) {
off_t size = lseek(attribs->fd[i], 0, SEEK_END);
zwlr_export_dmabuf_frame_v1_send_object(frame->resource, i,
attribs->fd[i], size, attribs->offset[i], attribs->stride[i], i);
}
wl_list_remove(&frame->output_commit.link);
wl_signal_add(&output->events.commit, &frame->output_commit);
frame->output_commit.notify = frame_output_handle_commit;
wlr_output_schedule_frame(output);
wl_list_remove(&frame->output_precommit.link);
wl_signal_add(&output->events.precommit, &frame->output_precommit);
frame->output_precommit.notify = frame_output_handle_precommit;
}
static void manager_handle_destroy(struct wl_client *client,

View file

@ -9,7 +9,7 @@
#include "util/signal.h"
#include "wlr-foreign-toplevel-management-unstable-v1-protocol.h"
#define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 2
#define FOREIGN_TOPLEVEL_MANAGEMENT_V1_VERSION 3
static const struct zwlr_foreign_toplevel_handle_v1_interface toplevel_handle_impl;
@ -405,6 +405,41 @@ void wlr_foreign_toplevel_handle_v1_set_fullscreen(
toplevel_send_state(toplevel);
}
static void toplevel_resource_send_parent(
struct wl_resource *toplevel_resource,
struct wlr_foreign_toplevel_handle_v1 *parent) {
if (wl_resource_get_version(toplevel_resource) <
ZWLR_FOREIGN_TOPLEVEL_HANDLE_V1_PARENT_SINCE_VERSION) {
return;
}
struct wl_client *client = wl_resource_get_client(toplevel_resource);
struct wl_resource *parent_resource = NULL;
if (parent) {
parent_resource = wl_resource_find_for_client(&parent->resources, client);
if (!parent_resource) {
/* don't send an event if this client destroyed the parent handle */
return;
}
}
zwlr_foreign_toplevel_handle_v1_send_parent(toplevel_resource,
parent_resource);
}
void wlr_foreign_toplevel_handle_v1_set_parent(
struct wlr_foreign_toplevel_handle_v1 *toplevel,
struct wlr_foreign_toplevel_handle_v1 *parent) {
if (parent == toplevel->parent) {
/* only send parent event to the clients if there was a change */
return;
}
struct wl_resource *toplevel_resource, *tmp;
wl_resource_for_each_safe(toplevel_resource, tmp, &toplevel->resources) {
toplevel_resource_send_parent(toplevel_resource, parent);
}
toplevel->parent = parent;
toplevel_update_idle_source(toplevel);
}
void wlr_foreign_toplevel_handle_v1_destroy(
struct wlr_foreign_toplevel_handle_v1 *toplevel) {
if (!toplevel) {
@ -432,6 +467,19 @@ void wlr_foreign_toplevel_handle_v1_destroy(
wl_list_remove(&toplevel->link);
/* need to ensure no other toplevels hold a pointer to this one as
* a parent, so that a later call to foreign_toplevel_manager_bind()
* will not result in a segfault */
struct wlr_foreign_toplevel_handle_v1 *tl, *tmp3;
wl_list_for_each_safe(tl, tmp3, &toplevel->manager->toplevels, link) {
if (tl->parent == toplevel) {
/* Note: we send a parent signal to all clients in this case;
* the caller should first destroy the child handles if it
* wishes to avoid this behavior. */
wlr_foreign_toplevel_handle_v1_set_parent(tl, NULL);
}
}
free(toplevel->title);
free(toplevel->app_id);
free(toplevel);
@ -542,6 +590,8 @@ static void toplevel_send_details_to_toplevel_resource(
zwlr_foreign_toplevel_handle_v1_send_state(resource, &states);
wl_array_release(&states);
toplevel_resource_send_parent(resource, toplevel->parent);
zwlr_foreign_toplevel_handle_v1_send_done(resource);
}
@ -560,9 +610,17 @@ static void foreign_toplevel_manager_bind(struct wl_client *client, void *data,
wl_list_insert(&manager->resources, wl_resource_get_link(resource));
struct wlr_foreign_toplevel_handle_v1 *toplevel, *tmp;
/* First loop: create a handle for all toplevels for all clients.
* Separation into two loops avoid the case where a child handle
* is created before a parent handle, so the parent relationship
* could not be sent to a client. */
wl_list_for_each_safe(toplevel, tmp, &manager->toplevels, link) {
create_toplevel_resource_for_resource(toplevel, resource);
}
/* Second loop: send details about each toplevel. */
wl_list_for_each_safe(toplevel, tmp, &manager->toplevels, link) {
struct wl_resource *toplevel_resource =
create_toplevel_resource_for_resource(toplevel, resource);
wl_resource_find_for_client(&toplevel->resources, client);
toplevel_send_details_to_toplevel_resource(toplevel,
toplevel_resource);
}

View file

@ -24,7 +24,9 @@ static void gamma_control_destroy(struct wlr_gamma_control_v1 *gamma_control) {
wlr_output_set_gamma(gamma_control->output, 0, NULL, NULL, NULL);
wl_resource_set_user_data(gamma_control->resource, NULL);
wl_list_remove(&gamma_control->output_destroy_listener.link);
wl_list_remove(&gamma_control->output_commit_listener.link);
wl_list_remove(&gamma_control->link);
free(gamma_control->table);
free(gamma_control);
}
@ -34,6 +36,22 @@ static void gamma_control_send_failed(
gamma_control_destroy(gamma_control);
}
static void gamma_control_apply(struct wlr_gamma_control_v1 *gamma_control) {
uint16_t *r = gamma_control->table;
uint16_t *g = gamma_control->table + gamma_control->ramp_size;
uint16_t *b = gamma_control->table + 2 * gamma_control->ramp_size;
wlr_output_set_gamma(gamma_control->output, gamma_control->ramp_size, r, g, b);
if (!wlr_output_test(gamma_control->output)) {
wlr_output_rollback(gamma_control->output);
gamma_control_send_failed(gamma_control);
return;
}
// Gamma LUT will be applied on next output commit
wlr_output_schedule_frame(gamma_control->output);
}
static const struct zwlr_gamma_control_v1_interface gamma_control_impl;
static struct wlr_gamma_control_v1 *gamma_control_from_resource(
@ -56,6 +74,17 @@ static void gamma_control_handle_output_destroy(struct wl_listener *listener,
gamma_control_destroy(gamma_control);
}
static void gamma_control_handle_output_commit(struct wl_listener *listener,
void *data) {
struct wlr_gamma_control_v1 *gamma_control =
wl_container_of(listener, gamma_control, output_commit_listener);
struct wlr_output_event_commit *event = data;
if ((event->committed & WLR_OUTPUT_STATE_ENABLED) &&
gamma_control->output->enabled) {
gamma_control_apply(gamma_control);
}
}
static void gamma_control_handle_set_gamma(struct wl_client *client,
struct wl_resource *gamma_control_resource, int fd) {
struct wlr_gamma_control_v1 *gamma_control =
@ -101,19 +130,13 @@ static void gamma_control_handle_set_gamma(struct wl_client *client,
close(fd);
fd = -1;
uint16_t *r = table;
uint16_t *g = table + ramp_size;
uint16_t *b = table + 2 * ramp_size;
free(gamma_control->table);
gamma_control->table = table;
gamma_control->ramp_size = ramp_size;
wlr_output_set_gamma(gamma_control->output, ramp_size, r, g, b);
if (!wlr_output_test(gamma_control->output)) {
gamma_control_send_failed(gamma_control);
goto error_table;
if (gamma_control->output->enabled) {
gamma_control_apply(gamma_control);
}
free(table);
// Gamma LUT will be applied on next output commit
wlr_output_schedule_frame(gamma_control->output);
return;
@ -176,6 +199,11 @@ static void gamma_control_manager_get_gamma_control(struct wl_client *client,
gamma_control->output_destroy_listener.notify =
gamma_control_handle_output_destroy;
wl_signal_add(&output->events.commit,
&gamma_control->output_commit_listener);
gamma_control->output_commit_listener.notify =
gamma_control_handle_output_commit;
wl_list_init(&gamma_control->link);
size_t gamma_size = wlr_output_get_gamma_size(output);

View file

@ -259,6 +259,9 @@ void wlr_input_method_keyboard_grab_v2_set_keyboard(
handle_keyboard_destroy;
wl_signal_add(&keyboard->events.destroy,
&keyboard_grab->keyboard_destroy);
wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab,
&keyboard->modifiers);
}
keyboard_grab->keyboard = keyboard;

View file

@ -74,7 +74,7 @@ static void layer_surface_handle_ack_configure(struct wl_client *client,
if (!found) {
wl_resource_post_error(resource,
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SURFACE_STATE,
"wrong configure serial: %u", serial);
"wrong configure serial: %" PRIu32, serial);
return;
}
// Then remove old configures from the list
@ -114,7 +114,7 @@ static void layer_surface_handle_set_anchor(struct wl_client *client,
if (anchor > max_anchor) {
wl_resource_post_error(resource,
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_ANCHOR,
"invalid anchor %d", anchor);
"invalid anchor %" PRIu32, anchor);
}
struct wlr_layer_surface_v1 *surface = layer_surface_from_resource(resource);
@ -187,7 +187,7 @@ static void layer_surface_set_layer(struct wl_client *client,
if (layer > ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) {
wl_resource_post_error(surface->resource,
ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER,
"Invalid layer %d", layer);
"Invalid layer %" PRIu32, layer);
return;
}
surface->client_pending.layer = layer;
@ -307,6 +307,26 @@ static void layer_surface_role_commit(struct wlr_surface *wlr_surface) {
return;
}
const uint32_t horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
if (surface->client_pending.desired_width == 0 &&
(surface->client_pending.anchor & horiz) != horiz) {
wl_resource_post_error(surface->resource,
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE,
"width 0 requested without setting left and right anchors");
return;
}
const uint32_t vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
if (surface->client_pending.desired_height == 0 &&
(surface->client_pending.anchor & vert) != vert) {
wl_resource_post_error(surface->resource,
ZWLR_LAYER_SURFACE_V1_ERROR_INVALID_SIZE,
"height 0 requested without setting top and bottom anchors");
return;
}
if (surface->closed) {
// Ignore commits after the compositor has closed it
return;
@ -403,7 +423,7 @@ static void layer_shell_handle_get_layer_surface(struct wl_client *wl_client,
free(surface);
wl_resource_post_error(client_resource,
ZWLR_LAYER_SHELL_V1_ERROR_INVALID_LAYER,
"Invalid layer %d", layer);
"Invalid layer %" PRIu32, layer);
return;
}
surface->namespace = strdup(namespace);
@ -534,16 +554,20 @@ static void xdg_surface_for_each_surface(struct wlr_xdg_surface *surface,
}
}
static void layer_surface_for_each_surface(struct wlr_layer_surface_v1 *surface,
int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) {
void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface,
wlr_surface_iterator_func_t iterator, void *user_data) {
struct layer_surface_iterator_data data = {
.user_iterator = iterator,
.user_data = user_data,
.x = x, .y = y,
.x = 0, .y = 0,
};
wlr_surface_for_each_surface(surface->surface,
layer_surface_iterator, &data);
wlr_layer_surface_v1_for_each_popup(surface, iterator, user_data);
}
void wlr_layer_surface_v1_for_each_popup(struct wlr_layer_surface_v1 *surface,
wlr_surface_iterator_func_t iterator, void *user_data){
struct wlr_xdg_popup *popup_state;
wl_list_for_each(popup_state, &surface->popups, link) {
struct wlr_xdg_surface *popup = popup_state->base;
@ -560,11 +584,6 @@ static void layer_surface_for_each_surface(struct wlr_layer_surface_v1 *surface,
}
}
void wlr_layer_surface_v1_for_each_surface(struct wlr_layer_surface_v1 *surface,
wlr_surface_iterator_func_t iterator, void *user_data) {
layer_surface_for_each_surface(surface, 0, 0, iterator, user_data);
}
struct wlr_surface *wlr_layer_surface_v1_surface_at(
struct wlr_layer_surface_v1 *surface, double sx, double sy,
double *sub_x, double *sub_y) {

View file

@ -210,7 +210,7 @@ static void params_create_common(struct wl_client *client,
if (buffer->attributes.offset[i] > size) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid offset %i for plane %d",
"invalid offset %" PRIu32 " for plane %d",
buffer->attributes.offset[i], i);
goto err_out;
}
@ -219,7 +219,7 @@ static void params_create_common(struct wl_client *client,
buffer->attributes.stride[i] == 0) {
wl_resource_post_error(params_resource,
ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
"invalid stride %i for plane %d",
"invalid stride %" PRIu32 " for plane %d",
buffer->attributes.stride[i], i);
goto err_out;
}

View file

@ -552,6 +552,10 @@ static bool output_basic_test(struct wlr_output *output) {
wlr_log(WLR_DEBUG, "Tried to enable adaptive sync on a disabled output");
return false;
}
if (!enabled && output->pending.committed & WLR_OUTPUT_STATE_GAMMA_LUT) {
wlr_log(WLR_DEBUG, "Tried to set the gamma lut on a disabled output");
return false;
}
return true;
}
@ -578,11 +582,11 @@ bool wlr_output_commit(struct wlr_output *output) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
struct wlr_output_event_precommit event = {
struct wlr_output_event_precommit pre_event = {
.output = output,
.when = &now,
};
wlr_signal_emit_safe(&output->events.precommit, &event);
wlr_signal_emit_safe(&output->events.precommit, &pre_event);
if (!output->impl->commit(output)) {
output_state_clear(&output->pending);
@ -601,7 +605,12 @@ bool wlr_output_commit(struct wlr_output *output) {
output->commit_seq++;
wlr_signal_emit_safe(&output->events.commit, output);
struct wlr_output_event_commit event = {
.output = output,
.committed = output->pending.committed,
.when = &now,
};
wlr_signal_emit_safe(&output->events.commit, &event);
bool scale_updated = output->pending.committed & WLR_OUTPUT_STATE_SCALE;
if (scale_updated) {

View file

@ -6,7 +6,7 @@
#include "util/signal.h"
#include "wlr-output-management-unstable-v1-protocol.h"
#define OUTPUT_MANAGER_VERSION 1
#define OUTPUT_MANAGER_VERSION 2
enum {
HEAD_STATE_ENABLED = 1 << 0,
@ -680,6 +680,9 @@ static void head_send_state(struct wlr_output_head_v1 *head,
if (state & HEAD_STATE_ENABLED) {
zwlr_output_head_v1_send_enabled(head_resource, head->state.enabled);
// On enabling we send all current data since clients have not been
// notified about potential data changes while the head was disabled.
state = HEAD_STATE_ALL;
}
if (!head->state.enabled) {
@ -761,6 +764,16 @@ static void manager_send_head(struct wlr_output_manager_v1 *manager,
output->phys_width, output->phys_height);
}
if (version >= ZWLR_OUTPUT_HEAD_V1_MAKE_SINCE_VERSION && output->make[0] != '\0') {
zwlr_output_head_v1_send_make(head_resource, output->make);
}
if (version >= ZWLR_OUTPUT_HEAD_V1_MODEL_SINCE_VERSION && output->model[0] != '\0') {
zwlr_output_head_v1_send_model(head_resource, output->model);
}
if (version >= ZWLR_OUTPUT_HEAD_V1_SERIAL_NUMBER_SINCE_VERSION && output->serial[0] != '\0') {
zwlr_output_head_v1_send_serial_number(head_resource, output->serial);
}
struct wlr_output_mode *mode;
wl_list_for_each(mode, &output->modes, link) {
head_send_mode(head, head_resource, mode);

View file

@ -23,7 +23,7 @@ static void output_power_destroy(struct wlr_output_power_v1 *output_power) {
}
wl_resource_set_user_data(output_power->resource, NULL);
wl_list_remove(&output_power->output_destroy_listener.link);
wl_list_remove(&output_power->output_enable_listener.link);
wl_list_remove(&output_power->output_commit_listener.link);
wl_list_remove(&output_power->link);
free(output_power);
}
@ -58,11 +58,14 @@ static void output_power_v1_send_mode(struct wlr_output_power_v1 *output_power)
zwlr_output_power_v1_send_mode(output_power->resource, mode);
}
static void output_power_handle_output_enable(struct wl_listener *listener,
static void output_power_handle_output_commit(struct wl_listener *listener,
void *data) {
struct wlr_output_power_v1 *output_power =
wl_container_of(listener, output_power, output_enable_listener);
output_power_v1_send_mode(output_power);
wl_container_of(listener, output_power, output_commit_listener);
struct wlr_output_event_commit *event = data;
if (event->committed & WLR_OUTPUT_STATE_ENABLED) {
output_power_v1_send_mode(output_power);
}
}
static void output_power_handle_set_mode(struct wl_client *client,
@ -147,10 +150,10 @@ static void output_power_manager_get_output_power(struct wl_client *client,
&output_power->output_destroy_listener);
output_power->output_destroy_listener.notify =
output_power_handle_output_destroy;
wl_signal_add(&output->events.enable,
&output_power->output_enable_listener);
output_power->output_enable_listener.notify =
output_power_handle_output_enable;
wl_signal_add(&output->events.commit,
&output_power->output_commit_listener);
output_power->output_commit_listener.notify =
output_power_handle_output_commit;
struct wlr_output_power_v1 *mgmt;
wl_list_for_each(mgmt, &manager->output_powers, link) {

View file

@ -143,6 +143,7 @@ static void frame_destroy(struct wlr_screencopy_frame_v1 *frame) {
}
wl_list_remove(&frame->link);
wl_list_remove(&frame->output_precommit.link);
wl_list_remove(&frame->output_commit.link);
wl_list_remove(&frame->output_destroy.link);
wl_list_remove(&frame->output_enable.link);
wl_list_remove(&frame->buffer_destroy.link);
@ -152,6 +153,41 @@ static void frame_destroy(struct wlr_screencopy_frame_v1 *frame) {
free(frame);
}
static void frame_send_damage(struct wlr_screencopy_frame_v1 *frame) {
if (!frame->with_damage) {
return;
}
struct screencopy_damage *damage =
screencopy_damage_get_or_create(frame->client, frame->output);
if (damage == NULL) {
return;
}
// TODO: send fine-grained damage events
struct pixman_box32 *damage_box =
pixman_region32_extents(&damage->damage);
int damage_x = damage_box->x1;
int damage_y = damage_box->y1;
int damage_width = damage_box->x2 - damage_box->x1;
int damage_height = damage_box->y2 - damage_box->y1;
zwlr_screencopy_frame_v1_send_damage(frame->resource,
damage_x, damage_y, damage_width, damage_height);
pixman_region32_clear(&damage->damage);
}
static void frame_send_ready(struct wlr_screencopy_frame_v1 *frame,
struct timespec *when) {
time_t tv_sec = when->tv_sec;
uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0;
uint32_t tv_sec_lo = tv_sec & 0xFFFFFFFF;
zwlr_screencopy_frame_v1_send_ready(frame->resource,
tv_sec_hi, tv_sec_lo, when->tv_nsec);
}
static void frame_handle_output_precommit(struct wl_listener *listener,
void *_data) {
struct wlr_screencopy_frame_v1 *frame =
@ -165,9 +201,14 @@ static void frame_handle_output_precommit(struct wl_listener *listener,
return;
}
struct screencopy_damage *damage = NULL;
struct wl_shm_buffer *shm_buffer = frame->shm_buffer;
if (shm_buffer == NULL) {
return;
}
if (frame->with_damage) {
damage = screencopy_damage_get_or_create(frame->client, output);
struct screencopy_damage *damage =
screencopy_damage_get_or_create(frame->client, output);
if (damage) {
screencopy_damage_accumulate(damage);
if (!pixman_region32_not_empty(&damage->damage)) {
@ -182,36 +223,19 @@ static void frame_handle_output_precommit(struct wl_listener *listener,
int x = frame->box.x;
int y = frame->box.y;
bool ok = false;
uint32_t flags = 0;
enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buffer);
int32_t width = wl_shm_buffer_get_width(shm_buffer);
int32_t height = wl_shm_buffer_get_height(shm_buffer);
int32_t stride = wl_shm_buffer_get_stride(shm_buffer);
struct wl_shm_buffer *shm_buffer = frame->shm_buffer;
struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer;
assert(shm_buffer || dma_buffer);
if (shm_buffer) {
enum wl_shm_format fmt = wl_shm_buffer_get_format(shm_buffer);
int32_t width = wl_shm_buffer_get_width(shm_buffer);
int32_t height = wl_shm_buffer_get_height(shm_buffer);
int32_t stride = wl_shm_buffer_get_stride(shm_buffer);
wl_shm_buffer_begin_access(shm_buffer);
void *data = wl_shm_buffer_get_data(shm_buffer);
uint32_t renderer_flags = 0;
ok = wlr_renderer_read_pixels(renderer, fmt, &renderer_flags,
stride, width, height, x, y, 0, 0, data);
flags |= renderer_flags & WLR_RENDERER_READ_PIXELS_Y_INVERT ?
ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0;
wl_shm_buffer_end_access(shm_buffer);
} else if (dma_buffer) {
struct wlr_dmabuf_attributes attr = { 0 };
ok = wlr_output_export_dmabuf(frame->output, &attr);
ok = ok && wlr_renderer_blit_dmabuf(renderer,
&dma_buffer->attributes, &attr);
flags |= dma_buffer->attributes.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT ?
ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0;
wlr_dmabuf_attributes_finish(&attr);
}
wl_shm_buffer_begin_access(shm_buffer);
void *data = wl_shm_buffer_get_data(shm_buffer);
uint32_t renderer_flags = 0;
bool ok = wlr_renderer_read_pixels(renderer, fmt, &renderer_flags,
stride, width, height, x, y, 0, 0, data);
uint32_t flags = renderer_flags & WLR_RENDERER_READ_PIXELS_Y_INVERT ?
ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0;
wl_shm_buffer_end_access(shm_buffer);
if (!ok) {
zwlr_screencopy_frame_v1_send_failed(frame->resource);
@ -220,29 +244,66 @@ static void frame_handle_output_precommit(struct wl_listener *listener,
}
zwlr_screencopy_frame_v1_send_flags(frame->resource, flags);
frame_send_damage(frame);
frame_send_ready(frame, event->when);
frame_destroy(frame);
}
// TODO: send fine-grained damage events
if (damage) {
struct pixman_box32 *damage_box =
pixman_region32_extents(&damage->damage);
static void frame_handle_output_commit(struct wl_listener *listener,
void *data) {
struct wlr_screencopy_frame_v1 *frame =
wl_container_of(listener, frame, output_commit);
struct wlr_output_event_commit *event = data;
struct wlr_output *output = frame->output;
struct wlr_renderer *renderer = wlr_backend_get_renderer(output->backend);
assert(renderer);
int damage_x = damage_box->x1;
int damage_y = damage_box->y1;
int damage_width = damage_box->x2 - damage_box->x1;
int damage_height = damage_box->y2 - damage_box->y1;
zwlr_screencopy_frame_v1_send_damage(frame->resource,
damage_x, damage_y, damage_width, damage_height);
pixman_region32_clear(&damage->damage);
if (!(event->committed & WLR_OUTPUT_STATE_BUFFER)) {
return;
}
time_t tv_sec = event->when->tv_sec;
uint32_t tv_sec_hi = (sizeof(tv_sec) > 4) ? tv_sec >> 32 : 0;
uint32_t tv_sec_lo = tv_sec & 0xFFFFFFFF;
zwlr_screencopy_frame_v1_send_ready(frame->resource,
tv_sec_hi, tv_sec_lo, event->when->tv_nsec);
struct wlr_dmabuf_v1_buffer *dma_buffer = frame->dma_buffer;
if (dma_buffer == NULL) {
return;
}
if (frame->with_damage) {
struct screencopy_damage *damage =
screencopy_damage_get_or_create(frame->client, output);
if (damage && !pixman_region32_not_empty(&damage->damage)) {
return;
}
}
wl_list_remove(&frame->output_commit.link);
wl_list_init(&frame->output_commit.link);
// TODO: add support for copying regions with DMA-BUFs
if (frame->box.x != 0 || frame->box.y != 0 ||
output->width != frame->box.width ||
output->height != frame->box.height) {
zwlr_screencopy_frame_v1_send_failed(frame->resource);
frame_destroy(frame);
return;
}
struct wlr_dmabuf_attributes attr = { 0 };
bool ok = wlr_output_export_dmabuf(output, &attr);
ok = ok && wlr_renderer_blit_dmabuf(renderer,
&dma_buffer->attributes, &attr);
uint32_t flags = dma_buffer->attributes.flags & WLR_DMABUF_ATTRIBUTES_FLAGS_Y_INVERT ?
ZWLR_SCREENCOPY_FRAME_V1_FLAGS_Y_INVERT : 0;
wlr_dmabuf_attributes_finish(&attr);
if (!ok) {
zwlr_screencopy_frame_v1_send_failed(frame->resource);
frame_destroy(frame);
return;
}
zwlr_screencopy_frame_v1_send_flags(frame->resource, flags);
frame_send_damage(frame);
frame_send_ready(frame, event->when);
frame_destroy(frame);
}
@ -364,6 +425,9 @@ static void frame_handle_copy(struct wl_client *wl_client,
wl_signal_add(&output->events.precommit, &frame->output_precommit);
frame->output_precommit.notify = frame_handle_output_precommit;
wl_signal_add(&output->events.commit, &frame->output_commit);
frame->output_commit.notify = frame_handle_output_commit;
wl_signal_add(&output->events.destroy, &frame->output_enable);
frame->output_enable.notify = frame_handle_output_enable;
@ -374,7 +438,6 @@ static void frame_handle_copy(struct wl_client *wl_client,
frame->buffer_destroy.notify = frame_handle_buffer_destroy;
// Schedule a buffer commit
output->needs_frame = true;
wlr_output_schedule_frame(output);
wlr_output_lock_attach_render(output, true);
@ -467,6 +530,7 @@ static void capture_output(struct wl_client *wl_client,
wl_list_insert(&client->manager->frames, &frame->link);
wl_list_init(&frame->output_precommit.link);
wl_list_init(&frame->output_commit.link);
wl_list_init(&frame->output_enable.link);
wl_list_init(&frame->output_destroy.link);
wl_list_init(&frame->buffer_destroy.link);

View file

@ -713,7 +713,7 @@ bool wlr_surface_set_role(struct wlr_surface *surface,
if (surface->role != NULL && surface->role != role) {
if (error_resource != NULL) {
wl_resource_post_error(error_resource, error_code,
"Cannot assign role %s to wl_surface@%d, already has role %s\n",
"Cannot assign role %s to wl_surface@%" PRIu32 ", already has role %s\n",
role->name, wl_resource_get_id(surface->resource),
surface->role->name);
}
@ -721,7 +721,7 @@ bool wlr_surface_set_role(struct wlr_surface *surface,
}
if (surface->role_data != NULL && surface->role_data != role_data) {
wl_resource_post_error(error_resource, error_code,
"Cannot reassign role %s to wl_surface@%d,"
"Cannot reassign role %s to wl_surface@%" PRIu32 ","
"role object still exists", role->name,
wl_resource_get_id(surface->resource));
return false;
@ -792,7 +792,7 @@ static void subsurface_handle_place_above(struct wl_client *client,
if (!sibling) {
wl_resource_post_error(subsurface->resource,
WL_SUBSURFACE_ERROR_BAD_SURFACE,
"%s: wl_surface@%d is not a parent or sibling",
"%s: wl_surface@%" PRIu32 "is not a parent or sibling",
"place_above", wl_resource_get_id(sibling_surface->resource));
return;
}
@ -819,7 +819,7 @@ static void subsurface_handle_place_below(struct wl_client *client,
if (!sibling) {
wl_resource_post_error(subsurface->resource,
WL_SUBSURFACE_ERROR_BAD_SURFACE,
"%s: wl_surface@%d is not a parent or sibling",
"%s: wl_surface@%" PRIu32 " is not a parent or sibling",
"place_below", wl_resource_get_id(sibling_surface->resource));
return;
}

View file

@ -1,6 +1,7 @@
#define _POSIX_C_SOURCE 199309L
#include <assert.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
@ -72,12 +73,14 @@ static void virtual_keyboard_keymap(struct wl_client *client,
keyboard->has_keymap = true;
xkb_keymap_unref(keymap);
xkb_context_unref(context);
close(fd);
return;
keymap_fail:
fd_fail:
xkb_context_unref(context);
context_fail:
wl_client_post_no_memory(client);
close(fd);
}
static void virtual_keyboard_key(struct wl_client *client,

View file

@ -94,7 +94,7 @@ static void virtual_pointer_axis(struct wl_client *client,
if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
wl_resource_post_error(resource,
ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS,
"Invalid enumeration value %d", axis);
"Invalid enumeration value %" PRIu32, axis);
return;
}
struct wlr_virtual_pointer_v1 *pointer =
@ -103,7 +103,8 @@ static void virtual_pointer_axis(struct wl_client *client,
return;
}
struct wlr_input_device *wlr_dev = &pointer->input_device;
pointer->axis_valid[axis] = true;
pointer->axis = axis;
pointer->axis_valid[pointer->axis] = true;
pointer->axis_event[pointer->axis].device = wlr_dev;
pointer->axis_event[pointer->axis].time_msec = time;
pointer->axis_event[pointer->axis].orientation = axis;
@ -139,7 +140,7 @@ static void virtual_pointer_axis_source(struct wl_client *client,
if (source > WL_POINTER_AXIS_SOURCE_WHEEL_TILT) {
wl_resource_post_error(resource,
ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS_SOURCE,
"Invalid enumeration value %d", source);
"Invalid enumeration value %" PRIu32, source);
return;
}
struct wlr_virtual_pointer_v1 *pointer =
@ -157,7 +158,7 @@ static void virtual_pointer_axis_stop(struct wl_client *client,
if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
wl_resource_post_error(resource,
ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS,
"Invalid enumeration value %d", axis);
"Invalid enumeration value %" PRIu32, axis);
return;
}
struct wlr_virtual_pointer_v1 *pointer =
@ -181,7 +182,7 @@ static void virtual_pointer_axis_discrete(struct wl_client *client,
if (axis > WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
wl_resource_post_error(resource,
ZWLR_VIRTUAL_POINTER_V1_ERROR_INVALID_AXIS,
"Invalid enumeration value %d", axis);
"Invalid enumeration value %" PRIu32, axis);
return;
}
struct wlr_virtual_pointer_v1 *pointer =

View file

@ -336,7 +336,9 @@ static void xdg_surface_handle_surface_commit(struct wl_listener *listener,
return;
}
if (surface->role == WLR_XDG_SURFACE_ROLE_NONE) {
// surface->role might be NONE for inert popups
// So we check surface->surface->role
if (surface->surface->role == NULL) {
wl_resource_post_error(surface->resource,
XDG_SURFACE_ERROR_NOT_CONSTRUCTED,
"xdg_surface must have a role");
@ -361,7 +363,8 @@ void handle_xdg_surface_commit(struct wlr_surface *wlr_surface) {
switch (surface->role) {
case WLR_XDG_SURFACE_ROLE_NONE:
assert(false);
// inert toplevel or popup
return;
case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
handle_xdg_surface_toplevel_committed(surface);
break;
@ -494,7 +497,7 @@ void reset_xdg_surface(struct wlr_xdg_surface *xdg_surface) {
break;
case WLR_XDG_SURFACE_ROLE_POPUP:
wl_resource_set_user_data(xdg_surface->popup->resource, NULL);
xdg_surface->toplevel->resource = NULL;
xdg_surface->popup->resource = NULL;
wl_list_remove(&xdg_surface->popup->link);

View file

@ -13,60 +13,44 @@ void handle_xdg_toplevel_ack_configure(
assert(surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
assert(configure->toplevel_state != NULL);
surface->toplevel->current.maximized =
configure->toplevel_state->maximized;
surface->toplevel->current.fullscreen =
configure->toplevel_state->fullscreen;
surface->toplevel->current.resizing =
configure->toplevel_state->resizing;
surface->toplevel->current.activated =
configure->toplevel_state->activated;
surface->toplevel->current.tiled =
configure->toplevel_state->tiled;
surface->toplevel->last_acked = *configure->toplevel_state;
}
bool compare_xdg_surface_toplevel_state(struct wlr_xdg_toplevel *state) {
struct {
struct wlr_xdg_toplevel_state state;
uint32_t width, height;
} configured;
// is pending state different from current state?
if (!state->base->configured) {
return false;
}
struct wlr_xdg_toplevel_state *configured = NULL;
if (wl_list_empty(&state->base->configure_list)) {
// last configure is actually the current state, just use it
configured.state = state->current;
configured.width = state->base->surface->current.width;
configured.height = state->base->surface->current.height;
// There are currently no pending configures, so check against the last
// state acked by the client.
configured = &state->last_acked;
} else {
struct wlr_xdg_surface_configure *configure =
wl_container_of(state->base->configure_list.prev, configure, link);
configured.state = *configure->toplevel_state;
configured.width = configure->toplevel_state->width;
configured.height = configure->toplevel_state->height;
configured = configure->toplevel_state;
}
if (state->server_pending.activated != configured.state.activated) {
if (state->server_pending.activated != configured->activated) {
return false;
}
if (state->server_pending.fullscreen != configured.state.fullscreen) {
if (state->server_pending.fullscreen != configured->fullscreen) {
return false;
}
if (state->server_pending.maximized != configured.state.maximized) {
if (state->server_pending.maximized != configured->maximized) {
return false;
}
if (state->server_pending.resizing != configured.state.resizing) {
if (state->server_pending.resizing != configured->resizing) {
return false;
}
if (state->server_pending.tiled != configured.state.tiled) {
if (state->server_pending.tiled != configured->tiled) {
return false;
}
if (state->server_pending.width == configured.width &&
state->server_pending.height == configured.height) {
if (state->server_pending.width == configured->width &&
state->server_pending.height == configured->height) {
return true;
}
@ -187,7 +171,10 @@ void handle_xdg_surface_toplevel_committed(struct wlr_xdg_surface *surface) {
return;
}
// update state that doesn't need compositor approval
// apply state from the last acked configure now that the client committed
surface->toplevel->current = surface->toplevel->last_acked;
// update state from the client that doesn't need compositor approval
surface->toplevel->current.max_width =
surface->toplevel->client_pending.max_width;
surface->toplevel->current.min_width =

View file

@ -1,585 +0,0 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "types/wlr_xdg_shell_v6.h"
#include "util/signal.h"
static struct wlr_xdg_surface_v6 *xdg_popup_grab_get_topmost(
struct wlr_xdg_popup_grab_v6 *grab) {
struct wlr_xdg_popup_v6 *popup;
wl_list_for_each(popup, &grab->popups, grab_link) {
return popup->base;
}
return NULL;
}
static void xdg_popup_grab_end(struct wlr_xdg_popup_grab_v6 *popup_grab) {
struct wlr_xdg_popup_v6 *popup, *tmp;
wl_list_for_each_safe(popup, tmp, &popup_grab->popups, grab_link) {
zxdg_popup_v6_send_popup_done(popup->resource);
}
wlr_seat_pointer_end_grab(popup_grab->seat);
wlr_seat_keyboard_end_grab(popup_grab->seat);
wlr_seat_touch_end_grab(popup_grab->seat);
}
static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab,
struct wlr_surface *surface, double sx, double sy) {
struct wlr_xdg_popup_grab_v6 *popup_grab = grab->data;
if (wl_resource_get_client(surface->resource) == popup_grab->client) {
wlr_seat_pointer_enter(grab->seat, surface, sx, sy);
} else {
wlr_seat_pointer_clear_focus(grab->seat);
}
}
static void xdg_pointer_grab_clear_focus(struct wlr_seat_pointer_grab *grab) {
wlr_seat_pointer_clear_focus(grab->seat);
}
static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab,
uint32_t time, double sx, double sy) {
wlr_seat_pointer_send_motion(grab->seat, time, sx, sy);
}
static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab,
uint32_t time, uint32_t button, uint32_t state) {
uint32_t serial =
wlr_seat_pointer_send_button(grab->seat, time, button, state);
if (serial) {
return serial;
} else {
xdg_popup_grab_end(grab->data);
return 0;
}
}
static void xdg_pointer_grab_axis(struct wlr_seat_pointer_grab *grab,
uint32_t time, enum wlr_axis_orientation orientation, double value,
int32_t value_discrete, enum wlr_axis_source source) {
wlr_seat_pointer_send_axis(grab->seat, time, orientation, value,
value_discrete, source);
}
static void xdg_pointer_grab_frame(struct wlr_seat_pointer_grab *grab) {
wlr_seat_pointer_send_frame(grab->seat);
}
static void xdg_pointer_grab_cancel(struct wlr_seat_pointer_grab *grab) {
xdg_popup_grab_end(grab->data);
}
static const struct wlr_pointer_grab_interface xdg_pointer_grab_impl = {
.enter = xdg_pointer_grab_enter,
.clear_focus = xdg_pointer_grab_clear_focus,
.motion = xdg_pointer_grab_motion,
.button = xdg_pointer_grab_button,
.cancel = xdg_pointer_grab_cancel,
.axis = xdg_pointer_grab_axis,
.frame = xdg_pointer_grab_frame,
};
static void xdg_keyboard_grab_enter(struct wlr_seat_keyboard_grab *grab,
struct wlr_surface *surface, uint32_t keycodes[], size_t num_keycodes,
struct wlr_keyboard_modifiers *modifiers) {
// keyboard focus should remain on the popup
}
static void xdg_keyboard_grab_clear_focus(struct wlr_seat_keyboard_grab *grab) {
// keyboard focus should remain on the popup
}
static void xdg_keyboard_grab_key(struct wlr_seat_keyboard_grab *grab,
uint32_t time, uint32_t key, uint32_t state) {
wlr_seat_keyboard_send_key(grab->seat, time, key, state);
}
static void xdg_keyboard_grab_modifiers(struct wlr_seat_keyboard_grab *grab,
struct wlr_keyboard_modifiers *modifiers) {
wlr_seat_keyboard_send_modifiers(grab->seat, modifiers);
}
static void xdg_keyboard_grab_cancel(struct wlr_seat_keyboard_grab *grab) {
wlr_seat_pointer_end_grab(grab->seat);
}
static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = {
.enter = xdg_keyboard_grab_enter,
.clear_focus = xdg_keyboard_grab_clear_focus,
.key = xdg_keyboard_grab_key,
.modifiers = xdg_keyboard_grab_modifiers,
.cancel = xdg_keyboard_grab_cancel,
};
static uint32_t xdg_touch_grab_down(struct wlr_seat_touch_grab *grab,
uint32_t time, struct wlr_touch_point *point) {
struct wlr_xdg_popup_grab_v6 *popup_grab = grab->data;
if (wl_resource_get_client(point->surface->resource) != popup_grab->client) {
xdg_popup_grab_end(grab->data);
return 0;
}
return wlr_seat_touch_send_down(grab->seat, point->surface, time,
point->touch_id, point->sx, point->sy);
}
static void xdg_touch_grab_up(struct wlr_seat_touch_grab *grab,
uint32_t time, struct wlr_touch_point *point) {
wlr_seat_touch_send_up(grab->seat, time, point->touch_id);
}
static void xdg_touch_grab_motion(struct wlr_seat_touch_grab *grab,
uint32_t time, struct wlr_touch_point *point) {
wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx,
point->sy);
}
static void xdg_touch_grab_enter(struct wlr_seat_touch_grab *grab,
uint32_t time, struct wlr_touch_point *point) {
}
static void xdg_touch_grab_cancel(struct wlr_seat_touch_grab *grab) {
wlr_seat_touch_end_grab(grab->seat);
}
static const struct wlr_touch_grab_interface xdg_touch_grab_impl = {
.down = xdg_touch_grab_down,
.up = xdg_touch_grab_up,
.motion = xdg_touch_grab_motion,
.enter = xdg_touch_grab_enter,
.cancel = xdg_touch_grab_cancel
};
static void xdg_popup_grab_handle_seat_destroy(
struct wl_listener *listener, void *data) {
struct wlr_xdg_popup_grab_v6 *xdg_grab =
wl_container_of(listener, xdg_grab, seat_destroy);
wl_list_remove(&xdg_grab->seat_destroy.link);
struct wlr_xdg_popup_v6 *popup, *next;
wl_list_for_each_safe(popup, next, &xdg_grab->popups, grab_link) {
destroy_xdg_surface_v6(popup->base);
}
wl_list_remove(&xdg_grab->link);
free(xdg_grab);
}
struct wlr_xdg_popup_grab_v6 *get_xdg_shell_v6_popup_grab_from_seat(
struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat) {
struct wlr_xdg_popup_grab_v6 *xdg_grab;
wl_list_for_each(xdg_grab, &shell->popup_grabs, link) {
if (xdg_grab->seat == seat) {
return xdg_grab;
}
}
xdg_grab = calloc(1, sizeof(struct wlr_xdg_popup_grab_v6));
if (!xdg_grab) {
return NULL;
}
xdg_grab->pointer_grab.data = xdg_grab;
xdg_grab->pointer_grab.interface = &xdg_pointer_grab_impl;
xdg_grab->keyboard_grab.data = xdg_grab;
xdg_grab->keyboard_grab.interface = &xdg_keyboard_grab_impl;
xdg_grab->touch_grab.data = xdg_grab;
xdg_grab->touch_grab.interface = &xdg_touch_grab_impl;
wl_list_init(&xdg_grab->popups);
wl_list_insert(&shell->popup_grabs, &xdg_grab->link);
xdg_grab->seat = seat;
xdg_grab->seat_destroy.notify = xdg_popup_grab_handle_seat_destroy;
wl_signal_add(&seat->events.destroy, &xdg_grab->seat_destroy);
return xdg_grab;
}
static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation;
static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_popup_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zxdg_popup_v6_interface,
&zxdg_popup_v6_implementation));
return wl_resource_get_user_data(resource);
}
void destroy_xdg_popup_v6(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP);
unmap_xdg_surface_v6(surface);
wl_resource_set_user_data(surface->popup->resource, NULL);
wl_list_remove(&surface->popup->link);
free(surface->popup);
surface->popup = NULL;
surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE;
}
static void xdg_popup_handle_grab(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *seat_resource,
uint32_t serial) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_popup_resource(resource);
struct wlr_seat_client *seat_client =
wlr_seat_client_from_resource(seat_resource);
if (!surface) {
return;
}
if (surface->popup->committed) {
wl_resource_post_error(surface->popup->resource,
ZXDG_POPUP_V6_ERROR_INVALID_GRAB,
"xdg_popup is already mapped");
return;
}
struct wlr_xdg_popup_grab_v6 *popup_grab =
get_xdg_shell_v6_popup_grab_from_seat(surface->client->shell,
seat_client->seat);
struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab);
bool parent_is_toplevel =
surface->popup->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL;
if ((topmost == NULL && !parent_is_toplevel) ||
(topmost != NULL && topmost != surface->popup->parent)) {
wl_resource_post_error(surface->client->resource,
ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was not created on the topmost popup");
return;
}
popup_grab->client = surface->client->client;
surface->popup->seat = seat_client->seat;
wl_list_insert(&popup_grab->popups, &surface->popup->grab_link);
wlr_seat_pointer_start_grab(seat_client->seat,
&popup_grab->pointer_grab);
wlr_seat_keyboard_start_grab(seat_client->seat,
&popup_grab->keyboard_grab);
wlr_seat_touch_start_grab(seat_client->seat,
&popup_grab->touch_grab);
}
static void xdg_popup_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_popup_resource(resource);
if (surface && !wl_list_empty(&surface->popups)) {
wl_resource_post_error(surface->client->resource,
ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP,
"xdg_popup was destroyed while it was not the topmost popup");
return;
}
wl_resource_destroy(resource);
}
static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = {
.destroy = xdg_popup_handle_destroy,
.grab = xdg_popup_handle_grab,
};
static void xdg_popup_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_popup_resource(resource);
if (surface != NULL) {
destroy_xdg_popup_v6(surface);
}
}
void handle_xdg_surface_v6_popup_committed(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP);
if (!surface->popup->committed) {
schedule_xdg_surface_v6_configure(surface);
surface->popup->committed = true;
}
}
const struct wlr_surface_role xdg_popup_v6_surface_role = {
.name = "xdg_popup_v6",
.commit = handle_xdg_surface_v6_commit,
.precommit = handle_xdg_surface_v6_precommit,
};
void create_xdg_popup_v6(struct wlr_xdg_surface_v6 *xdg_surface,
struct wlr_xdg_surface_v6 *parent,
struct wlr_xdg_positioner_v6_resource *positioner, int32_t id) {
if (positioner->attrs.size.width == 0 ||
positioner->attrs.anchor_rect.width == 0) {
wl_resource_post_error(xdg_surface->resource,
ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER,
"positioner object is not complete");
return;
}
if (!wlr_surface_set_role(xdg_surface->surface, &xdg_popup_v6_surface_role,
xdg_surface, xdg_surface->resource, ZXDG_SHELL_V6_ERROR_ROLE)) {
return;
}
xdg_surface->popup = calloc(1, sizeof(struct wlr_xdg_popup_v6));
if (!xdg_surface->popup) {
wl_resource_post_no_memory(xdg_surface->resource);
return;
}
xdg_surface->popup->resource =
wl_resource_create(xdg_surface->client->client, &zxdg_popup_v6_interface,
wl_resource_get_version(xdg_surface->resource), id);
if (xdg_surface->popup->resource == NULL) {
free(xdg_surface->popup);
wl_resource_post_no_memory(xdg_surface->resource);
return;
}
wl_resource_set_implementation(xdg_surface->popup->resource,
&zxdg_popup_v6_implementation, xdg_surface,
xdg_popup_handle_resource_destroy);
xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_POPUP;
xdg_surface->popup->base = xdg_surface;
xdg_surface->popup->parent = parent;
xdg_surface->popup->geometry =
wlr_xdg_positioner_v6_get_geometry(&positioner->attrs);
// positioner properties
memcpy(&xdg_surface->popup->positioner, &positioner->attrs,
sizeof(struct wlr_xdg_positioner_v6));
wl_list_insert(&parent->popups, &xdg_surface->popup->link);
wlr_signal_emit_safe(&parent->events.new_popup, xdg_surface->popup);
}
void wlr_xdg_popup_v6_get_anchor_point(struct wlr_xdg_popup_v6 *popup,
int *root_sx, int *root_sy) {
struct wlr_box rect = popup->positioner.anchor_rect;
enum zxdg_positioner_v6_anchor anchor = popup->positioner.anchor;
int sx = 0, sy = 0;
if (anchor == ZXDG_POSITIONER_V6_ANCHOR_NONE) {
sx = (rect.x + rect.width) / 2;
sy = (rect.y + rect.height) / 2;
} else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_TOP) {
sx = (rect.x + rect.width) / 2;
sy = rect.y;
} else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) {
sx = (rect.x + rect.width) / 2;
sy = rect.y + rect.height;
} else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_LEFT) {
sx = rect.x;
sy = (rect.y + rect.height) / 2;
} else if (anchor == ZXDG_POSITIONER_V6_ANCHOR_RIGHT) {
sx = rect.x + rect.width;
sy = (rect.y + rect.height) / 2;
} else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_TOP |
ZXDG_POSITIONER_V6_ANCHOR_LEFT)) {
sx = rect.x;
sy = rect.y;
} else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_TOP |
ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) {
sx = rect.x + rect.width;
sy = rect.y;
} else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
ZXDG_POSITIONER_V6_ANCHOR_LEFT)) {
sx = rect.x;
sy = rect.y + rect.height;
} else if (anchor == (ZXDG_POSITIONER_V6_ANCHOR_BOTTOM |
ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) {
sx = rect.x + rect.width;
sy = rect.y + rect.height;
}
*root_sx = sx;
*root_sy = sy;
}
void wlr_xdg_popup_v6_get_toplevel_coords(struct wlr_xdg_popup_v6 *popup,
int popup_sx, int popup_sy, int *toplevel_sx, int *toplevel_sy) {
struct wlr_xdg_surface_v6 *parent = popup->parent;
while (parent != NULL && parent->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) {
popup_sx += parent->popup->geometry.x;
popup_sy += parent->popup->geometry.y;
parent = parent->popup->parent;
}
assert(parent);
*toplevel_sx = popup_sx + parent->geometry.x;
*toplevel_sy = popup_sy + parent->geometry.y;
}
static void xdg_popup_v6_box_constraints(struct wlr_xdg_popup_v6 *popup,
struct wlr_box *toplevel_sx_box, int *offset_x, int *offset_y) {
int popup_width = popup->geometry.width;
int popup_height = popup->geometry.height;
int anchor_sx = 0, anchor_sy = 0;
wlr_xdg_popup_v6_get_anchor_point(popup, &anchor_sx, &anchor_sy);
int popup_sx = 0, popup_sy = 0;
wlr_xdg_popup_v6_get_toplevel_coords(popup, popup->geometry.x,
popup->geometry.y, &popup_sx, &popup_sy);
*offset_x = 0, *offset_y = 0;
if (popup_sx < toplevel_sx_box->x) {
*offset_x = toplevel_sx_box->x - popup_sx;
} else if (popup_sx + popup_width >
toplevel_sx_box->x + toplevel_sx_box->width) {
*offset_x = toplevel_sx_box->x + toplevel_sx_box->width -
(popup_sx + popup_width);
}
if (popup_sy < toplevel_sx_box->y) {
*offset_y = toplevel_sx_box->y - popup_sy;
} else if (popup_sy + popup_height >
toplevel_sx_box->y + toplevel_sx_box->height) {
*offset_y = toplevel_sx_box->y + toplevel_sx_box->height -
(popup_sy + popup_height);
}
}
static bool xdg_popup_v6_unconstrain_flip(struct wlr_xdg_popup_v6 *popup,
struct wlr_box *toplevel_sx_box) {
int offset_x = 0, offset_y = 0;
xdg_popup_v6_box_constraints(popup, toplevel_sx_box,
&offset_x, &offset_y);
if (!offset_x && !offset_y) {
return true;
}
bool flip_x = offset_x &&
(popup->positioner.constraint_adjustment &
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X);
bool flip_y = offset_y &&
(popup->positioner.constraint_adjustment &
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y);
if (flip_x) {
wlr_positioner_v6_invert_x(&popup->positioner);
}
if (flip_y) {
wlr_positioner_v6_invert_y(&popup->positioner);
}
popup->geometry =
wlr_xdg_positioner_v6_get_geometry(&popup->positioner);
xdg_popup_v6_box_constraints(popup, toplevel_sx_box,
&offset_x, &offset_y);
if (!offset_x && !offset_y) {
// no longer constrained
return true;
}
// revert the positioner back if it didn't fix it and go to the next part
if (offset_x && flip_x) {
wlr_positioner_v6_invert_x(&popup->positioner);
}
if (offset_y && flip_y) {
wlr_positioner_v6_invert_y(&popup->positioner);
}
popup->geometry =
wlr_xdg_positioner_v6_get_geometry(&popup->positioner);
return false;
}
static bool xdg_popup_v6_unconstrain_slide(struct wlr_xdg_popup_v6 *popup,
struct wlr_box *toplevel_sx_box) {
int offset_x = 0, offset_y = 0;
xdg_popup_v6_box_constraints(popup, toplevel_sx_box,
&offset_x, &offset_y);
if (!offset_x && !offset_y) {
return true;
}
bool slide_x = offset_x &&
(popup->positioner.constraint_adjustment &
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X);
bool slide_y = offset_y &&
(popup->positioner.constraint_adjustment &
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y);
if (slide_x) {
popup->geometry.x += offset_x;
}
if (slide_y) {
popup->geometry.y += offset_y;
}
int toplevel_x = 0, toplevel_y = 0;
wlr_xdg_popup_v6_get_toplevel_coords(popup, popup->geometry.x,
popup->geometry.y, &toplevel_x, &toplevel_y);
if (slide_x && toplevel_x < toplevel_sx_box->x) {
popup->geometry.x += toplevel_sx_box->x - toplevel_x;
}
if (slide_y && toplevel_y < toplevel_sx_box->y) {
popup->geometry.y += toplevel_sx_box->y - toplevel_y;
}
xdg_popup_v6_box_constraints(popup, toplevel_sx_box,
&offset_x, &offset_y);
return !offset_x && !offset_y;
}
static bool xdg_popup_v6_unconstrain_resize(struct wlr_xdg_popup_v6 *popup,
struct wlr_box *toplevel_sx_box) {
int offset_x, offset_y;
xdg_popup_v6_box_constraints(popup, toplevel_sx_box,
&offset_x, &offset_y);
if (!offset_x && !offset_y) {
return true;
}
bool resize_x = offset_x &&
(popup->positioner.constraint_adjustment &
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X);
bool resize_y = offset_y &&
(popup->positioner.constraint_adjustment &
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y);
if (resize_x) {
popup->geometry.width -= offset_x;
}
if (resize_y) {
popup->geometry.height -= offset_y;
}
xdg_popup_v6_box_constraints(popup, toplevel_sx_box,
&offset_x, &offset_y);
return !offset_x && !offset_y;
}
void wlr_xdg_popup_v6_unconstrain_from_box(struct wlr_xdg_popup_v6 *popup,
struct wlr_box *toplevel_sx_box) {
if (xdg_popup_v6_unconstrain_flip(popup, toplevel_sx_box)) {
return;
}
if (xdg_popup_v6_unconstrain_slide(popup, toplevel_sx_box)) {
return;
}
if (xdg_popup_v6_unconstrain_resize(popup, toplevel_sx_box)) {
return;
}
}

View file

@ -1,230 +0,0 @@
#include <assert.h>
#include <stdlib.h>
#include "types/wlr_xdg_shell_v6.h"
static const struct zxdg_positioner_v6_interface
zxdg_positioner_v6_implementation;
struct wlr_xdg_positioner_v6_resource *get_xdg_positioner_v6_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zxdg_positioner_v6_interface,
&zxdg_positioner_v6_implementation));
return wl_resource_get_user_data(resource);
}
static void xdg_positioner_destroy(struct wl_resource *resource) {
struct wlr_xdg_positioner_v6_resource *positioner =
get_xdg_positioner_v6_from_resource(resource);
free(positioner);
}
static void xdg_positioner_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void xdg_positioner_handle_set_size(struct wl_client *client,
struct wl_resource *resource, int32_t width, int32_t height) {
struct wlr_xdg_positioner_v6_resource *positioner =
get_xdg_positioner_v6_from_resource(resource);
if (width < 1 || height < 1) {
wl_resource_post_error(resource,
ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
"width and height must be positive and non-zero");
return;
}
positioner->attrs.size.width = width;
positioner->attrs.size.height = height;
}
static void xdg_positioner_handle_set_anchor_rect(struct wl_client *client,
struct wl_resource *resource, int32_t x, int32_t y, int32_t width,
int32_t height) {
struct wlr_xdg_positioner_v6_resource *positioner =
get_xdg_positioner_v6_from_resource(resource);
if (width < 1 || height < 1) {
wl_resource_post_error(resource,
ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
"width and height must be positive and non-zero");
return;
}
positioner->attrs.anchor_rect.x = x;
positioner->attrs.anchor_rect.y = y;
positioner->attrs.anchor_rect.width = width;
positioner->attrs.anchor_rect.height = height;
}
static void xdg_positioner_handle_set_anchor(struct wl_client *client,
struct wl_resource *resource, uint32_t anchor) {
struct wlr_xdg_positioner_v6_resource *positioner =
get_xdg_positioner_v6_from_resource(resource);
if (((anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP ) &&
(anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) ||
((anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) &&
(anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT))) {
wl_resource_post_error(resource,
ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
"same-axis values are not allowed");
return;
}
positioner->attrs.anchor = anchor;
}
static void xdg_positioner_handle_set_gravity(struct wl_client *client,
struct wl_resource *resource, uint32_t gravity) {
struct wlr_xdg_positioner_v6_resource *positioner =
get_xdg_positioner_v6_from_resource(resource);
if (((gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) &&
(gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) ||
((gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) &&
(gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT))) {
wl_resource_post_error(resource,
ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
"same-axis values are not allowed");
return;
}
positioner->attrs.gravity = gravity;
}
static void xdg_positioner_handle_set_constraint_adjustment(
struct wl_client *client, struct wl_resource *resource,
uint32_t constraint_adjustment) {
struct wlr_xdg_positioner_v6_resource *positioner =
get_xdg_positioner_v6_from_resource(resource);
positioner->attrs.constraint_adjustment = constraint_adjustment;
}
static void xdg_positioner_handle_set_offset(struct wl_client *client,
struct wl_resource *resource, int32_t x, int32_t y) {
struct wlr_xdg_positioner_v6_resource *positioner =
get_xdg_positioner_v6_from_resource(resource);
positioner->attrs.offset.x = x;
positioner->attrs.offset.y = y;
}
static const struct zxdg_positioner_v6_interface
zxdg_positioner_v6_implementation = {
.destroy = xdg_positioner_handle_destroy,
.set_size = xdg_positioner_handle_set_size,
.set_anchor_rect = xdg_positioner_handle_set_anchor_rect,
.set_anchor = xdg_positioner_handle_set_anchor,
.set_gravity = xdg_positioner_handle_set_gravity,
.set_constraint_adjustment =
xdg_positioner_handle_set_constraint_adjustment,
.set_offset = xdg_positioner_handle_set_offset,
};
struct wlr_box wlr_xdg_positioner_v6_get_geometry(
struct wlr_xdg_positioner_v6 *positioner) {
struct wlr_box geometry = {
.x = positioner->offset.x,
.y = positioner->offset.y,
.width = positioner->size.width,
.height = positioner->size.height,
};
if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) {
geometry.y += positioner->anchor_rect.y;
} else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) {
geometry.y +=
positioner->anchor_rect.y + positioner->anchor_rect.height;
} else {
geometry.y +=
positioner->anchor_rect.y + positioner->anchor_rect.height / 2;
}
if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) {
geometry.x += positioner->anchor_rect.x;
} else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) {
geometry.x += positioner->anchor_rect.x + positioner->anchor_rect.width;
} else {
geometry.x +=
positioner->anchor_rect.x + positioner->anchor_rect.width / 2;
}
if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) {
geometry.y -= geometry.height;
} else if (!(positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) {
geometry.y -= geometry.height / 2;
}
if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) {
geometry.x -= geometry.width;
} else if (!(positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT)) {
geometry.x -= geometry.width / 2;
}
if (positioner->constraint_adjustment ==
ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE) {
return geometry;
}
return geometry;
}
void wlr_positioner_v6_invert_x(struct wlr_xdg_positioner_v6 *positioner) {
if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT) {
positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_LEFT;
positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
} else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT) {
positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_LEFT;
}
if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT) {
positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_LEFT;
} else if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT) {
positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_LEFT;
positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
}
}
void wlr_positioner_v6_invert_y(
struct wlr_xdg_positioner_v6 *positioner) {
if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP) {
positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_TOP;
positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
} else if (positioner->anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM) {
positioner->anchor &= ~ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
positioner->anchor |= ZXDG_POSITIONER_V6_ANCHOR_TOP;
}
if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP) {
positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_TOP;
positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
} else if (positioner->gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM) {
positioner->gravity &= ~ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
positioner->gravity |= ZXDG_POSITIONER_V6_GRAVITY_TOP;
}
}
void create_xdg_positioner_v6(struct wlr_xdg_client_v6 *client, uint32_t id) {
struct wlr_xdg_positioner_v6_resource *positioner =
calloc(1, sizeof(struct wlr_xdg_positioner_v6_resource));
if (positioner == NULL) {
wl_client_post_no_memory(client->client);
return;
}
positioner->resource = wl_resource_create(client->client,
&zxdg_positioner_v6_interface,
wl_resource_get_version(client->resource), id);
if (positioner->resource == NULL) {
free(positioner);
wl_client_post_no_memory(client->client);
return;
}
wl_resource_set_implementation(positioner->resource,
&zxdg_positioner_v6_implementation, positioner, xdg_positioner_destroy);
}

View file

@ -1,168 +0,0 @@
#include <assert.h>
#include <stdlib.h>
#include "types/wlr_xdg_shell_v6.h"
#include "util/signal.h"
#define SHELL_VERSION 1
static const struct zxdg_shell_v6_interface xdg_shell_impl;
static struct wlr_xdg_client_v6 *xdg_client_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zxdg_shell_v6_interface,
&xdg_shell_impl));
return wl_resource_get_user_data(resource);
}
static void xdg_shell_handle_create_positioner(struct wl_client *wl_client,
struct wl_resource *resource, uint32_t id) {
struct wlr_xdg_client_v6 *client =
xdg_client_from_resource(resource);
create_xdg_positioner_v6(client, id);
}
static void xdg_shell_handle_get_xdg_surface(struct wl_client *wl_client,
struct wl_resource *client_resource, uint32_t id,
struct wl_resource *surface_resource) {
struct wlr_xdg_client_v6 *client =
xdg_client_from_resource(client_resource);
struct wlr_surface *surface = wlr_surface_from_resource(surface_resource);
create_xdg_surface_v6(client, surface, id);
}
static void xdg_shell_handle_pong(struct wl_client *wl_client,
struct wl_resource *resource, uint32_t serial) {
struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource);
if (client->ping_serial != serial) {
return;
}
wl_event_source_timer_update(client->ping_timer, 0);
client->ping_serial = 0;
}
static void xdg_shell_handle_destroy(struct wl_client *wl_client,
struct wl_resource *resource) {
struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource);
if (!wl_list_empty(&client->surfaces)) {
wl_resource_post_error(client->resource,
ZXDG_SHELL_V6_ERROR_DEFUNCT_SURFACES,
"xdg_wm_base was destroyed before children");
return;
}
wl_resource_destroy(resource);
}
static const struct zxdg_shell_v6_interface xdg_shell_impl = {
.destroy = xdg_shell_handle_destroy,
.create_positioner = xdg_shell_handle_create_positioner,
.get_xdg_surface = xdg_shell_handle_get_xdg_surface,
.pong = xdg_shell_handle_pong,
};
static void xdg_client_v6_handle_resource_destroy(
struct wl_resource *resource) {
struct wlr_xdg_client_v6 *client = xdg_client_from_resource(resource);
struct wlr_xdg_surface_v6 *surface, *tmp = NULL;
wl_list_for_each_safe(surface, tmp, &client->surfaces, link) {
wl_resource_destroy(surface->resource);
}
if (client->ping_timer != NULL) {
wl_event_source_remove(client->ping_timer);
}
wl_list_remove(&client->link);
free(client);
}
static int xdg_client_v6_ping_timeout(void *user_data) {
struct wlr_xdg_client_v6 *client = user_data;
struct wlr_xdg_surface_v6 *surface;
wl_list_for_each(surface, &client->surfaces, link) {
wlr_signal_emit_safe(&surface->events.ping_timeout, surface);
}
client->ping_serial = 0;
return 1;
}
static void xdg_shell_bind(struct wl_client *wl_client, void *data,
uint32_t version, uint32_t id) {
struct wlr_xdg_shell_v6 *xdg_shell = data;
assert(wl_client && xdg_shell);
struct wlr_xdg_client_v6 *client =
calloc(1, sizeof(struct wlr_xdg_client_v6));
if (client == NULL) {
wl_client_post_no_memory(wl_client);
return;
}
wl_list_init(&client->surfaces);
client->resource =
wl_resource_create(wl_client, &zxdg_shell_v6_interface, version, id);
if (client->resource == NULL) {
free(client);
wl_client_post_no_memory(wl_client);
return;
}
client->client = wl_client;
client->shell = xdg_shell;
wl_resource_set_implementation(client->resource, &xdg_shell_impl, client,
xdg_client_v6_handle_resource_destroy);
wl_list_insert(&xdg_shell->clients, &client->link);
struct wl_display *display = wl_client_get_display(client->client);
struct wl_event_loop *loop = wl_display_get_event_loop(display);
client->ping_timer = wl_event_loop_add_timer(loop,
xdg_client_v6_ping_timeout, client);
if (client->ping_timer == NULL) {
wl_client_post_no_memory(client->client);
}
}
static void handle_display_destroy(struct wl_listener *listener, void *data) {
struct wlr_xdg_shell_v6 *xdg_shell =
wl_container_of(listener, xdg_shell, display_destroy);
wlr_signal_emit_safe(&xdg_shell->events.destroy, xdg_shell);
wl_list_remove(&xdg_shell->display_destroy.link);
wl_global_destroy(xdg_shell->global);
free(xdg_shell);
}
struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) {
struct wlr_xdg_shell_v6 *xdg_shell =
calloc(1, sizeof(struct wlr_xdg_shell_v6));
if (!xdg_shell) {
return NULL;
}
xdg_shell->ping_timeout = 10000;
wl_list_init(&xdg_shell->clients);
wl_list_init(&xdg_shell->popup_grabs);
struct wl_global *global = wl_global_create(display,
&zxdg_shell_v6_interface, SHELL_VERSION, xdg_shell, xdg_shell_bind);
if (!global) {
free(xdg_shell);
return NULL;
}
xdg_shell->global = global;
wl_signal_init(&xdg_shell->events.new_surface);
wl_signal_init(&xdg_shell->events.destroy);
xdg_shell->display_destroy.notify = handle_display_destroy;
wl_display_add_destroy_listener(display, &xdg_shell->display_destroy);
return xdg_shell;
}

View file

@ -1,606 +0,0 @@
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <wlr/util/log.h>
#include "types/wlr_xdg_shell_v6.h"
#include "util/signal.h"
bool wlr_surface_is_xdg_surface_v6(struct wlr_surface *surface) {
return surface->role == &xdg_toplevel_v6_surface_role ||
surface->role == &xdg_popup_v6_surface_role;
}
struct wlr_xdg_surface_v6 *wlr_xdg_surface_v6_from_wlr_surface(
struct wlr_surface *surface) {
assert(wlr_surface_is_xdg_surface_v6(surface));
return (struct wlr_xdg_surface_v6 *)surface->role_data;
}
static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation;
static struct wlr_xdg_surface_v6 *xdg_surface_from_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zxdg_surface_v6_interface,
&zxdg_surface_v6_implementation));
return wl_resource_get_user_data(resource);
}
static void xdg_surface_configure_destroy(
struct wlr_xdg_surface_v6_configure *configure) {
if (configure == NULL) {
return;
}
wl_list_remove(&configure->link);
free(configure->toplevel_state);
free(configure);
}
void unmap_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE);
// TODO: probably need to ungrab before this event
if (surface->mapped) {
wlr_signal_emit_safe(&surface->events.unmap, surface);
}
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
free(surface->toplevel->title);
surface->toplevel->title = NULL;
free(surface->toplevel->app_id);
surface->toplevel->app_id = NULL;
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
if (surface->popup->seat != NULL) {
struct wlr_xdg_popup_grab_v6 *grab =
get_xdg_shell_v6_popup_grab_from_seat(surface->client->shell,
surface->popup->seat);
wl_list_remove(&surface->popup->grab_link);
if (wl_list_empty(&grab->popups)) {
if (grab->seat->pointer_state.grab == &grab->pointer_grab) {
wlr_seat_pointer_end_grab(grab->seat);
}
if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) {
wlr_seat_keyboard_end_grab(grab->seat);
}
}
surface->popup->seat = NULL;
}
break;
case WLR_XDG_SURFACE_V6_ROLE_NONE:
assert(false && "not reached");
}
struct wlr_xdg_surface_v6_configure *configure, *tmp;
wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) {
xdg_surface_configure_destroy(configure);
}
surface->configured = surface->mapped = false;
surface->configure_serial = 0;
if (surface->configure_idle) {
wl_event_source_remove(surface->configure_idle);
surface->configure_idle = NULL;
}
surface->configure_next_serial = 0;
surface->has_next_geometry = false;
memset(&surface->geometry, 0, sizeof(struct wlr_box));
memset(&surface->next_geometry, 0, sizeof(struct wlr_box));
}
void destroy_xdg_surface_v6(struct wlr_xdg_surface_v6 *surface) {
if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) {
unmap_xdg_surface_v6(surface);
}
wlr_signal_emit_safe(&surface->events.destroy, surface);
struct wlr_xdg_popup_v6 *popup_state, *next;
wl_list_for_each_safe(popup_state, next, &surface->popups, link) {
zxdg_popup_v6_send_popup_done(popup_state->resource);
destroy_xdg_popup_v6(popup_state->base);
}
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
destroy_xdg_toplevel_v6(surface);
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
destroy_xdg_popup_v6(surface);
break;
case WLR_XDG_SURFACE_V6_ROLE_NONE:
// This space is intentionally left blank
break;
}
wl_resource_set_user_data(surface->resource, NULL);
surface->surface->role_data = NULL;
wl_list_remove(&surface->link);
wl_list_remove(&surface->surface_destroy.link);
wl_list_remove(&surface->surface_commit.link);
free(surface);
}
static void xdg_surface_handle_get_toplevel(struct wl_client *client,
struct wl_resource *resource, uint32_t id) {
struct wlr_xdg_surface_v6 *xdg_surface = xdg_surface_from_resource(resource);
create_xdg_toplevel_v6(xdg_surface, id);
}
static void xdg_surface_handle_get_popup(struct wl_client *wl_client,
struct wl_resource *resource, uint32_t id,
struct wl_resource *parent_resource,
struct wl_resource *positioner_resource) {
struct wlr_xdg_surface_v6 *xdg_surface =
xdg_surface_from_resource(resource);
struct wlr_xdg_surface_v6 *parent =
xdg_surface_from_resource(parent_resource);
struct wlr_xdg_positioner_v6_resource *positioner =
get_xdg_positioner_v6_from_resource(positioner_resource);
create_xdg_popup_v6(xdg_surface, parent, positioner, id);
}
static void xdg_surface_handle_ack_configure(struct wl_client *client,
struct wl_resource *resource, uint32_t serial) {
struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource);
if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) {
wl_resource_post_error(surface->resource,
ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
"xdg_surface must have a role");
return;
}
// First find the ack'ed configure
bool found = false;
struct wlr_xdg_surface_v6_configure *configure, *tmp;
wl_list_for_each(configure, &surface->configure_list, link) {
if (configure->serial == serial) {
found = true;
break;
}
}
if (!found) {
wl_resource_post_error(surface->client->resource,
ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
"wrong configure serial: %u", serial);
return;
}
// Then remove old configures from the list
wl_list_for_each_safe(configure, tmp, &surface->configure_list, link) {
if (configure->serial == serial) {
break;
}
xdg_surface_configure_destroy(configure);
}
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_NONE:
assert(0 && "not reached");
break;
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
handle_xdg_toplevel_v6_ack_configure(surface, configure);
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
break;
}
surface->configured = true;
surface->configure_serial = serial;
xdg_surface_configure_destroy(configure);
}
static void xdg_surface_handle_set_window_geometry(struct wl_client *client,
struct wl_resource *resource, int32_t x, int32_t y, int32_t width,
int32_t height) {
struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource);
if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) {
wl_resource_post_error(surface->resource,
ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
"xdg_surface must have a role");
return;
}
if (width <= 0 || height <= 0) {
wlr_log(WLR_ERROR, "Client tried to set invalid geometry");
wl_resource_post_error(resource, -1, "Tried to set invalid xdg-surface geometry");
}
surface->has_next_geometry = true;
surface->next_geometry.height = height;
surface->next_geometry.width = width;
surface->next_geometry.x = x;
surface->next_geometry.y = y;
}
static void xdg_surface_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource);
if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) {
wlr_log(WLR_ERROR, "Tried to destroy an xdg_surface before its role "
"object");
return;
}
wl_resource_destroy(resource);
}
static const struct zxdg_surface_v6_interface zxdg_surface_v6_implementation = {
.destroy = xdg_surface_handle_destroy,
.get_toplevel = xdg_surface_handle_get_toplevel,
.get_popup = xdg_surface_handle_get_popup,
.ack_configure = xdg_surface_handle_ack_configure,
.set_window_geometry = xdg_surface_handle_set_window_geometry,
};
static void xdg_surface_send_configure(void *user_data) {
struct wlr_xdg_surface_v6 *surface = user_data;
surface->configure_idle = NULL;
struct wlr_xdg_surface_v6_configure *configure =
calloc(1, sizeof(struct wlr_xdg_surface_v6_configure));
if (configure == NULL) {
wl_client_post_no_memory(surface->client->client);
return;
}
wl_list_insert(surface->configure_list.prev, &configure->link);
configure->serial = surface->configure_next_serial;
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_NONE:
assert(0 && "not reached");
break;
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
send_xdg_toplevel_v6_configure(surface, configure);
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
zxdg_popup_v6_send_configure(surface->popup->resource,
surface->popup->geometry.x,
surface->popup->geometry.y,
surface->popup->geometry.width,
surface->popup->geometry.height);
break;
}
zxdg_surface_v6_send_configure(surface->resource, configure->serial);
}
uint32_t schedule_xdg_surface_v6_configure(struct wlr_xdg_surface_v6 *surface) {
struct wl_display *display = wl_client_get_display(surface->client->client);
struct wl_event_loop *loop = wl_display_get_event_loop(display);
bool pending_same = false;
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_NONE:
assert(0 && "not reached");
break;
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
pending_same =
compare_xdg_surface_v6_toplevel_state(surface->toplevel);
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
break;
}
if (surface->configure_idle != NULL) {
if (!pending_same) {
// configure request already scheduled
return surface->configure_next_serial;
}
// configure request not necessary anymore
wl_event_source_remove(surface->configure_idle);
surface->configure_idle = NULL;
return 0;
} else {
if (pending_same) {
// configure request not necessary
return 0;
}
surface->configure_next_serial = wl_display_next_serial(display);
surface->configure_idle = wl_event_loop_add_idle(loop,
xdg_surface_send_configure, surface);
return surface->configure_next_serial;
}
}
void wlr_xdg_surface_v6_ping(struct wlr_xdg_surface_v6 *surface) {
if (surface->client->ping_serial != 0) {
// already pinged
return;
}
surface->client->ping_serial =
wl_display_next_serial(wl_client_get_display(surface->client->client));
wl_event_source_timer_update(surface->client->ping_timer,
surface->client->shell->ping_timeout);
zxdg_shell_v6_send_ping(surface->client->resource,
surface->client->ping_serial);
}
void wlr_xdg_surface_v6_send_close(struct wlr_xdg_surface_v6 *surface) {
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_NONE:
assert(0 && "not reached");
break;
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
if (surface->toplevel) {
zxdg_toplevel_v6_send_close(surface->toplevel->resource);
}
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
if (surface->popup) {
zxdg_popup_v6_send_popup_done(surface->popup->resource);
}
break;
}
}
static void xdg_surface_handle_surface_destroy(struct wl_listener *listener,
void *data) {
struct wlr_xdg_surface_v6 *xdg_surface =
wl_container_of(listener, xdg_surface, surface_destroy);
destroy_xdg_surface_v6(xdg_surface);
}
static void xdg_surface_handle_surface_commit(struct wl_listener *listener,
void *data) {
struct wlr_xdg_surface_v6 *surface =
wl_container_of(listener, surface, surface_commit);
if (wlr_surface_has_buffer(surface->surface) && !surface->configured) {
wl_resource_post_error(surface->resource,
ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
"xdg_surface has never been configured");
return;
}
if (surface->role == WLR_XDG_SURFACE_V6_ROLE_NONE) {
wl_resource_post_error(surface->resource,
ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
"xdg_surface must have a role");
return;
}
}
void handle_xdg_surface_v6_commit(struct wlr_surface *wlr_surface) {
struct wlr_xdg_surface_v6 *surface =
wlr_xdg_surface_v6_from_wlr_surface(wlr_surface);
if (surface == NULL) {
return;
}
if (surface->has_next_geometry) {
surface->has_next_geometry = false;
surface->geometry.x = surface->next_geometry.x;
surface->geometry.y = surface->next_geometry.y;
surface->geometry.width = surface->next_geometry.width;
surface->geometry.height = surface->next_geometry.height;
}
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_NONE:
assert(false);
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
handle_xdg_surface_v6_toplevel_committed(surface);
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
handle_xdg_surface_v6_popup_committed(surface);
break;
}
if (!surface->added) {
surface->added = true;
wlr_signal_emit_safe(&surface->client->shell->events.new_surface,
surface);
}
if (surface->configured && wlr_surface_has_buffer(surface->surface) &&
!surface->mapped) {
surface->mapped = true;
wlr_signal_emit_safe(&surface->events.map, surface);
}
}
void handle_xdg_surface_v6_precommit(struct wlr_surface *wlr_surface) {
struct wlr_xdg_surface_v6 *surface =
wlr_xdg_surface_v6_from_wlr_surface(wlr_surface);
if (surface == NULL) {
return;
}
if (wlr_surface->pending.committed & WLR_SURFACE_STATE_BUFFER &&
wlr_surface->pending.buffer_resource == NULL) {
// This is a NULL commit
if (surface->configured && surface->mapped) {
unmap_xdg_surface_v6(surface);
}
}
}
static void xdg_surface_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface = xdg_surface_from_resource(resource);
if (surface != NULL) {
destroy_xdg_surface_v6(surface);
}
}
struct wlr_xdg_surface_v6 *create_xdg_surface_v6(
struct wlr_xdg_client_v6 *client, struct wlr_surface *surface,
uint32_t id) {
if (wlr_surface_has_buffer(surface)) {
wl_resource_post_error(client->resource,
ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER,
"xdg_surface must not have a buffer at creation");
return NULL;
}
struct wlr_xdg_surface_v6 *xdg_surface =
calloc(1, sizeof(struct wlr_xdg_surface_v6));
if (xdg_surface == NULL) {
wl_client_post_no_memory(client->client);
return NULL;
}
xdg_surface->client = client;
xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE;
xdg_surface->surface = surface;
xdg_surface->resource = wl_resource_create(client->client,
&zxdg_surface_v6_interface, wl_resource_get_version(client->resource),
id);
if (xdg_surface->resource == NULL) {
free(xdg_surface);
wl_client_post_no_memory(client->client);
return NULL;
}
wl_resource_set_implementation(xdg_surface->resource,
&zxdg_surface_v6_implementation, xdg_surface,
xdg_surface_handle_resource_destroy);
wl_list_init(&xdg_surface->configure_list);
wl_list_init(&xdg_surface->popups);
wl_signal_init(&xdg_surface->events.destroy);
wl_signal_init(&xdg_surface->events.ping_timeout);
wl_signal_init(&xdg_surface->events.new_popup);
wl_signal_init(&xdg_surface->events.map);
wl_signal_init(&xdg_surface->events.unmap);
wl_signal_add(&xdg_surface->surface->events.destroy,
&xdg_surface->surface_destroy);
xdg_surface->surface_destroy.notify = xdg_surface_handle_surface_destroy;
wl_signal_add(&xdg_surface->surface->events.commit,
&xdg_surface->surface_commit);
xdg_surface->surface_commit.notify = xdg_surface_handle_surface_commit;
wlr_log(WLR_DEBUG, "new xdg_surface %p (res %p)", xdg_surface,
xdg_surface->resource);
wl_list_insert(&client->surfaces, &xdg_surface->link);
return xdg_surface;
}
static void xdg_popup_v6_get_position(struct wlr_xdg_popup_v6 *popup,
double *popup_sx, double *popup_sy) {
struct wlr_xdg_surface_v6 *parent = popup->parent;
struct wlr_box parent_geo;
wlr_xdg_surface_v6_get_geometry(parent, &parent_geo);
*popup_sx = parent_geo.x + popup->geometry.x -
popup->base->geometry.x;
*popup_sy = parent_geo.y + popup->geometry.y -
popup->base->geometry.y;
}
struct wlr_surface *wlr_xdg_surface_v6_surface_at(
struct wlr_xdg_surface_v6 *surface, double sx, double sy,
double *sub_x, double *sub_y) {
struct wlr_xdg_popup_v6 *popup_state;
wl_list_for_each(popup_state, &surface->popups, link) {
struct wlr_xdg_surface_v6 *popup = popup_state->base;
double popup_sx, popup_sy;
xdg_popup_v6_get_position(popup_state, &popup_sx, &popup_sy);
struct wlr_surface *sub = wlr_xdg_surface_v6_surface_at(popup,
sx - popup_sx,
sy - popup_sy,
sub_x, sub_y);
if (sub != NULL) {
return sub;
}
}
return wlr_surface_surface_at(surface->surface, sx, sy, sub_x, sub_y);
}
struct xdg_surface_v6_iterator_data {
wlr_surface_iterator_func_t user_iterator;
void *user_data;
int x, y;
};
static void xdg_surface_v6_iterator(struct wlr_surface *surface,
int sx, int sy, void *data) {
struct xdg_surface_v6_iterator_data *iter_data = data;
iter_data->user_iterator(surface, iter_data->x + sx, iter_data->y + sy,
iter_data->user_data);
}
static void xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface,
int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) {
struct xdg_surface_v6_iterator_data data = {
.user_iterator = iterator,
.user_data = user_data,
.x = x, .y = y,
};
wlr_surface_for_each_surface(surface->surface, xdg_surface_v6_iterator,
&data);
struct wlr_xdg_popup_v6 *popup_state;
wl_list_for_each(popup_state, &surface->popups, link) {
struct wlr_xdg_surface_v6 *popup = popup_state->base;
if (!popup->configured) {
continue;
}
double popup_sx, popup_sy;
xdg_popup_v6_get_position(popup_state, &popup_sx, &popup_sy);
xdg_surface_v6_for_each_surface(popup,
x + popup_sx,
y + popup_sy,
iterator, user_data);
}
}
static void xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface,
int x, int y, wlr_surface_iterator_func_t iterator, void *user_data) {
struct wlr_xdg_popup_v6 *popup_state;
wl_list_for_each(popup_state, &surface->popups, link) {
struct wlr_xdg_surface_v6 *popup = popup_state->base;
if (!popup->configured) {
continue;
}
double popup_sx, popup_sy;
xdg_popup_v6_get_position(popup_state, &popup_sx, &popup_sy);
iterator(popup->surface, x + popup_sx, y + popup_sy, user_data);
xdg_surface_v6_for_each_popup(popup,
x + popup_sx,
y + popup_sy,
iterator, user_data);
}
}
void wlr_xdg_surface_v6_for_each_surface(struct wlr_xdg_surface_v6 *surface,
wlr_surface_iterator_func_t iterator, void *user_data) {
xdg_surface_v6_for_each_surface(surface, 0, 0, iterator, user_data);
}
void wlr_xdg_surface_v6_for_each_popup(struct wlr_xdg_surface_v6 *surface,
wlr_surface_iterator_func_t iterator, void *user_data) {
xdg_surface_v6_for_each_popup(surface, 0, 0, iterator, user_data);
}
void wlr_xdg_surface_v6_get_geometry(struct wlr_xdg_surface_v6 *surface, struct wlr_box *box) {
wlr_surface_get_extends(surface->surface, box);
/* The client never set the geometry */
if (!surface->geometry.width) {
return;
}
wlr_box_intersection(box, &surface->geometry, box);
}

View file

@ -1,536 +0,0 @@
#define _POSIX_C_SOURCE 200809L
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <wlr/util/log.h>
#include "types/wlr_xdg_shell_v6.h"
#include "util/signal.h"
static const struct zxdg_toplevel_v6_interface zxdg_toplevel_v6_implementation;
static struct wlr_xdg_surface_v6 *xdg_surface_from_xdg_toplevel_resource(
struct wl_resource *resource) {
assert(wl_resource_instance_of(resource, &zxdg_toplevel_v6_interface,
&zxdg_toplevel_v6_implementation));
return wl_resource_get_user_data(resource);
}
void destroy_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
unmap_xdg_surface_v6(surface);
if (surface->toplevel->client_pending.fullscreen_output) {
struct wlr_xdg_toplevel_v6_state *client_pending =
&surface->toplevel->client_pending;
wl_list_remove(&client_pending->fullscreen_output_destroy.link);
}
wl_resource_set_user_data(surface->toplevel->resource, NULL);
free(surface->toplevel);
surface->toplevel = NULL;
surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE;
}
static void xdg_toplevel_handle_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}
static void xdg_toplevel_handle_set_parent(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *parent_resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
struct wlr_xdg_surface_v6 *parent = NULL;
if (parent_resource != NULL) {
parent = xdg_surface_from_xdg_toplevel_resource(parent_resource);
}
surface->toplevel->parent = parent;
wlr_signal_emit_safe(&surface->toplevel->events.set_parent, surface);
}
static void xdg_toplevel_handle_set_title(struct wl_client *client,
struct wl_resource *resource, const char *title) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
char *tmp = strdup(title);
if (tmp == NULL) {
return;
}
free(surface->toplevel->title);
surface->toplevel->title = tmp;
wlr_signal_emit_safe(&surface->toplevel->events.set_title, surface);
}
static void xdg_toplevel_handle_set_app_id(struct wl_client *client,
struct wl_resource *resource, const char *app_id) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
char *tmp = strdup(app_id);
if (tmp == NULL) {
return;
}
free(surface->toplevel->app_id);
surface->toplevel->app_id = tmp;
wlr_signal_emit_safe(&surface->toplevel->events.set_app_id, surface);
}
static void xdg_toplevel_handle_show_window_menu(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *seat_resource,
uint32_t serial, int32_t x, int32_t y) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
struct wlr_seat_client *seat =
wlr_seat_client_from_resource(seat_resource);
if (!surface->configured) {
wl_resource_post_error(surface->toplevel->resource,
ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
"surface has not been configured yet");
return;
}
if (!wlr_seat_validate_grab_serial(seat->seat, serial)) {
wlr_log(WLR_DEBUG, "invalid serial for grab");
return;
}
struct wlr_xdg_toplevel_v6_show_window_menu_event event = {
.surface = surface,
.seat = seat,
.serial = serial,
.x = x,
.y = y,
};
wlr_signal_emit_safe(&surface->toplevel->events.request_show_window_menu,
&event);
}
static void xdg_toplevel_handle_move(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *seat_resource,
uint32_t serial) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
struct wlr_seat_client *seat =
wlr_seat_client_from_resource(seat_resource);
if (!surface->configured) {
wl_resource_post_error(surface->toplevel->resource,
ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
"surface has not been configured yet");
return;
}
if (!wlr_seat_validate_grab_serial(seat->seat, serial)) {
wlr_log(WLR_DEBUG, "invalid serial for grab");
return;
}
struct wlr_xdg_toplevel_v6_move_event event = {
.surface = surface,
.seat = seat,
.serial = serial,
};
wlr_signal_emit_safe(&surface->toplevel->events.request_move, &event);
}
static void xdg_toplevel_handle_resize(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *seat_resource,
uint32_t serial, uint32_t edges) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
struct wlr_seat_client *seat =
wlr_seat_client_from_resource(seat_resource);
if (!surface->configured) {
wl_resource_post_error(surface->toplevel->resource,
ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
"surface has not been configured yet");
return;
}
if (!wlr_seat_validate_grab_serial(seat->seat, serial)) {
wlr_log(WLR_DEBUG, "invalid serial for grab");
return;
}
struct wlr_xdg_toplevel_v6_resize_event event = {
.surface = surface,
.seat = seat,
.serial = serial,
.edges = edges,
};
wlr_signal_emit_safe(&surface->toplevel->events.request_resize, &event);
}
static void xdg_toplevel_handle_set_max_size(struct wl_client *client,
struct wl_resource *resource, int32_t width, int32_t height) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->client_pending.max_width = width;
surface->toplevel->client_pending.max_height = height;
}
static void xdg_toplevel_handle_set_min_size(struct wl_client *client,
struct wl_resource *resource, int32_t width, int32_t height) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->client_pending.min_width = width;
surface->toplevel->client_pending.min_height = height;
}
static void xdg_toplevel_handle_set_maximized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->client_pending.maximized = true;
wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface);
}
static void xdg_toplevel_handle_unset_maximized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
surface->toplevel->client_pending.maximized = false;
wlr_signal_emit_safe(&surface->toplevel->events.request_maximize, surface);
}
static void handle_fullscreen_output_destroy(struct wl_listener *listener,
void *data) {
struct wlr_xdg_toplevel_v6_state *state =
wl_container_of(listener, state, fullscreen_output_destroy);
state->fullscreen_output = NULL;
wl_list_remove(&state->fullscreen_output_destroy.link);
}
static void store_fullscreen_pending(struct wlr_xdg_surface_v6 *surface,
bool fullscreen, struct wlr_output *output) {
struct wlr_xdg_toplevel_v6_state *state =
&surface->toplevel->client_pending;
state->fullscreen = fullscreen;
if (state->fullscreen_output) {
wl_list_remove(&state->fullscreen_output_destroy.link);
}
state->fullscreen_output = output;
if (state->fullscreen_output) {
state->fullscreen_output_destroy.notify =
handle_fullscreen_output_destroy;
wl_signal_add(&state->fullscreen_output->events.destroy,
&state->fullscreen_output_destroy);
}
}
static void xdg_toplevel_handle_set_fullscreen(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *output_resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
struct wlr_output *output = NULL;
if (output_resource != NULL) {
output = wlr_output_from_resource(output_resource);
}
store_fullscreen_pending(surface, true, output);
struct wlr_xdg_toplevel_v6_set_fullscreen_event event = {
.surface = surface,
.fullscreen = true,
.output = output,
};
wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event);
}
static void xdg_toplevel_handle_unset_fullscreen(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
store_fullscreen_pending(surface, false, NULL);
struct wlr_xdg_toplevel_v6_set_fullscreen_event event = {
.surface = surface,
.fullscreen = false,
.output = NULL,
};
wlr_signal_emit_safe(&surface->toplevel->events.request_fullscreen, &event);
}
static void xdg_toplevel_handle_set_minimized(struct wl_client *client,
struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
wlr_signal_emit_safe(&surface->toplevel->events.request_minimize, surface);
}
static const struct zxdg_toplevel_v6_interface
zxdg_toplevel_v6_implementation = {
.destroy = xdg_toplevel_handle_destroy,
.set_parent = xdg_toplevel_handle_set_parent,
.set_title = xdg_toplevel_handle_set_title,
.set_app_id = xdg_toplevel_handle_set_app_id,
.show_window_menu = xdg_toplevel_handle_show_window_menu,
.move = xdg_toplevel_handle_move,
.resize = xdg_toplevel_handle_resize,
.set_max_size = xdg_toplevel_handle_set_max_size,
.set_min_size = xdg_toplevel_handle_set_min_size,
.set_maximized = xdg_toplevel_handle_set_maximized,
.unset_maximized = xdg_toplevel_handle_unset_maximized,
.set_fullscreen = xdg_toplevel_handle_set_fullscreen,
.unset_fullscreen = xdg_toplevel_handle_unset_fullscreen,
.set_minimized = xdg_toplevel_handle_set_minimized,
};
void handle_xdg_toplevel_v6_ack_configure(struct wlr_xdg_surface_v6 *surface,
struct wlr_xdg_surface_v6_configure *configure) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
assert(configure->toplevel_state != NULL);
surface->toplevel->current.maximized =
configure->toplevel_state->maximized;
surface->toplevel->current.fullscreen =
configure->toplevel_state->fullscreen;
surface->toplevel->current.resizing =
configure->toplevel_state->resizing;
surface->toplevel->current.activated =
configure->toplevel_state->activated;
}
bool compare_xdg_surface_v6_toplevel_state(struct wlr_xdg_toplevel_v6 *state) {
struct {
struct wlr_xdg_toplevel_v6_state state;
uint32_t width, height;
} configured;
// is pending state different from current state?
if (!state->base->configured) {
return false;
}
if (wl_list_empty(&state->base->configure_list)) {
// last configure is actually the current state, just use it
configured.state = state->current;
configured.width = state->base->surface->current.width;
configured.height = state->base->surface->current.height;
} else {
struct wlr_xdg_surface_v6_configure *configure =
wl_container_of(state->base->configure_list.prev, configure, link);
configured.state = *configure->toplevel_state;
configured.width = configure->toplevel_state->width;
configured.height = configure->toplevel_state->height;
}
if (state->server_pending.activated != configured.state.activated) {
return false;
}
if (state->server_pending.fullscreen != configured.state.fullscreen) {
return false;
}
if (state->server_pending.maximized != configured.state.maximized) {
return false;
}
if (state->server_pending.resizing != configured.state.resizing) {
return false;
}
if (state->server_pending.width == configured.width &&
state->server_pending.height == configured.height) {
return true;
}
if (state->server_pending.width == 0 && state->server_pending.height == 0) {
return true;
}
return false;
}
void send_xdg_toplevel_v6_configure(struct wlr_xdg_surface_v6 *surface,
struct wlr_xdg_surface_v6_configure *configure) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
configure->toplevel_state = malloc(sizeof(*configure->toplevel_state));
if (configure->toplevel_state == NULL) {
wlr_log(WLR_ERROR, "Allocation failed");
wl_resource_post_no_memory(surface->toplevel->resource);
return;
}
*configure->toplevel_state = surface->toplevel->server_pending;
uint32_t *s;
struct wl_array states;
wl_array_init(&states);
if (surface->toplevel->server_pending.maximized) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(WLR_ERROR,
"Could not allocate state for maximized xdg_toplevel");
goto error_out;
}
*s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED;
}
if (surface->toplevel->server_pending.fullscreen) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(WLR_ERROR,
"Could not allocate state for fullscreen xdg_toplevel");
goto error_out;
}
*s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN;
}
if (surface->toplevel->server_pending.resizing) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(WLR_ERROR,
"Could not allocate state for resizing xdg_toplevel");
goto error_out;
}
*s = ZXDG_TOPLEVEL_V6_STATE_RESIZING;
}
if (surface->toplevel->server_pending.activated) {
s = wl_array_add(&states, sizeof(uint32_t));
if (!s) {
wlr_log(WLR_ERROR,
"Could not allocate state for activated xdg_toplevel");
goto error_out;
}
*s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED;
}
uint32_t width = surface->toplevel->server_pending.width;
uint32_t height = surface->toplevel->server_pending.height;
zxdg_toplevel_v6_send_configure(surface->toplevel->resource, width,
height, &states);
wl_array_release(&states);
return;
error_out:
wl_array_release(&states);
wl_resource_post_no_memory(surface->toplevel->resource);
}
void handle_xdg_surface_v6_toplevel_committed(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
if (!surface->toplevel->added) {
// on the first commit, send a configure request to tell the client it
// is added
schedule_xdg_surface_v6_configure(surface);
surface->toplevel->added = true;
return;
}
// update state that doesn't need compositor approval
surface->toplevel->current.max_width =
surface->toplevel->client_pending.max_width;
surface->toplevel->current.min_width =
surface->toplevel->client_pending.min_width;
surface->toplevel->current.max_height =
surface->toplevel->client_pending.max_height;
surface->toplevel->current.min_height =
surface->toplevel->client_pending.min_height;
}
static void xdg_toplevel_handle_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource);
if (surface != NULL) {
destroy_xdg_toplevel_v6(surface);
}
}
const struct wlr_surface_role xdg_toplevel_v6_surface_role = {
.name = "xdg_toplevel_v6",
.commit = handle_xdg_surface_v6_commit,
.precommit = handle_xdg_surface_v6_precommit,
};
void create_xdg_toplevel_v6(struct wlr_xdg_surface_v6 *xdg_surface,
uint32_t id) {
if (!wlr_surface_set_role(xdg_surface->surface, &xdg_toplevel_v6_surface_role,
xdg_surface, xdg_surface->resource, ZXDG_SHELL_V6_ERROR_ROLE)) {
return;
}
xdg_surface->toplevel = calloc(1, sizeof(struct wlr_xdg_toplevel_v6));
if (xdg_surface->toplevel == NULL) {
wl_resource_post_no_memory(xdg_surface->resource);
return;
}
wl_signal_init(&xdg_surface->toplevel->events.request_maximize);
wl_signal_init(&xdg_surface->toplevel->events.request_fullscreen);
wl_signal_init(&xdg_surface->toplevel->events.request_minimize);
wl_signal_init(&xdg_surface->toplevel->events.request_move);
wl_signal_init(&xdg_surface->toplevel->events.request_resize);
wl_signal_init(&xdg_surface->toplevel->events.request_show_window_menu);
wl_signal_init(&xdg_surface->toplevel->events.set_parent);
wl_signal_init(&xdg_surface->toplevel->events.set_title);
wl_signal_init(&xdg_surface->toplevel->events.set_app_id);
xdg_surface->role = WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL;
xdg_surface->toplevel->base = xdg_surface;
struct wl_resource *toplevel_resource = wl_resource_create(
xdg_surface->client->client, &zxdg_toplevel_v6_interface,
wl_resource_get_version(xdg_surface->resource), id);
if (toplevel_resource == NULL) {
free(xdg_surface->toplevel);
wl_resource_post_no_memory(xdg_surface->resource);
return;
}
xdg_surface->toplevel->resource = toplevel_resource;
wl_resource_set_implementation(toplevel_resource,
&zxdg_toplevel_v6_implementation, xdg_surface,
xdg_toplevel_handle_resource_destroy);
}
uint32_t wlr_xdg_toplevel_v6_set_size(struct wlr_xdg_surface_v6 *surface,
uint32_t width, uint32_t height) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->server_pending.width = width;
surface->toplevel->server_pending.height = height;
return schedule_xdg_surface_v6_configure(surface);
}
uint32_t wlr_xdg_toplevel_v6_set_activated(struct wlr_xdg_surface_v6 *surface,
bool activated) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->server_pending.activated = activated;
return schedule_xdg_surface_v6_configure(surface);
}
uint32_t wlr_xdg_toplevel_v6_set_maximized(struct wlr_xdg_surface_v6 *surface,
bool maximized) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->server_pending.maximized = maximized;
return schedule_xdg_surface_v6_configure(surface);
}
uint32_t wlr_xdg_toplevel_v6_set_fullscreen(struct wlr_xdg_surface_v6 *surface,
bool fullscreen) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->server_pending.fullscreen = fullscreen;
return schedule_xdg_surface_v6_configure(surface);
}
uint32_t wlr_xdg_toplevel_v6_set_resizing(struct wlr_xdg_surface_v6 *surface,
bool resizing) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
surface->toplevel->server_pending.resizing = resizing;
return schedule_xdg_surface_v6_configure(surface);
}

View file

@ -24,7 +24,7 @@
*/
#define _POSIX_C_SOURCE 200809L
#include <stdint.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -245,7 +245,7 @@ struct wlr_xcursor_theme *wlr_xcursor_theme_load(const char *name, int size) {
for (size_t i = 0; i < theme->cursor_count; ++i) {
struct wlr_xcursor *c = theme->cursors[i];
struct wlr_xcursor_image *i = c->images[0];
wlr_log(WLR_DEBUG, "%s (%u images) %dx%d+%d,%d",
wlr_log(WLR_DEBUG, "%s (%u images) %" PRIu32 "x%" PRIu32 "+%" PRIu32 ",%" PRIu32,
c->name, c->image_count,
i->width, i->height, i->hotspot_x, i->hotspot_y);
}

View file

@ -285,11 +285,12 @@ _XcursorReadUInt (XcursorFile *file, XcursorUInt *u)
return XcursorFalse;
if ((*file->read) (file, bytes, 4) != 4)
return XcursorFalse;
*u = ((bytes[0] << 0) |
(bytes[1] << 8) |
(bytes[2] << 16) |
(bytes[3] << 24));
return XcursorFalse;
*u = ((XcursorUInt)(bytes[0]) << 0) |
((XcursorUInt)(bytes[1]) << 8) |
((XcursorUInt)(bytes[2]) << 16) |
((XcursorUInt)(bytes[3]) << 24);
return XcursorTrue;
}

Some files were not shown because too many files have changed in this diff Show more