Compare commits

17 Commits
master ... dev

Author SHA1 Message Date
Dany LE
3c50d9f92b refactor code + fix memory leak 2025-11-05 14:29:45 +01:00
Dany LE
0c9c144919 use wlroots 0.19.2 2025-11-05 12:02:16 +01:00
Dany LE
0c6eb8df47 bump to version 0.1.3 2025-11-03 21:59:29 +01:00
Dany LE
510a59e69d fix(touch): alway emulate mouse with touch 2025-11-03 21:59:08 +01:00
b0cf86aa00 feat: add support for wlr_pointer_gestures_v1 2025-07-29 16:39:52 +02:00
0f31545ccd feat: add more protocols + touch support:
* add touch support (experimental)
* add support for wlr_cursor_shape_v1
* add support for wlr_relative_pointer_manager_v1
2025-07-29 15:33:19 +02:00
0b738f4476 update wlroot dependency 2025-07-21 21:20:45 +02:00
2cc5bb045b refactor code 2025-07-10 09:57:29 +02:00
DanyLE
9cc2408dc8 add support to protocol: output-power-manager + output-manager 2025-07-09 20:32:33 +02:00
DanyLE
194b7894cd feat: add support to two new wayland protocols
- Idle notify
- Idle inhibit
2025-07-07 16:37:23 +02:00
DanyLE
dd8242abc6 update README.md 2025-07-05 20:40:57 +02:00
DanyLE
f62a21d3b2 fix: compilation errors 2025-07-05 20:37:04 +02:00
DanyLE
0a77ed8d91 switch to meson build + refactor code to remove compile warning 2025-07-05 20:33:49 +02:00
DanyLE
13543e1382 add support for the following protocols:
- wlr_xdg_output_v1
 - wlr_screencopy_v1
 - wlr_export_dmabuf_v1
 - wlr_data_control_v1
 - wlr_single_pixel_buffer_v1

minor feature: add option -v to increase the log level
2025-07-05 19:07:57 +02:00
6be0e9b5c4 fix: init foreign toplevel only when the surface is first mapped 2025-07-03 15:51:38 +02:00
ea98928849 fix: xdg surface handle pending configure + dont update usable area when new layer surface firt create 2025-07-03 14:58:20 +02:00
DanyLE
c1393a1366 fix: update to wlroot 0.18 2025-07-02 22:54:16 +02:00
28 changed files with 1958 additions and 341 deletions

4
.gitignore vendored
View File

@@ -139,7 +139,5 @@ m4/lt~obsolete.m4
# can automatically generate from config.status script # can automatically generate from config.status script
# (which is called by configure script)) # (which is called by configure script))
# Makefile # Makefile
xdg-shell-protocol.* build*
diyac
.vscode .vscode
wlr-layer-shell-unstable-v1-protocol*

View File

@@ -1,53 +0,0 @@
WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner)
LIBS=\
$(shell pkg-config --cflags --libs wlroots) \
$(shell pkg-config --cflags --libs wayland-server) \
$(shell pkg-config --cflags --libs xkbcommon)
OBJS=\
diyac.c \
cursor.c \
output.c \
seat.c \
node.c \
view.c \
foreign.c \
xdg.c \
xdg-shell-protocol.c \
layer.c \
session.c \
wlr-layer-shell-unstable-v1-protocol.c
# wayland-scanner is a tool which generates C headers and rigging for Wayland
# protocols, which are specified in XML. wlroots requires you to rig these up
# to your build system yourself and provide them in the include path.
xdg-shell-protocol.h:
$(WAYLAND_SCANNER) server-header \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
xdg-shell-protocol.c: xdg-shell-protocol.h
$(WAYLAND_SCANNER) private-code \
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
wlr-layer-shell-unstable-v1-protocol.c: wlr-layer-shell-unstable-v1-protocol.h
$(WAYLAND_SCANNER) private-code \
protocol/wlr-layer-shell-unstable-v1.xml $@
wlr-layer-shell-unstable-v1-protocol.h:
$(WAYLAND_SCANNER) server-header \
protocol/wlr-layer-shell-unstable-v1.xml $@
diyac: $(OBJS)
echo "Object is $(OBJS)"
$(CC) $(CFLAGS) \
-g -Werror -I. \
-DWLR_USE_UNSTABLE \
-o $@ $(OBJS) \
$(LIBS)
clean:
rm -f diyac xdg-shell-protocol.* wlr-layer-shell-unstable-v1-protocol.*
.DEFAULT_GOAL=diyac
.PHONY: clean

View File

@@ -1,2 +1,3 @@
# diyac # diyac
Simple Wayland compositor used mainly by diya-session manager and diya shell

177
cursor.c
View File

@@ -1,10 +1,14 @@
#define _POSIX_C_SOURCE 200112L #define _POSIX_C_SOURCE 200112L
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <wlr/types/wlr_cursor_shape_v1.h>
#include <assert.h> #include <assert.h>
#include "cursor.h" #include "cursor.h"
#include "view.h" #include "view.h"
#include "seat.h" #include "seat.h"
#include "node.h" #include "node.h"
#include "idle.h"
#include "touch.h"
#include "gestures.h"
void diyac_cursor_focus(struct diyac_server *server) void diyac_cursor_focus(struct diyac_server *server)
{ {
@@ -13,7 +17,7 @@ void diyac_cursor_focus(struct diyac_server *server)
struct diyac_node_descriptor *desc = diyac_node_at(server, struct diyac_node_descriptor *desc = diyac_node_at(server,
server->seat.cursor->x, server->seat.cursor->y, &surface, &sx, &sy); server->seat.cursor->x, server->seat.cursor->y, &surface, &sx, &sy);
struct diyac_layer_surface *layer; struct diyac_layer_surface *layer;
struct diyac_view *root = NULL; // struct diyac_view *root = NULL;
if (!desc) if (!desc)
{ {
return; return;
@@ -55,9 +59,10 @@ void diyac_reset_cursor_mode(struct diyac_server *server)
static void process_cursor_move(struct diyac_server *server, uint32_t time) static void process_cursor_move(struct diyac_server *server, uint32_t time)
{ {
(void)time;
struct diyac_view *toplevel = server->grabbed_view; struct diyac_view *toplevel = server->grabbed_view;
/* Move the grabbed toplevel to the new position. */ /* Move the grabbed toplevel to the new position. */
if(!toplevel->output) if (!toplevel->output)
{ {
return; return;
} }
@@ -84,6 +89,7 @@ static void process_cursor_move(struct diyac_server *server, uint32_t time)
static void process_cursor_resize(struct diyac_server *server, uint32_t time) static void process_cursor_resize(struct diyac_server *server, uint32_t time)
{ {
(void)time;
/* /*
* Resizing the grabbed toplevel can be a little bit complicated, because we * Resizing the grabbed toplevel can be a little bit complicated, because we
* could be resizing from any corner or edge. This not only resizes the * could be resizing from any corner or edge. This not only resizes the
@@ -95,7 +101,7 @@ static void process_cursor_resize(struct diyac_server *server, uint32_t time)
* size, then commit any movement that was prepared. * size, then commit any movement that was prepared.
*/ */
struct diyac_view *toplevel = server->grabbed_view; struct diyac_view *toplevel = server->grabbed_view;
if(toplevel->state.fullscreen) if (toplevel->state.fullscreen)
{ {
return; return;
} }
@@ -139,10 +145,9 @@ static void process_cursor_resize(struct diyac_server *server, uint32_t time)
} }
} }
struct wlr_box geo_box; struct wlr_box* geo_box = &toplevel->xdg_toplevel->base->geometry;
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box); toplevel->pending_size.x = new_left - geo_box->x;
toplevel->pending_size.x = new_left - geo_box.x; toplevel->pending_size.y = new_top - geo_box->y;
toplevel->pending_size.y = new_top - geo_box.y;
int new_width = new_right - new_left; int new_width = new_right - new_left;
int new_height = new_bottom - new_top; int new_height = new_bottom - new_top;
toplevel->pending_size.width = new_width; toplevel->pending_size.width = new_width;
@@ -214,6 +219,12 @@ static void server_cursor_motion(struct wl_listener *listener, void *data)
struct diyac_seat *seat = struct diyac_seat *seat =
wl_container_of(listener, seat, cursor_motion); wl_container_of(listener, seat, cursor_motion);
struct wlr_pointer_motion_event *event = data; struct wlr_pointer_motion_event *event = data;
diyac_idle_manager_notify_activity(seat);
wlr_relative_pointer_manager_v1_send_relative_motion(
seat->server->relative_pointer_manager,
seat->wlr_seat, (uint64_t)event->time_msec * 1000,
event->delta_x, event->delta_y, event->unaccel_dx,
event->unaccel_dy);
/* The cursor doesn't move unless we tell it to. The cursor automatically /* The cursor doesn't move unless we tell it to. The cursor automatically
* handles constraining the motion to the output layout, as well as any * handles constraining the motion to the output layout, as well as any
* special configuration applied for the specific input device which * special configuration applied for the specific input device which
@@ -235,7 +246,18 @@ static void server_cursor_motion_absolute(
* emits these events. */ * emits these events. */
struct diyac_seat *seat = struct diyac_seat *seat =
wl_container_of(listener, seat, cursor_motion_absolute); wl_container_of(listener, seat, cursor_motion_absolute);
diyac_idle_manager_notify_activity(seat);
struct wlr_pointer_motion_absolute_event *event = data; struct wlr_pointer_motion_absolute_event *event = data;
double lx, ly;
wlr_cursor_absolute_to_layout_coords(seat->cursor,
&event->pointer->base, event->x, event->y, &lx, &ly);
double dx = lx - seat->cursor->x;
double dy = ly - seat->cursor->y;
wlr_relative_pointer_manager_v1_send_relative_motion(
seat->server->relative_pointer_manager,
seat->wlr_seat, (uint64_t)event->time_msec * 1000,
dx, dy, dx, dy);
wlr_cursor_warp_absolute(seat->cursor, &event->pointer->base, event->x, wlr_cursor_warp_absolute(seat->cursor, &event->pointer->base, event->x,
event->y); event->y);
process_cursor_motion(seat->server, event->time_msec); process_cursor_motion(seat->server, event->time_msec);
@@ -248,11 +270,12 @@ static void server_cursor_button(struct wl_listener *listener, void *data)
struct diyac_seat *seat = struct diyac_seat *seat =
wl_container_of(listener, seat, cursor_button); wl_container_of(listener, seat, cursor_button);
struct wlr_pointer_button_event *event = data; struct wlr_pointer_button_event *event = data;
diyac_idle_manager_notify_activity(seat);
/* Notify the client with pointer focus that a button press has occurred */ /* Notify the client with pointer focus that a button press has occurred */
wlr_seat_pointer_notify_button(seat->wlr_seat, wlr_seat_pointer_notify_button(seat->wlr_seat,
event->time_msec, event->button, event->state); event->time_msec, event->button, event->state);
if (event->state == WLR_BUTTON_RELEASED) if (event->state == WL_POINTER_BUTTON_STATE_RELEASED)
{ {
/* If you released any buttons, we exit interactive move/resize mode. */ /* If you released any buttons, we exit interactive move/resize mode. */
diyac_reset_cursor_mode(seat->server); diyac_reset_cursor_mode(seat->server);
@@ -269,15 +292,17 @@ static void server_cursor_axis(struct wl_listener *listener, void *data)
* for example when you move the scroll wheel. */ * for example when you move the scroll wheel. */
struct diyac_seat *seat = struct diyac_seat *seat =
wl_container_of(listener, seat, cursor_axis); wl_container_of(listener, seat, cursor_axis);
diyac_idle_manager_notify_activity(seat);
struct wlr_pointer_axis_event *event = data; struct wlr_pointer_axis_event *event = data;
/* Notify the client with pointer focus of the axis event. */ /* Notify the client with pointer focus of the axis event. */
wlr_seat_pointer_notify_axis(seat->wlr_seat, wlr_seat_pointer_notify_axis(seat->wlr_seat,
event->time_msec, event->orientation, event->delta, event->time_msec, event->orientation, event->delta,
event->delta_discrete, event->source); event->delta_discrete, event->source, event->delta);
} }
static void server_cursor_frame(struct wl_listener *listener, void *data) static void server_cursor_frame(struct wl_listener *listener, void *data)
{ {
(void)data;
/* This event is forwarded by the cursor when a pointer emits an frame /* This event is forwarded by the cursor when a pointer emits an frame
* event. Frame events are sent after regular pointer events to group * event. Frame events are sent after regular pointer events to group
* multiple events together. For instance, two axis events may happen at the * multiple events together. For instance, two axis events may happen at the
@@ -288,6 +313,111 @@ static void server_cursor_frame(struct wl_listener *listener, void *data)
wlr_seat_pointer_notify_frame(seat->wlr_seat); wlr_seat_pointer_notify_frame(seat->wlr_seat);
} }
static void request_set_shape_notify(struct wl_listener *listener, void *data)
{
struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
const char *shape_name = wlr_cursor_shape_v1_name(event->shape);
struct diyac_seat *seat = wl_container_of(listener, seat, request_set_shape);
struct wlr_seat_client *focused_client = seat->wlr_seat->pointer_state.focused_client;
/* Prevent setting a cursor image when moving or resizing */
if (seat->cursor_mode != DIYAC_CURSOR_PASSTHROUGH)
{
return;
}
/*
* Omit set shape when the current cursor is
* invisible, e.g. on touch input.
if (!seat->cursor_visible)
{
return;
}
*/
/*
* This can be sent by any client, so we check to make sure this one
* actually has pointer focus first.
*/
if (event->seat_client != focused_client)
{
wlr_log(WLR_INFO, "seat client %p != focused client %p",
event->seat_client, focused_client);
return;
}
wlr_log(WLR_DEBUG, "set xcursor to shape %s", shape_name);
wlr_cursor_set_xcursor(seat->cursor, seat->cursor_mgr, shape_name);
}
void diyac_cursor_emulate_move(struct diyac_seat *seat, struct wlr_input_device *device, double dx, double dy, uint32_t time_msec)
{
if (!dx && !dy)
{
wlr_log(WLR_DEBUG, "dropping useless cursor_emulate: %.10f,%.10f", dx, dy);
return;
}
wlr_relative_pointer_manager_v1_send_relative_motion(
seat->server->relative_pointer_manager,
seat->wlr_seat, (uint64_t)time_msec * 1000,
dx, dy, dx, dy);
wlr_cursor_move(seat->cursor, device, dx, dy);
process_cursor_motion(seat->server, time_msec);
}
void diyac_cursor_emulate_move_absolute(struct diyac_seat *seat, struct wlr_input_device *device, double x, double y, uint32_t time_msec)
{
double lx, ly;
wlr_cursor_absolute_to_layout_coords(seat->cursor, device, x, y, &lx, &ly);
double dx = lx - seat->cursor->x;
double dy = ly - seat->cursor->y;
diyac_cursor_emulate_move(seat, device, dx, dy, time_msec);
}
void diyac_cursor_emulate_button(struct diyac_seat *seat, uint32_t button, enum wl_pointer_button_state state, uint32_t time_msec)
{
switch (state)
{
case WL_POINTER_BUTTON_STATE_PRESSED:
wlr_seat_pointer_notify_button(seat->wlr_seat, time_msec, button, state);
diyac_cursor_focus(seat->server);
break;
case WL_POINTER_BUTTON_STATE_RELEASED:
wlr_seat_pointer_notify_button(seat->wlr_seat, time_msec, button, state);
diyac_reset_cursor_mode(seat->server);
break;
default:
break;
}
wlr_seat_pointer_notify_frame(seat->wlr_seat);
}
static void seat_request_cursor(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(
listener, seat, request_cursor);
/* This event is raised by the seat when a client provides a cursor image */
struct wlr_seat_pointer_request_set_cursor_event *event = data;
struct wlr_seat_client *focused_client =
seat->wlr_seat->pointer_state.focused_client;
/* This can be sent by any client, so we check to make sure this one is
* actually has pointer focus first. */
if (focused_client == event->seat_client)
{
/* Once we've vetted the client, we can tell the cursor to use the
* provided surface as the cursor image. It will set the hardware cursor
* on the output that it's currently on and continue to do so as the
* cursor moves between outputs. */
wlr_cursor_set_surface(seat->cursor, event->surface,
event->hotspot_x, event->hotspot_y);
}
}
void diyac_init_cursor_manager(struct diyac_server *server) void diyac_init_cursor_manager(struct diyac_server *server)
{ {
/* /*
@@ -325,4 +455,33 @@ void diyac_init_cursor_manager(struct diyac_server *server)
wl_signal_add(&server->seat.cursor->events.axis, &server->seat.cursor_axis); wl_signal_add(&server->seat.cursor->events.axis, &server->seat.cursor_axis);
server->seat.cursor_frame.notify = server_cursor_frame; server->seat.cursor_frame.notify = server_cursor_frame;
wl_signal_add(&server->seat.cursor->events.frame, &server->seat.cursor_frame); wl_signal_add(&server->seat.cursor->events.frame, &server->seat.cursor_frame);
server->seat.request_cursor.notify = seat_request_cursor;
wl_signal_add(&server->seat.wlr_seat->events.request_set_cursor,
&server->seat.request_cursor);
struct wlr_cursor_shape_manager_v1 *cursor_shape_manager =
wlr_cursor_shape_manager_v1_create(server->wl_display, 1);
if (cursor_shape_manager)
{
server->seat.request_set_shape.notify = request_set_shape_notify;
wl_signal_add(&cursor_shape_manager->events.request_set_shape,
&server->seat.request_set_shape);
}
diyac_touch_init(&server->seat);
diyac_gestures_init(&server->seat);
}
void diyac_finish_cusor_manager(struct diyac_server *server)
{
wl_list_remove(&server->seat.request_cursor.link);
wl_list_remove(&server->seat.cursor_motion.link);
wl_list_remove(&server->seat.cursor_motion_absolute.link);
wl_list_remove(&server->seat.cursor_button.link);
wl_list_remove(&server->seat.cursor_axis.link);
wl_list_remove(&server->seat.cursor_frame.link);
wl_list_remove(&server->seat.request_set_shape.link);
diyac_touch_drop(&server->seat);
diyac_gestures_drop(&server->seat);
wlr_xcursor_manager_destroy(server->seat.cursor_mgr);
wlr_cursor_destroy(server->seat.cursor);
} }

View File

@@ -6,4 +6,8 @@
void diyac_init_cursor_manager(struct diyac_server * server); void diyac_init_cursor_manager(struct diyac_server * server);
void diyac_reset_cursor_mode(struct diyac_server *server); void diyac_reset_cursor_mode(struct diyac_server *server);
void diyac_cursor_focus(struct diyac_server *server); void diyac_cursor_focus(struct diyac_server *server);
void diyac_finish_cusor_manager(struct diyac_server* server);
void diyac_cursor_emulate_move(struct diyac_seat *seat, struct wlr_input_device *device,double dx, double dy, uint32_t time_msec);
void diyac_cursor_emulate_move_absolute(struct diyac_seat *seat, struct wlr_input_device *device,double x, double y, uint32_t time_msec);
void diyac_cursor_emulate_button(struct diyac_seat *seat, uint32_t button, enum wl_pointer_button_state state, uint32_t time_msec);
#endif #endif

71
diyac.c
View File

@@ -8,20 +8,31 @@
#include <errno.h> #include <errno.h>
#include <string.h> #include <string.h>
#include <signal.h> #include <signal.h>
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include "output.h" #include "output.h"
#include "xdg.h" #include "xdg.h"
#include "cursor.h" #include "cursor.h"
#include "seat.h" #include "seat.h"
#include "layer.h" #include "layer.h"
#include "session.h" #include "session.h"
#include "idle.h"
#define PROC_MON_TO 100 #define PROC_MON_TO 100
void help() void help()
{ {
printf("diyac - a simple Wayland compositor\n");
printf("Usage: diyac [-x] [startup command]\n"); printf("Usage: diyac [-x] [startup command]\n");
printf("Options:\n"); printf("Options:\n");
printf(" -x exit with the session\n"); printf(" -x exit with the session\n");
printf(" -v increase log level\n");
printf(" -h show this help message\n");
#ifdef __COMPOSITOR_VERSION__
printf("Version: %s\n", __COMPOSITOR_VERSION__);
#endif
} }
/** /**
@@ -54,15 +65,20 @@ static int session_monitor(void *data)
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
wlr_log_init(WLR_INFO, NULL);
char *startup_cmd = NULL; char *startup_cmd = NULL;
int exit_with_session = 0; int exit_with_session = 0;
int log_level = WLR_ERROR;
int c; int c;
while ((c = getopt(argc, argv, "xh")) != -1) while ((c = getopt(argc, argv, "xvh")) != -1)
{ {
switch (c) switch (c)
{ {
case 'v':
if (log_level < WLR_DEBUG)
{
log_level++;
}
break;
case 'x': case 'x':
exit_with_session = 1; exit_with_session = 1;
break; break;
@@ -78,7 +94,7 @@ int main(int argc, char *argv[])
} }
if (optind < argc) if (optind < argc)
{ {
if(optind != argc - 1) if (optind != argc - 1)
{ {
help(); help();
return 1; return 1;
@@ -86,6 +102,7 @@ int main(int argc, char *argv[])
// the last argument is the startup command // the last argument is the startup command
startup_cmd = argv[optind]; startup_cmd = argv[optind];
} }
wlr_log_init(log_level, NULL);
struct diyac_server server = {0}; struct diyac_server server = {0};
/* The Wayland display is managed by libwayland. It handles accepting /* The Wayland display is managed by libwayland. It handles accepting
* clients from the Unix socket, manging Wayland globals, and so on. */ * clients from the Unix socket, manging Wayland globals, and so on. */
@@ -95,7 +112,7 @@ int main(int argc, char *argv[])
* output hardware. The autocreate option will choose the most suitable * output hardware. The autocreate option will choose the most suitable
* backend based on the current environment, such as opening an X11 window * backend based on the current environment, such as opening an X11 window
* if an X11 server is running. */ * if an X11 server is running. */
server.backend = wlr_backend_autocreate(server.wl_display, NULL); server.backend = wlr_backend_autocreate(server.wl_event_loop, NULL);
if (server.backend == NULL) if (server.backend == NULL)
{ {
wlr_log(WLR_ERROR, "failed to create wlr_backend"); wlr_log(WLR_ERROR, "failed to create wlr_backend");
@@ -149,15 +166,6 @@ int main(int argc, char *argv[])
*/ */
wlr_primary_selection_v1_device_manager_create(server.wl_display); wlr_primary_selection_v1_device_manager_create(server.wl_display);
/* Creates an output layout, which a wlroots utility for working with an
* arrangement of screens in a physical layout. */
server.output_layout = wlr_output_layout_create();
/* Configure a listener to be notified when new outputs are available on the
* backend. */
wl_list_init(&server.outputs);
server.new_output.notify = diyac_server_new_output;
wl_signal_add(&server.backend->events.new_output, &server.new_output);
/* Create a scene graph. This is a wlroots abstraction that handles all /* Create a scene graph. This is a wlroots abstraction that handles all
* rendering and damage tracking. All the compositor author needs to do * rendering and damage tracking. All the compositor author needs to do
@@ -166,8 +174,15 @@ int main(int argc, char *argv[])
* necessary. * necessary.
*/ */
server.scene = wlr_scene_create(); server.scene = wlr_scene_create();
server.scene_layout = wlr_scene_attach_output_layout(server.scene, server.output_layout); diyac_output_init(&server);
wlr_fractional_scale_manager_v1_create(server.wl_display,1); wlr_export_dmabuf_manager_v1_create(server.wl_display);
wlr_data_control_manager_v1_create(server.wl_display);
wlr_screencopy_manager_v1_create(server.wl_display);
wlr_single_pixel_buffer_manager_v1_create(server.wl_display);
wlr_fractional_scale_manager_v1_create(server.wl_display, 1);
diyac_init_idle_manager(&server);
server.relative_pointer_manager = wlr_relative_pointer_manager_v1_create(server.wl_display);
/* Set up xdg-shell version 6 The xdg-shell is a Wayland protocol which is /* Set up xdg-shell version 6 The xdg-shell is a Wayland protocol which is
* used for application windows. For more detail on shells, refer to * used for application windows. For more detail on shells, refer to
* https://drewdevault.com/2018/07/29/Wayland-shells.html. * https://drewdevault.com/2018/07/29/Wayland-shells.html.
@@ -180,9 +195,9 @@ int main(int argc, char *argv[])
server.xdg_popup_tree = wlr_scene_tree_create(&server.scene->tree); server.xdg_popup_tree = wlr_scene_tree_create(&server.scene->tree);
server.xdg_shell = wlr_xdg_shell_create(server.wl_display, 6); server.xdg_shell = wlr_xdg_shell_create(server.wl_display, 6);
server.new_xdg_surface.notify = diyac_new_xdg_surface; server.new_xdg_toplevel.notify = diyac_new_xdg_toplevel;
wl_signal_add(&server.xdg_shell->events.new_surface, wl_signal_add(&server.xdg_shell->events.new_toplevel,
&server.new_xdg_surface); &server.new_xdg_toplevel);
server.layer_shell = wlr_layer_shell_v1_create(server.wl_display, 4); server.layer_shell = wlr_layer_shell_v1_create(server.wl_display, 4);
server.new_layer_surface.notify = diyac_new_layer_surface; server.new_layer_surface.notify = diyac_new_layer_surface;
@@ -190,7 +205,6 @@ int main(int argc, char *argv[])
&server.new_layer_surface); &server.new_layer_surface);
diyac_init_session_lock(&server); diyac_init_session_lock(&server);
diyac_init_cursor_manager(&server);
/* /*
* Configures a seat, which is a single "seat" at which a user sits and * Configures a seat, which is a single "seat" at which a user sits and
@@ -202,6 +216,7 @@ int main(int argc, char *argv[])
/* foreign toplevel manager for create shell panel for application control */ /* foreign toplevel manager for create shell panel for application control */
server.foreign_toplevel_manager = wlr_foreign_toplevel_manager_v1_create(server.wl_display); server.foreign_toplevel_manager = wlr_foreign_toplevel_manager_v1_create(server.wl_display);
diyac_init_seat(&server); diyac_init_seat(&server);
diyac_init_cursor_manager(&server);
/* Add a Unix socket to the Wayland display. */ /* Add a Unix socket to the Wayland display. */
const char *socket = wl_display_add_socket_auto(server.wl_display); const char *socket = wl_display_add_socket_auto(server.wl_display);
@@ -239,7 +254,7 @@ int main(int argc, char *argv[])
wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s", wlr_log(WLR_INFO, "Running Wayland compositor on WAYLAND_DISPLAY=%s",
socket); socket);
server.proc_mon = NULL; server.proc_mon = NULL;
if( startup_cmd && exit_with_session) if (startup_cmd && exit_with_session)
{ {
if (server.session_pid == -1) if (server.session_pid == -1)
{ {
@@ -259,15 +274,25 @@ int main(int argc, char *argv[])
/* Once wl_display_run returns, we destroy all clients then shut down the /* Once wl_display_run returns, we destroy all clients then shut down the
* server. */ * server. */
if(server.proc_mon) if (server.proc_mon)
{ {
wl_event_source_remove(server.proc_mon); wl_event_source_remove(server.proc_mon);
} }
diyac_finish_cusor_manager(&server);
diyac_release_idle_manager(&server);
diyac_release_seat(&server);
wl_list_remove(&server.new_xdg_toplevel.link);
wl_list_remove(&server.new_layer_surface.link);
wl_list_remove(&server.new_output.link);
wl_list_remove(&server.output_power_manager_set_mode.link);
wl_list_remove(&server.output_manager_apply.link);
wl_list_remove(&server.output_manager_test.link);
wl_list_remove(&server.output_layout_change.link);
wl_display_destroy_clients(server.wl_display); wl_display_destroy_clients(server.wl_display);
// wlr_scene_node_destroy(&server.scene->tree.node); // wlr_scene_node_destroy(&server.scene->tree.node);
wlr_xcursor_manager_destroy(server.seat.cursor_mgr);
wlr_output_layout_destroy(server.output_layout); wlr_output_layout_destroy(server.output_layout);
wl_display_destroy(server.wl_display); wl_display_destroy(server.wl_display);
wlr_log(WLR_INFO, "Diyac session ended");
return 0; return 0;
} }

63
diyac.h
View File

@@ -18,6 +18,9 @@
#include <wlr/types/wlr_foreign_toplevel_management_v1.h> #include <wlr/types/wlr_foreign_toplevel_management_v1.h>
#include <wlr/types/wlr_session_lock_v1.h> #include <wlr/types/wlr_session_lock_v1.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h> #include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_output_power_management_v1.h>
#include <wlr/types/wlr_output_management_v1.h>
#include <wlr/types/wlr_relative_pointer_v1.h>
#define LAYER_TREE_SZ 4 #define LAYER_TREE_SZ 4
@@ -67,8 +70,28 @@ struct diyac_seat
struct wl_listener cursor_button; struct wl_listener cursor_button;
struct wl_listener cursor_axis; struct wl_listener cursor_axis;
struct wl_listener cursor_frame; struct wl_listener cursor_frame;
struct wl_listener new_input;
struct wl_listener request_cursor; struct wl_listener request_cursor;
struct wl_listener request_set_shape;
/*touch*/
struct wl_listener touch_down;
struct wl_listener touch_up;
struct wl_listener touch_motion;
struct wl_listener touch_frame;
struct wl_list touch_points; /* struct touch_point.link */
/*wlr_pointer_gestures_v1*/
struct wlr_pointer_gestures_v1 *pointer_gestures;
struct wl_listener pinch_begin;
struct wl_listener pinch_update;
struct wl_listener pinch_end;
struct wl_listener swipe_begin;
struct wl_listener swipe_update;
struct wl_listener swipe_end;
struct wl_listener hold_begin;
struct wl_listener hold_end;
struct wl_listener new_input;
struct wl_listener request_set_selection; struct wl_listener request_set_selection;
struct wl_listener request_set_primary_selection; struct wl_listener request_set_primary_selection;
// struct wl_list keyboards; // struct wl_list keyboards;
@@ -110,13 +133,13 @@ struct diyac_node_descriptor
struct diyac_session_lock struct diyac_session_lock
{ {
bool abandoned; bool abandoned;
struct wlr_surface * focused; struct wlr_surface *focused;
struct wlr_session_lock_v1* wlr_session_lock; struct wlr_session_lock_v1 *wlr_session_lock;
struct wl_listener new_surface; struct wl_listener new_surface;
struct wl_listener unlock; struct wl_listener unlock;
struct wl_listener destroy; struct wl_listener destroy;
//struct wl_listener new_output; // struct wl_listener new_output;
}; };
struct diyac_server struct diyac_server
@@ -131,10 +154,12 @@ struct diyac_server
struct wlr_xdg_shell *xdg_shell; struct wlr_xdg_shell *xdg_shell;
struct wlr_layer_shell_v1 *layer_shell; struct wlr_layer_shell_v1 *layer_shell;
struct wl_listener new_xdg_surface;
struct wl_listener new_xdg_toplevel;
struct wl_listener new_layer_surface; struct wl_listener new_layer_surface;
struct wl_list views; struct wl_list views;
struct diyac_view * active_view; struct diyac_view *active_view;
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
/* /*
* Popups need to be rendered above always-on-top views, so we reparent * Popups need to be rendered above always-on-top views, so we reparent
@@ -154,9 +179,22 @@ struct diyac_server
struct wl_list outputs; struct wl_list outputs;
struct wl_listener new_output; struct wl_listener new_output;
struct diyac_session_lock * lock; struct wlr_output_power_manager_v1 *output_power_manager;
struct wl_listener output_power_manager_set_mode;
struct wlr_relative_pointer_manager_v1 *relative_pointer_manager;
struct wl_event_source* proc_mon; struct wlr_output_manager_v1 *output_manager;
struct wl_listener output_manager_test;
struct wl_listener output_manager_apply;
struct wl_listener output_layout_change;
struct wlr_idle_inhibit_manager_v1 *idle_inhibitor_mngr;
struct wl_listener idle_inhibitor_new;
struct wlr_idle_notifier_v1 *idle_notifier;
struct diyac_session_lock *lock;
struct wl_event_source *proc_mon;
pid_t session_pid; pid_t session_pid;
}; };
@@ -179,7 +217,7 @@ struct diyac_output_lock_handle
struct wlr_scene_rect *background; struct wlr_scene_rect *background;
struct wlr_session_lock_surface_v1 *surface; struct wlr_session_lock_surface_v1 *surface;
struct diyac_output * output; struct diyac_output *output;
struct wl_listener surface_destroy; struct wl_listener surface_destroy;
struct wl_listener surface_map; struct wl_listener surface_map;
@@ -195,13 +233,15 @@ struct diyac_output
struct wl_listener request_state; struct wl_listener request_state;
struct wl_listener destroy; struct wl_listener destroy;
struct wlr_box usable_area; struct wlr_box usable_area;
struct wlr_output_state pending_state;
struct wlr_scene_output *scene_output;
// layer output // layer output
struct diyac_output_scenes scenes; struct diyac_output_scenes scenes;
// alias to diyac_output_scenes elements // alias to diyac_output_scenes elements
struct wlr_scene_tree *layer_tree[LAYER_TREE_SZ]; struct wlr_scene_tree *layer_tree[LAYER_TREE_SZ];
// lock handle // lock handle
struct diyac_output_lock_handle * lock_handle; struct diyac_output_lock_handle *lock_handle;
}; };
struct foreign_toplevel struct foreign_toplevel
@@ -225,7 +265,7 @@ struct diyac_view
struct diyac_view_state state; struct diyac_view_state state;
struct diyac_view_state requested; struct diyac_view_state requested;
uint32_t configuration_serial; uint32_t configuration_serial;
struct wl_event_source * configuration_timeout; struct wl_event_source *configuration_timeout;
/* /*
* Geometry of the wlr_surface contained within the view, as * Geometry of the wlr_surface contained within the view, as
* currently displayed. Should be kept in sync with the * currently displayed. Should be kept in sync with the
@@ -244,7 +284,6 @@ struct diyac_view
struct wl_listener request_minimize; struct wl_listener request_minimize;
struct wl_listener request_maximize; struct wl_listener request_maximize;
struct wl_listener request_fullscreen; struct wl_listener request_fullscreen;
struct wl_listener set_app_id; struct wl_listener set_app_id;
struct wl_listener new_popup; struct wl_listener new_popup;
struct wl_listener set_title; struct wl_listener set_title;

View File

@@ -29,6 +29,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
static void handle_request_activate(struct wl_listener *listener, void *data) static void handle_request_activate(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_view *view = wl_container_of(listener, view, toplevel.activate); struct diyac_view *view = wl_container_of(listener, view, toplevel.activate);
// struct wlr_foreign_toplevel_handle_v1_activated_event *event = data; // struct wlr_foreign_toplevel_handle_v1_activated_event *event = data;
/* In a multi-seat world we would select seat based on event->seat here. */ /* In a multi-seat world we would select seat based on event->seat here. */
@@ -39,6 +40,7 @@ static void handle_request_activate(struct wl_listener *listener, void *data)
static void static void
handle_request_close(struct wl_listener *listener, void *data) handle_request_close(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_view *view = wl_container_of(listener, view, toplevel.close); struct diyac_view *view = wl_container_of(listener, view, toplevel.close);
wlr_xdg_toplevel_send_close(view->xdg_toplevel); wlr_xdg_toplevel_send_close(view->xdg_toplevel);
} }
@@ -46,6 +48,7 @@ handle_request_close(struct wl_listener *listener, void *data)
static void static void
handle_destroy(struct wl_listener *listener, void *data) handle_destroy(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_view *view = wl_container_of(listener, view, toplevel.destroy); struct diyac_view *view = wl_container_of(listener, view, toplevel.destroy);
struct foreign_toplevel *toplevel = &view->toplevel; struct foreign_toplevel *toplevel = &view->toplevel;
wl_list_remove(&toplevel->maximize.link); wl_list_remove(&toplevel->maximize.link);

139
gestures.c Normal file
View File

@@ -0,0 +1,139 @@
#include <wlr/types/wlr_pointer_gestures_v1.h>
#include "gestures.h"
#include "idle.h"
static void gesture_pinch_begin(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, pinch_begin);
struct wlr_pointer_pinch_begin_event *event = data;
diyac_idle_manager_notify_activity(seat);
// cursor_set_visible(seat, /* visible */ true);
wlr_pointer_gestures_v1_send_pinch_begin(seat->pointer_gestures,
seat->wlr_seat, event->time_msec, event->fingers);
}
static void gesture_pinch_update(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, pinch_update);
struct wlr_pointer_pinch_update_event *event = data;
diyac_idle_manager_notify_activity(seat);
// cursor_set_visible(seat, /* visible */ true);
wlr_pointer_gestures_v1_send_pinch_update(seat->pointer_gestures,
seat->wlr_seat, event->time_msec, event->dx, event->dy,
event->scale, event->rotation);
}
static void gesture_pinch_end(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, pinch_end);
struct wlr_pointer_pinch_end_event *event = data;
diyac_idle_manager_notify_activity(seat);
// cursor_set_visible(seat, /* visible */ true);
wlr_pointer_gestures_v1_send_pinch_end(seat->pointer_gestures,
seat->wlr_seat, event->time_msec, event->cancelled);
}
static void gesture_swipe_begin(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, swipe_begin);
struct wlr_pointer_swipe_begin_event *event = data;
diyac_idle_manager_notify_activity(seat);
// cursor_set_visible(seat, /* visible */ true);
wlr_pointer_gestures_v1_send_swipe_begin(seat->pointer_gestures,
seat->wlr_seat, event->time_msec, event->fingers);
}
static void gesture_swipe_update(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, swipe_update);
struct wlr_pointer_swipe_update_event *event = data;
diyac_idle_manager_notify_activity(seat);
// cursor_set_visible(seat, /* visible */ true);
wlr_pointer_gestures_v1_send_swipe_update(seat->pointer_gestures,
seat->wlr_seat, event->time_msec, event->dx, event->dy);
}
static void gesture_swipe_end(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, swipe_end);
struct wlr_pointer_swipe_end_event *event = data;
diyac_idle_manager_notify_activity(seat);
// cursor_set_visible(seat, /* visible */ true);
wlr_pointer_gestures_v1_send_swipe_end(seat->pointer_gestures,
seat->wlr_seat, event->time_msec, event->cancelled);
}
static void gesture_hold_begin(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, hold_begin);
struct wlr_pointer_hold_begin_event *event = data;
diyac_idle_manager_notify_activity(seat);
// cursor_set_visible(seat, /* visible */ true);
wlr_pointer_gestures_v1_send_hold_begin(seat->pointer_gestures,
seat->wlr_seat, event->time_msec, event->fingers);
}
static void gesture_hold_end(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, hold_end);
struct wlr_pointer_hold_end_event *event = data;
diyac_idle_manager_notify_activity(seat);
// cursor_set_visible(seat, /* visible */ true);
wlr_pointer_gestures_v1_send_hold_end(seat->pointer_gestures,
seat->wlr_seat, event->time_msec, event->cancelled);
}
void diyac_gestures_init(struct diyac_seat *seat)
{
seat->pinch_begin.notify = gesture_pinch_begin;
wl_signal_add(&seat->cursor->events.pinch_begin, &seat->pinch_begin);
seat->pinch_update.notify = gesture_pinch_update;
wl_signal_add(&seat->cursor->events.pinch_update, &seat->pinch_update);
seat->pinch_end.notify = gesture_pinch_end;
wl_signal_add(&seat->cursor->events.pinch_end, &seat->pinch_end);
seat->swipe_begin.notify = gesture_swipe_begin;
wl_signal_add(&seat->cursor->events.swipe_begin, &seat->swipe_begin);
seat->swipe_update.notify = gesture_swipe_update;
wl_signal_add(&seat->cursor->events.swipe_update, &seat->swipe_update);
seat->swipe_end.notify = gesture_swipe_end;
wl_signal_add(&seat->cursor->events.swipe_end, &seat->swipe_end);
seat->hold_begin.notify = gesture_hold_begin;
wl_signal_add(&seat->cursor->events.hold_begin, &seat->hold_begin);
seat->hold_end.notify = gesture_hold_end;
wl_signal_add(&seat->cursor->events.hold_end, &seat->hold_end);
}
void diyac_gestures_drop(struct diyac_seat *seat)
{
wl_list_remove(&seat->pinch_begin.link);
wl_list_remove(&seat->pinch_update.link);
wl_list_remove(&seat->pinch_end.link);
wl_list_remove(&seat->swipe_begin.link);
wl_list_remove(&seat->swipe_update.link);
wl_list_remove(&seat->swipe_end.link);
wl_list_remove(&seat->hold_begin.link);
wl_list_remove(&seat->hold_end.link);
}

8
gestures.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef DIYAC_GESTURES_H
#define DIYAC_GESTURES_H
#include "diyac.h"
void diyac_gestures_init(struct diyac_seat *seat);
void diyac_gestures_drop(struct diyac_seat *seat);
#endif

73
idle.c Normal file
View File

@@ -0,0 +1,73 @@
#include "diyac.h"
#include "idle.h"
#include <stdlib.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include <wlr/types/wlr_idle_inhibit_v1.h>
struct diya_idle_inhibitor
{
struct wlr_idle_inhibitor_v1 *wlr_inhibitor;
struct wl_listener on_inhibitor_destroy;
struct diyac_server *server;
};
static void handle_idle_inhibitor_destroy(struct wl_listener *listener, void *data)
{
(void) data;
struct diya_idle_inhibitor *inhibitor = wl_container_of(listener, inhibitor, on_inhibitor_destroy);
if (inhibitor->server->idle_notifier) {
bool still_inhibited = wl_list_length(&inhibitor->server->idle_inhibitor_mngr->inhibitors) > 1;
wlr_idle_notifier_v1_set_inhibited(inhibitor->server->idle_notifier, still_inhibited);
}
wl_list_remove(&inhibitor->on_inhibitor_destroy.link);
free(inhibitor);
}
/*
static void handle_display_destroy(struct wl_listener *listener, void *data)
{
(void) data;
(void) listener;
wl_list_remove(&g_idle_mngr.on_display_destroy.link);
g_idle_mngr.wlr_idle_notifier = NULL;
}
*/
static void handle_idle_inhibitor_new(struct wl_listener *listener, void *data)
{
struct wlr_idle_inhibitor_v1 *wlr_inhibitor = data;
struct diyac_server *server = wl_container_of(listener, server, idle_inhibitor_new);
struct diya_idle_inhibitor *inhibitor = malloc(sizeof(struct diya_idle_inhibitor));
inhibitor->wlr_inhibitor = wlr_inhibitor;
inhibitor->on_inhibitor_destroy.notify = handle_idle_inhibitor_destroy;
inhibitor->server = server;
wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->on_inhibitor_destroy);
wlr_idle_notifier_v1_set_inhibited(server->idle_notifier, true);
}
void diyac_init_idle_manager(struct diyac_server *server)
{
server->idle_notifier = wlr_idle_notifier_v1_create(server->wl_display);
server->idle_inhibitor_mngr = wlr_idle_inhibit_v1_create(server->wl_display);
server->idle_inhibitor_new.notify = handle_idle_inhibitor_new;
wl_signal_add(&server->idle_inhibitor_mngr->events.new_inhibitor,&server->idle_inhibitor_new);
//g_idle_mngr.on_display_destroy.notify = handle_display_destroy;
//wl_display_add_destroy_listener(display, &g_idle_mngr.on_display_destroy);
}
void diyac_idle_manager_notify_activity(struct diyac_seat *seat)
{
if (seat->server->idle_notifier) {
wlr_idle_notifier_v1_notify_activity(seat->server->idle_notifier, seat->wlr_seat);
}
}
void diyac_release_idle_manager(struct diyac_server *server)
{
wl_list_remove(&server->idle_inhibitor_new.link);
}

10
idle.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef DIYAC_IDLE_H
#define DIYAC_IDLE_H
struct diyac_server;
struct diyac_seat;
void diyac_init_idle_manager(struct diyac_server *server);
void diyac_idle_manager_notify_activity(struct diyac_seat *seat);
void diyac_release_idle_manager(struct diyac_server *server);
#endif

13
layer.c
View File

@@ -53,6 +53,7 @@ static void process_keyboard_interactivity(struct diyac_layer_surface *layer)
} }
static void layer_surface_commit(struct wl_listener *listener, void *data) static void layer_surface_commit(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_layer_surface *layer = struct diyac_layer_surface *layer =
wl_container_of(listener, layer, surface_commit); wl_container_of(listener, layer, surface_commit);
struct wlr_layer_surface_v1 *layer_surface = struct wlr_layer_surface_v1 *layer_surface =
@@ -94,6 +95,7 @@ static void layer_surface_commit(struct wl_listener *listener, void *data)
} }
static void layer_surface_unmap(struct wl_listener *listener, void *data) static void layer_surface_unmap(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_layer_surface *layer = wl_container_of(listener, layer, unmap); struct diyac_layer_surface *layer = wl_container_of(listener, layer, unmap);
struct wlr_layer_surface_v1 *layer_surface = struct wlr_layer_surface_v1 *layer_surface =
layer->scene_layer_surface->layer_surface; layer->scene_layer_surface->layer_surface;
@@ -109,6 +111,7 @@ static void layer_surface_unmap(struct wl_listener *listener, void *data)
static void layer_surface_map(struct wl_listener *listener, void *data) static void layer_surface_map(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_layer_surface *layer = wl_container_of(listener, layer, map); struct diyac_layer_surface *layer = wl_container_of(listener, layer, map);
struct wlr_output *wlr_output = struct wlr_output *wlr_output =
layer->scene_layer_surface->layer_surface->output; layer->scene_layer_surface->layer_surface->output;
@@ -127,6 +130,7 @@ static void layer_surface_map(struct wl_listener *listener, void *data)
} }
static void layer_surface_node_destroy(struct wl_listener *listener, void *data) static void layer_surface_node_destroy(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_layer_surface *layer = struct diyac_layer_surface *layer =
wl_container_of(listener, layer, node_destroy); wl_container_of(listener, layer, node_destroy);
@@ -142,6 +146,7 @@ static void layer_surface_node_destroy(struct wl_listener *listener, void *data)
} }
static void layer_surface_output_destroy(struct wl_listener *listener, void *data) static void layer_surface_output_destroy(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_layer_surface *layer = struct diyac_layer_surface *layer =
wl_container_of(listener, layer, output_destroy); wl_container_of(listener, layer, output_destroy);
layer->scene_layer_surface->layer_surface->output = NULL; layer->scene_layer_surface->layer_surface->output = NULL;
@@ -150,6 +155,7 @@ static void layer_surface_output_destroy(struct wl_listener *listener, void *dat
static void static void
popup_handle_destroy(struct wl_listener *listener, void *data) popup_handle_destroy(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_popup *popup = wl_container_of(listener, popup, destroy); struct diyac_popup *popup = wl_container_of(listener, popup, destroy);
wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->new_popup.link);
@@ -165,12 +171,11 @@ popup_handle_destroy(struct wl_listener *listener, void *data)
static void popup_handle_commit(struct wl_listener *listener, void *data) static void popup_handle_commit(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_popup *popup = struct diyac_popup *popup =
wl_container_of(listener, popup, commit); wl_container_of(listener, popup, commit);
struct wlr_box popup_box ;
wlr_xdg_surface_get_geometry(popup->wlr_popup->base, &popup_box);
wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &popup->output_toplevel_sx_box); wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &popup->output_toplevel_sx_box);
if (!wlr_box_empty(&popup_box)) if (!wlr_box_empty(&popup->wlr_popup->base->geometry))
//if (popup->wlr_popup->base->initial_commit) //if (popup->wlr_popup->base->initial_commit)
{ {
@@ -352,7 +357,7 @@ void diyac_new_layer_surface(struct wl_listener *listener, void *data)
*/ */
struct wlr_layer_surface_v1_state old_state = layer_surface->current; struct wlr_layer_surface_v1_state old_state = layer_surface->current;
layer_surface->current = layer_surface->pending; layer_surface->current = layer_surface->pending;
diyac_output_update_usable_area(output); // diyac_output_update_usable_area(output);
layer_surface->current = old_state; layer_surface->current = old_state;
} }

80
meson.build Normal file
View File

@@ -0,0 +1,80 @@
project('diyac',
['c'],
version: '0.1.3',
license: 'MIT',
meson_version: '>=0.58.0',
default_options: ['c_std=gnu11', 'warning_level=3'])
lib_so_version = '0'
add_project_arguments(
[
'-Wno-pedantic',
'-Werror=implicit-function-declaration',
'-Werror=return-type',
'-DWLR_USE_UNSTABLE',
'-D__COMPOSITOR_VERSION__="@0@"'.format(meson.project_version())
],
language: 'c')
wlroots = dependency('wlroots-0.19')
wayland_server = dependency('wayland-server', version: '>=1.10.0')
xkbcommon = dependency('xkbcommon')
# wayland_scanner is required, but we can find it without pkg-config
wayland_scanner = find_program('wayland-scanner')
wayland_protocols = dependency('wayland-protocols', version: '>=1.16')
wl_protocol_dir = wayland_protocols.get_variable('pkgdatadir')
wayland_targets=[]
wl_protocols = [
wl_protocol_dir / 'stable/xdg-shell/xdg-shell',
wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1',
# we don't really support tablet v2, it is here because of curosr-shape-v1 depends on it
wl_protocol_dir / 'stable/tablet/tablet-v2',
'protocol/wlr-layer-shell-unstable-v1',
'protocol/wlr-output-power-management-unstable-v1',
]
foreach proto : wl_protocols
xml = ''.join([proto,'.xml'])
header = ''.join([proto.split('/').get(-1),'-protocol.h'])
cfile = ''.join([proto.split('/').get(-1),'-protocol.c'])
wayland_targets += custom_target(header,output:header,input:xml,
command: [ wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@' ] )
wayland_targets += custom_target(cfile,output:cfile,input:xml,
command: [ wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@' ] )
endforeach
incdir = include_directories([
])
src = [
'diyac.c',
'cursor.c',
'output.c',
'seat.c',
'node.c',
'view.c',
'foreign.c',
'xdg.c',
'layer.c',
'session.c',
'idle.c',
'touch.c',
'gestures.c',
wayland_targets
]
buil_dep = [wlroots, wayland_server, xkbcommon]
executable(
'diyac',
src,
dependencies: buil_dep,
include_directories : incdir)

20
node.c
View File

@@ -5,6 +5,7 @@
static void destroy_notify(struct wl_listener *listener, void *data) static void destroy_notify(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_node_descriptor *node_descriptor = struct diyac_node_descriptor *node_descriptor =
wl_container_of(listener, node_descriptor, destroy); wl_container_of(listener, node_descriptor, destroy);
wl_list_remove(&node_descriptor->destroy.link); wl_list_remove(&node_descriptor->destroy.link);
@@ -36,7 +37,7 @@ struct diyac_view *diyac_view_from_node(struct wlr_scene_node *wlr_scene_node)
return (struct diyac_view *)node_descriptor->data; return (struct diyac_view *)node_descriptor->data;
} }
struct diyac_node_descriptor * diyac_node_at(struct diyac_server* server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) struct diyac_node_descriptor *diyac_node_at(struct diyac_server *server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy)
{ {
/* This returns the topmost node in the scene at the given layout coords. /* This returns the topmost node in the scene at the given layout coords.
* We only care about surface nodes as we are specifically looking for a * We only care about surface nodes as we are specifically looking for a
@@ -65,3 +66,20 @@ struct diyac_node_descriptor * diyac_node_at(struct diyac_server* server, double
} }
return tree->node.data; return tree->node.data;
} }
struct wlr_surface *diyac_wlr_surface_from_node(struct wlr_scene_node *node)
{
struct wlr_scene_buffer *buffer;
struct wlr_scene_surface *scene_surface;
if (node && node->type == WLR_SCENE_NODE_BUFFER)
{
buffer = wlr_scene_buffer_from_node(node);
scene_surface = wlr_scene_surface_try_from_buffer(buffer);
if (scene_surface)
{
return scene_surface->surface;
}
}
return NULL;
}

1
node.h
View File

@@ -4,6 +4,7 @@
void diyac_node_descriptor_create(struct wlr_scene_node *scene_node,enum diyac_node_descriptor_type type, void *data); void diyac_node_descriptor_create(struct wlr_scene_node *scene_node,enum diyac_node_descriptor_type type, void *data);
struct diyac_layer_surface * diyac_layer_surface_from_node(struct wlr_scene_node *wlr_scene_node); struct diyac_layer_surface * diyac_layer_surface_from_node(struct wlr_scene_node *wlr_scene_node);
struct wlr_surface * diyac_wlr_surface_from_node(struct wlr_scene_node* node);
struct diyac_view *diyac_view_from_node(struct wlr_scene_node *wlr_scene_node); struct diyac_view *diyac_view_from_node(struct wlr_scene_node *wlr_scene_node);
struct diyac_node_descriptor * diyac_node_at(struct diyac_server* server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy); struct diyac_node_descriptor * diyac_node_at(struct diyac_server* server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy);
#endif #endif

672
output.c
View File

@@ -3,14 +3,66 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <wlr/backend/wayland.h>
#include <wlr/types/wlr_output.h>
#include <wlr/types/wlr_xdg_output_v1.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/util/log.h>
#include <assert.h>
#include "output.h" #include "output.h"
#include "layer.h" #include "layer.h"
#include "node.h" #include "node.h"
#include "view.h" #include "view.h"
#include "session.h" #include "session.h"
/*
* While an output layout change is in process, this counter is
* non-zero and causes change-events from the wlr_output_layout
* to be ignored (to prevent, for example, moving views in a
* transitory layout state). Once the counter reaches zero,
* do_output_layout_change() must be called explicitly.
*/
static int g_pending_output_layout_change = 0;
static void output_state_init(struct diyac_output *output)
{
wlr_output_state_init(&output->pending_state);
/*
* As there is no direct way to convert an existing output
* configuration to an output_state we first convert it
* to a temporary output-management config and then apply
* it to an empty wlr_output_state.
*/
struct wlr_output_configuration_v1 *backup_config =
wlr_output_configuration_v1_create();
struct wlr_output_configuration_head_v1 *backup_head =
wlr_output_configuration_head_v1_create(
backup_config, output->wlr_output);
wlr_output_head_v1_state_apply(&backup_head->state, &output->pending_state);
wlr_output_configuration_v1_destroy(backup_config);
}
static bool output_state_commit(struct diyac_output *output)
{
bool committed =
wlr_output_commit_state(output->wlr_output, &output->pending_state);
if (committed)
{
wlr_output_state_finish(&output->pending_state);
wlr_output_state_init(&output->pending_state);
}
else
{
wlr_log(WLR_ERROR, "Failed to commit frame");
}
return committed;
}
static void output_frame(struct wl_listener *listener, void *data) static void output_frame(struct wl_listener *listener, void *data)
{ {
(void)data;
/* This function is called every time an output is ready to display a frame, /* This function is called every time an output is ready to display a frame,
* generally at the output's refresh rate (e.g. 60Hz). */ * generally at the output's refresh rate (e.g. 60Hz). */
struct diyac_output *output = wl_container_of(listener, output, frame); struct diyac_output *output = wl_container_of(listener, output, frame);
@@ -27,20 +79,126 @@ static void output_frame(struct wl_listener *listener, void *data)
wlr_scene_output_send_frame_done(scene_output, &now); wlr_scene_output_send_frame_done(scene_output, &now);
} }
static struct wlr_output_configuration_v1 *create_output_config(struct diyac_server *server)
{
struct wlr_output_configuration_v1 *config =
wlr_output_configuration_v1_create();
if (!config)
{
wlr_log(WLR_ERROR, "wlr_output_configuration_v1_create()");
return NULL;
}
struct diyac_output *output;
wl_list_for_each(output, &server->outputs, link)
{
struct wlr_output_configuration_head_v1 *head =
wlr_output_configuration_head_v1_create(config,
output->wlr_output);
if (!head)
{
wlr_log(WLR_ERROR,
"wlr_output_configuration_head_v1_create()");
wlr_output_configuration_v1_destroy(config);
return NULL;
}
struct wlr_box box;
wlr_output_layout_get_box(server->output_layout,
output->wlr_output, &box);
if (!wlr_box_empty(&box))
{
head->state.x = box.x;
head->state.y = box.y;
}
else
{
wlr_log(WLR_ERROR, "failed to get output layout box");
}
}
return config;
}
/* returns true if usable area changed */
static bool update_usable_area(struct diyac_output *output)
{
struct wlr_box old = output->usable_area;
diyac_layers_arrange(output);
return !wlr_box_equal(&old, &output->usable_area);
}
static void do_output_layout_change(struct diyac_server *server)
{
if (!g_pending_output_layout_change)
{
struct wlr_output_configuration_v1 *config =
create_output_config(server);
if (config)
{
wlr_output_manager_v1_set_configuration(
server->output_manager, config);
}
else
{
wlr_log(WLR_ERROR,
"wlr_output_manager_v1_set_configuration()");
}
struct diyac_output *output;
wl_list_for_each(output, &server->outputs, link)
{
diyac_output_update_usable_area(output);
}
wlr_cursor_move(server->seat.cursor, NULL, 0, 0);
}
}
static void output_request_state(struct wl_listener *listener, void *data) static void output_request_state(struct wl_listener *listener, void *data)
{ {
/* This function is called when the backend requests a new state for /* This ensures nested backends can be resized */
* the output. For example, Wayland and X11 backends request a new mode
* when the output window is resized. */
struct diyac_output *output = wl_container_of(listener, output, request_state); struct diyac_output *output = wl_container_of(listener, output, request_state);
const struct wlr_output_event_request_state *event = data; const struct wlr_output_event_request_state *event = data;
wlr_output_commit_state(output->wlr_output, event->state);
/*
* If wlroots ever requests other state changes here we could
* restore more of ddc9047a67cd53b2948f71fde1bbe9118000dd3f.
*/
if (event->state->committed == WLR_OUTPUT_STATE_MODE)
{
/* Only the mode has changed */
switch (event->state->mode_type)
{
case WLR_OUTPUT_STATE_MODE_FIXED:
wlr_output_state_set_mode(&output->pending_state,
event->state->mode);
break;
case WLR_OUTPUT_STATE_MODE_CUSTOM:
wlr_output_state_set_custom_mode(&output->pending_state,
event->state->custom_mode.width,
event->state->custom_mode.height,
event->state->custom_mode.refresh);
break;
}
wlr_output_schedule_frame(output->wlr_output);
return;
}
/*
* Fallback path for everything that we didn't handle above.
* The commit will cause a black frame injection so this
* path causes flickering during resize of nested outputs.
*/
if (!wlr_output_commit_state(output->wlr_output, event->state))
{
wlr_log(WLR_ERROR, "Backend requested a new state that could not be applied");
}
} }
static void output_destroy(struct wl_listener *listener, void *data) static void output_destroy(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_output *output = wl_container_of(listener, output, destroy); struct diyac_output *output = wl_container_of(listener, output, destroy);
if(output->lock_handle) if (output->lock_handle)
{ {
diyac_session_unlock_output(output); diyac_session_unlock_output(output);
} }
@@ -51,31 +209,141 @@ static void output_destroy(struct wl_listener *listener, void *data)
wlr_scene_node_destroy(&output->scenes.overlay->node); wlr_scene_node_destroy(&output->scenes.overlay->node);
wlr_scene_node_destroy(&output->scenes.session->node); wlr_scene_node_destroy(&output->scenes.session->node);
wl_list_remove(&output->frame.link); wl_list_remove(&output->frame.link);
wl_list_remove(&output->request_state.link); wl_list_remove(&output->request_state.link);
wl_list_remove(&output->destroy.link); wl_list_remove(&output->destroy.link);
wl_list_remove(&output->link); wl_list_remove(&output->link);
struct diyac_server* server = output->server; struct diyac_server *server = output->server;
struct diyac_view * view; struct diyac_view *view;
wl_list_for_each(view, &server->views, link) { wl_list_for_each(view, &server->views, link)
if (view->output == output) { {
if (view->output == output)
{
/** /**
* TODO: testing this case * TODO: testing this case
*/ */
view->output = NULL; view->output = NULL;
if(&server->outputs != server->outputs.next) if (&server->outputs != server->outputs.next)
{ {
view->output = wl_container_of(server->outputs.next, view->output, link); view->output = wl_container_of(server->outputs.next, view->output, link);
diyac_view_update_geometry(view, false); diyac_view_update_geometry(view, false);
} }
} }
} }
wlr_output_state_finish(&output->pending_state);
free(output); free(output);
} }
void diyac_server_new_output(struct wl_listener *listener, void *data) static bool output_test_auto(struct wlr_output *wlr_output, struct wlr_output_state *state,
bool is_client_request)
{
wlr_log(WLR_DEBUG, "testing modes for %s", wlr_output->name);
/*
* When a client requests a specific mode, test only that mode. Here
* we interpret a custom_mode of all zeroes as "none/any"; this is
* seen e.g. with kanshi configs containing no "mode" field. In
* theory, (state->committed & WLR_OUTPUT_STATE_MODE) should be zero
* in this case, but this is not seen in practice.
*
* If the wlr_output_state did not come from a client request, then
* ignore the mode/custom_mode fields which are not meaningful.
*/
if (is_client_request && (state->mode || state->custom_mode.width || state->custom_mode.height || state->custom_mode.refresh))
{
if (state->mode)
{
wlr_log(WLR_DEBUG, "testing requested mode %dx%d@%d",
state->mode->width, state->mode->height,
state->mode->refresh);
}
else
{
wlr_log(WLR_DEBUG, "testing custom mode %dx%d@%d",
state->custom_mode.width,
state->custom_mode.height,
state->custom_mode.refresh);
}
return wlr_output_test_state(wlr_output, state);
}
struct wlr_output_mode *preferred_mode =
wlr_output_preferred_mode(wlr_output);
if (preferred_mode)
{
wlr_log(WLR_DEBUG, "testing preferred mode %dx%d@%d",
preferred_mode->width, preferred_mode->height,
preferred_mode->refresh);
wlr_output_state_set_mode(state, preferred_mode);
if (wlr_output_test_state(wlr_output, state))
{
return true;
}
}
/*
* Sometimes the preferred mode is not available due to hardware
* constraints (e.g. GPU or cable bandwidth limitations). In these
* cases it's better to fallback to lower modes than to end up with
* a black screen. See sway@4cdc4ac6
*/
struct wlr_output_mode *mode;
wl_list_for_each(mode, &wlr_output->modes, link)
{
if (mode == preferred_mode)
{
continue;
}
wlr_log(WLR_DEBUG, "testing fallback mode %dx%d@%d",
mode->width, mode->height, mode->refresh);
wlr_output_state_set_mode(state, mode);
if (wlr_output_test_state(wlr_output, state))
{
return true;
}
}
/* Reset mode if none worked (we may still try to commit) */
wlr_output_state_set_mode(state, NULL);
return false;
}
static void add_output_to_layout(struct diyac_server *server, struct diyac_output *output)
{
struct wlr_output *wlr_output = output->wlr_output;
struct wlr_output_layout_output *layout_output =
wlr_output_layout_add_auto(server->output_layout, wlr_output);
if (!layout_output)
{
wlr_log(WLR_ERROR, "unable to add output to layout");
return;
}
if (!output->scene_output)
{
output->scene_output =
wlr_scene_output_create(server->scene, wlr_output);
if (!output->scene_output)
{
wlr_log(WLR_ERROR, "unable to create scene output");
return;
}
/*
* Note: wlr_scene_output_layout_add_output() is not
* safe to call twice, so we call it only when initially
* creating the scene_output.
*/
wlr_scene_output_layout_add_output(server->scene_layout,
layout_output, output->scene_output);
}
/* Create lock surface if needed */
if (server->lock)
{
diyac_session_lock_output(output);
}
}
static void diyac_server_new_output(struct wl_listener *listener, void *data)
{ {
/* This event is raised by the backend when a new output (aka a display or /* This event is raised by the backend when a new output (aka a display or
* monitor) becomes available. */ * monitor) becomes available. */
@@ -87,26 +355,6 @@ void diyac_server_new_output(struct wl_listener *listener, void *data)
* and our renderer. Must be done once, before commiting the output */ * and our renderer. Must be done once, before commiting the output */
wlr_output_init_render(wlr_output, server->allocator, server->renderer); wlr_output_init_render(wlr_output, server->allocator, server->renderer);
/* The output may be disabled, switch it on. */
struct wlr_output_state state;
wlr_output_state_init(&state);
wlr_output_state_set_enabled(&state, true);
/* Some backends don't have modes. DRM+KMS does, and we need to set a mode
* before we can use the output. The mode is a tuple of (width, height,
* refresh rate), and each monitor supports only a specific set of modes. We
* just pick the monitor's preferred mode, a more sophisticated compositor
* would let the user configure it. */
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
if (mode != NULL)
{
wlr_output_state_set_mode(&state, mode);
}
/* Atomically applies the new output state. */
wlr_output_commit_state(wlr_output, &state);
wlr_output_state_finish(&state);
/* Allocates and configures our state for this output */ /* Allocates and configures our state for this output */
struct diyac_output *output = calloc(1, sizeof(*output)); struct diyac_output *output = calloc(1, sizeof(*output));
output->wlr_output = wlr_output; output->wlr_output = wlr_output;
@@ -116,6 +364,9 @@ void diyac_server_new_output(struct wl_listener *listener, void *data)
output->usable_area.y = 0; output->usable_area.y = 0;
output->usable_area.width = wlr_output->width; output->usable_area.width = wlr_output->width;
output->usable_area.height = wlr_output->height; output->usable_area.height = wlr_output->height;
output_state_init(output);
/* Sets up a listener for the frame event. */ /* Sets up a listener for the frame event. */
output->frame.notify = output_frame; output->frame.notify = output_frame;
wl_signal_add(&wlr_output->events.frame, &output->frame); wl_signal_add(&wlr_output->events.frame, &output->frame);
@@ -154,10 +405,6 @@ void diyac_server_new_output(struct wl_listener *listener, void *data)
output->layer_tree[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY] = output->scenes.overlay; output->layer_tree[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY] = output->scenes.overlay;
output->lock_handle = NULL; output->lock_handle = NULL;
if(server->lock)
{
diyac_session_lock_output(output);
}
/* /*
* Set the z-positions to achieve the following order (from top to * Set the z-positions to achieve the following order (from top to
* bottom): * bottom):
@@ -176,28 +423,25 @@ void diyac_server_new_output(struct wl_listener *listener, void *data)
wlr_scene_node_raise_to_top(&output->scenes.popup->node); wlr_scene_node_raise_to_top(&output->scenes.popup->node);
wlr_scene_node_raise_to_top(&output->scenes.session->node); wlr_scene_node_raise_to_top(&output->scenes.session->node);
/* Adds this to the output layout. The add_auto function arranges outputs wlr_output_state_set_enabled(&output->pending_state, true);
* from left-to-right in the order they appear. A more sophisticated
* compositor would let the user configure the arrangement of outputs in the if (!output_test_auto(wlr_output, &output->pending_state,
* layout. /* is_client_request */ false))
* {
* The output layout utility automatically adds a wl_output global to the wlr_log(WLR_INFO, "mode test failed for output %s",
* display, which Wayland clients can see to find out information about the wlr_output->name);
* output (such as DPI, scale factor, manufacturer, etc). /*
* Continue anyway. For some reason, the test fails when
* running nested, yet the following commit succeeds.
*/ */
struct wlr_output_layout_output *l_output = wlr_output_layout_add_auto(server->output_layout, }
wlr_output); output_state_commit(output);
struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output); wlr_output_effective_resolution(wlr_output,
wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output); &output->usable_area.width, &output->usable_area.height);
} g_pending_output_layout_change++;
add_output_to_layout(server, output);
/* returns true if usable area changed */ g_pending_output_layout_change--;
static bool update_usable_area(struct diyac_output *output) do_output_layout_change(server);
{
struct wlr_box old = output->usable_area;
diyac_layers_arrange(output);
return !wlr_box_equal(&old, &output->usable_area);
} }
void diyac_output_update_usable_area(struct diyac_output *output) void diyac_output_update_usable_area(struct diyac_output *output)
@@ -223,9 +467,9 @@ struct diyac_output *diyac_output_from_cursor(struct diyac_server *server)
return output->data; return output->data;
} }
void diyac_output_usable_area(struct diyac_output *output,struct wlr_box* area) void diyac_output_usable_area(struct diyac_output *output, struct wlr_box *area)
{ {
if(!area | !output) if (!area | !output)
{ {
return; return;
} }
@@ -235,12 +479,12 @@ void diyac_output_usable_area(struct diyac_output *output,struct wlr_box* area)
output->wlr_output, &ox, &oy); output->wlr_output, &ox, &oy);
box.x -= ox; box.x -= ox;
box.y -= oy; box.y -= oy;
memcpy(area,&box,sizeof(box)); memcpy(area, &box, sizeof(box));
} }
void diyac_output_full_area(struct diyac_output *output,struct wlr_box* area) void diyac_output_full_area(struct diyac_output *output, struct wlr_box *area)
{ {
if(!area | !output) if (!area | !output)
{ {
return; return;
} }
@@ -252,5 +496,307 @@ void diyac_output_full_area(struct diyac_output *output,struct wlr_box* area)
output->wlr_output, &ox, &oy); output->wlr_output, &ox, &oy);
box.x -= ox; box.x -= ox;
box.y -= oy; box.y -= oy;
memcpy(area,&box,sizeof(box)); memcpy(area, &box, sizeof(box));
}
static void diyac_output_power_manager_set_mode(struct wl_listener *listener, void *data)
{
struct diyac_server *server = wl_container_of(listener, server,
output_power_manager_set_mode);
struct wlr_output_power_v1_set_mode_event *event = data;
struct diyac_output *output = event->output->data;
assert(output);
switch (event->mode)
{
case ZWLR_OUTPUT_POWER_V1_MODE_OFF:
if (!event->output->enabled)
{
return;
}
wlr_output_state_set_enabled(&output->pending_state, false);
output_state_commit(output);
break;
case ZWLR_OUTPUT_POWER_V1_MODE_ON:
if (event->output->enabled)
{
return;
}
wlr_output_state_set_enabled(&output->pending_state, true);
output_state_commit(output);
/*
* Re-set the cursor image so that the cursor
* isn't invisible on the newly enabled output.
*/
// cursor_update_image(&server->seat);
break;
}
}
static void handle_output_layout_change(struct wl_listener *listener, void *data)
{
(void)data;
struct diyac_server *server =
wl_container_of(listener, server, output_layout_change);
do_output_layout_change(server);
}
static bool verify_output_config_v1(const struct wlr_output_configuration_v1 *config)
{
const char *err_msg = NULL;
struct wlr_output_configuration_head_v1 *head;
wl_list_for_each(head, &config->heads, link)
{
if (!head->state.enabled)
{
continue;
}
/* Handle custom modes */
if (!head->state.mode)
{
int32_t refresh = head->state.custom_mode.refresh;
if (wlr_output_is_wl(head->state.output) && refresh != 0)
{
/* Wayland backend does not support refresh rates */
err_msg = "Wayland backend refresh rates unsupported";
goto custom_mode_failed;
}
}
if (wlr_output_is_wl(head->state.output) && !head->state.adaptive_sync_enabled)
{
err_msg = "Wayland backend requires adaptive sync";
goto custom_mode_failed;
}
/*
* Ensure the new output state can be applied on
* its own and inform the client when it can not.
*
* Applying the changes may still fail later when
* getting mixed with wlr_output->pending which
* may contain further unrelated changes.
*/
struct wlr_output_state output_state;
wlr_output_state_init(&output_state);
wlr_output_head_v1_state_apply(&head->state, &output_state);
if (!output_test_auto(head->state.output, &output_state,
/* is_client_request */ true))
{
wlr_output_state_finish(&output_state);
return false;
}
wlr_output_state_finish(&output_state);
}
return true;
custom_mode_failed:
assert(err_msg);
wlr_log(WLR_INFO, "%s (%s: %dx%d@%d)",
err_msg,
head->state.output->name,
head->state.custom_mode.width,
head->state.custom_mode.height,
head->state.custom_mode.refresh);
return false;
}
void diyac_output_enable_adaptive_sync(struct diyac_output *output, bool enabled)
{
wlr_output_state_set_adaptive_sync_enabled(&output->pending_state, enabled);
if (!wlr_output_test_state(output->wlr_output, &output->pending_state))
{
wlr_output_state_set_adaptive_sync_enabled(&output->pending_state, false);
wlr_log(WLR_DEBUG,
"failed to enable adaptive sync for output %s",
output->wlr_output->name);
}
else
{
wlr_log(WLR_INFO, "adaptive sync %sabled for output %s",
enabled ? "en" : "dis", output->wlr_output->name);
}
}
static bool output_config_apply(struct diyac_server *server, struct wlr_output_configuration_v1 *config)
{
bool success = true;
g_pending_output_layout_change++;
struct wlr_output_configuration_head_v1 *head;
wl_list_for_each(head, &config->heads, link)
{
struct wlr_output *o = head->state.output;
struct diyac_output *output = o->data;
struct wlr_output_state *os = &output->pending_state;
bool output_enabled = head->state.enabled;
wlr_output_state_set_enabled(os, output_enabled);
if (output_enabled)
{
/* Output specific actions only */
if (head->state.mode)
{
wlr_output_state_set_mode(os, head->state.mode);
}
else
{
wlr_output_state_set_custom_mode(os,
head->state.custom_mode.width,
head->state.custom_mode.height,
head->state.custom_mode.refresh);
}
/*
* Try to ensure a valid mode. Ignore failures
* here and just check the commit below.
*/
(void)output_test_auto(o, os,
/* is_client_request */ true);
wlr_output_state_set_scale(os, head->state.scale);
wlr_output_state_set_transform(os, head->state.transform);
diyac_output_enable_adaptive_sync(output,
head->state.adaptive_sync_enabled);
}
if (!output_state_commit(output))
{
/*
* FIXME: This is only part of the story, we should revert
* all previously committed outputs as well here.
*
* See https://github.com/labwc/labwc/pull/1528
*/
wlr_log(WLR_INFO, "Output config commit failed: %s", o->name);
success = false;
break;
}
/*
* Add or remove output from layout only if the commit went
* through. Note that at startup, the output may have already
* been enabled but not yet been added to the layout.
*/
bool was_in_layout =
!!wlr_output_layout_get(server->output_layout, o);
if (output_enabled)
{
if (!was_in_layout)
{
add_output_to_layout(server, output);
}
struct wlr_box pos = {0};
wlr_output_layout_get_box(server->output_layout, o, &pos);
if (pos.x != head->state.x || pos.y != head->state.y)
{
/*
* This overrides the automatic layout
*
* wlr_output_layout_add() in fact means _move()
*/
wlr_output_layout_add(server->output_layout, o,
head->state.x, head->state.y);
}
}
else if (was_in_layout)
{
/*
* At time of writing, wlr_output_layout_remove()
* indirectly destroys the wlr_scene_output, but
* this behavior may change in future. To remove
* doubt and avoid either a leak or double-free,
* explicitly destroy the wlr_scene_output before
* calling wlr_output_layout_remove().
*/
wlr_scene_output_destroy(output->scene_output);
wlr_output_layout_remove(server->output_layout, o);
output->scene_output = NULL;
}
}
g_pending_output_layout_change--;
do_output_layout_change(server);
return success;
}
static void handle_output_manager_apply(struct wl_listener *listener, void *data)
{
struct diyac_server *server =
wl_container_of(listener, server, output_manager_apply);
struct wlr_output_configuration_v1 *config = data;
bool config_is_good = verify_output_config_v1(config);
if (config_is_good && output_config_apply(server, config))
{
wlr_output_configuration_v1_send_succeeded(config);
}
else
{
wlr_output_configuration_v1_send_failed(config);
}
wlr_output_configuration_v1_destroy(config);
/*
struct output *output;
wl_list_for_each(output, &server->outputs, link)
{
wlr_xcursor_manager_load(server->seat.xcursor_manager,
output->wlr_output->scale);
}
cursor_update_focus(server);
cursor_update_image(&server->seat);
*/
}
static void handle_output_manager_test(struct wl_listener *listener, void *data)
{
(void) listener;
struct wlr_output_configuration_v1 *config = data;
if (verify_output_config_v1(config))
{
wlr_output_configuration_v1_send_succeeded(config);
}
else
{
wlr_output_configuration_v1_send_failed(config);
}
wlr_output_configuration_v1_destroy(config);
}
void diyac_output_init(struct diyac_server *server)
{
/* Creates an output layout, which a wlroots utility for working with an
* arrangement of screens in a physical layout. */
server->output_layout = wlr_output_layout_create(server->wl_display);
/* Configure a listener to be notified when new outputs are available on the
* backend. */
wl_list_init(&server->outputs);
server->new_output.notify = diyac_server_new_output;
wl_signal_add(&server->backend->events.new_output, &server->new_output);
server->scene_layout = wlr_scene_attach_output_layout(server->scene, server->output_layout);
wlr_xdg_output_manager_v1_create(server->wl_display, server->output_layout);
server->output_layout_change.notify = handle_output_layout_change;
wl_signal_add(&server->output_layout->events.change,
&server->output_layout_change);
server->output_manager = wlr_output_manager_v1_create(server->wl_display);
server->output_manager_apply.notify = handle_output_manager_apply;
wl_signal_add(&server->output_manager->events.apply,
&server->output_manager_apply);
server->output_manager_test.notify = handle_output_manager_test;
wl_signal_add(&server->output_manager->events.test,
&server->output_manager_test);
server->output_power_manager =
wlr_output_power_manager_v1_create(server->wl_display);
server->output_power_manager_set_mode.notify =
diyac_output_power_manager_set_mode;
wl_signal_add(&server->output_power_manager->events.set_mode,
&server->output_power_manager_set_mode);
} }

View File

@@ -2,9 +2,10 @@
#define DIYAC_OUTPUT_H #define DIYAC_OUTPUT_H
#include "diyac.h" #include "diyac.h"
void diyac_server_new_output(struct wl_listener *listener, void *data);
void diyac_output_update_usable_area(struct diyac_output *output); void diyac_output_update_usable_area(struct diyac_output *output);
struct diyac_output *diyac_output_from_cursor(struct diyac_server *server); struct diyac_output *diyac_output_from_cursor(struct diyac_server *server);
void diyac_output_usable_area(struct diyac_output * output,struct wlr_box* box); void diyac_output_usable_area(struct diyac_output * output,struct wlr_box* box);
void diyac_output_full_area(struct diyac_output *output,struct wlr_box* area); void diyac_output_full_area(struct diyac_output *output,struct wlr_box* area);
void diyac_output_init(struct diyac_server * server);
void diyac_output_enable_adaptive_sync(struct diyac_output *output, bool enabled);
#endif #endif

View File

@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_output_power_management_unstable_v1">
<copyright>
Copyright © 2019 Purism SPC
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
</copyright>
<description summary="Control power management modes of outputs">
This protocol allows clients to control power management modes
of outputs that are currently part of the compositor space. The
intent is to allow special clients like desktop shells to power
down outputs when the system is idle.
To modify outputs not currently part of the compositor space see
wlr-output-management.
Warning! The protocol described in this file is experimental and
backward incompatible changes may be made. Backward compatible changes
may be added together with the corresponding interface version bump.
Backward incompatible changes are done by bumping the version number in
the protocol and interface names and resetting the interface version.
Once the protocol is to be declared stable, the 'z' prefix and the
version number in the protocol and interface names are removed and the
interface version number is reset.
</description>
<interface name="zwlr_output_power_manager_v1" version="1">
<description summary="manager to create per-output power management">
This interface is a manager that allows creating per-output power
management mode controls.
</description>
<request name="get_output_power">
<description summary="get a power management for an output">
Create an output power management mode control that can be used to
adjust the power management mode for a given output.
</description>
<arg name="id" type="new_id" interface="zwlr_output_power_v1"/>
<arg name="output" type="object" interface="wl_output"/>
</request>
<request name="destroy" type="destructor">
<description summary="destroy the manager">
All objects created by the manager will still remain valid, until their
appropriate destroy request has been called.
</description>
</request>
</interface>
<interface name="zwlr_output_power_v1" version="1">
<description summary="adjust power management mode for an output">
This object offers requests to set the power management mode of
an output.
</description>
<enum name="mode">
<entry name="off" value="0"
summary="Output is turned off."/>
<entry name="on" value="1"
summary="Output is turned on, no power saving"/>
</enum>
<enum name="error">
<entry name="invalid_mode" value="1" summary="nonexistent power save mode"/>
</enum>
<request name="set_mode">
<description summary="Set an outputs power save mode">
Set an output's power save mode to the given mode. The mode change
is effective immediately. If the output does not support the given
mode a failed event is sent.
</description>
<arg name="mode" type="uint" enum="mode" summary="the power save mode to set"/>
</request>
<event name="mode">
<description summary="Report a power management mode change">
Report the power management mode change of an output.
The mode event is sent after an output changed its power
management mode. The reason can be a client using set_mode or the
compositor deciding to change an output's mode.
This event is also sent immediately when the object is created
so the client is informed about the current power management mode.
</description>
<arg name="mode" type="uint" enum="mode"
summary="the output's new power management mode"/>
</event>
<event name="failed">
<description summary="object no longer valid">
This event indicates that the output power management mode control
is no longer valid. This can happen for a number of reasons,
including:
- The output doesn't support power management
- Another client already has exclusive power management mode control
for this output
- The output disappeared
Upon receiving this event, the client should destroy this object.
</description>
</event>
<request name="destroy" type="destructor">
<description summary="destroy this power management">
Destroys the output power management mode control object.
</description>
</request>
</interface>
</protocol>

356
seat.c
View File

@@ -4,32 +4,54 @@
#include <stdlib.h> #include <stdlib.h>
#include <wlr/util/log.h> #include <wlr/util/log.h>
#include <assert.h> #include <assert.h>
#include <strings.h>
#include <wlr/types/wlr_touch.h>
#include "seat.h" #include "seat.h"
#include "view.h" #include "view.h"
#include "output.h" #include "output.h"
#include "idle.h"
static void configure_keyboard(struct diyac_seat* seat, struct diyac_input* input, bool force) static struct wlr_output *output_by_name(struct diyac_server *server, const char *name)
{ {
assert(name);
struct diyac_output *output;
wl_list_for_each(output, &server->outputs, link)
{
if (!strcasecmp(output->wlr_output->name, name))
{
return output->wlr_output;
}
}
return NULL;
}
static void configure_keyboard(struct diyac_seat *seat, struct diyac_input *input, bool force)
{
(void)seat;
struct wlr_input_device *device = input->device; struct wlr_input_device *device = input->device;
assert(device->type == WLR_INPUT_DEVICE_KEYBOARD); assert(device->type == WLR_INPUT_DEVICE_KEYBOARD);
struct diyac_keyboard *keyboard = (struct diyac_keyboard *)input; struct diyac_keyboard *keyboard = (struct diyac_keyboard *)input;
struct wlr_keyboard *kb = wlr_keyboard_from_input_device(device); struct wlr_keyboard *kb = wlr_keyboard_from_input_device(device);
if(!keyboard->is_virtual || force) if (!keyboard->is_virtual || force)
{ {
/* /*
* Set layout based on environment variables XKB_DEFAULT_LAYOUT, * Set layout based on environment variables XKB_DEFAULT_LAYOUT,
* XKB_DEFAULT_OPTIONS, and friends. * XKB_DEFAULT_OPTIONS, and friends.
*/ */
struct xkb_rule_names rules = { 0 }; struct xkb_rule_names rules = {0};
struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules,XKB_KEYMAP_COMPILE_NO_FLAGS); struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (keymap) { if (keymap)
if (!wlr_keyboard_keymaps_match(kb->keymap, keymap)) { {
if (!wlr_keyboard_keymaps_match(kb->keymap, keymap))
{
wlr_keyboard_set_keymap(kb, keymap); wlr_keyboard_set_keymap(kb, keymap);
} }
xkb_keymap_unref(keymap); xkb_keymap_unref(keymap);
} else { }
else
{
wlr_log(WLR_ERROR, "Failed to create xkb keymap"); wlr_log(WLR_ERROR, "Failed to create xkb keymap");
} }
xkb_context_unref(context); xkb_context_unref(context);
@@ -37,10 +59,10 @@ static void configure_keyboard(struct diyac_seat* seat, struct diyac_input* inpu
wlr_keyboard_set_repeat_info(kb, 25, 600); wlr_keyboard_set_repeat_info(kb, 25, 600);
} }
static void keyboard_handle_modifiers( static void keyboard_handle_modifiers(
struct wl_listener *listener, void *data) struct wl_listener *listener, void *data)
{ {
(void)data;
/* This event is raised when a modifier key, such as shift or alt, is /* This event is raised when a modifier key, such as shift or alt, is
* pressed. We simply communicate this to the client. */ * pressed. We simply communicate this to the client. */
struct diyac_keyboard *keyboard = struct diyac_keyboard *keyboard =
@@ -95,7 +117,7 @@ static void keyboard_handle_key(
wl_container_of(listener, keyboard, key); wl_container_of(listener, keyboard, key);
struct wlr_keyboard_key_event *event = data; struct wlr_keyboard_key_event *event = data;
struct wlr_seat *seat = keyboard->input.seat->wlr_seat; struct wlr_seat *seat = keyboard->input.seat->wlr_seat;
diyac_idle_manager_notify_activity(keyboard->input.seat);
/* Translate libinput keycode -> xkbcommon */ /* Translate libinput keycode -> xkbcommon */
// wlr_log(WLR_INFO, "receive keycode %d", event->keycode); // wlr_log(WLR_INFO, "receive keycode %d", event->keycode);
uint32_t keycode = event->keycode + 8; uint32_t keycode = event->keycode + 8;
@@ -113,7 +135,7 @@ static void keyboard_handle_key(
* process it as a compositor keybinding. */ * process it as a compositor keybinding. */
for (int i = 0; i < nsyms; i++) for (int i = 0; i < nsyms; i++)
{ {
handled = handle_keybinding(keyboard->input.seat->server, syms[i]); handled |= handle_keybinding(keyboard->input.seat->server, syms[i]);
} }
} }
@@ -128,6 +150,7 @@ static void keyboard_handle_key(
static void input_handle_destroy(struct wl_listener *listener, void *data) static void input_handle_destroy(struct wl_listener *listener, void *data)
{ {
(void)data;
/* This event is raised by the keyboard base wlr_input_device to signal /* This event is raised by the keyboard base wlr_input_device to signal
* the destruction of the wlr_keyboard. It will no longer receive events * the destruction of the wlr_keyboard. It will no longer receive events
* and should be destroyed. * and should be destroyed.
@@ -136,10 +159,10 @@ static void input_handle_destroy(struct wl_listener *listener, void *data)
wl_list_remove(&input->link); wl_list_remove(&input->link);
wl_list_remove(&input->destroy.link); wl_list_remove(&input->destroy.link);
if(input->device->type == WLR_INPUT_DEVICE_KEYBOARD) if (input->device->type == WLR_INPUT_DEVICE_KEYBOARD)
{ {
struct diyac_keyboard* keyboard = (struct diyac_keyboard*) input; struct diyac_keyboard *keyboard = (struct diyac_keyboard *)input;
if(keyboard->is_virtual) if (keyboard->is_virtual)
{ {
wlr_log(WLR_INFO, "Virtual keyboard destroyed"); wlr_log(WLR_INFO, "Virtual keyboard destroyed");
} }
@@ -149,7 +172,7 @@ static void input_handle_destroy(struct wl_listener *listener, void *data)
free(input); free(input);
} }
static struct diyac_input* server_new_keyboard(struct diyac_seat *seat, static struct diyac_input *server_new_keyboard(struct diyac_seat *seat,
struct wlr_input_device *device, bool is_virtual) struct wlr_input_device *device, bool is_virtual)
{ {
struct wlr_keyboard *wlr_keyboard = wlr_keyboard_from_input_device(device); struct wlr_keyboard *wlr_keyboard = wlr_keyboard_from_input_device(device);
@@ -164,7 +187,7 @@ static struct diyac_input* server_new_keyboard(struct diyac_seat *seat,
* Force configure default keyboard keymap for all new * Force configure default keyboard keymap for all new
* keyboard, including virtual keyboard * keyboard, including virtual keyboard
*/ */
configure_keyboard(seat,&keyboard->input, true); configure_keyboard(seat, &keyboard->input, true);
/* Here we set up listeners for keyboard events. */ /* Here we set up listeners for keyboard events. */
keyboard->modifiers.notify = keyboard_handle_modifiers; keyboard->modifiers.notify = keyboard_handle_modifiers;
@@ -176,24 +199,191 @@ static struct diyac_input* server_new_keyboard(struct diyac_seat *seat,
wlr_seat_set_keyboard(seat->wlr_seat, keyboard->wlr_keyboard); wlr_seat_set_keyboard(seat->wlr_seat, keyboard->wlr_keyboard);
/* And add the keyboard to our list of keyboards */ /* And add the keyboard to our list of keyboards */
//wl_list_insert(&server->seat.keyboards, &keyboard->link); // wl_list_insert(&server->seat.keyboards, &keyboard->link);
return (struct diyac_input*) keyboard; return (struct diyac_input *)keyboard;
} }
/*
static void configure_libinput(struct wlr_input_device *wlr_input_device)
{
if (!wlr_input_device) {
wlr_log(WLR_ERROR, "no wlr_input_device");
return;
}
struct input *input = wlr_input_device->data;
static struct diyac_input* server_new_pointer(struct diyac_seat *seat, if (!wlr_input_device_is_libinput(wlr_input_device)) {
struct wlr_input_device *device) input->scroll_factor = 1.0;
return;
}
struct libinput_device *libinput_dev =
wlr_libinput_get_device_handle(wlr_input_device);
if (!libinput_dev) {
wlr_log(WLR_ERROR, "no libinput_dev");
return;
}
struct libinput_category *dc = get_category(wlr_input_device);
assert(dc);
if (libinput_device_config_tap_get_finger_count(libinput_dev) <= 0) {
wlr_log(WLR_INFO, "tap unavailable");
} else {
wlr_log(WLR_INFO, "tap configured");
libinput_device_config_tap_set_enabled(libinput_dev, dc->tap);
libinput_device_config_tap_set_button_map(libinput_dev,
dc->tap_button_map);
}
if (libinput_device_config_tap_get_finger_count(libinput_dev) <= 0
|| dc->tap_and_drag < 0) {
wlr_log(WLR_INFO, "tap-and-drag not configured");
} else {
wlr_log(WLR_INFO, "tap-and-drag configured");
libinput_device_config_tap_set_drag_enabled(
libinput_dev, dc->tap_and_drag);
}
if (libinput_device_config_tap_get_finger_count(libinput_dev) <= 0
|| dc->drag_lock < 0) {
wlr_log(WLR_INFO, "drag lock not configured");
} else {
wlr_log(WLR_INFO, "drag lock configured");
libinput_device_config_tap_set_drag_lock_enabled(
libinput_dev, dc->drag_lock);
}
if (libinput_device_config_scroll_has_natural_scroll(libinput_dev) <= 0
|| dc->natural_scroll < 0) {
wlr_log(WLR_INFO, "natural scroll not configured");
} else {
wlr_log(WLR_INFO, "natural scroll configured");
libinput_device_config_scroll_set_natural_scroll_enabled(
libinput_dev, dc->natural_scroll);
}
if (libinput_device_config_left_handed_is_available(libinput_dev) <= 0
|| dc->left_handed < 0) {
wlr_log(WLR_INFO, "left-handed mode not configured");
} else {
wlr_log(WLR_INFO, "left-handed mode configured");
libinput_device_config_left_handed_set(libinput_dev,
dc->left_handed);
}
if (libinput_device_config_accel_is_available(libinput_dev) == 0) {
wlr_log(WLR_INFO, "pointer acceleration unavailable");
} else {
wlr_log(WLR_INFO, "pointer acceleration configured");
if (dc->pointer_speed >= -1) {
libinput_device_config_accel_set_speed(libinput_dev,
dc->pointer_speed);
}
if (dc->accel_profile > 0) {
libinput_device_config_accel_set_profile(libinput_dev,
dc->accel_profile);
}
}
if (libinput_device_config_middle_emulation_is_available(libinput_dev)
== 0 || dc->middle_emu < 0) {
wlr_log(WLR_INFO, "middle emulation not configured");
} else {
wlr_log(WLR_INFO, "middle emulation configured");
libinput_device_config_middle_emulation_set_enabled(
libinput_dev, dc->middle_emu);
}
if (libinput_device_config_dwt_is_available(libinput_dev) == 0
|| dc->dwt < 0) {
wlr_log(WLR_INFO, "dwt not configured");
} else {
wlr_log(WLR_INFO, "dwt configured");
libinput_device_config_dwt_set_enabled(libinput_dev, dc->dwt);
}
if ((dc->click_method != LIBINPUT_CONFIG_CLICK_METHOD_NONE
&& (libinput_device_config_click_get_methods(libinput_dev)
& dc->click_method) == 0)
|| dc->click_method < 0) {
wlr_log(WLR_INFO, "click method not configured");
} else {
wlr_log(WLR_INFO, "click method configured");
libinput_device_config_click_set_method(libinput_dev, dc->click_method);
}
if ((dc->send_events_mode != LIBINPUT_CONFIG_SEND_EVENTS_ENABLED
&& (libinput_device_config_send_events_get_modes(libinput_dev)
& dc->send_events_mode) == 0)
|| dc->send_events_mode < 0) {
wlr_log(WLR_INFO, "send events mode not configured");
} else {
wlr_log(WLR_INFO, "send events mode configured");
libinput_device_config_send_events_set_mode(libinput_dev, dc->send_events_mode);
}
if (libinput_device_config_calibration_has_matrix(libinput_dev) == 0
|| !dc->have_calibration_matrix) {
wlr_log(WLR_INFO, "calibration matrix not configured");
} else {
wlr_log(WLR_INFO, "calibration matrix configured");
libinput_device_config_calibration_set_matrix(libinput_dev, dc->calibration_matrix);
}
wlr_log(WLR_INFO, "scroll factor configured");
input->scroll_factor = dc->scroll_factor;
}
*/
static struct diyac_input *server_new_pointer(struct diyac_seat *seat, struct wlr_input_device *device)
{ {
struct diyac_input *input = calloc(1, sizeof(*input)); struct diyac_input *input = calloc(1, sizeof(*input));
input->device = device; input->device = device;
/* We don't do anything special with pointers. All of our pointer handling device->data = input;
* is proxied through wlr_cursor. On another compositor, you might take this /**
* opportunity to do libinput configuration on the device to set * @TODO:
* acceleration, etc. */ * configure pointer via libinput
*
*/
wlr_cursor_attach_input_device(seat->cursor, device); wlr_cursor_attach_input_device(seat->cursor, device);
struct wlr_pointer *pointer = wlr_pointer_from_input_device(device);
wlr_log(WLR_INFO, "map pointer to output %s", pointer->output_name);
struct wlr_output *output = NULL;
if (pointer->output_name)
{
output = output_by_name(seat->server, pointer->output_name);
}
wlr_cursor_map_input_to_output(seat->cursor, device, output);
wlr_cursor_map_input_to_region(seat->cursor, device, NULL);
return input; return input;
} }
static void seat_add_input(struct diyac_seat* seat, struct diyac_input* input) static struct diyac_input *server_new_touch(struct diyac_seat *seat, struct wlr_input_device *device)
{
struct diyac_input *input = calloc(1, sizeof(*input));
input->device = device;
device->data = input;
/**
* @TODO:
* configure touch device via libinput
*
*/
wlr_cursor_attach_input_device(seat->cursor, device);
struct wlr_touch *touch = wlr_touch_from_input_device(device);
wlr_log(WLR_INFO, "map touch to output %s", touch->output_name);
struct wlr_output *output = NULL;
if (touch->output_name)
{
output = output_by_name(seat->server, touch->output_name);
}
wlr_cursor_map_input_to_output(seat->cursor, device, output);
wlr_cursor_map_input_to_region(seat->cursor, device, NULL);
return input;
}
static void seat_add_input(struct diyac_seat *seat, struct diyac_input *input)
{ {
input->seat = seat; input->seat = seat;
input->destroy.notify = input_handle_destroy; input->destroy.notify = input_handle_destroy;
@@ -206,8 +396,10 @@ static void seat_add_input(struct diyac_seat* seat, struct diyac_input* input)
* there are no pointer devices, so we always include that capability. */ * there are no pointer devices, so we always include that capability. */
uint32_t caps = 0; uint32_t caps = 0;
wl_list_for_each(input, &seat->inputs, link) { wl_list_for_each(input, &seat->inputs, link)
switch (input->device->type) { {
switch (input->device->type)
{
case WLR_INPUT_DEVICE_KEYBOARD: case WLR_INPUT_DEVICE_KEYBOARD:
caps |= WL_SEAT_CAPABILITY_KEYBOARD; caps |= WL_SEAT_CAPABILITY_KEYBOARD;
break; break;
@@ -231,7 +423,7 @@ static void server_new_input(struct wl_listener *listener, void *data)
struct diyac_seat *seat = struct diyac_seat *seat =
wl_container_of(listener, seat, new_input); wl_container_of(listener, seat, new_input);
struct wlr_input_device *device = data; struct wlr_input_device *device = data;
struct diyac_input* input = NULL; struct diyac_input *input = NULL;
switch (device->type) switch (device->type)
{ {
@@ -241,34 +433,15 @@ static void server_new_input(struct wl_listener *listener, void *data)
case WLR_INPUT_DEVICE_POINTER: case WLR_INPUT_DEVICE_POINTER:
input = server_new_pointer(seat, device); input = server_new_pointer(seat, device);
break; break;
default: case WLR_INPUT_DEVICE_TOUCH:
input = server_new_touch(seat, device);
break; break;
default:
return; return;
} }
seat_add_input(seat, input); seat_add_input(seat, input);
} }
static void seat_request_cursor(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(
listener, seat, request_cursor);
/* This event is raised by the seat when a client provides a cursor image */
struct wlr_seat_pointer_request_set_cursor_event *event = data;
struct wlr_seat_client *focused_client =
seat->wlr_seat->pointer_state.focused_client;
/* This can be sent by any client, so we check to make sure this one is
* actually has pointer focus first. */
if (focused_client == event->seat_client)
{
/* Once we've vetted the client, we can tell the cursor to use the
* provided surface as the cursor image. It will set the hardware cursor
* on the output that it's currently on and continue to do so as the
* cursor moves between outputs. */
wlr_cursor_set_surface(seat->cursor, event->surface,
event->hotspot_x, event->hotspot_y);
}
}
static void seat_request_set_selection(struct wl_listener *listener, void *data) static void seat_request_set_selection(struct wl_listener *listener, void *data)
{ {
/* This event is raised by the seat when a client wants to set the selection, /* This event is raised by the seat when a client wants to set the selection,
@@ -281,15 +454,6 @@ static void seat_request_set_selection(struct wl_listener *listener, void *data)
wlr_seat_set_selection(seat->wlr_seat, event->source, event->serial); wlr_seat_set_selection(seat->wlr_seat, event->source, event->serial);
} }
static void request_set_selection_notify(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(
listener, seat, request_set_selection);
struct wlr_seat_request_set_selection_event *event = data;
wlr_seat_set_selection(seat->wlr_seat, event->source,
event->serial);
}
static void request_set_primary_selection_notify(struct wl_listener *listener, void *data) static void request_set_primary_selection_notify(struct wl_listener *listener, void *data)
{ {
struct diyac_seat *seat = wl_container_of( struct diyac_seat *seat = wl_container_of(
@@ -324,13 +488,11 @@ void diyac_init_seat(struct diyac_server *server)
server->seat.new_input.notify = server_new_input; server->seat.new_input.notify = server_new_input;
wl_signal_add(&server->backend->events.new_input, &server->seat.new_input); wl_signal_add(&server->backend->events.new_input, &server->seat.new_input);
server->seat.wlr_seat = wlr_seat_create(server->wl_display, "seat0"); server->seat.wlr_seat = wlr_seat_create(server->wl_display, "seat0");
server->seat.request_cursor.notify = seat_request_cursor;
wl_signal_add(&server->seat.wlr_seat->events.request_set_cursor, wl_list_init(&server->seat.touch_points);
&server->seat.request_cursor); wl_list_init(&server->seat.inputs);
server->seat.request_set_selection.notify = seat_request_set_selection; server->seat.request_set_selection.notify = seat_request_set_selection;
wl_signal_add(&server->seat.wlr_seat->events.request_set_selection,
&server->seat.request_set_selection);
server->seat.request_set_selection.notify = request_set_selection_notify;
wl_signal_add(&server->seat.wlr_seat->events.request_set_selection, wl_signal_add(&server->seat.wlr_seat->events.request_set_selection,
&server->seat.request_set_selection); &server->seat.request_set_selection);
@@ -346,6 +508,16 @@ void diyac_init_seat(struct diyac_server *server)
server->seat.virtual_keyboard_new.notify = new_virtual_keyboard; server->seat.virtual_keyboard_new.notify = new_virtual_keyboard;
} }
void diyac_release_seat(struct diyac_server* server)
{
wl_list_remove(&server->seat.request_set_selection.link);
wl_list_remove(&server->seat.request_set_primary_selection.link);
wl_list_remove(&server->seat.new_input.link);
wl_list_remove(&server->seat.virtual_keyboard_new.link);
wl_list_remove(&server->seat.inputs);
}
static void seat_focus(struct diyac_seat *seat, struct wlr_surface *surface, bool is_lock_surface) static void seat_focus(struct diyac_seat *seat, struct wlr_surface *surface, bool is_lock_surface)
{ {
/* /*
@@ -414,12 +586,12 @@ void diyac_seat_focus_layer(struct diyac_seat *seat, struct wlr_layer_surface_v1
return; return;
*/ */
} }
if(seat->focused_layer == layer) if (seat->focused_layer == layer)
{ {
return; return;
} }
if(seat->focused_layer) if (seat->focused_layer)
wlr_log(WLR_INFO,"Layer focus changed %s -> %s", seat->focused_layer->namespace, layer->namespace); wlr_log(WLR_INFO, "Layer focus changed %s -> %s", seat->focused_layer->namespace, layer->namespace);
// unfocus currently focus view // unfocus currently focus view
if (seat->server->active_view) if (seat->server->active_view)
@@ -436,20 +608,23 @@ void diyac_seat_focus_layer(struct diyac_seat *seat, struct wlr_layer_surface_v1
*/ */
} }
void diyac_seat_configure(struct diyac_server* server) void diyac_seat_configure(struct diyac_server *server)
{ {
struct diyac_seat* seat = &server->seat; struct diyac_seat *seat = &server->seat;
struct diyac_input* input = NULL; struct diyac_input *input = NULL;
wl_list_for_each(input, &seat->inputs, link) wl_list_for_each(input, &seat->inputs, link)
{ {
switch (input->device->type) { switch (input->device->type)
{
case WLR_INPUT_DEVICE_KEYBOARD: case WLR_INPUT_DEVICE_KEYBOARD:
configure_keyboard(seat, input, false); configure_keyboard(seat, input, false);
break; break;
case WLR_INPUT_DEVICE_POINTER: case WLR_INPUT_DEVICE_POINTER:
/*TODO: reconfigure libinput*/
break; break;
case WLR_INPUT_DEVICE_TOUCH: case WLR_INPUT_DEVICE_TOUCH:
/*TODO: reconfigure libinput*/
break; break;
default: default:
break; break;
@@ -457,27 +632,27 @@ void diyac_seat_configure(struct diyac_server* server)
} }
} }
void diyac_seat_focus_topmost(struct diyac_seat* seat, struct diyac_output* output) void diyac_seat_focus_topmost(struct diyac_seat *seat, struct diyac_output *output)
{ {
for(int i = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i >= ZWLR_LAYER_SHELL_V1_LAYER_TOP; i--) for (int i = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; i >= ZWLR_LAYER_SHELL_V1_LAYER_TOP; i--)
{ {
struct wlr_scene_tree *scene = output->layer_tree[i]; struct wlr_scene_tree *scene = output->layer_tree[i];
struct wl_list *node_list = & scene->children; struct wl_list *node_list = &scene->children;
struct wlr_scene_node *node; struct wlr_scene_node *node;
wl_list_for_each_reverse(node,node_list, link) wl_list_for_each_reverse(node, node_list, link)
{ {
struct diyac_node_descriptor *node_descriptor = node->data; struct diyac_node_descriptor *node_descriptor = node->data;
if (!node->enabled || !node_descriptor || node_descriptor->type != DIYAC_NODE_LAYER_SURFACE) if (!node->enabled || !node_descriptor || node_descriptor->type != DIYAC_NODE_LAYER_SURFACE)
{ {
continue; continue;
} }
struct diyac_layer_surface* surface = (struct diyac_layer_surface *)node_descriptor->data; struct diyac_layer_surface *surface = (struct diyac_layer_surface *)node_descriptor->data;
struct wlr_layer_surface_v1* layer_surface = surface->scene_layer_surface->layer_surface; struct wlr_layer_surface_v1 *layer_surface = surface->scene_layer_surface->layer_surface;
if(!surface->mapped || layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE) if (!surface->mapped || layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE)
{ {
continue; continue;
} }
wlr_log(WLR_INFO," Update focus on layer: %s", layer_surface->namespace); wlr_log(WLR_INFO, " Update focus on layer: %s", layer_surface->namespace);
diyac_seat_focus_layer(seat, layer_surface); diyac_seat_focus_layer(seat, layer_surface);
return; return;
} }
@@ -485,3 +660,26 @@ void diyac_seat_focus_topmost(struct diyac_seat* seat, struct diyac_output* outp
seat->focused_layer = NULL; seat->focused_layer = NULL;
diyac_focus_topmost_view(seat->server, true); diyac_focus_topmost_view(seat->server, true);
} }
void diyac_seat_pointer_end_grab(struct diyac_seat *seat, struct wlr_surface *surface)
{
if (!surface || !wlr_seat_pointer_has_grab(seat->wlr_seat))
{
return;
}
struct wlr_xdg_surface *xdg_surface =
wlr_xdg_surface_try_from_wlr_surface(surface);
if (!xdg_surface || xdg_surface->role != WLR_XDG_SURFACE_ROLE_POPUP)
{
/*
* If we have an active popup grab (an open popup) and we are
* not on the popup itself, end that grab to close the popup.
* Contrary to pointer button notifications, a tablet/touch
* button notification sometimes doesn't end grabs automatically
* on button notifications in another client (observed in GTK4),
* so end the grab manually.
*/
wlr_seat_pointer_end_grab(seat->wlr_seat);
}
}

4
seat.h
View File

@@ -7,6 +7,8 @@ void diyac_seat_focus_surface(struct diyac_seat *seat, struct wlr_surface *surfa
void diyac_seat_focus_lock_surface(struct diyac_seat *seat, struct wlr_surface *surface); void diyac_seat_focus_lock_surface(struct diyac_seat *seat, struct wlr_surface *surface);
void diyac_seat_focus_layer(struct diyac_seat *seat, struct wlr_layer_surface_v1 *layer); void diyac_seat_focus_layer(struct diyac_seat *seat, struct wlr_layer_surface_v1 *layer);
void diyac_seat_focus_topmost(struct diyac_seat* seat, struct diyac_output* output); void diyac_seat_focus_topmost(struct diyac_seat* seat, struct diyac_output* output);
void diyac_seat_pointer_end_grab(struct diyac_seat *seat, struct wlr_surface *surface);
void diyac_seat_configure(struct diyac_server* server); void diyac_seat_configure(struct diyac_server* server);
void diyac_release_seat(struct diyac_server* server);
#endif #endif

View File

@@ -39,6 +39,7 @@ static void session_lock_update_geometry(struct diyac_output *output, bool align
static void handle_surface_map(struct wl_listener *listener, void *data) static void handle_surface_map(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_output_lock_handle *handle = wl_container_of(listener, handle, surface_map); struct diyac_output_lock_handle *handle = wl_container_of(listener, handle, surface_map);
if (!g_server->lock->focused) if (!g_server->lock->focused)
{ {
@@ -49,6 +50,7 @@ static void handle_surface_map(struct wl_listener *listener, void *data)
static void handle_surface_destroy(struct wl_listener *listener, void *data) static void handle_surface_destroy(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_output_lock_handle *handle = wl_container_of(listener, handle, surface_destroy); struct diyac_output_lock_handle *handle = wl_container_of(listener, handle, surface_destroy);
if (g_server->lock->focused == handle->surface->surface) if (g_server->lock->focused == handle->surface->surface)
@@ -123,6 +125,7 @@ static void session_lock_destroy(struct diyac_session_lock *lock)
static void handle_unlock(struct wl_listener *listener, void *data) static void handle_unlock(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_session_lock *lock = wl_container_of(listener, lock, unlock); struct diyac_session_lock *lock = wl_container_of(listener, lock, unlock);
wlr_log(WLR_INFO, "handle_unlock: Lock session is unlocked"); wlr_log(WLR_INFO, "handle_unlock: Lock session is unlocked");
session_lock_destroy(lock); session_lock_destroy(lock);
@@ -131,6 +134,7 @@ static void handle_unlock(struct wl_listener *listener, void *data)
static void handle_session_lock_destroy(struct wl_listener *listener, void *data) static void handle_session_lock_destroy(struct wl_listener *listener, void *data)
{ {
(void) data;
struct diyac_session_lock *lock = wl_container_of(listener, lock, destroy); struct diyac_session_lock *lock = wl_container_of(listener, lock, destroy);
lock->abandoned = true; lock->abandoned = true;
wlr_log(WLR_INFO, "handle_session_lock_destroy: Lock session is destroyed without unlocking, session abandoned"); wlr_log(WLR_INFO, "handle_session_lock_destroy: Lock session is destroyed without unlocking, session abandoned");
@@ -141,6 +145,7 @@ static void handle_session_lock_destroy(struct wl_listener *listener, void *data
static void handle_new_session_lock(struct wl_listener *listener, void *data) static void handle_new_session_lock(struct wl_listener *listener, void *data)
{ {
(void) listener;
struct wlr_session_lock_v1 *lock = data; struct wlr_session_lock_v1 *lock = data;
if (g_server->lock) if (g_server->lock)
{ {
@@ -200,6 +205,8 @@ static void handle_commit(struct wl_listener *listener, void *data)
static void handle_lock_manager_destroy(struct wl_listener *listener, void *data) static void handle_lock_manager_destroy(struct wl_listener *listener, void *data)
{ {
(void) data;
(void) listener;
if (g_server->lock) if (g_server->lock)
{ {
session_lock_destroy(g_server->lock); session_lock_destroy(g_server->lock);
@@ -245,9 +252,9 @@ void diyac_session_lock_output(struct diyac_output *output)
handle->background = wlr_scene_rect_create(handle->tree, 0, 0, black); handle->background = wlr_scene_rect_create(handle->tree, 0, 0, black);
if (!handle->background) if (!handle->background)
{ {
wlr_scene_node_destroy(&handle->tree->node);
free(handle); free(handle);
wlr_log(WLR_ERROR, "diyac_session_lock_output:Unable to create lock background"); wlr_log(WLR_ERROR, "diyac_session_lock_output:Unable to create lock background");
wlr_scene_node_destroy(&handle->tree->node);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
handle->surface = NULL; handle->surface = NULL;

190
touch.c Normal file
View File

@@ -0,0 +1,190 @@
#include <wayland-util.h>
#include <wlr/types/wlr_touch.h>
#include <linux/input-event-codes.h>
#include <wlr/util/log.h>
#include <stdlib.h>
#include "touch.h"
#include "idle.h"
#include "node.h"
#include "seat.h"
#include "cursor.h"
struct touch_point
{
int32_t touch_id;
uint32_t x_offset;
uint32_t y_offset;
struct wlr_surface *surface;
struct wl_list link; /* seat.touch_points */
};
static void seat_touch_down(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, touch_down);
struct wlr_touch_down_event *event = data;
diyac_idle_manager_notify_activity(seat);
/* Compute layout => surface offset and save for this touch point */
struct touch_point *touch_point = calloc(1, sizeof(*touch_point));
double x_offset = 0.0, y_offset = 0.0;
// get surface from touch point
struct wlr_touch *touch = event->touch;
/* Convert coordinates: first [0, 1] => layout, then layout => surface */
double lx, ly;
wlr_cursor_absolute_to_layout_coords(seat->cursor, &touch->base, event->x, event->y, &lx, &ly);
double sx, sy;
struct wlr_scene_node *node = wlr_scene_node_at(&seat->server->scene->tree.node, lx, ly, &sx, &sy);
x_offset = lx - sx;
y_offset = ly - sy;
/* Find the surface and return it if it accepts touch events */
struct wlr_surface *surface = diyac_wlr_surface_from_node(node);
if (surface && !wlr_surface_accepts_touch(surface, seat->wlr_seat))
{
surface = NULL;
}
touch_point->surface = surface;
touch_point->touch_id = event->touch_id;
touch_point->x_offset = x_offset;
touch_point->y_offset = y_offset;
wl_list_insert(&seat->touch_points, &touch_point->link);
int touch_point_count = wl_list_length(&seat->touch_points);
/* hide the cursor when starting touch input */
// cursor_set_visible(seat, /* visible */ false);
if (touch_point->surface)
{
diyac_seat_pointer_end_grab(seat, touch_point->surface);
/* Clear focus to not interfere with touch input */
wlr_seat_pointer_notify_clear_focus(seat->wlr_seat);
/*
NOTE: default behaviour: Only emulate mouse if no target surface found
if (touch_point_count == 1)
{
wlr_cursor_warp_absolute(seat->cursor, &event->touch->base, event->x, event->y);
}
*/
wlr_seat_touch_notify_down(seat->wlr_seat, touch_point->surface, event->time_msec, event->touch_id, sx, sy);
}
//else
//{
if (touch_point_count == 1)
{
diyac_cursor_emulate_move_absolute(seat, &event->touch->base, event->x, event->y, event->time_msec);
}
diyac_cursor_emulate_button(seat, BTN_LEFT, WL_POINTER_BUTTON_STATE_PRESSED, event->time_msec);
//}
}
static void seat_touch_up(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, touch_up);
struct wlr_touch_up_event *event = data;
diyac_idle_manager_notify_activity(seat);
/* Remove the touch point from the seat */
struct touch_point *touch_point, *tmp;
wl_list_for_each_safe(touch_point, tmp, &seat->touch_points, link)
{
wlr_log(WLR_DEBUG, "seat_touch_up %d vs %d", touch_point->touch_id, event->touch_id);
if (touch_point->touch_id == event->touch_id)
{
if (touch_point->surface)
{
wlr_seat_touch_notify_up(seat->wlr_seat, event->time_msec,
event->touch_id);
}
// NOTE: default behavior: only emulate mouse button if no target surface found
//else
//{
diyac_cursor_emulate_button(seat, BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED, event->time_msec);
//}
wl_list_remove(&touch_point->link);
free(touch_point);
break;
}
}
}
static void seat_touch_motion(struct wl_listener *listener, void *data)
{
struct diyac_seat *seat = wl_container_of(listener, seat, touch_motion);
struct wlr_touch_motion_event *event = data;
diyac_idle_manager_notify_activity(seat);
int touch_point_count = wl_list_length(&seat->touch_points);
/* Find existing touch point to determine initial offsets to subtract */
struct touch_point *touch_point;
wl_list_for_each(touch_point, &seat->touch_points, link)
{
if (touch_point->touch_id == event->touch_id)
{
if (touch_point->surface)
{
/* Convert coordinates: first [0, 1] => layout */
double lx, ly;
wlr_cursor_absolute_to_layout_coords(seat->cursor,
&event->touch->base, event->x, event->y, &lx, &ly);
/* Apply offsets to get surface coords before reporting event */
double sx = lx - touch_point->x_offset;
double sy = ly - touch_point->y_offset;
/*
* NOTE: Defaut behaviour, set mouse position, but do not emulate mouse
if (touch_point_count == 1)
{
wlr_cursor_warp_absolute(seat->cursor, &event->touch->base, event->x, event->y);
}
*/
wlr_seat_touch_notify_motion(seat->wlr_seat, event->time_msec,
event->touch_id, sx, sy);
}
//else
//{
if (touch_point_count == 1)
{
diyac_cursor_emulate_move_absolute(seat, &event->touch->base, event->x, event->y, event->time_msec);
}
//}
return;
}
}
}
static void seat_touch_frame(struct wl_listener *listener, void *data)
{
(void) data;
struct diyac_seat *seat = wl_container_of(listener, seat, touch_frame);
wlr_seat_touch_notify_frame(seat->wlr_seat);
}
void diyac_touch_init(struct diyac_seat *seat)
{
seat->touch_down.notify = seat_touch_down;
wl_signal_add(&seat->cursor->events.touch_down, &seat->touch_down);
seat->touch_up.notify = seat_touch_up;
wl_signal_add(&seat->cursor->events.touch_up, &seat->touch_up);
seat->touch_motion.notify = seat_touch_motion;
wl_signal_add(&seat->cursor->events.touch_motion, &seat->touch_motion);
seat->touch_frame.notify = seat_touch_frame;
wl_signal_add(&seat->cursor->events.touch_frame, &seat->touch_frame);
}
void diyac_touch_drop(struct diyac_seat *seat)
{
wl_list_remove(&seat->touch_points);
wl_list_remove(&seat->touch_down.link);
wl_list_remove(&seat->touch_up.link);
wl_list_remove(&seat->touch_motion.link);
wl_list_remove(&seat->touch_frame.link);
}

8
touch.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef DIYAC_TOUCH_H
#define DIYAC_TOUCH_H
#include "diyac.h"
void diyac_touch_init(struct diyac_seat *seat);
void diyac_touch_drop(struct diyac_seat *seat);
#endif

37
view.c
View File

@@ -26,10 +26,9 @@ static int handle_configure_timeout(void *data)
return 0; /* ignored per wl_event_loop docs */ return 0; /* ignored per wl_event_loop docs */
} }
static void diyac_view_configure(struct diyac_view *view, struct wlr_box geo) void diya_view_set_pending_configure_serial(struct diyac_view* view, uint32_t serial)
{ {
view->pending_size = geo; view->configuration_serial = serial;
view->configuration_serial = wlr_xdg_toplevel_set_size(view->xdg_toplevel, geo.width, geo.height);
if (!view->configuration_timeout) if (!view->configuration_timeout)
{ {
view->configuration_timeout = wl_event_loop_add_timer(view->server->wl_event_loop, handle_configure_timeout, view); view->configuration_timeout = wl_event_loop_add_timer(view->server->wl_event_loop, handle_configure_timeout, view);
@@ -37,10 +36,24 @@ static void diyac_view_configure(struct diyac_view *view, struct wlr_box geo)
wl_event_source_timer_update(view->configuration_timeout, CONFIGURE_TIMEOUT_MS); wl_event_source_timer_update(view->configuration_timeout, CONFIGURE_TIMEOUT_MS);
} }
static void diyac_view_configure(struct diyac_view *view, struct wlr_box geo)
{
view->pending_size = geo;
uint32_t serial = wlr_xdg_toplevel_set_size(view->xdg_toplevel, geo.width, geo.height);
if(serial > 0)
{
diya_view_set_pending_configure_serial(view, serial);
}
}
static void diyac_view_set_activated(struct diyac_view *view, bool activated) static void diyac_view_set_activated(struct diyac_view *view, bool activated)
{ {
struct diyac_server *server = view->server; struct diyac_server *server = view->server;
wlr_xdg_toplevel_set_activated(view->xdg_toplevel, activated); uint32_t serial = wlr_xdg_toplevel_set_activated(view->xdg_toplevel, activated);
if(serial > 0)
{
diya_view_set_pending_configure_serial(view, serial);
}
if (view->toplevel.handle) if (view->toplevel.handle)
{ {
wlr_foreign_toplevel_handle_v1_set_activated(view->toplevel.handle, activated); wlr_foreign_toplevel_handle_v1_set_activated(view->toplevel.handle, activated);
@@ -170,8 +183,8 @@ void diyac_focus_topmost_view(struct diyac_server *server, bool raise)
struct diyac_view *diyac_topmost_focusable_view(struct diyac_server *server) struct diyac_view *diyac_topmost_focusable_view(struct diyac_server *server)
{ {
struct wlr_surface *prev = //struct wlr_surface *prev =
server->seat.wlr_seat->keyboard_state.focused_surface; // server->seat.wlr_seat->keyboard_state.focused_surface;
struct diyac_view *view; struct diyac_view *view;
struct wl_list *node_list; struct wl_list *node_list;
struct wlr_scene_node *node; struct wlr_scene_node *node;
@@ -462,14 +475,14 @@ void diyac_view_update_app_id(struct diyac_view *view)
void diyac_view_sync_geo(struct diyac_view *view) void diyac_view_sync_geo(struct diyac_view *view)
{ {
struct wlr_box size; struct wlr_box* size = NULL;
int current_x, current_y, next_x, next_y; int current_x, current_y, next_x, next_y;
if(!view->mapped) if(!view->mapped)
{ {
return; return;
} }
wlr_scene_node_coords(&view->scene_tree->node, &current_x, &current_y); wlr_scene_node_coords(&view->scene_tree->node, &current_x, &current_y);
wlr_xdg_surface_get_geometry(view->xdg_surface, &size); size = &view->xdg_surface->geometry;
if (!view->state.fullscreen && !view->state.maximized) if (!view->state.fullscreen && !view->state.maximized)
{ {
@@ -478,7 +491,7 @@ void diyac_view_sync_geo(struct diyac_view *view)
(view->original.x != view->pending_size.x) && (view->original.x != view->pending_size.x) &&
(view->original.x + view->original.width == view->pending_size.x + view->pending_size.width))) (view->original.x + view->original.width == view->pending_size.x + view->pending_size.width)))
{ {
view->original.x = view->pending_size.x + view->pending_size.width - size.width; view->original.x = view->pending_size.x + view->pending_size.width - size->width;
} }
else else
{ {
@@ -488,15 +501,15 @@ void diyac_view_sync_geo(struct diyac_view *view)
(view->original.y != view->pending_size.y) && (view->original.y != view->pending_size.y) &&
(view->original.y + view->original.height == view->pending_size.y + view->pending_size.height))) (view->original.y + view->original.height == view->pending_size.y + view->pending_size.height)))
{ {
view->original.y = view->pending_size.y + view->pending_size.height - size.height; view->original.y = view->pending_size.y + view->pending_size.height - size->height;
} }
else else
{ {
view->original.y = view->pending_size.y; view->original.y = view->pending_size.y;
} }
view->original.width = size.width; view->original.width = size->width;
view->original.height = size.height; view->original.height = size->height;
next_x = view->original.x; next_x = view->original.x;
next_y = view->original.y; next_y = view->original.y;
view->pending_size = view->original; view->pending_size = view->original;

1
view.h
View File

@@ -22,4 +22,5 @@ void diyac_view_update_title(struct diyac_view * view);
void diyac_view_update_app_id(struct diyac_view * view); void diyac_view_update_app_id(struct diyac_view * view);
void diyac_view_sync_geo(struct diyac_view *view); void diyac_view_sync_geo(struct diyac_view *view);
void diya_view_unfocus(struct diyac_view* view); void diya_view_unfocus(struct diyac_view* view);
void diya_view_set_pending_configure_serial(struct diyac_view* view, uint32_t serial);
#endif #endif

139
xdg.c
View File

@@ -20,7 +20,7 @@ static void begin_interactive(struct diyac_view *toplevel,
struct diyac_server *server = toplevel->server; struct diyac_server *server = toplevel->server;
struct wlr_surface *focused_surface = struct wlr_surface *focused_surface =
server->seat.wlr_seat->pointer_state.focused_surface; server->seat.wlr_seat->pointer_state.focused_surface;
if (toplevel->xdg_toplevel->base->surface != if (focused_surface && toplevel->xdg_toplevel->base->surface !=
wlr_surface_get_root_surface(focused_surface)) wlr_surface_get_root_surface(focused_surface))
{ {
/* Deny move/resize requests from unfocused clients. */ /* Deny move/resize requests from unfocused clients. */
@@ -36,17 +36,16 @@ static void begin_interactive(struct diyac_view *toplevel,
} }
else else
{ {
struct wlr_box geo_box; struct wlr_box* geo_box = &toplevel->xdg_toplevel->base->geometry;
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
double border_x = (toplevel->scene_tree->node.x + geo_box.x) + double border_x = (toplevel->scene_tree->node.x + geo_box->x) +
((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0); ((edges & WLR_EDGE_RIGHT) ? geo_box->width : 0);
double border_y = (toplevel->scene_tree->node.y + geo_box.y) + double border_y = (toplevel->scene_tree->node.y + geo_box->y) +
((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0); ((edges & WLR_EDGE_BOTTOM) ? geo_box->height : 0);
server->grab_x = server->seat.cursor->x - border_x; server->grab_x = server->seat.cursor->x - border_x;
server->grab_y = server->seat.cursor->y - border_y; server->grab_y = server->seat.cursor->y - border_y;
server->grab_geobox = geo_box; server->grab_geobox = *geo_box;
server->grab_geobox.x += toplevel->scene_tree->node.x; server->grab_geobox.x += toplevel->scene_tree->node.x;
server->grab_geobox.y += toplevel->scene_tree->node.y; server->grab_geobox.y += toplevel->scene_tree->node.y;
@@ -55,38 +54,53 @@ static void begin_interactive(struct diyac_view *toplevel,
} }
static void xdg_toplevel_commit(struct wl_listener *listener, void *data) static void xdg_toplevel_commit(struct wl_listener *listener, void *data)
{ {
struct diyac_view *view = wl_container_of(listener, view, commit); (void)data;
uint32_t serial = view->configuration_serial; struct diyac_view *toplevel = wl_container_of(listener, toplevel, commit);
if (serial > 0 && serial == view->xdg_surface->current.configure_serial) uint32_t serial = toplevel->configuration_serial;
struct wlr_xdg_surface *xdg_surface = toplevel->xdg_surface;
if (xdg_surface->initial_commit)
{ {
wl_event_source_remove(view->configuration_timeout); uint32_t serial =
view->configuration_serial = 0; wlr_xdg_surface_schedule_configure(xdg_surface);
view->configuration_timeout = NULL; uint32_t wm_caps = WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE | WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN | WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE;
wlr_xdg_toplevel_set_wm_capabilities(toplevel->xdg_toplevel, wm_caps);
if(serial > 0)
{
diya_view_set_pending_configure_serial(toplevel, serial);
}
return;
}
if (serial > 0 && serial == toplevel->xdg_surface->current.configure_serial)
{
wl_event_source_remove(toplevel->configuration_timeout);
toplevel->configuration_serial = 0;
toplevel->configuration_timeout = NULL;
// TODO move view // TODO move view
} }
diyac_view_sync_geo(view); diyac_view_sync_geo(toplevel);
} }
static void xdg_toplevel_map(struct wl_listener *listener, void *data) static void xdg_toplevel_map(struct wl_listener *listener, void *data)
{ {
(void)data;
wlr_log(WLR_INFO, "xdg_toplevel_map: %p", listener);
/* Called when the surface is mapped, or ready to display on-screen. */ /* Called when the surface is mapped, or ready to display on-screen. */
struct diyac_view *toplevel = wl_container_of(listener, toplevel, map); struct diyac_view *toplevel = wl_container_of(listener, toplevel, map);
if (toplevel->mapped) if (toplevel->mapped)
{ {
return; return;
} }
diyac_init_foreign_toplevel(toplevel);
/* /*
wlr_xdg_toplevel_set_wm_capabilities(toplevel->xdg_toplevel, wlr_xdg_toplevel_set_wm_capabilities(toplevel->xdg_toplevel,
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE | WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE |
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE); WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE);
//WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN //WLR_XDG_TOPLEVEL_WM_CAPABILITIES_FULLSCREEN
*/ */
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &toplevel->pending_size); toplevel->pending_size = toplevel->xdg_toplevel->base->geometry;
wlr_scene_node_set_enabled(&toplevel->scene_tree->node, true); wlr_scene_node_set_enabled(&toplevel->scene_tree->node, true);
toplevel->mapped = true; toplevel->mapped = true;
wl_list_insert(&toplevel->server->views, &toplevel->link);
toplevel->commit.notify = xdg_toplevel_commit;
wl_signal_add(&toplevel->xdg_surface->surface->events.commit, &toplevel->commit);
diyac_view_update_app_id(toplevel); diyac_view_update_app_id(toplevel);
diyac_view_update_title(toplevel); diyac_view_update_title(toplevel);
@@ -106,6 +120,7 @@ static void xdg_toplevel_map(struct wl_listener *listener, void *data)
static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
{ {
(void)data;
/* Called when the surface is unmapped, and should no longer be shown. */ /* Called when the surface is unmapped, and should no longer be shown. */
struct diyac_view *toplevel = wl_container_of(listener, toplevel, unmap); struct diyac_view *toplevel = wl_container_of(listener, toplevel, unmap);
toplevel->mapped = false; toplevel->mapped = false;
@@ -139,11 +154,23 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
} }
wl_list_remove(&toplevel->link); wl_list_remove(&toplevel->link);
wl_list_remove(&toplevel->request_move.link);
wl_list_remove(&toplevel->request_resize.link);
wl_list_remove(&toplevel->request_maximize.link);
wl_list_remove(&toplevel->request_minimize.link);
wl_list_remove(&toplevel->request_fullscreen.link);
wl_list_remove(&toplevel->set_app_id.link);
wl_list_remove(&toplevel->new_popup.link);
wl_list_remove(&toplevel->set_title.link);
} }
static void xdg_toplevel_request_move( static void xdg_toplevel_request_move(
struct wl_listener *listener, void *data) struct wl_listener *listener, void *data)
{ {
(void)data;
/* This event is raised when a client would like to begin an interactive /* This event is raised when a client would like to begin an interactive
* move, typically because the user clicked on their client-side * move, typically because the user clicked on their client-side
* decorations. Note that a more sophisticated compositor should check the * decorations. Note that a more sophisticated compositor should check the
@@ -170,6 +197,7 @@ static void xdg_toplevel_request_resize(
static void xdg_toplevel_request_maximize( static void xdg_toplevel_request_maximize(
struct wl_listener *listener, void *data) struct wl_listener *listener, void *data)
{ {
(void)data;
/* This event is raised when a client would like to maximize itself, /* This event is raised when a client would like to maximize itself,
* typically because the user clicked on the maximize button on * typically because the user clicked on the maximize button on
* client-side decorations. diyac doesn't support maximization, but * client-side decorations. diyac doesn't support maximization, but
@@ -183,6 +211,7 @@ static void xdg_toplevel_request_maximize(
static void xdg_toplevel_request_fullscreen(struct wl_listener *listener, void *data) static void xdg_toplevel_request_fullscreen(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_view *toplevel = struct diyac_view *toplevel =
wl_container_of(listener, toplevel, request_fullscreen); wl_container_of(listener, toplevel, request_fullscreen);
diyac_view_set_fullscreen(toplevel, toplevel->xdg_toplevel->requested.fullscreen); diyac_view_set_fullscreen(toplevel, toplevel->xdg_toplevel->requested.fullscreen);
@@ -190,6 +219,7 @@ static void xdg_toplevel_request_fullscreen(struct wl_listener *listener, void *
static void xdg_toplevel_request_minimize(struct wl_listener *listener, void *data) static void xdg_toplevel_request_minimize(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_view *toplevel = struct diyac_view *toplevel =
wl_container_of(listener, toplevel, request_minimize); wl_container_of(listener, toplevel, request_minimize);
diyac_view_set_mimimize(toplevel, toplevel->xdg_toplevel->requested.minimized); diyac_view_set_mimimize(toplevel, toplevel->xdg_toplevel->requested.minimized);
@@ -197,8 +227,13 @@ static void xdg_toplevel_request_minimize(struct wl_listener *listener, void *da
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
{ {
(void)data;
/* Called when the xdg_toplevel is destroyed. */ /* Called when the xdg_toplevel is destroyed. */
struct diyac_view *toplevel = wl_container_of(listener, toplevel, destroy); struct diyac_view *toplevel = wl_container_of(listener, toplevel, destroy);
struct wlr_xdg_popup *popup, *tmp;
wl_list_for_each_safe(popup, tmp, &toplevel->xdg_surface->popups, link) {
wlr_xdg_popup_destroy(popup);
}
if (toplevel->toplevel.handle) if (toplevel->toplevel.handle)
{ {
wlr_foreign_toplevel_handle_v1_destroy(toplevel->toplevel.handle); wlr_foreign_toplevel_handle_v1_destroy(toplevel->toplevel.handle);
@@ -208,27 +243,16 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
wl_event_source_remove(toplevel->configuration_timeout); wl_event_source_remove(toplevel->configuration_timeout);
toplevel->configuration_timeout = NULL; toplevel->configuration_timeout = NULL;
} }
if(toplevel->mapped)
{
wl_list_remove(&toplevel->commit.link);
}
wl_list_remove(&toplevel->map.link); wl_list_remove(&toplevel->map.link);
wl_list_remove(&toplevel->unmap.link); wl_list_remove(&toplevel->unmap.link);
wl_list_remove(&toplevel->commit.link);
wl_list_remove(&toplevel->destroy.link); wl_list_remove(&toplevel->destroy.link);
wl_list_remove(&toplevel->request_move.link);
wl_list_remove(&toplevel->request_resize.link);
wl_list_remove(&toplevel->request_maximize.link);
wl_list_remove(&toplevel->request_fullscreen.link);
wl_list_remove(&toplevel->set_app_id.link);
wl_list_remove(&toplevel->new_popup.link);
wl_list_remove(&toplevel->set_title.link);
free(toplevel); free(toplevel);
} }
static void handle_xdg_popup_destroy(struct wl_listener *listener, void *data) static void handle_xdg_popup_destroy(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_popup *popup = wl_container_of(listener, popup, destroy); struct diyac_popup *popup = wl_container_of(listener, popup, destroy);
wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->new_popup.link);
@@ -244,13 +268,13 @@ static void handle_xdg_popup_destroy(struct wl_listener *listener, void *data)
static void popup_unconstrain(struct diyac_popup *popup) static void popup_unconstrain(struct diyac_popup *popup)
{ {
struct diyac_view *view = popup->parent; struct diyac_view *view = popup->parent;
if(!view->output) if (!view->output)
{ {
return; return;
} }
struct diyac_server *server = view->server; // struct diyac_server *server = view->server;
struct wlr_output_layout *output_layout = server->output_layout; //struct wlr_output_layout *output_layout = server->output_layout;
struct wlr_output *wlr_output = view->output->wlr_output; //struct wlr_output *wlr_output = view->output->wlr_output;
struct wlr_box usable = { struct wlr_box usable = {
.x = 0, .x = 0,
.y = 0, .y = 0,
@@ -273,14 +297,14 @@ static void popup_unconstrain(struct diyac_popup *popup)
static void handle_xdg_popup_commit(struct wl_listener *listener, void *data) static void handle_xdg_popup_commit(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_popup *popup = wl_container_of(listener, popup, commit); struct diyac_popup *popup = wl_container_of(listener, popup, commit);
struct wlr_box popup_box; struct wlr_box* popup_box = &popup->wlr_popup->base->geometry;
wlr_xdg_surface_get_geometry(popup->wlr_popup->base, &popup_box);
popup_unconstrain(popup); popup_unconstrain(popup);
if (!wlr_box_empty(&popup_box)) if (!wlr_box_empty(popup_box))
// if (popup->wlr_popup->base->initial_commit) // if (popup->wlr_popup->base->initial_commit)
{ {
struct diyac_view *view = popup->parent; // struct diyac_view *view = popup->parent;
// wlr_output_commit(view->output->wlr_output); // wlr_output_commit(view->output->wlr_output);
/* Prevent getting called over and over again */ /* Prevent getting called over and over again */
wl_list_remove(&popup->commit.link); wl_list_remove(&popup->commit.link);
@@ -352,12 +376,14 @@ static void xdg_popup_create(struct diyac_view *view, struct wlr_xdg_popup *wlr_
static void xdg_set_appid_notify(struct wl_listener *listener, void *data) static void xdg_set_appid_notify(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_view *view = wl_container_of(listener, view, set_app_id); struct diyac_view *view = wl_container_of(listener, view, set_app_id);
diyac_view_update_app_id(view); diyac_view_update_app_id(view);
} }
static void xdg_set_title_notify(struct wl_listener *listener, void *data) static void xdg_set_title_notify(struct wl_listener *listener, void *data)
{ {
(void)data;
struct diyac_view *view = wl_container_of(listener, view, set_title); struct diyac_view *view = wl_container_of(listener, view, set_title);
diyac_view_update_title(view); diyac_view_update_title(view);
} }
@@ -370,31 +396,15 @@ static void xdg_new_popup_notify(struct wl_listener *listener, void *data)
xdg_popup_create(view, wlr_popup); xdg_popup_create(view, wlr_popup);
} }
void diyac_new_xdg_surface(struct wl_listener *listener, void *data) void diyac_new_xdg_toplevel(struct wl_listener *listener, void *data)
{ {
/* This event is raised when wlr_xdg_shell receives a new xdg surface from a /* This event is raised when wlr_xdg_shell receives a new xdg surface from a
* client, either a toplevel (application window) or popup. */ * client, either a toplevel (application window) or popup. */
struct diyac_server *server = struct diyac_server *server =
wl_container_of(listener, server, new_xdg_surface); wl_container_of(listener, server, new_xdg_toplevel);
struct wlr_xdg_surface *xdg_surface = data; struct wlr_xdg_toplevel *xdg_toplevel = data;
struct wlr_xdg_surface *xdg_surface = xdg_toplevel->base;
/* We must add xdg popups to the scene graph so they get rendered. The
* wlroots scene graph provides a helper for this, but to use it we must
* provide the proper parent scene node of the xdg popup. To enable this,
* we always set the user data field of xdg_surfaces to the corresponding
* scene node. */
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP)
{
/*struct wlr_xdg_surface *parent =
wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
assert(parent != NULL);
struct wlr_scene_tree *parent_tree = parent->data;
xdg_surface->data = wlr_scene_xdg_surface_create(
parent_tree, xdg_surface);
return;*/
wlr_log(WLR_INFO, "diyac_new_xdg_surface: Creating new dialog using view popup");
return;
}
assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL); assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
wlr_log(WLR_INFO, "diyac_new_xdg_surface: Creating new application windows"); wlr_log(WLR_INFO, "diyac_new_xdg_surface: Creating new application windows");
wlr_xdg_surface_ping(xdg_surface); wlr_xdg_surface_ping(xdg_surface);
@@ -421,7 +431,6 @@ void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
wlr_scene_node_set_enabled(&toplevel->scene_tree->node, false); wlr_scene_node_set_enabled(&toplevel->scene_tree->node, false);
diyac_node_descriptor_create(&toplevel->scene_tree->node, diyac_node_descriptor_create(&toplevel->scene_tree->node,
DIYAC_NODE_VIEW, toplevel); DIYAC_NODE_VIEW, toplevel);
diyac_init_foreign_toplevel(toplevel);
/* Listen to the various events it can emit */ /* Listen to the various events it can emit */
toplevel->map.notify = xdg_toplevel_map; toplevel->map.notify = xdg_toplevel_map;
@@ -432,7 +441,6 @@ void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
wl_signal_add(&xdg_surface->events.destroy, &toplevel->destroy); wl_signal_add(&xdg_surface->events.destroy, &toplevel->destroy);
/* cotd */ /* cotd */
struct wlr_xdg_toplevel *xdg_toplevel = xdg_surface->toplevel;
toplevel->request_move.notify = xdg_toplevel_request_move; toplevel->request_move.notify = xdg_toplevel_request_move;
wl_signal_add(&xdg_toplevel->events.request_move, &toplevel->request_move); wl_signal_add(&xdg_toplevel->events.request_move, &toplevel->request_move);
toplevel->request_resize.notify = xdg_toplevel_request_resize; toplevel->request_resize.notify = xdg_toplevel_request_resize;
@@ -453,4 +461,9 @@ void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
toplevel->set_title.notify = xdg_set_title_notify; toplevel->set_title.notify = xdg_set_title_notify;
wl_signal_add(&xdg_toplevel->events.set_title, &toplevel->set_title); wl_signal_add(&xdg_toplevel->events.set_title, &toplevel->set_title);
toplevel->commit.notify = xdg_toplevel_commit;
wl_signal_add(&toplevel->xdg_surface->surface->events.commit, &toplevel->commit);
wl_list_insert(&toplevel->server->views, &toplevel->link);
} }

2
xdg.h
View File

@@ -2,5 +2,5 @@
#define DIYAC_XDG_H #define DIYAC_XDG_H
#include "diyac.h" #include "diyac.h"
void diyac_new_xdg_surface(struct wl_listener *listener, void *data); void diyac_new_xdg_toplevel(struct wl_listener *listener, void *data);
#endif #endif