Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c50d9f92b | ||
|
|
0c9c144919 | ||
|
|
0c6eb8df47 | ||
|
|
510a59e69d | ||
| b0cf86aa00 | |||
| 0f31545ccd | |||
| 0b738f4476 | |||
| 2cc5bb045b | |||
|
|
9cc2408dc8 | ||
|
|
194b7894cd | ||
|
|
dd8242abc6 | ||
|
|
f62a21d3b2 | ||
|
|
0a77ed8d91 | ||
|
|
13543e1382 | ||
| 6be0e9b5c4 | |||
| ea98928849 | |||
|
|
c1393a1366 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -139,7 +139,5 @@ m4/lt~obsolete.m4
|
||||
# can automatically generate from config.status script
|
||||
# (which is called by configure script))
|
||||
# Makefile
|
||||
xdg-shell-protocol.*
|
||||
diyac
|
||||
.vscode
|
||||
wlr-layer-shell-unstable-v1-protocol*
|
||||
build*
|
||||
.vscode
|
||||
53
Makefile
53
Makefile
@@ -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
|
||||
@@ -1,2 +1,3 @@
|
||||
# diyac
|
||||
|
||||
Simple Wayland compositor used mainly by diya-session manager and diya shell
|
||||
|
||||
177
cursor.c
177
cursor.c
@@ -1,10 +1,14 @@
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/types/wlr_cursor_shape_v1.h>
|
||||
#include <assert.h>
|
||||
#include "cursor.h"
|
||||
#include "view.h"
|
||||
#include "seat.h"
|
||||
#include "node.h"
|
||||
#include "idle.h"
|
||||
#include "touch.h"
|
||||
#include "gestures.h"
|
||||
|
||||
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,
|
||||
server->seat.cursor->x, server->seat.cursor->y, &surface, &sx, &sy);
|
||||
struct diyac_layer_surface *layer;
|
||||
struct diyac_view *root = NULL;
|
||||
// struct diyac_view *root = NULL;
|
||||
if (!desc)
|
||||
{
|
||||
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)
|
||||
{
|
||||
(void)time;
|
||||
struct diyac_view *toplevel = server->grabbed_view;
|
||||
/* Move the grabbed toplevel to the new position. */
|
||||
if(!toplevel->output)
|
||||
if (!toplevel->output)
|
||||
{
|
||||
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)
|
||||
{
|
||||
(void)time;
|
||||
/*
|
||||
* 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
|
||||
@@ -95,7 +101,7 @@ static void process_cursor_resize(struct diyac_server *server, uint32_t time)
|
||||
* size, then commit any movement that was prepared.
|
||||
*/
|
||||
struct diyac_view *toplevel = server->grabbed_view;
|
||||
if(toplevel->state.fullscreen)
|
||||
if (toplevel->state.fullscreen)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -139,10 +145,9 @@ static void process_cursor_resize(struct diyac_server *server, uint32_t time)
|
||||
}
|
||||
}
|
||||
|
||||
struct wlr_box geo_box;
|
||||
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
|
||||
toplevel->pending_size.x = new_left - geo_box.x;
|
||||
toplevel->pending_size.y = new_top - geo_box.y;
|
||||
struct wlr_box* geo_box = &toplevel->xdg_toplevel->base->geometry;
|
||||
toplevel->pending_size.x = new_left - geo_box->x;
|
||||
toplevel->pending_size.y = new_top - geo_box->y;
|
||||
int new_width = new_right - new_left;
|
||||
int new_height = new_bottom - new_top;
|
||||
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 =
|
||||
wl_container_of(listener, seat, cursor_motion);
|
||||
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
|
||||
* handles constraining the motion to the output layout, as well as any
|
||||
* special configuration applied for the specific input device which
|
||||
@@ -235,7 +246,18 @@ static void server_cursor_motion_absolute(
|
||||
* emits these events. */
|
||||
struct diyac_seat *seat =
|
||||
wl_container_of(listener, seat, cursor_motion_absolute);
|
||||
diyac_idle_manager_notify_activity(seat);
|
||||
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,
|
||||
event->y);
|
||||
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 =
|
||||
wl_container_of(listener, seat, cursor_button);
|
||||
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 */
|
||||
wlr_seat_pointer_notify_button(seat->wlr_seat,
|
||||
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. */
|
||||
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. */
|
||||
struct diyac_seat *seat =
|
||||
wl_container_of(listener, seat, cursor_axis);
|
||||
diyac_idle_manager_notify_activity(seat);
|
||||
struct wlr_pointer_axis_event *event = data;
|
||||
/* Notify the client with pointer focus of the axis event. */
|
||||
wlr_seat_pointer_notify_axis(seat->wlr_seat,
|
||||
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)
|
||||
{
|
||||
(void)data;
|
||||
/* This event is forwarded by the cursor when a pointer emits an frame
|
||||
* event. Frame events are sent after regular pointer events to group
|
||||
* 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/*
|
||||
@@ -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);
|
||||
server->seat.cursor_frame.notify = server_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);
|
||||
}
|
||||
4
cursor.h
4
cursor.h
@@ -6,4 +6,8 @@
|
||||
void diyac_init_cursor_manager(struct diyac_server * server);
|
||||
void diyac_reset_cursor_mode(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
|
||||
77
diyac.c
77
diyac.c
@@ -8,20 +8,31 @@
|
||||
#include <errno.h>
|
||||
#include <string.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 "xdg.h"
|
||||
#include "cursor.h"
|
||||
#include "seat.h"
|
||||
#include "layer.h"
|
||||
#include "session.h"
|
||||
#include "idle.h"
|
||||
|
||||
#define PROC_MON_TO 100
|
||||
|
||||
void help()
|
||||
{
|
||||
printf("diyac - a simple Wayland compositor\n");
|
||||
printf("Usage: diyac [-x] [startup command]\n");
|
||||
printf("Options:\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[])
|
||||
{
|
||||
wlr_log_init(WLR_INFO, NULL);
|
||||
char *startup_cmd = NULL;
|
||||
int exit_with_session = 0;
|
||||
|
||||
int log_level = WLR_ERROR;
|
||||
int c;
|
||||
while ((c = getopt(argc, argv, "xh")) != -1)
|
||||
while ((c = getopt(argc, argv, "xvh")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'v':
|
||||
if (log_level < WLR_DEBUG)
|
||||
{
|
||||
log_level++;
|
||||
}
|
||||
break;
|
||||
case 'x':
|
||||
exit_with_session = 1;
|
||||
break;
|
||||
@@ -78,7 +94,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
if (optind < argc)
|
||||
{
|
||||
if(optind != argc - 1)
|
||||
if (optind != argc - 1)
|
||||
{
|
||||
help();
|
||||
return 1;
|
||||
@@ -86,6 +102,7 @@ int main(int argc, char *argv[])
|
||||
// the last argument is the startup command
|
||||
startup_cmd = argv[optind];
|
||||
}
|
||||
wlr_log_init(log_level, NULL);
|
||||
struct diyac_server server = {0};
|
||||
/* The Wayland display is managed by libwayland. It handles accepting
|
||||
* 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
|
||||
* backend based on the current environment, such as opening an X11 window
|
||||
* 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)
|
||||
{
|
||||
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);
|
||||
|
||||
/* 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
|
||||
* rendering and damage tracking. All the compositor author needs to do
|
||||
@@ -166,23 +174,30 @@ int main(int argc, char *argv[])
|
||||
* necessary.
|
||||
*/
|
||||
server.scene = wlr_scene_create();
|
||||
server.scene_layout = wlr_scene_attach_output_layout(server.scene, server.output_layout);
|
||||
wlr_fractional_scale_manager_v1_create(server.wl_display,1);
|
||||
diyac_output_init(&server);
|
||||
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
|
||||
* used for application windows. For more detail on shells, refer to
|
||||
* https://drewdevault.com/2018/07/29/Wayland-shells.html.
|
||||
*/
|
||||
wl_list_init(&server.views);
|
||||
/**
|
||||
* TODO: free these tree when finish
|
||||
*/
|
||||
* TODO: free these tree when finish
|
||||
*/
|
||||
server.view_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.new_xdg_surface.notify = diyac_new_xdg_surface;
|
||||
wl_signal_add(&server.xdg_shell->events.new_surface,
|
||||
&server.new_xdg_surface);
|
||||
server.new_xdg_toplevel.notify = diyac_new_xdg_toplevel;
|
||||
wl_signal_add(&server.xdg_shell->events.new_toplevel,
|
||||
&server.new_xdg_toplevel);
|
||||
|
||||
server.layer_shell = wlr_layer_shell_v1_create(server.wl_display, 4);
|
||||
server.new_layer_surface.notify = diyac_new_layer_surface;
|
||||
@@ -190,7 +205,6 @@ int main(int argc, char *argv[])
|
||||
&server.new_layer_surface);
|
||||
|
||||
diyac_init_session_lock(&server);
|
||||
diyac_init_cursor_manager(&server);
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
server.foreign_toplevel_manager = wlr_foreign_toplevel_manager_v1_create(server.wl_display);
|
||||
diyac_init_seat(&server);
|
||||
diyac_init_cursor_manager(&server);
|
||||
|
||||
/* Add a Unix socket to the Wayland 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",
|
||||
socket);
|
||||
server.proc_mon = NULL;
|
||||
if( startup_cmd && exit_with_session)
|
||||
if (startup_cmd && exit_with_session)
|
||||
{
|
||||
if (server.session_pid == -1)
|
||||
{
|
||||
@@ -259,20 +274,30 @@ int main(int argc, char *argv[])
|
||||
|
||||
/* Once wl_display_run returns, we destroy all clients then shut down the
|
||||
* server. */
|
||||
if(server.proc_mon)
|
||||
if (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);
|
||||
// wlr_scene_node_destroy(&server.scene->tree.node);
|
||||
wlr_xcursor_manager_destroy(server.seat.cursor_mgr);
|
||||
wlr_output_layout_destroy(server.output_layout);
|
||||
wl_display_destroy(server.wl_display);
|
||||
wlr_log(WLR_INFO, "Diyac session ended");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TODO
|
||||
* reload configuration (keymap, etc.) when sighub is received
|
||||
*
|
||||
*
|
||||
*/
|
||||
63
diyac.h
63
diyac.h
@@ -18,6 +18,9 @@
|
||||
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
|
||||
#include <wlr/types/wlr_session_lock_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
|
||||
|
||||
@@ -67,8 +70,28 @@ struct diyac_seat
|
||||
struct wl_listener cursor_button;
|
||||
struct wl_listener cursor_axis;
|
||||
struct wl_listener cursor_frame;
|
||||
struct wl_listener new_input;
|
||||
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_primary_selection;
|
||||
// struct wl_list keyboards;
|
||||
@@ -110,13 +133,13 @@ struct diyac_node_descriptor
|
||||
struct diyac_session_lock
|
||||
{
|
||||
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 unlock;
|
||||
struct wl_listener destroy;
|
||||
//struct wl_listener new_output;
|
||||
// struct wl_listener new_output;
|
||||
};
|
||||
|
||||
struct diyac_server
|
||||
@@ -131,10 +154,12 @@ struct diyac_server
|
||||
|
||||
struct wlr_xdg_shell *xdg_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_list views;
|
||||
struct diyac_view * active_view;
|
||||
struct diyac_view *active_view;
|
||||
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
|
||||
/*
|
||||
* 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_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;
|
||||
};
|
||||
|
||||
@@ -179,7 +217,7 @@ struct diyac_output_lock_handle
|
||||
struct wlr_scene_rect *background;
|
||||
|
||||
struct wlr_session_lock_surface_v1 *surface;
|
||||
struct diyac_output * output;
|
||||
struct diyac_output *output;
|
||||
struct wl_listener surface_destroy;
|
||||
struct wl_listener surface_map;
|
||||
|
||||
@@ -195,13 +233,15 @@ struct diyac_output
|
||||
struct wl_listener request_state;
|
||||
struct wl_listener destroy;
|
||||
struct wlr_box usable_area;
|
||||
struct wlr_output_state pending_state;
|
||||
struct wlr_scene_output *scene_output;
|
||||
|
||||
// layer output
|
||||
struct diyac_output_scenes scenes;
|
||||
// alias to diyac_output_scenes elements
|
||||
struct wlr_scene_tree *layer_tree[LAYER_TREE_SZ];
|
||||
// lock handle
|
||||
struct diyac_output_lock_handle * lock_handle;
|
||||
struct diyac_output_lock_handle *lock_handle;
|
||||
};
|
||||
|
||||
struct foreign_toplevel
|
||||
@@ -225,7 +265,7 @@ struct diyac_view
|
||||
struct diyac_view_state state;
|
||||
struct diyac_view_state requested;
|
||||
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
|
||||
* 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_maximize;
|
||||
struct wl_listener request_fullscreen;
|
||||
|
||||
struct wl_listener set_app_id;
|
||||
struct wl_listener new_popup;
|
||||
struct wl_listener set_title;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_view *view = wl_container_of(listener, view, toplevel.activate);
|
||||
// struct wlr_foreign_toplevel_handle_v1_activated_event *event = data;
|
||||
/* 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
|
||||
handle_request_close(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_view *view = wl_container_of(listener, view, toplevel.close);
|
||||
wlr_xdg_toplevel_send_close(view->xdg_toplevel);
|
||||
}
|
||||
@@ -46,6 +48,7 @@ handle_request_close(struct wl_listener *listener, void *data)
|
||||
static void
|
||||
handle_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_view *view = wl_container_of(listener, view, toplevel.destroy);
|
||||
struct foreign_toplevel *toplevel = &view->toplevel;
|
||||
wl_list_remove(&toplevel->maximize.link);
|
||||
|
||||
139
gestures.c
Normal file
139
gestures.c
Normal 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
8
gestures.h
Normal 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
73
idle.c
Normal 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
10
idle.h
Normal 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
13
layer.c
@@ -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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_layer_surface *layer =
|
||||
wl_container_of(listener, layer, surface_commit);
|
||||
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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_layer_surface *layer = wl_container_of(listener, layer, unmap);
|
||||
struct wlr_layer_surface_v1 *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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_layer_surface *layer = wl_container_of(listener, layer, map);
|
||||
struct wlr_output *wlr_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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_layer_surface *layer =
|
||||
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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_layer_surface *layer =
|
||||
wl_container_of(listener, layer, output_destroy);
|
||||
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
|
||||
popup_handle_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)data;
|
||||
struct diyac_popup *popup = wl_container_of(listener, popup, destroy);
|
||||
wl_list_remove(&popup->destroy.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)
|
||||
{
|
||||
(void)data;
|
||||
struct diyac_popup *popup =
|
||||
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);
|
||||
if (!wlr_box_empty(&popup_box))
|
||||
if (!wlr_box_empty(&popup->wlr_popup->base->geometry))
|
||||
//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;
|
||||
layer_surface->current = layer_surface->pending;
|
||||
diyac_output_update_usable_area(output);
|
||||
// diyac_output_update_usable_area(output);
|
||||
layer_surface->current = old_state;
|
||||
}
|
||||
|
||||
|
||||
80
meson.build
Normal file
80
meson.build
Normal 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
20
node.c
@@ -5,6 +5,7 @@
|
||||
|
||||
static void destroy_notify(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)data;
|
||||
struct diyac_node_descriptor *node_descriptor =
|
||||
wl_container_of(listener, node_descriptor, destroy);
|
||||
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;
|
||||
}
|
||||
|
||||
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.
|
||||
* We only care about surface nodes as we are specifically looking for a
|
||||
@@ -64,4 +65,21 @@ struct diyac_node_descriptor * diyac_node_at(struct diyac_server* server, double
|
||||
tree = tree->node.parent;
|
||||
}
|
||||
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
1
node.h
@@ -4,6 +4,7 @@
|
||||
|
||||
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 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_node_descriptor * diyac_node_at(struct diyac_server* server, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy);
|
||||
#endif
|
||||
|
||||
680
output.c
680
output.c
@@ -3,14 +3,66 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.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 "layer.h"
|
||||
#include "node.h"
|
||||
#include "view.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)
|
||||
{
|
||||
(void)data;
|
||||
/* This function is called every time an output is ready to display a frame,
|
||||
* generally at the output's refresh rate (e.g. 60Hz). */
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
/* This function is called when the backend requests a new state for
|
||||
* the output. For example, Wayland and X11 backends request a new mode
|
||||
* when the output window is resized. */
|
||||
/* This ensures nested backends can be resized */
|
||||
struct diyac_output *output = wl_container_of(listener, output, request_state);
|
||||
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)
|
||||
{
|
||||
(void)data;
|
||||
struct diyac_output *output = wl_container_of(listener, output, destroy);
|
||||
if(output->lock_handle)
|
||||
if (output->lock_handle)
|
||||
{
|
||||
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.session->node);
|
||||
|
||||
|
||||
wl_list_remove(&output->frame.link);
|
||||
wl_list_remove(&output->request_state.link);
|
||||
wl_list_remove(&output->destroy.link);
|
||||
wl_list_remove(&output->link);
|
||||
|
||||
struct diyac_server* server = output->server;
|
||||
struct diyac_view * view;
|
||||
wl_list_for_each(view, &server->views, link) {
|
||||
if (view->output == output) {
|
||||
struct diyac_server *server = output->server;
|
||||
struct diyac_view *view;
|
||||
wl_list_for_each(view, &server->views, link)
|
||||
{
|
||||
if (view->output == output)
|
||||
{
|
||||
/**
|
||||
* TODO: testing this case
|
||||
*/
|
||||
* TODO: testing this case
|
||||
*/
|
||||
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);
|
||||
diyac_view_update_geometry(view, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
wlr_output_state_finish(&output->pending_state);
|
||||
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
|
||||
* 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 */
|
||||
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 */
|
||||
struct diyac_output *output = calloc(1, sizeof(*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.width = wlr_output->width;
|
||||
output->usable_area.height = wlr_output->height;
|
||||
|
||||
output_state_init(output);
|
||||
|
||||
/* Sets up a listener for the frame event. */
|
||||
output->frame.notify = 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->lock_handle = NULL;
|
||||
if(server->lock)
|
||||
{
|
||||
diyac_session_lock_output(output);
|
||||
}
|
||||
/*
|
||||
* Set the z-positions to achieve the following order (from top to
|
||||
* 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.session->node);
|
||||
|
||||
/* Adds this to the output layout. The add_auto function arranges outputs
|
||||
* from left-to-right in the order they appear. A more sophisticated
|
||||
* compositor would let the user configure the arrangement of outputs in the
|
||||
* layout.
|
||||
*
|
||||
* The output layout utility automatically adds a wl_output global to the
|
||||
* display, which Wayland clients can see to find out information about the
|
||||
* output (such as DPI, scale factor, manufacturer, etc).
|
||||
*/
|
||||
struct wlr_output_layout_output *l_output = wlr_output_layout_add_auto(server->output_layout,
|
||||
wlr_output);
|
||||
struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, wlr_output);
|
||||
wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output);
|
||||
}
|
||||
wlr_output_state_set_enabled(&output->pending_state, true);
|
||||
|
||||
/* 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);
|
||||
if (!output_test_auto(wlr_output, &output->pending_state,
|
||||
/* is_client_request */ false))
|
||||
{
|
||||
wlr_log(WLR_INFO, "mode test failed for output %s",
|
||||
wlr_output->name);
|
||||
/*
|
||||
* Continue anyway. For some reason, the test fails when
|
||||
* running nested, yet the following commit succeeds.
|
||||
*/
|
||||
}
|
||||
output_state_commit(output);
|
||||
wlr_output_effective_resolution(wlr_output,
|
||||
&output->usable_area.width, &output->usable_area.height);
|
||||
g_pending_output_layout_change++;
|
||||
add_output_to_layout(server, output);
|
||||
g_pending_output_layout_change--;
|
||||
do_output_layout_change(server);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -235,22 +479,324 @@ void diyac_output_usable_area(struct diyac_output *output,struct wlr_box* area)
|
||||
output->wlr_output, &ox, &oy);
|
||||
box.x -= ox;
|
||||
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;
|
||||
}
|
||||
struct wlr_box box = {0};
|
||||
wlr_output_effective_resolution(output->wlr_output,
|
||||
&box.width, &box.height);
|
||||
&box.width, &box.height);
|
||||
double ox = 0, oy = 0;
|
||||
wlr_output_layout_output_coords(output->server->output_layout,
|
||||
output->wlr_output, &ox, &oy);
|
||||
output->wlr_output, &ox, &oy);
|
||||
box.x -= ox;
|
||||
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);
|
||||
}
|
||||
3
output.h
3
output.h
@@ -2,9 +2,10 @@
|
||||
#define DIYAC_OUTPUT_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);
|
||||
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_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
|
||||
128
protocol/wlr-output-power-management-unstable-v1.xml
Normal file
128
protocol/wlr-output-power-management-unstable-v1.xml
Normal 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>
|
||||
370
seat.c
370
seat.c
@@ -4,32 +4,54 @@
|
||||
#include <stdlib.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <assert.h>
|
||||
#include <strings.h>
|
||||
#include <wlr/types/wlr_touch.h>
|
||||
#include "seat.h"
|
||||
#include "view.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;
|
||||
assert(device->type == WLR_INPUT_DEVICE_KEYBOARD);
|
||||
struct diyac_keyboard *keyboard = (struct diyac_keyboard *)input;
|
||||
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,
|
||||
* XKB_DEFAULT_OPTIONS, and friends.
|
||||
*/
|
||||
struct xkb_rule_names rules = { 0 };
|
||||
* Set layout based on environment variables XKB_DEFAULT_LAYOUT,
|
||||
* XKB_DEFAULT_OPTIONS, and friends.
|
||||
*/
|
||||
struct xkb_rule_names rules = {0};
|
||||
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);
|
||||
if (keymap) {
|
||||
if (!wlr_keyboard_keymaps_match(kb->keymap, keymap)) {
|
||||
struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
|
||||
if (keymap)
|
||||
{
|
||||
if (!wlr_keyboard_keymaps_match(kb->keymap, keymap))
|
||||
{
|
||||
wlr_keyboard_set_keymap(kb, keymap);
|
||||
}
|
||||
xkb_keymap_unref(keymap);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
wlr_log(WLR_ERROR, "Failed to create xkb keymap");
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void keyboard_handle_modifiers(
|
||||
struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)data;
|
||||
/* This event is raised when a modifier key, such as shift or alt, is
|
||||
* pressed. We simply communicate this to the client. */
|
||||
struct diyac_keyboard *keyboard =
|
||||
@@ -95,7 +117,7 @@ static void keyboard_handle_key(
|
||||
wl_container_of(listener, keyboard, key);
|
||||
struct wlr_keyboard_key_event *event = data;
|
||||
struct wlr_seat *seat = keyboard->input.seat->wlr_seat;
|
||||
|
||||
diyac_idle_manager_notify_activity(keyboard->input.seat);
|
||||
/* Translate libinput keycode -> xkbcommon */
|
||||
// wlr_log(WLR_INFO, "receive keycode %d", event->keycode);
|
||||
uint32_t keycode = event->keycode + 8;
|
||||
@@ -113,7 +135,7 @@ static void keyboard_handle_key(
|
||||
* process it as a compositor keybinding. */
|
||||
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)
|
||||
{
|
||||
(void)data;
|
||||
/* 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
|
||||
* 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->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;
|
||||
if(keyboard->is_virtual)
|
||||
struct diyac_keyboard *keyboard = (struct diyac_keyboard *)input;
|
||||
if (keyboard->is_virtual)
|
||||
{
|
||||
wlr_log(WLR_INFO, "Virtual keyboard destroyed");
|
||||
}
|
||||
@@ -149,8 +172,8 @@ static void input_handle_destroy(struct wl_listener *listener, void *data)
|
||||
free(input);
|
||||
}
|
||||
|
||||
static struct diyac_input* server_new_keyboard(struct diyac_seat *seat,
|
||||
struct wlr_input_device *device, bool is_virtual)
|
||||
static struct diyac_input *server_new_keyboard(struct diyac_seat *seat,
|
||||
struct wlr_input_device *device, bool is_virtual)
|
||||
{
|
||||
struct wlr_keyboard *wlr_keyboard = wlr_keyboard_from_input_device(device);
|
||||
|
||||
@@ -164,36 +187,203 @@ static struct diyac_input* server_new_keyboard(struct diyac_seat *seat,
|
||||
* Force configure default keyboard keymap for all new
|
||||
* keyboard, including virtual keyboard
|
||||
*/
|
||||
configure_keyboard(seat,&keyboard->input, true);
|
||||
configure_keyboard(seat, &keyboard->input, true);
|
||||
|
||||
/* Here we set up listeners for keyboard events. */
|
||||
keyboard->modifiers.notify = keyboard_handle_modifiers;
|
||||
wl_signal_add(&wlr_keyboard->events.modifiers, &keyboard->modifiers);
|
||||
|
||||
|
||||
keyboard->key.notify = keyboard_handle_key;
|
||||
wl_signal_add(&wlr_keyboard->events.key, &keyboard->key);
|
||||
|
||||
wlr_seat_set_keyboard(seat->wlr_seat, keyboard->wlr_keyboard);
|
||||
|
||||
/* And add the keyboard to our list of keyboards */
|
||||
//wl_list_insert(&server->seat.keyboards, &keyboard->link);
|
||||
return (struct diyac_input*) keyboard;
|
||||
// wl_list_insert(&server->seat.keyboards, &keyboard->link);
|
||||
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,
|
||||
struct wlr_input_device *device)
|
||||
if (!wlr_input_device_is_libinput(wlr_input_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));
|
||||
input->device = device;
|
||||
/* We don't do anything special with pointers. All of our pointer handling
|
||||
* is proxied through wlr_cursor. On another compositor, you might take this
|
||||
* opportunity to do libinput configuration on the device to set
|
||||
* acceleration, etc. */
|
||||
device->data = input;
|
||||
/**
|
||||
* @TODO:
|
||||
* configure pointer via libinput
|
||||
*
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
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->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. */
|
||||
uint32_t caps = 0;
|
||||
|
||||
wl_list_for_each(input, &seat->inputs, link) {
|
||||
switch (input->device->type) {
|
||||
wl_list_for_each(input, &seat->inputs, link)
|
||||
{
|
||||
switch (input->device->type)
|
||||
{
|
||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||
caps |= WL_SEAT_CAPABILITY_KEYBOARD;
|
||||
break;
|
||||
@@ -231,7 +423,7 @@ static void server_new_input(struct wl_listener *listener, void *data)
|
||||
struct diyac_seat *seat =
|
||||
wl_container_of(listener, seat, new_input);
|
||||
struct wlr_input_device *device = data;
|
||||
struct diyac_input* input = NULL;
|
||||
struct diyac_input *input = NULL;
|
||||
|
||||
switch (device->type)
|
||||
{
|
||||
@@ -241,34 +433,15 @@ static void server_new_input(struct wl_listener *listener, void *data)
|
||||
case WLR_INPUT_DEVICE_POINTER:
|
||||
input = server_new_pointer(seat, device);
|
||||
break;
|
||||
default:
|
||||
case WLR_INPUT_DEVICE_TOUCH:
|
||||
input = server_new_touch(seat, device);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
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)
|
||||
{
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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.request_cursor.notify = seat_request_cursor;
|
||||
wl_signal_add(&server->seat.wlr_seat->events.request_set_cursor,
|
||||
&server->seat.request_cursor);
|
||||
|
||||
wl_list_init(&server->seat.touch_points);
|
||||
wl_list_init(&server->seat.inputs);
|
||||
|
||||
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,
|
||||
&server->seat.request_set_selection);
|
||||
|
||||
@@ -342,10 +504,20 @@ void diyac_init_seat(struct diyac_server *server)
|
||||
// virtual keyboard support
|
||||
server->seat.virtual_keyboard_manager = wlr_virtual_keyboard_manager_v1_create(server->wl_display);
|
||||
wl_signal_add(&server->seat.virtual_keyboard_manager->events.new_virtual_keyboard,
|
||||
&server->seat.virtual_keyboard_new);
|
||||
&server->seat.virtual_keyboard_new);
|
||||
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)
|
||||
{
|
||||
/*
|
||||
@@ -414,13 +586,13 @@ void diyac_seat_focus_layer(struct diyac_seat *seat, struct wlr_layer_surface_v1
|
||||
return;
|
||||
*/
|
||||
}
|
||||
if(seat->focused_layer == layer)
|
||||
if (seat->focused_layer == layer)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(seat->focused_layer)
|
||||
wlr_log(WLR_INFO,"Layer focus changed %s -> %s", seat->focused_layer->namespace, layer->namespace);
|
||||
|
||||
if (seat->focused_layer)
|
||||
wlr_log(WLR_INFO, "Layer focus changed %s -> %s", seat->focused_layer->namespace, layer->namespace);
|
||||
|
||||
// unfocus currently focus 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_input* input = NULL;
|
||||
struct diyac_seat *seat = &server->seat;
|
||||
struct diyac_input *input = NULL;
|
||||
|
||||
wl_list_for_each(input, &seat->inputs, link)
|
||||
{
|
||||
switch (input->device->type) {
|
||||
switch (input->device->type)
|
||||
{
|
||||
case WLR_INPUT_DEVICE_KEYBOARD:
|
||||
configure_keyboard(seat, input, false);
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_POINTER:
|
||||
/*TODO: reconfigure libinput*/
|
||||
break;
|
||||
case WLR_INPUT_DEVICE_TOUCH:
|
||||
/*TODO: reconfigure libinput*/
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -457,31 +632,54 @@ 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 wl_list *node_list = & scene->children;
|
||||
struct wl_list *node_list = &scene->children;
|
||||
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;
|
||||
if (!node->enabled || !node_descriptor || node_descriptor->type != DIYAC_NODE_LAYER_SURFACE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
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;
|
||||
if(!surface->mapped || layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE)
|
||||
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;
|
||||
if (!surface->mapped || layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE)
|
||||
{
|
||||
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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
seat->focused_layer = NULL;
|
||||
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
4
seat.h
@@ -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_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_pointer_end_grab(struct diyac_seat *seat, struct wlr_surface *surface);
|
||||
void diyac_seat_configure(struct diyac_server* server);
|
||||
|
||||
void diyac_release_seat(struct diyac_server* server);
|
||||
#endif
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_output_lock_handle *handle = wl_container_of(listener, handle, surface_map);
|
||||
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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_output_lock_handle *handle = wl_container_of(listener, handle, surface_destroy);
|
||||
|
||||
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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_session_lock *lock = wl_container_of(listener, lock, unlock);
|
||||
wlr_log(WLR_INFO, "handle_unlock: Lock session is unlocked");
|
||||
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)
|
||||
{
|
||||
(void) data;
|
||||
struct diyac_session_lock *lock = wl_container_of(listener, lock, destroy);
|
||||
lock->abandoned = true;
|
||||
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)
|
||||
{
|
||||
(void) listener;
|
||||
struct wlr_session_lock_v1 *lock = data;
|
||||
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)
|
||||
{
|
||||
(void) data;
|
||||
(void) listener;
|
||||
if (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);
|
||||
if (!handle->background)
|
||||
{
|
||||
wlr_scene_node_destroy(&handle->tree->node);
|
||||
free(handle);
|
||||
wlr_log(WLR_ERROR, "diyac_session_lock_output:Unable to create lock background");
|
||||
wlr_scene_node_destroy(&handle->tree->node);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
handle->surface = NULL;
|
||||
|
||||
190
touch.c
Normal file
190
touch.c
Normal 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
8
touch.h
Normal 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
37
view.c
@@ -26,10 +26,9 @@ static int handle_configure_timeout(void *data)
|
||||
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 = wlr_xdg_toplevel_set_size(view->xdg_toplevel, geo.width, geo.height);
|
||||
view->configuration_serial = serial;
|
||||
if (!view->configuration_timeout)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 wlr_surface *prev =
|
||||
server->seat.wlr_seat->keyboard_state.focused_surface;
|
||||
//struct wlr_surface *prev =
|
||||
// server->seat.wlr_seat->keyboard_state.focused_surface;
|
||||
struct diyac_view *view;
|
||||
struct wl_list *node_list;
|
||||
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)
|
||||
{
|
||||
struct wlr_box size;
|
||||
struct wlr_box* size = NULL;
|
||||
int current_x, current_y, next_x, next_y;
|
||||
if(!view->mapped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
wlr_scene_node_coords(&view->scene_tree->node, ¤t_x, ¤t_y);
|
||||
wlr_xdg_surface_get_geometry(view->xdg_surface, &size);
|
||||
size = &view->xdg_surface->geometry;
|
||||
|
||||
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->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
|
||||
{
|
||||
@@ -488,15 +501,15 @@ void diyac_view_sync_geo(struct diyac_view *view)
|
||||
(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->pending_size.y + view->pending_size.height - size.height;
|
||||
view->original.y = view->pending_size.y + view->pending_size.height - size->height;
|
||||
}
|
||||
else
|
||||
{
|
||||
view->original.y = view->pending_size.y;
|
||||
}
|
||||
|
||||
view->original.width = size.width;
|
||||
view->original.height = size.height;
|
||||
view->original.width = size->width;
|
||||
view->original.height = size->height;
|
||||
next_x = view->original.x;
|
||||
next_y = view->original.y;
|
||||
view->pending_size = view->original;
|
||||
|
||||
1
view.h
1
view.h
@@ -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_sync_geo(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
|
||||
139
xdg.c
139
xdg.c
@@ -20,7 +20,7 @@ static void begin_interactive(struct diyac_view *toplevel,
|
||||
struct diyac_server *server = toplevel->server;
|
||||
struct wlr_surface *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))
|
||||
{
|
||||
/* Deny move/resize requests from unfocused clients. */
|
||||
@@ -36,17 +36,16 @@ static void begin_interactive(struct diyac_view *toplevel,
|
||||
}
|
||||
else
|
||||
{
|
||||
struct wlr_box geo_box;
|
||||
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
|
||||
struct wlr_box* geo_box = &toplevel->xdg_toplevel->base->geometry;
|
||||
|
||||
double border_x = (toplevel->scene_tree->node.x + geo_box.x) +
|
||||
((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
|
||||
double border_y = (toplevel->scene_tree->node.y + geo_box.y) +
|
||||
((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0);
|
||||
double border_x = (toplevel->scene_tree->node.x + geo_box->x) +
|
||||
((edges & WLR_EDGE_RIGHT) ? geo_box->width : 0);
|
||||
double border_y = (toplevel->scene_tree->node.y + geo_box->y) +
|
||||
((edges & WLR_EDGE_BOTTOM) ? geo_box->height : 0);
|
||||
server->grab_x = server->seat.cursor->x - border_x;
|
||||
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.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)
|
||||
{
|
||||
struct diyac_view *view = wl_container_of(listener, view, commit);
|
||||
uint32_t serial = view->configuration_serial;
|
||||
if (serial > 0 && serial == view->xdg_surface->current.configure_serial)
|
||||
(void)data;
|
||||
struct diyac_view *toplevel = wl_container_of(listener, toplevel, commit);
|
||||
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);
|
||||
view->configuration_serial = 0;
|
||||
view->configuration_timeout = NULL;
|
||||
uint32_t serial =
|
||||
wlr_xdg_surface_schedule_configure(xdg_surface);
|
||||
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
|
||||
}
|
||||
diyac_view_sync_geo(view);
|
||||
diyac_view_sync_geo(toplevel);
|
||||
}
|
||||
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. */
|
||||
struct diyac_view *toplevel = wl_container_of(listener, toplevel, map);
|
||||
if (toplevel->mapped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
diyac_init_foreign_toplevel(toplevel);
|
||||
/*
|
||||
wlr_xdg_toplevel_set_wm_capabilities(toplevel->xdg_toplevel,
|
||||
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE |
|
||||
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MINIMIZE);
|
||||
//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);
|
||||
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_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)
|
||||
{
|
||||
(void)data;
|
||||
/* Called when the surface is unmapped, and should no longer be shown. */
|
||||
struct diyac_view *toplevel = wl_container_of(listener, toplevel, unmap);
|
||||
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->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(
|
||||
struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)data;
|
||||
/* This event is raised when a client would like to begin an interactive
|
||||
* move, typically because the user clicked on their client-side
|
||||
* 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(
|
||||
struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)data;
|
||||
/* This event is raised when a client would like to maximize itself,
|
||||
* typically because the user clicked on the maximize button on
|
||||
* 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)
|
||||
{
|
||||
(void)data;
|
||||
struct diyac_view *toplevel =
|
||||
wl_container_of(listener, toplevel, request_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)
|
||||
{
|
||||
(void)data;
|
||||
struct diyac_view *toplevel =
|
||||
wl_container_of(listener, toplevel, request_minimize);
|
||||
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)
|
||||
{
|
||||
(void)data;
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
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)
|
||||
{
|
||||
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);
|
||||
toplevel->configuration_timeout = NULL;
|
||||
}
|
||||
if(toplevel->mapped)
|
||||
{
|
||||
wl_list_remove(&toplevel->commit.link);
|
||||
}
|
||||
wl_list_remove(&toplevel->map.link);
|
||||
wl_list_remove(&toplevel->unmap.link);
|
||||
wl_list_remove(&toplevel->commit.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);
|
||||
}
|
||||
|
||||
static void handle_xdg_popup_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
(void)data;
|
||||
struct diyac_popup *popup = wl_container_of(listener, popup, destroy);
|
||||
wl_list_remove(&popup->destroy.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)
|
||||
{
|
||||
struct diyac_view *view = popup->parent;
|
||||
if(!view->output)
|
||||
if (!view->output)
|
||||
{
|
||||
return;
|
||||
}
|
||||
struct diyac_server *server = view->server;
|
||||
struct wlr_output_layout *output_layout = server->output_layout;
|
||||
struct wlr_output *wlr_output = view->output->wlr_output;
|
||||
// struct diyac_server *server = view->server;
|
||||
//struct wlr_output_layout *output_layout = server->output_layout;
|
||||
//struct wlr_output *wlr_output = view->output->wlr_output;
|
||||
struct wlr_box usable = {
|
||||
.x = 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)
|
||||
{
|
||||
(void)data;
|
||||
struct diyac_popup *popup = wl_container_of(listener, popup, commit);
|
||||
struct wlr_box popup_box;
|
||||
wlr_xdg_surface_get_geometry(popup->wlr_popup->base, &popup_box);
|
||||
struct wlr_box* popup_box = &popup->wlr_popup->base->geometry;
|
||||
popup_unconstrain(popup);
|
||||
if (!wlr_box_empty(&popup_box))
|
||||
if (!wlr_box_empty(popup_box))
|
||||
// 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);
|
||||
/* Prevent getting called over and over again */
|
||||
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)
|
||||
{
|
||||
(void)data;
|
||||
struct diyac_view *view = wl_container_of(listener, view, set_app_id);
|
||||
diyac_view_update_app_id(view);
|
||||
}
|
||||
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
||||
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
|
||||
* client, either a toplevel (application window) or popup. */
|
||||
struct diyac_server *server =
|
||||
wl_container_of(listener, server, new_xdg_surface);
|
||||
struct wlr_xdg_surface *xdg_surface = data;
|
||||
wl_container_of(listener, server, new_xdg_toplevel);
|
||||
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);
|
||||
wlr_log(WLR_INFO, "diyac_new_xdg_surface: Creating new application windows");
|
||||
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);
|
||||
diyac_node_descriptor_create(&toplevel->scene_tree->node,
|
||||
DIYAC_NODE_VIEW, toplevel);
|
||||
diyac_init_foreign_toplevel(toplevel);
|
||||
|
||||
/* Listen to the various events it can emit */
|
||||
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);
|
||||
|
||||
/* cotd */
|
||||
struct wlr_xdg_toplevel *xdg_toplevel = xdg_surface->toplevel;
|
||||
toplevel->request_move.notify = xdg_toplevel_request_move;
|
||||
wl_signal_add(&xdg_toplevel->events.request_move, &toplevel->request_move);
|
||||
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;
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user