feat: add support layershell protocol
This commit is contained in:
parent
c1960f0438
commit
55719d6dba
12
Makefile
12
Makefile
@ -10,8 +10,12 @@ OBJS=\
|
|||||||
cursor.c \
|
cursor.c \
|
||||||
output.c \
|
output.c \
|
||||||
seat.c \
|
seat.c \
|
||||||
|
node.c \
|
||||||
|
desktop.c \
|
||||||
xdg.c \
|
xdg.c \
|
||||||
xdg-shell-protocol.c
|
xdg-shell-protocol.c \
|
||||||
|
layer.c \
|
||||||
|
wlr-layer-shell-unstable-v1-protocol.c
|
||||||
|
|
||||||
# wayland-scanner is a tool which generates C headers and rigging for Wayland
|
# 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
|
# protocols, which are specified in XML. wlroots requires you to rig these up
|
||||||
@ -24,6 +28,10 @@ xdg-shell-protocol.c: xdg-shell-protocol.h
|
|||||||
$(WAYLAND_SCANNER) private-code \
|
$(WAYLAND_SCANNER) private-code \
|
||||||
$(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@
|
$(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:
|
wlr-layer-shell-unstable-v1-protocol.h:
|
||||||
$(WAYLAND_SCANNER) server-header \
|
$(WAYLAND_SCANNER) server-header \
|
||||||
protocol/wlr-layer-shell-unstable-v1.xml $@
|
protocol/wlr-layer-shell-unstable-v1.xml $@
|
||||||
@ -37,7 +45,7 @@ diyac: $(OBJS)
|
|||||||
$(LIBS)
|
$(LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f diyac xdg-shell-protocol.h xdg-shell-protocol.c
|
rm -f diyac xdg-shell-protocol.* wlr-layer-shell-unstable-v1-protocol.*
|
||||||
|
|
||||||
.DEFAULT_GOAL=diyac
|
.DEFAULT_GOAL=diyac
|
||||||
.PHONY: clean
|
.PHONY: clean
|
41
cursor.c
41
cursor.c
@ -1,23 +1,29 @@
|
|||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200112L
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/util/log.h>
|
||||||
#include <wlr/types/wlr_xcursor_manager.h>
|
#include <assert.h>
|
||||||
#include <wlr/types/wlr_scene.h>
|
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
|
#include "desktop.h"
|
||||||
|
|
||||||
void diyac_reset_cursor_mode(struct diyac_server *server)
|
void diyac_reset_cursor_mode(struct diyac_server *server)
|
||||||
{
|
{
|
||||||
/* Reset the cursor mode to passthrough. */
|
/* Reset the cursor mode to passthrough. */
|
||||||
server->seat.cursor_mode = DIYAC_CURSOR_PASSTHROUGH;
|
server->seat.cursor_mode = DIYAC_CURSOR_PASSTHROUGH;
|
||||||
server->grabbed_toplevel = NULL;
|
server->grabbed_view = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_cursor_move(struct diyac_server *server, uint32_t time)
|
static void process_cursor_move(struct diyac_server *server, uint32_t time)
|
||||||
{
|
{
|
||||||
/* Move the grabbed toplevel to the new position. */
|
/* Move the grabbed toplevel to the new position. */
|
||||||
struct diyac_toplevel *toplevel = server->grabbed_toplevel;
|
struct diyac_view *toplevel = server->grabbed_view;
|
||||||
|
toplevel->current.x = server->seat.cursor->x - server->grab_x;
|
||||||
|
toplevel->current.y = server->seat.cursor->y - server->grab_y;
|
||||||
|
toplevel->state = DIYAC_VIEW_NORMAL;
|
||||||
|
diyac_view_update_geometry(toplevel, false);
|
||||||
|
/*
|
||||||
wlr_scene_node_set_position(&toplevel->scene_tree->node,
|
wlr_scene_node_set_position(&toplevel->scene_tree->node,
|
||||||
server->seat.cursor->x - server->grab_x,
|
toplevel->current.x ,
|
||||||
server->seat.cursor->y - server->grab_y);
|
toplevel->current.y);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_cursor_resize(struct diyac_server *server, uint32_t time)
|
static void process_cursor_resize(struct diyac_server *server, uint32_t time)
|
||||||
@ -32,7 +38,7 @@ static void process_cursor_resize(struct diyac_server *server, uint32_t time)
|
|||||||
* compositor, you'd wait for the client to prepare a buffer at the new
|
* compositor, you'd wait for the client to prepare a buffer at the new
|
||||||
* size, then commit any movement that was prepared.
|
* size, then commit any movement that was prepared.
|
||||||
*/
|
*/
|
||||||
struct diyac_toplevel *toplevel = server->grabbed_toplevel;
|
struct diyac_view *toplevel = server->grabbed_view;
|
||||||
double border_x = server->seat.cursor->x - server->grab_x;
|
double border_x = server->seat.cursor->x - server->grab_x;
|
||||||
double border_y = server->seat.cursor->y - server->grab_y;
|
double border_y = server->seat.cursor->y - server->grab_y;
|
||||||
int new_left = server->grab_geobox.x;
|
int new_left = server->grab_geobox.x;
|
||||||
@ -75,12 +81,19 @@ static void process_cursor_resize(struct diyac_server *server, uint32_t time)
|
|||||||
|
|
||||||
struct wlr_box geo_box;
|
struct wlr_box geo_box;
|
||||||
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
|
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &geo_box);
|
||||||
wlr_scene_node_set_position(&toplevel->scene_tree->node,
|
toplevel->current.x = new_left - geo_box.x;
|
||||||
new_left - geo_box.x, new_top - geo_box.y);
|
toplevel->current.y = new_top - geo_box.y;
|
||||||
|
|
||||||
int new_width = new_right - new_left;
|
int new_width = new_right - new_left;
|
||||||
int new_height = new_bottom - new_top;
|
int new_height = new_bottom - new_top;
|
||||||
|
toplevel->current.width = new_width;
|
||||||
|
toplevel->current.height = new_height;
|
||||||
|
toplevel->state = DIYAC_VIEW_NORMAL;
|
||||||
|
diyac_view_update_geometry(toplevel, true);
|
||||||
|
/*
|
||||||
|
wlr_scene_node_set_position(&toplevel->scene_tree->node,
|
||||||
|
toplevel->current.x, toplevel->current.y);
|
||||||
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, new_width, new_height);
|
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, new_width, new_height);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
static void process_cursor_motion(struct diyac_server *server, uint32_t time)
|
static void process_cursor_motion(struct diyac_server *server, uint32_t time)
|
||||||
@ -101,7 +114,7 @@ static void process_cursor_motion(struct diyac_server *server, uint32_t time)
|
|||||||
double sx, sy;
|
double sx, sy;
|
||||||
struct wlr_seat *seat = server->seat.wlr_seat;
|
struct wlr_seat *seat = server->seat.wlr_seat;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
struct diyac_toplevel *toplevel = diyac_toplevel_at(server,
|
struct diyac_view *toplevel = diyac_view_at(server,
|
||||||
server->seat.cursor->x, server->seat.cursor->y, &surface, &sx, &sy);
|
server->seat.cursor->x, server->seat.cursor->y, &surface, &sx, &sy);
|
||||||
if (!toplevel)
|
if (!toplevel)
|
||||||
{
|
{
|
||||||
@ -180,7 +193,7 @@ static void server_cursor_button(struct wl_listener *listener, void *data)
|
|||||||
event->time_msec, event->button, event->state);
|
event->time_msec, event->button, event->state);
|
||||||
double sx, sy;
|
double sx, sy;
|
||||||
struct wlr_surface *surface = NULL;
|
struct wlr_surface *surface = NULL;
|
||||||
struct diyac_toplevel *toplevel = diyac_toplevel_at(seat->server,
|
struct diyac_view *toplevel = diyac_view_at(seat->server,
|
||||||
seat->cursor->x, seat->cursor->y, &surface, &sx, &sy);
|
seat->cursor->x, seat->cursor->y, &surface, &sx, &sy);
|
||||||
if (event->state == WLR_BUTTON_RELEASED)
|
if (event->state == WLR_BUTTON_RELEASED)
|
||||||
{
|
{
|
||||||
@ -190,7 +203,7 @@ static void server_cursor_button(struct wl_listener *listener, void *data)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Focus that client if the button was _pressed_ */
|
/* Focus that client if the button was _pressed_ */
|
||||||
diyac_focus_toplevel(toplevel, surface);
|
diyac_focus_view(toplevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
226
desktop.c
Normal file
226
desktop.c
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
#define _POSIX_C_SOURCE 200112L
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "desktop.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "seat.h"
|
||||||
|
#include "output.h"
|
||||||
|
|
||||||
|
void diyac_focus_view(struct diyac_view *toplevel)
|
||||||
|
{
|
||||||
|
/* Note: this function only deals with keyboard focus. */
|
||||||
|
if (toplevel == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct diyac_server *server = toplevel->server;
|
||||||
|
struct wlr_surface *prev_surface = server->seat.wlr_seat->keyboard_state.focused_surface;
|
||||||
|
if (prev_surface == toplevel->xdg_toplevel->base->surface)
|
||||||
|
{
|
||||||
|
/* Don't re-focus an already focused surface. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (prev_surface)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Deactivate the previously focused surface. This lets the client know
|
||||||
|
* it no longer has focus and the client will repaint accordingly, e.g.
|
||||||
|
* stop displaying a caret.
|
||||||
|
*/
|
||||||
|
struct wlr_xdg_toplevel *prev_toplevel =
|
||||||
|
wlr_xdg_toplevel_try_from_wlr_surface(prev_surface);
|
||||||
|
if (prev_toplevel != NULL)
|
||||||
|
{
|
||||||
|
wlr_xdg_toplevel_set_activated(prev_toplevel, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Move the toplevel to the front */
|
||||||
|
wlr_scene_node_raise_to_top(&toplevel->scene_tree->node);
|
||||||
|
wl_list_remove(&toplevel->link);
|
||||||
|
wl_list_insert(&server->views, &toplevel->link);
|
||||||
|
/* Activate the new surface */
|
||||||
|
wlr_xdg_toplevel_set_activated(toplevel->xdg_toplevel, true);
|
||||||
|
/*
|
||||||
|
* Tell the seat to have the keyboard enter this surface. wlroots will keep
|
||||||
|
* track of this and automatically send key events to the appropriate
|
||||||
|
* clients without additional work on your part.
|
||||||
|
*/
|
||||||
|
diyac_seat_focus_surface(&server->seat, toplevel->xdg_toplevel->base->surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct diyac_view *diyac_view_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
|
||||||
|
* surface in the surface tree of a diyac_view. */
|
||||||
|
struct wlr_scene_node *node = wlr_scene_node_at(
|
||||||
|
&server->scene->tree.node, lx, ly, sx, sy);
|
||||||
|
if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
|
||||||
|
struct wlr_scene_surface *scene_surface =
|
||||||
|
wlr_scene_surface_try_from_buffer(scene_buffer);
|
||||||
|
if (!scene_surface)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*surface = scene_surface->surface;
|
||||||
|
/* Find the node corresponding to the diyac_view at the root of this
|
||||||
|
* surface tree, it is the only one for which we set the data field. */
|
||||||
|
struct wlr_scene_tree *tree = node->parent;
|
||||||
|
while (tree != NULL && tree->node.data == NULL)
|
||||||
|
{
|
||||||
|
tree = tree->node.parent;
|
||||||
|
}
|
||||||
|
struct diyac_node_descriptor *node_descriptor = tree->node.data;
|
||||||
|
if (!node_descriptor || node_descriptor->type != DIYAC_NODE_VIEW)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return node_descriptor->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void diyac_focus_topmost_view(struct diyac_server *server)
|
||||||
|
{
|
||||||
|
struct diyac_view *view = diyac_topmost_focusable_view(server);
|
||||||
|
if (view)
|
||||||
|
{
|
||||||
|
diyac_focus_view(view);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Defocus previous focused surface/view if no longer
|
||||||
|
* focusable (e.g. unmapped or on a different workspace).
|
||||||
|
*/
|
||||||
|
diyac_seat_focus_surface(&server->seat, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct diyac_view *diyac_topmost_focusable_view(struct diyac_server *server)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
node_list = &server->view_tree->children;
|
||||||
|
wl_list_for_each_reverse(node, node_list, link)
|
||||||
|
{
|
||||||
|
if (!node->data)
|
||||||
|
{
|
||||||
|
/* We found some non-view, most likely the region overlay */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
view = diyac_view_from_node(node);
|
||||||
|
return view;
|
||||||
|
/*
|
||||||
|
if (view->mapped && view_is_focusable_from(view, prev))
|
||||||
|
{
|
||||||
|
return view;
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void diyac_arrange_all_views(struct diyac_server *server)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Adjust window positions/sizes. Skip views with no size since
|
||||||
|
* we can't do anything useful with them; they will presumably
|
||||||
|
* be initialized with valid positions/sizes later.
|
||||||
|
*
|
||||||
|
* We do not simply check view->mapped/been_mapped here because
|
||||||
|
* views can have maximized/fullscreen geometry applied while
|
||||||
|
* still unmapped. We do want to adjust the geometry of those
|
||||||
|
* views.
|
||||||
|
*/
|
||||||
|
struct diyac_view *view;
|
||||||
|
wl_list_for_each(view, &server->views, link)
|
||||||
|
{
|
||||||
|
diyac_view_update_geometry(view, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool diyac_view_update_geometry(struct diyac_view *view, bool resize)
|
||||||
|
{
|
||||||
|
assert(view);
|
||||||
|
bool adjusted = false;
|
||||||
|
struct wlr_box geo_box;
|
||||||
|
struct wlr_box* geometry = &view->current;
|
||||||
|
// if (wlr_output_layout_intersects(view->server->output_layout,
|
||||||
|
// view->output->wlr_output, &view->current))
|
||||||
|
//{
|
||||||
|
struct wlr_box usable = diyac_output_usable_area(view->output);
|
||||||
|
wlr_log(WLR_INFO, "diyac_view_update_geometry: current: [%d,%d,%d,%d], usable: [%d,%d,%d,%d] ",
|
||||||
|
geometry->x, geometry->y, geometry->width, geometry->height,
|
||||||
|
usable.x, usable.y, usable.width, usable.height);
|
||||||
|
|
||||||
|
switch (view->state)
|
||||||
|
{
|
||||||
|
case DIYAC_VIEW_MAXIMIZE:
|
||||||
|
/**
|
||||||
|
* We dont change the current_view geometry in maximize state
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
wlr_scene_node_set_position(&view->scene_tree->node, usable.x, usable.y);
|
||||||
|
wlr_xdg_toplevel_set_size(view->xdg_toplevel, usable.width, usable.height);
|
||||||
|
return true;
|
||||||
|
case DIYAC_VIEW_MINIMIZE:
|
||||||
|
wlr_log(WLR_INFO, "diyac_view_update_geometry: minimize ignore");
|
||||||
|
return false;
|
||||||
|
case DIYAC_VIEW_FULL_SCREEN:
|
||||||
|
wlr_log(WLR_INFO, "diyac_view_update_geometry: full-screen ignore");
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
|
||||||
|
if(!wlr_box_equal(geometry, &geo_box))
|
||||||
|
{
|
||||||
|
adjusted = true;
|
||||||
|
}
|
||||||
|
/**Normal state, recalculate current geometry*/
|
||||||
|
if (geometry->x < usable.x)
|
||||||
|
{
|
||||||
|
geometry->x = usable.x;
|
||||||
|
adjusted = true;
|
||||||
|
}
|
||||||
|
if((! resize) && (geometry->x + geometry->width > usable.width))
|
||||||
|
{
|
||||||
|
geometry->x = usable.width - geometry->width;
|
||||||
|
adjusted = true;
|
||||||
|
}
|
||||||
|
if (geometry->y < usable.y)
|
||||||
|
{
|
||||||
|
geometry->y = usable.y;
|
||||||
|
adjusted = true;
|
||||||
|
}
|
||||||
|
if((! resize) && (geometry->y + geometry->height > usable.height))
|
||||||
|
{
|
||||||
|
geometry->y = usable.height - geometry->height;
|
||||||
|
adjusted = true;
|
||||||
|
}
|
||||||
|
if (resize && geometry->width > usable.width)
|
||||||
|
{
|
||||||
|
geometry->width = usable.width;
|
||||||
|
adjusted = true;
|
||||||
|
}
|
||||||
|
if (resize && geometry->height > usable.height)
|
||||||
|
{
|
||||||
|
geometry->height = usable.height;
|
||||||
|
adjusted = true;
|
||||||
|
}
|
||||||
|
if (adjusted)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_INFO, "diyac_view_update_geometry: updating geometry");
|
||||||
|
wlr_scene_node_set_position(&view->scene_tree->node, geometry->x, geometry->y);
|
||||||
|
wlr_xdg_toplevel_set_size(view->xdg_toplevel, geometry->width, geometry->height);
|
||||||
|
}
|
||||||
|
return adjusted;
|
||||||
|
}
|
||||||
|
}
|
12
desktop.h
Normal file
12
desktop.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef DIYAC_DESKTOP_H
|
||||||
|
#define DIYAC_DESKTOP_H
|
||||||
|
#include "diyac.h"
|
||||||
|
void diyac_focus_view(struct diyac_view *toplevel);
|
||||||
|
struct diyac_view *diyac_view_at(
|
||||||
|
struct diyac_server *server, double lx, double ly,
|
||||||
|
struct wlr_surface **surface, double *sx, double *sy);
|
||||||
|
void diyac_focus_topmost_view(struct diyac_server *server);
|
||||||
|
struct diyac_view * diyac_topmost_focusable_view(struct diyac_server *server);
|
||||||
|
bool diyac_view_update_geometry(struct diyac_view *view, bool resize);
|
||||||
|
void diyac_arrange_all_views(struct diyac_server *server);
|
||||||
|
#endif
|
104
diyac.c
104
diyac.c
@ -3,100 +3,12 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <wlr/types/wlr_scene.h>
|
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include <wlr/render/allocator.h>
|
|
||||||
#include <wlr/types/wlr_compositor.h>
|
|
||||||
#include <wlr/types/wlr_subcompositor.h>
|
|
||||||
#include <wlr/types/wlr_data_device.h>
|
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
|
||||||
#include <wlr/types/wlr_xcursor_manager.h>
|
|
||||||
|
|
||||||
#include "diyac.h"
|
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
#include "xdg.h"
|
#include "xdg.h"
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
#include "seat.h"
|
#include "seat.h"
|
||||||
|
#include "layer.h"
|
||||||
void diyac_focus_toplevel(struct diyac_toplevel *toplevel, struct wlr_surface *surface)
|
|
||||||
{
|
|
||||||
/* Note: this function only deals with keyboard focus. */
|
|
||||||
if (toplevel == NULL)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
struct diyac_server *server = toplevel->server;
|
|
||||||
struct wlr_seat *seat = server->seat.wlr_seat;
|
|
||||||
struct wlr_surface *prev_surface = seat->keyboard_state.focused_surface;
|
|
||||||
if (prev_surface == surface)
|
|
||||||
{
|
|
||||||
/* Don't re-focus an already focused surface. */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (prev_surface)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Deactivate the previously focused surface. This lets the client know
|
|
||||||
* it no longer has focus and the client will repaint accordingly, e.g.
|
|
||||||
* stop displaying a caret.
|
|
||||||
*/
|
|
||||||
struct wlr_xdg_toplevel *prev_toplevel =
|
|
||||||
wlr_xdg_toplevel_try_from_wlr_surface(prev_surface);
|
|
||||||
if (prev_toplevel != NULL)
|
|
||||||
{
|
|
||||||
wlr_xdg_toplevel_set_activated(prev_toplevel, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat);
|
|
||||||
/* Move the toplevel to the front */
|
|
||||||
wlr_scene_node_raise_to_top(&toplevel->scene_tree->node);
|
|
||||||
wl_list_remove(&toplevel->link);
|
|
||||||
wl_list_insert(&server->toplevels, &toplevel->link);
|
|
||||||
/* Activate the new surface */
|
|
||||||
wlr_xdg_toplevel_set_activated(toplevel->xdg_toplevel, true);
|
|
||||||
/*
|
|
||||||
* Tell the seat to have the keyboard enter this surface. wlroots will keep
|
|
||||||
* track of this and automatically send key events to the appropriate
|
|
||||||
* clients without additional work on your part.
|
|
||||||
*/
|
|
||||||
if (keyboard != NULL)
|
|
||||||
{
|
|
||||||
wlr_seat_keyboard_notify_enter(seat, toplevel->xdg_toplevel->base->surface,
|
|
||||||
keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct diyac_toplevel *diyac_toplevel_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
|
|
||||||
* surface in the surface tree of a diyac_toplevel. */
|
|
||||||
struct wlr_scene_node *node = wlr_scene_node_at(
|
|
||||||
&server->scene->tree.node, lx, ly, sx, sy);
|
|
||||||
if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
|
|
||||||
struct wlr_scene_surface *scene_surface =
|
|
||||||
wlr_scene_surface_try_from_buffer(scene_buffer);
|
|
||||||
if (!scene_surface)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*surface = scene_surface->surface;
|
|
||||||
/* Find the node corresponding to the diyac_toplevel at the root of this
|
|
||||||
* surface tree, it is the only one for which we set the data field. */
|
|
||||||
struct wlr_scene_tree *tree = node->parent;
|
|
||||||
while (tree != NULL && tree->node.data == NULL)
|
|
||||||
{
|
|
||||||
tree = tree->node.parent;
|
|
||||||
}
|
|
||||||
return tree->node.data;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -196,20 +108,20 @@ int main(int argc, char *argv[])
|
|||||||
* used for application windows. For more detail on shells, refer to
|
* used for application windows. For more detail on shells, refer to
|
||||||
* https://drewdevault.com/2018/07/29/Wayland-shells.html.
|
* https://drewdevault.com/2018/07/29/Wayland-shells.html.
|
||||||
*/
|
*/
|
||||||
wl_list_init(&server.toplevels);
|
wl_list_init(&server.views);
|
||||||
|
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, 3);
|
server.xdg_shell = wlr_xdg_shell_create(server.wl_display, 3);
|
||||||
server.new_xdg_surface.notify = diyac_new_xdg_surface;
|
server.new_xdg_surface.notify = diyac_new_xdg_surface;
|
||||||
wl_signal_add(&server.xdg_shell->events.new_surface,
|
wl_signal_add(&server.xdg_shell->events.new_surface,
|
||||||
&server.new_xdg_surface);
|
&server.new_xdg_surface);
|
||||||
|
|
||||||
/**
|
server.layer_shell = wlr_layer_shell_v1_create(server.wl_display,4);
|
||||||
* TODO
|
server.new_layer_surface.notify = diyac_new_layer_surface;
|
||||||
*
|
|
||||||
|
|
||||||
server.new_layer_surface.notify = server_new_layer_surface;
|
|
||||||
wl_signal_add(&server.layer_shell->events.new_surface,
|
wl_signal_add(&server.layer_shell->events.new_surface,
|
||||||
&server.new_layer_surface);
|
&server.new_layer_surface);
|
||||||
*/
|
|
||||||
diyac_init_cursor_manager(&server);
|
diyac_init_cursor_manager(&server);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
102
diyac.h
102
diyac.h
@ -4,6 +4,16 @@
|
|||||||
#include <wlr/backend.h>
|
#include <wlr/backend.h>
|
||||||
#include <wlr/types/wlr_xdg_shell.h>
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
#include <wlr/types/wlr_layer_shell_v1.h>
|
#include <wlr/types/wlr_layer_shell_v1.h>
|
||||||
|
#include <wlr/types/wlr_scene.h>
|
||||||
|
#include <wlr/types/wlr_cursor.h>
|
||||||
|
#include <wlr/types/wlr_xcursor_manager.h>
|
||||||
|
#include <wlr/render/allocator.h>
|
||||||
|
#include <wlr/types/wlr_compositor.h>
|
||||||
|
#include <wlr/types/wlr_subcompositor.h>
|
||||||
|
#include <wlr/types/wlr_data_device.h>
|
||||||
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
|
||||||
|
#define LAYER_TREE_SZ 4
|
||||||
/* For brevity's sake, struct members are annotated where they are used. */
|
/* For brevity's sake, struct members are annotated where they are used. */
|
||||||
enum diyac_cursor_mode
|
enum diyac_cursor_mode
|
||||||
{
|
{
|
||||||
@ -12,25 +22,76 @@ enum diyac_cursor_mode
|
|||||||
DIYAC_CURSOR_RESIZE,
|
DIYAC_CURSOR_RESIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct diyac_seat {
|
enum diyac_node_descriptor_type
|
||||||
|
{
|
||||||
|
DIYAC_NODE_NONE = 0,
|
||||||
|
DIYAC_NODE_VIEW,
|
||||||
|
DIYAC_NODE_XDG_POPUP,
|
||||||
|
DIYAC_NODE_LAYER_SURFACE,
|
||||||
|
DIYAC_NODE_LAYER_POPUP,
|
||||||
|
DIYAC_NODE_TREE,
|
||||||
|
// DIYAC_NODE_MENUITEM,
|
||||||
|
// LAB_NODE_TREE,
|
||||||
|
// LAB_NODE_SSD_BUTTON,
|
||||||
|
};
|
||||||
|
enum diyac_view_state
|
||||||
|
{
|
||||||
|
DIYAC_VIEW_NORMAL = 0,
|
||||||
|
DIYAC_VIEW_MAXIMIZE,
|
||||||
|
DIYAC_VIEW_MINIMIZE,
|
||||||
|
DIYAC_VIEW_FULL_SCREEN,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct diyac_seat
|
||||||
|
{
|
||||||
struct wlr_seat *wlr_seat;
|
struct wlr_seat *wlr_seat;
|
||||||
struct diyac_server *server;
|
struct diyac_server *server;
|
||||||
|
|
||||||
struct wlr_cursor *cursor;
|
struct wlr_cursor *cursor;
|
||||||
enum diyac_cursor_mode cursor_mode;
|
enum diyac_cursor_mode cursor_mode;
|
||||||
struct wlr_xcursor_manager *cursor_mgr;
|
struct wlr_xcursor_manager *cursor_mgr;
|
||||||
|
|
||||||
|
struct wlr_layer_surface_v1 *focused_layer;
|
||||||
|
|
||||||
struct wl_listener cursor_motion;
|
struct wl_listener cursor_motion;
|
||||||
struct wl_listener cursor_motion_absolute;
|
struct wl_listener cursor_motion_absolute;
|
||||||
struct wl_listener cursor_button;
|
struct wl_listener cursor_button;
|
||||||
struct wl_listener cursor_axis;
|
struct wl_listener cursor_axis;
|
||||||
struct wl_listener cursor_frame;
|
struct wl_listener cursor_frame;
|
||||||
|
|
||||||
struct wl_listener new_input;
|
struct wl_listener new_input;
|
||||||
struct wl_listener request_cursor;
|
struct wl_listener request_cursor;
|
||||||
struct wl_listener request_set_selection;
|
struct wl_listener request_set_selection;
|
||||||
struct wl_list keyboards;
|
struct wl_list keyboards;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct diyac_popup
|
||||||
|
{
|
||||||
|
struct wlr_xdg_popup *wlr_popup;
|
||||||
|
struct wlr_scene_tree *scene_tree;
|
||||||
|
struct wl_listener commit;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
struct wl_listener new_popup;
|
||||||
|
struct wlr_box output_toplevel_sx_box;
|
||||||
|
void *parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct diyac_layer_scenes
|
||||||
|
{
|
||||||
|
struct wlr_scene_tree *background;
|
||||||
|
struct wlr_scene_tree *bottom;
|
||||||
|
struct wlr_scene_tree *top;
|
||||||
|
struct wlr_scene_tree *overlay;
|
||||||
|
struct wlr_scene_tree *popup;
|
||||||
|
struct wlr_scene_tree *session;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct diyac_node_descriptor
|
||||||
|
{
|
||||||
|
enum diyac_node_descriptor_type type;
|
||||||
|
void *data;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
};
|
||||||
|
|
||||||
struct diyac_server
|
struct diyac_server
|
||||||
{
|
{
|
||||||
struct wl_display *wl_display;
|
struct wl_display *wl_display;
|
||||||
@ -44,11 +105,17 @@ struct diyac_server
|
|||||||
struct wlr_layer_shell_v1 *layer_shell;
|
struct wlr_layer_shell_v1 *layer_shell;
|
||||||
struct wl_listener new_xdg_surface;
|
struct wl_listener new_xdg_surface;
|
||||||
struct wl_listener new_layer_surface;
|
struct wl_listener new_layer_surface;
|
||||||
struct wl_list toplevels;
|
struct wl_list views;
|
||||||
|
/*
|
||||||
|
* Popups need to be rendered above always-on-top views, so we reparent
|
||||||
|
* them to this dedicated tree
|
||||||
|
*/
|
||||||
|
struct wlr_scene_tree *xdg_popup_tree;
|
||||||
|
struct wlr_scene_tree *view_tree;
|
||||||
|
|
||||||
struct diyac_seat seat;
|
struct diyac_seat seat;
|
||||||
|
|
||||||
struct diyac_toplevel *grabbed_toplevel;
|
struct diyac_view *grabbed_view;
|
||||||
double grab_x, grab_y;
|
double grab_x, grab_y;
|
||||||
struct wlr_box grab_geobox;
|
struct wlr_box grab_geobox;
|
||||||
uint32_t resize_edges;
|
uint32_t resize_edges;
|
||||||
@ -79,18 +146,31 @@ struct diyac_output
|
|||||||
struct wl_listener frame;
|
struct wl_listener frame;
|
||||||
struct wl_listener request_state;
|
struct wl_listener request_state;
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
|
struct wlr_box usable_area;
|
||||||
|
|
||||||
// layer output
|
// layer output
|
||||||
struct wlr_scene_tree *layer_tree[4];
|
struct diyac_layer_scenes scenes;
|
||||||
|
// alias to diyac_layer_scenes elements
|
||||||
|
struct wlr_scene_tree *layer_tree[LAYER_TREE_SZ];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct diyac_toplevel
|
struct diyac_view
|
||||||
{
|
{
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
struct diyac_server *server;
|
struct diyac_server *server;
|
||||||
|
struct wlr_xdg_surface *xdg_surface;
|
||||||
struct wlr_xdg_toplevel *xdg_toplevel;
|
struct wlr_xdg_toplevel *xdg_toplevel;
|
||||||
struct wlr_scene_tree *scene_tree;
|
struct wlr_scene_tree *scene_tree;
|
||||||
struct wlr_output *output;
|
enum diyac_view_state state;
|
||||||
|
/*
|
||||||
|
* Geometry of the wlr_surface contained within the view, as
|
||||||
|
* currently displayed. Should be kept in sync with the
|
||||||
|
* scene-graph at all times.
|
||||||
|
*/
|
||||||
|
struct wlr_box current;
|
||||||
|
|
||||||
|
struct diyac_output* output;
|
||||||
|
|
||||||
struct wl_listener map;
|
struct wl_listener map;
|
||||||
struct wl_listener unmap;
|
struct wl_listener unmap;
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
@ -98,6 +178,9 @@ struct diyac_toplevel
|
|||||||
struct wl_listener request_resize;
|
struct wl_listener request_resize;
|
||||||
struct wl_listener request_maximize;
|
struct wl_listener request_maximize;
|
||||||
struct wl_listener request_fullscreen;
|
struct wl_listener request_fullscreen;
|
||||||
|
|
||||||
|
struct wl_listener set_app_id;
|
||||||
|
struct wl_listener new_popup;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct diyac_keyboard
|
struct diyac_keyboard
|
||||||
@ -111,9 +194,4 @@ struct diyac_keyboard
|
|||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
};
|
};
|
||||||
|
|
||||||
void diyac_focus_toplevel(struct diyac_toplevel *toplevel, struct wlr_surface *surface);
|
|
||||||
struct diyac_toplevel *diyac_toplevel_at(
|
|
||||||
struct diyac_server *server, double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
330
layer.c
330
layer.c
@ -1,3 +1,55 @@
|
|||||||
|
#define _POSIX_C_SOURCE 200112L
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "layer.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "output.h"
|
||||||
|
#include "seat.h"
|
||||||
|
|
||||||
|
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
|
||||||
|
static struct diyac_popup *create_layer_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_tree *parent);
|
||||||
|
static void process_keyboard_interactivity(struct diyac_layer_surface *layer)
|
||||||
|
{
|
||||||
|
struct wlr_layer_surface_v1 *layer_surface = layer->scene_layer_surface->layer_surface;
|
||||||
|
struct diyac_seat *seat = &layer->server->seat;
|
||||||
|
|
||||||
|
if (layer_surface->current.keyboard_interactive && layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Give keyboard focus to surface if
|
||||||
|
* - keyboard-interactivity is 'exclusive' or 'on-demand'; and
|
||||||
|
* - surface is in top/overlay layers; and
|
||||||
|
* - currently focused layer has a lower precedence
|
||||||
|
*
|
||||||
|
* In other words, when dealing with two surfaces with
|
||||||
|
* exclusive/on-demand keyboard-interactivity (firstly the
|
||||||
|
* currently focused 'focused_layer' and secondly the
|
||||||
|
* 'layer_surface' for which we're just responding to a
|
||||||
|
* map/commit event), the following logic applies:
|
||||||
|
*
|
||||||
|
* | focused_layer | layer_surface | who gets keyboard focus |
|
||||||
|
* |---------------|---------------|-------------------------|
|
||||||
|
* | overlay | top | focused_layer |
|
||||||
|
* | overlay | overlay | layer_surface |
|
||||||
|
* | top | top | layer_surface |
|
||||||
|
* | top | overlay | layer_surface |
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (!seat->focused_layer || seat->focused_layer->current.layer <= layer_surface->current.layer)
|
||||||
|
{
|
||||||
|
diyac_seat_focus_layer(seat, layer_surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (seat->focused_layer && !seat->focused_layer->current.keyboard_interactive)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Clear focus if keyboard-interactivity has been set to
|
||||||
|
* ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE
|
||||||
|
*/
|
||||||
|
diyac_seat_focus_layer(seat, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
static void layer_surface_commit(struct wl_listener *listener, void *data)
|
static void layer_surface_commit(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
struct diyac_layer_surface *layer =
|
struct diyac_layer_surface *layer =
|
||||||
@ -7,7 +59,8 @@ static void layer_surface_commit(struct wl_listener *listener, void *data)
|
|||||||
struct wlr_output *wlr_output =
|
struct wlr_output *wlr_output =
|
||||||
layer->scene_layer_surface->layer_surface->output;
|
layer->scene_layer_surface->layer_surface->output;
|
||||||
|
|
||||||
if (!wlr_output) {
|
if (!wlr_output)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,23 +68,28 @@ static void layer_surface_commit(struct wl_listener *listener, void *data)
|
|||||||
struct diyac_output *output = (struct diyac_output *)wlr_output->data;
|
struct diyac_output *output = (struct diyac_output *)wlr_output->data;
|
||||||
|
|
||||||
/* Process layer change */
|
/* Process layer change */
|
||||||
if (committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) {
|
if (committed & WLR_LAYER_SURFACE_V1_STATE_LAYER)
|
||||||
|
{
|
||||||
wlr_scene_node_reparent(&layer->scene_layer_surface->tree->node,
|
wlr_scene_node_reparent(&layer->scene_layer_surface->tree->node,
|
||||||
output->layer_tree[layer_surface->current.layer]);
|
output->layer_tree[layer_surface->current.layer]);
|
||||||
}
|
}
|
||||||
/* Process keyboard-interactivity change */
|
/* Process keyboard-interactivity change */
|
||||||
if (committed & WLR_LAYER_SURFACE_V1_STATE_KEYBOARD_INTERACTIVITY) {
|
if (committed & WLR_LAYER_SURFACE_V1_STATE_KEYBOARD_INTERACTIVITY)
|
||||||
//process_keyboard_interactivity(layer);
|
{
|
||||||
|
wlr_log(WLR_INFO, "Process keyboard");
|
||||||
|
process_keyboard_interactivity(layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (committed || layer->mapped != layer_surface->surface->mapped) {
|
if (committed || layer->mapped != layer_surface->surface->mapped)
|
||||||
|
{
|
||||||
layer->mapped = layer_surface->surface->mapped;
|
layer->mapped = layer_surface->surface->mapped;
|
||||||
//output_update_usable_area(output);
|
diyac_output_update_usable_area(output);
|
||||||
/*
|
/*
|
||||||
* Update cursor focus here to ensure we
|
* Update cursor focus here to ensure we
|
||||||
* enter a new/moved/resized layer surface.
|
* enter a new/moved/resized layer surface.
|
||||||
*/
|
*/
|
||||||
// cursor_update_focus(layer->server);
|
// cursor_update_focus(layer->server);
|
||||||
|
wlr_log(WLR_INFO, "update focus");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static void
|
static void
|
||||||
@ -40,13 +98,14 @@ layer_surface_unmap(struct wl_listener *listener, void *data)
|
|||||||
struct diyac_layer_surface *layer = wl_container_of(listener, layer, unmap);
|
struct diyac_layer_surface *layer = wl_container_of(listener, layer, unmap);
|
||||||
struct wlr_layer_surface_v1 *layer_surface =
|
struct wlr_layer_surface_v1 *layer_surface =
|
||||||
layer->scene_layer_surface->layer_surface;
|
layer->scene_layer_surface->layer_surface;
|
||||||
if (layer_surface->output) {
|
if (layer_surface->output)
|
||||||
//output_update_usable_area(layer_surface->output->data);
|
{
|
||||||
|
diyac_output_update_usable_area(layer_surface->output->data);
|
||||||
|
}
|
||||||
|
struct diyac_seat *seat = &layer->server->seat;
|
||||||
|
if (seat->focused_layer == layer_surface) {
|
||||||
|
diyac_seat_focus_layer(seat, NULL);
|
||||||
}
|
}
|
||||||
struct wlr_seat *seat = layer->server->seat;
|
|
||||||
//if (seat->focused_layer == layer_surface) {
|
|
||||||
//seat_set_focus_layer(seat, NULL);
|
|
||||||
//}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void layer_surface_map(struct wl_listener *listener, void *data)
|
static void layer_surface_map(struct wl_listener *listener, void *data)
|
||||||
@ -54,8 +113,9 @@ static void layer_surface_map(struct wl_listener *listener, void *data)
|
|||||||
struct diyac_layer_surface *layer = wl_container_of(listener, layer, map);
|
struct diyac_layer_surface *layer = wl_container_of(listener, layer, map);
|
||||||
struct wlr_output *wlr_output =
|
struct wlr_output *wlr_output =
|
||||||
layer->scene_layer_surface->layer_surface->output;
|
layer->scene_layer_surface->layer_surface->output;
|
||||||
if (wlr_output) {
|
if (wlr_output)
|
||||||
//output_update_usable_area(wlr_output->data);
|
{
|
||||||
|
diyac_output_update_usable_area(wlr_output->data);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Since moving to the wlroots scene-graph API, there is no need to
|
* Since moving to the wlroots scene-graph API, there is no need to
|
||||||
@ -64,10 +124,9 @@ static void layer_surface_map(struct wl_listener *listener, void *data)
|
|||||||
* the scene. See wlr_scene_surface_create() documentation.
|
* the scene. See wlr_scene_surface_create() documentation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//process_keyboard_interactivity(layer);
|
process_keyboard_interactivity(layer);
|
||||||
}
|
}
|
||||||
static void
|
static void layer_surface_node_destroy(struct wl_listener *listener, void *data)
|
||||||
layer_surface_node_destroy(struct wl_listener *listener, void *data)
|
|
||||||
{
|
{
|
||||||
struct diyac_layer_surface *layer =
|
struct diyac_layer_surface *layer =
|
||||||
wl_container_of(listener, layer, node_destroy);
|
wl_container_of(listener, layer, node_destroy);
|
||||||
@ -86,36 +145,158 @@ layer_surface_node_destroy(struct wl_listener *listener, void *data)
|
|||||||
wl_list_remove(&layer->node_destroy.link);
|
wl_list_remove(&layer->node_destroy.link);
|
||||||
free(layer);
|
free(layer);
|
||||||
}
|
}
|
||||||
static void
|
static void layer_surface_output_destroy(struct wl_listener *listener, void *data)
|
||||||
layer_surface_output_destroy(struct wl_listener *listener, void *data)
|
|
||||||
{
|
{
|
||||||
struct diyac_layer_surface *layer =
|
struct diyac_layer_surface *layer =
|
||||||
wl_container_of(listener, layer, output_destroy);
|
wl_container_of(listener, layer, output_destroy);
|
||||||
layer->scene_layer_surface->layer_surface->output = NULL;
|
layer->scene_layer_surface->layer_surface->output = NULL;
|
||||||
wlr_layer_surface_v1_destroy(layer->scene_layer_surface->layer_surface);
|
wlr_layer_surface_v1_destroy(layer->scene_layer_surface->layer_surface);
|
||||||
}
|
}
|
||||||
/* This popup's parent is a layer popup */
|
|
||||||
static void
|
static void
|
||||||
layer_surface_new_popup(struct wl_listener *listener, void *data)
|
popup_handle_destroy(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
/*struct lab_layer_popup *lab_layer_popup =
|
struct diyac_popup *popup = wl_container_of(listener, popup, destroy);
|
||||||
wl_container_of(listener, lab_layer_popup, new_popup);
|
wl_list_remove(&popup->destroy.link);
|
||||||
struct wlr_xdg_popup *wlr_popup = data;
|
wl_list_remove(&popup->new_popup.link);
|
||||||
struct lab_layer_popup *new_popup = create_popup(wlr_popup,
|
|
||||||
lab_layer_popup->scene_tree);
|
/* Usually already removed unless there was no commit at all */
|
||||||
new_popup->output_toplevel_sx_box =
|
if (popup->commit.notify)
|
||||||
lab_layer_popup->output_toplevel_sx_box;*/
|
{
|
||||||
|
wl_list_remove(&popup->commit.link);
|
||||||
}
|
}
|
||||||
static void server_new_layer_surface(struct wl_listener *listener, void *data)
|
|
||||||
|
free(popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void popup_handle_commit(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct diyac_popup *popup =
|
||||||
|
wl_container_of(listener, popup, commit);
|
||||||
|
|
||||||
|
if (popup->wlr_popup->base->initial_commit)
|
||||||
|
{
|
||||||
|
wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &popup->output_toplevel_sx_box);
|
||||||
|
|
||||||
|
/* Prevent getting called over and over again */
|
||||||
|
wl_list_remove(&popup->commit.link);
|
||||||
|
popup->commit.notify = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* This popup's parent is a layer popup */
|
||||||
|
static void popup_handle_new_popup(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct diyac_popup *popup =
|
||||||
|
wl_container_of(listener, popup, new_popup);
|
||||||
|
struct wlr_xdg_popup *wlr_popup = data;
|
||||||
|
struct diyac_popup *new_popup = create_layer_popup(wlr_popup,
|
||||||
|
popup->scene_tree);
|
||||||
|
new_popup->output_toplevel_sx_box = popup->output_toplevel_sx_box;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct diyac_popup *create_layer_popup(struct wlr_xdg_popup *wlr_popup, struct wlr_scene_tree *parent)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_INFO,
|
||||||
|
"create_layer_popup: popup create");
|
||||||
|
struct diyac_popup *popup = calloc(1, sizeof(*popup));
|
||||||
|
popup->wlr_popup = wlr_popup;
|
||||||
|
popup->scene_tree =
|
||||||
|
wlr_scene_xdg_surface_create(parent, wlr_popup->base);
|
||||||
|
if (!popup->scene_tree)
|
||||||
|
{
|
||||||
|
free(popup);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
diyac_node_descriptor_create(&popup->scene_tree->node,
|
||||||
|
DIYAC_NODE_LAYER_POPUP, popup);
|
||||||
|
|
||||||
|
popup->destroy.notify = popup_handle_destroy;
|
||||||
|
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
|
||||||
|
|
||||||
|
popup->new_popup.notify = popup_handle_new_popup;
|
||||||
|
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
|
||||||
|
|
||||||
|
popup->commit.notify = popup_handle_commit;
|
||||||
|
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
|
||||||
|
|
||||||
|
return popup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We move popups from the bottom to the top layer so that they are
|
||||||
|
* rendered above views.
|
||||||
|
*/
|
||||||
|
static void move_popup_to_top_layer(struct diyac_layer_surface *toplevel,
|
||||||
|
struct diyac_popup *popup)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_INFO,
|
||||||
|
"move_popup_to_top_layer: popup notif");
|
||||||
|
struct diyac_server *server = toplevel->server;
|
||||||
|
struct wlr_output *wlr_output =
|
||||||
|
toplevel->scene_layer_surface->layer_surface->output;
|
||||||
|
struct diyac_output *output = (struct diyac_output *)wlr_output->data;
|
||||||
|
struct wlr_box box = {0};
|
||||||
|
wlr_output_layout_get_box(server->output_layout, wlr_output, &box);
|
||||||
|
int lx = toplevel->scene_layer_surface->tree->node.x + box.x;
|
||||||
|
int ly = toplevel->scene_layer_surface->tree->node.y + box.y;
|
||||||
|
|
||||||
|
struct wlr_scene_node *node = &popup->scene_tree->node;
|
||||||
|
wlr_scene_node_reparent(node, output->scenes.popup);
|
||||||
|
/* FIXME: verify the whole tree should be repositioned */
|
||||||
|
wlr_scene_node_set_position(&output->scenes.popup->node, lx, ly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This popup's parent is a layer popup */
|
||||||
|
static void layer_popup_new(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_INFO,
|
||||||
|
"layer_popup_new: popup notif");
|
||||||
|
struct diyac_layer_surface *toplevel =
|
||||||
|
wl_container_of(listener, toplevel, new_popup);
|
||||||
|
struct wlr_xdg_popup *wlr_popup = data;
|
||||||
|
|
||||||
|
struct diyac_server *server = toplevel->server;
|
||||||
|
struct wlr_scene_layer_surface_v1 *surface = toplevel->scene_layer_surface;
|
||||||
|
struct diyac_output *output = surface->layer_surface->output->data;
|
||||||
|
|
||||||
|
int lx, ly;
|
||||||
|
wlr_scene_node_coords(&surface->tree->node, &lx, &ly);
|
||||||
|
|
||||||
|
struct wlr_box output_box = {0};
|
||||||
|
wlr_output_layout_get_box(server->output_layout,
|
||||||
|
output->wlr_output, &output_box);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output geometry expressed in the coordinate system of the toplevel
|
||||||
|
* parent of popup. We store this struct the lab_layer_popup struct
|
||||||
|
* to make it easier to unconstrain children when we move popups from
|
||||||
|
* the bottom to the top layer.
|
||||||
|
*/
|
||||||
|
struct wlr_box output_toplevel_sx_box = {
|
||||||
|
.x = output_box.x - lx,
|
||||||
|
.y = output_box.y - ly,
|
||||||
|
.width = output_box.width,
|
||||||
|
.height = output_box.height,
|
||||||
|
};
|
||||||
|
struct diyac_popup *popup = create_layer_popup(wlr_popup, surface->tree);
|
||||||
|
popup->output_toplevel_sx_box = output_toplevel_sx_box;
|
||||||
|
|
||||||
|
if (surface->layer_surface->current.layer <= ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM)
|
||||||
|
{
|
||||||
|
move_popup_to_top_layer(toplevel, popup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void diyac_new_layer_surface(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
struct diyac_server *server = wl_container_of(listener, server, new_layer_surface);
|
struct diyac_server *server = wl_container_of(listener, server, new_layer_surface);
|
||||||
struct wlr_layer_surface_v1 *layer_surface = data;
|
struct wlr_layer_surface_v1 *layer_surface = data;
|
||||||
|
|
||||||
if (!layer_surface->output) {
|
if (!layer_surface->output)
|
||||||
|
{
|
||||||
struct wlr_output *output = wlr_output_layout_output_at(
|
struct wlr_output *output = wlr_output_layout_output_at(
|
||||||
server->output_layout, server->seat.cursor->x,
|
server->output_layout, server->seat.cursor->x,
|
||||||
server->seat.cursor->y);
|
server->seat.cursor->y);
|
||||||
if (!output) {
|
if (!output)
|
||||||
|
{
|
||||||
wlr_log(WLR_INFO,
|
wlr_log(WLR_INFO,
|
||||||
"No output available to assign layer surface");
|
"No output available to assign layer surface");
|
||||||
wlr_layer_surface_v1_destroy(layer_surface);
|
wlr_layer_surface_v1_destroy(layer_surface);
|
||||||
@ -133,14 +314,15 @@ static void server_new_layer_surface(struct wl_listener *listener, void *data)
|
|||||||
|
|
||||||
surface->scene_layer_surface = wlr_scene_layer_surface_v1_create(
|
surface->scene_layer_surface = wlr_scene_layer_surface_v1_create(
|
||||||
selected_layer, layer_surface);
|
selected_layer, layer_surface);
|
||||||
if (!surface->scene_layer_surface) {
|
if (!surface->scene_layer_surface)
|
||||||
|
{
|
||||||
wlr_layer_surface_v1_destroy(layer_surface);
|
wlr_layer_surface_v1_destroy(layer_surface);
|
||||||
wlr_log(WLR_ERROR, "could not create layer surface");
|
wlr_log(WLR_ERROR, "could not create layer surface");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//node_descriptor_create(&surface->scene_layer_surface->tree->node,
|
diyac_node_descriptor_create(&surface->scene_layer_surface->tree->node,
|
||||||
// LAB_NODE_DESC_LAYER_SURFACE, surface);
|
DIYAC_NODE_LAYER_SURFACE, surface);
|
||||||
|
|
||||||
surface->server = server;
|
surface->server = server;
|
||||||
surface->scene_layer_surface->layer_surface = layer_surface;
|
surface->scene_layer_surface->layer_surface = layer_surface;
|
||||||
@ -155,7 +337,7 @@ static void server_new_layer_surface(struct wl_listener *listener, void *data)
|
|||||||
surface->unmap.notify = layer_surface_unmap;
|
surface->unmap.notify = layer_surface_unmap;
|
||||||
wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap);
|
wl_signal_add(&layer_surface->surface->events.unmap, &surface->unmap);
|
||||||
|
|
||||||
surface->new_popup.notify = layer_surface_new_popup;
|
surface->new_popup.notify = layer_popup_new;
|
||||||
wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
|
wl_signal_add(&layer_surface->events.new_popup, &surface->new_popup);
|
||||||
|
|
||||||
surface->output_destroy.notify = layer_surface_output_destroy;
|
surface->output_destroy.notify = layer_surface_output_destroy;
|
||||||
@ -170,8 +352,78 @@ static void server_new_layer_surface(struct wl_listener *listener, void *data)
|
|||||||
* Temporarily set the layer's current state to pending so that
|
* Temporarily set the layer's current state to pending so that
|
||||||
* it can easily be arranged.
|
* it can easily be arranged.
|
||||||
*/
|
*/
|
||||||
//struct wlr_layer_surface_v1_state old_state = layer_surface->current;
|
struct wlr_layer_surface_v1_state old_state = layer_surface->current;
|
||||||
//layer_surface->current = layer_surface->pending;
|
layer_surface->current = layer_surface->pending;
|
||||||
//output_update_usable_area(output);
|
diyac_output_update_usable_area(output);
|
||||||
//layer_surface->current = old_state;
|
layer_surface->current = old_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arrange_one_layer(const struct wlr_box *full_area, struct wlr_box *usable_area,
|
||||||
|
struct wlr_scene_tree *tree, bool exclusive)
|
||||||
|
{
|
||||||
|
struct wlr_scene_node *node;
|
||||||
|
wl_list_for_each(node, &tree->children, link)
|
||||||
|
{
|
||||||
|
struct diyac_layer_surface *surface = diyac_layer_surface_from_node(node);
|
||||||
|
struct wlr_scene_layer_surface_v1 *scene = surface->scene_layer_surface;
|
||||||
|
if (!!scene->layer_surface->current.exclusive_zone != exclusive)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
wlr_scene_layer_surface_v1_configure(scene, full_area, usable_area);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To ensure outputs/views are left in a consistent state, this
|
||||||
|
* function should be called ONLY from output_update_usable_area()
|
||||||
|
* or output_update_all_usable_areas().
|
||||||
|
*/
|
||||||
|
void diyac_layers_arrange(struct diyac_output *output)
|
||||||
|
{
|
||||||
|
assert(output);
|
||||||
|
struct wlr_box full_area = {0};
|
||||||
|
wlr_output_effective_resolution(output->wlr_output,
|
||||||
|
&full_area.width, &full_area.height);
|
||||||
|
struct wlr_box usable_area = full_area;
|
||||||
|
struct diyac_server *server = output->server;
|
||||||
|
struct wlr_scene_output *scene_output =
|
||||||
|
wlr_scene_get_scene_output(server->scene, output->wlr_output);
|
||||||
|
if (!scene_output)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_DEBUG, "no wlr_scene_output");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = LAYER_TREE_SZ - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
struct wlr_scene_tree *layer = output->layer_tree[i];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Process exclusive-zone clients before non-exclusive-zone
|
||||||
|
* clients, so that the latter give way to the former regardless
|
||||||
|
* of the order in which they were launched.
|
||||||
|
*
|
||||||
|
* Also start calculating the usable_area for exclusive-zone
|
||||||
|
* clients from the Overlay layer down to the Background layer
|
||||||
|
* to ensure that higher layers have a higher preference for
|
||||||
|
* placement.
|
||||||
|
*
|
||||||
|
* The 'exclusive' boolean also matches -1 which means that
|
||||||
|
* the layershell client wants to use the full screen rather
|
||||||
|
* than the usable area.
|
||||||
|
*/
|
||||||
|
arrange_one_layer(&full_area, &usable_area, layer, /* exclusive */ true);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < LAYER_TREE_SZ; i++)
|
||||||
|
{
|
||||||
|
struct wlr_scene_tree *layer = output->layer_tree[i];
|
||||||
|
arrange_one_layer(&full_area, &usable_area, layer, /* exclusive */ false);
|
||||||
|
|
||||||
|
/* Set node position to account for output layout change */
|
||||||
|
wlr_scene_node_set_position(&layer->node, scene_output->x, scene_output->y);
|
||||||
|
}
|
||||||
|
|
||||||
|
output->usable_area = usable_area;
|
||||||
}
|
}
|
7
layer.h
Normal file
7
layer.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef DIYAC_LAYER_H
|
||||||
|
#define DIYAC_LAYER_H
|
||||||
|
#include "diyac.h"
|
||||||
|
|
||||||
|
void diyac_new_layer_surface(struct wl_listener *listener, void *data);
|
||||||
|
void diyac_layers_arrange(struct diyac_output *output);
|
||||||
|
#endif
|
37
node.c
Normal file
37
node.c
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#define _POSIX_C_SOURCE 200112L
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
static void destroy_notify(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct diyac_node_descriptor *node_descriptor =
|
||||||
|
wl_container_of(listener, node_descriptor, destroy);
|
||||||
|
wl_list_remove(&node_descriptor->destroy.link);
|
||||||
|
free(node_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diyac_node_descriptor_create(struct wlr_scene_node *scene_node, enum diyac_node_descriptor_type type, void *data)
|
||||||
|
{
|
||||||
|
struct diyac_node_descriptor *node_descriptor = calloc(1, sizeof(*node_descriptor));
|
||||||
|
node_descriptor->type = type;
|
||||||
|
node_descriptor->data = data;
|
||||||
|
node_descriptor->destroy.notify = destroy_notify;
|
||||||
|
wl_signal_add(&scene_node->events.destroy, &node_descriptor->destroy);
|
||||||
|
scene_node->data = node_descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct diyac_layer_surface *diyac_layer_surface_from_node(struct wlr_scene_node *wlr_scene_node)
|
||||||
|
{
|
||||||
|
assert(wlr_scene_node->data);
|
||||||
|
struct diyac_node_descriptor *node_descriptor = wlr_scene_node->data;
|
||||||
|
assert(node_descriptor->type == DIYAC_NODE_LAYER_SURFACE);
|
||||||
|
return (struct diyac_layer_surface *)node_descriptor->data;
|
||||||
|
}
|
||||||
|
struct diyac_view *diyac_view_from_node(struct wlr_scene_node *wlr_scene_node)
|
||||||
|
{
|
||||||
|
assert(wlr_scene_node->data);
|
||||||
|
struct diyac_node_descriptor *node_descriptor = wlr_scene_node->data;
|
||||||
|
assert(node_descriptor->type == DIYAC_NODE_VIEW || node_descriptor->type == DIYAC_NODE_XDG_POPUP);
|
||||||
|
return (struct diyac_view *)node_descriptor->data;
|
||||||
|
}
|
8
node.h
Normal file
8
node.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef DIYAC_NODE_H
|
||||||
|
#define DIYAC_NODE_H
|
||||||
|
#include "diyac.h"
|
||||||
|
|
||||||
|
void diyac_node_descriptor_create(struct wlr_scene_node *scene_node,enum diyac_node_descriptor_type type, void *data);
|
||||||
|
struct diyac_layer_surface * diyac_layer_surface_from_node(struct wlr_scene_node *wlr_scene_node);
|
||||||
|
struct diyac_view *diyac_view_from_node(struct wlr_scene_node *wlr_scene_node);
|
||||||
|
#endif
|
115
output.c
115
output.c
@ -1,11 +1,13 @@
|
|||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200112L
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <wlr/types/wlr_scene.h>
|
#include <stdbool.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
|
||||||
#include "output.h"
|
#include "output.h"
|
||||||
|
#include "layer.h"
|
||||||
static void output_frame(struct wl_listener *listener, void *data) {
|
#include "node.h"
|
||||||
|
#include "desktop.h"
|
||||||
|
static void output_frame(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
/* This function is called every time an output is ready to display a frame,
|
/* This function is called every time an output is ready to display a frame,
|
||||||
* generally at the output's refresh rate (e.g. 60Hz). */
|
* generally at the output's refresh rate (e.g. 60Hz). */
|
||||||
struct diyac_output *output = wl_container_of(listener, output, frame);
|
struct diyac_output *output = wl_container_of(listener, output, frame);
|
||||||
@ -22,7 +24,8 @@ static void output_frame(struct wl_listener *listener, void *data) {
|
|||||||
wlr_scene_output_send_frame_done(scene_output, &now);
|
wlr_scene_output_send_frame_done(scene_output, &now);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_request_state(struct wl_listener *listener, void *data) {
|
static void output_request_state(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
/* This function is called when the backend requests a new state for
|
/* This function is called when the backend requests a new state for
|
||||||
* the output. For example, Wayland and X11 backends request a new mode
|
* the output. For example, Wayland and X11 backends request a new mode
|
||||||
* when the output window is resized. */
|
* when the output window is resized. */
|
||||||
@ -31,7 +34,8 @@ static void output_request_state(struct wl_listener *listener, void *data) {
|
|||||||
wlr_output_commit_state(output->wlr_output, event->state);
|
wlr_output_commit_state(output->wlr_output, event->state);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_destroy(struct wl_listener *listener, void *data) {
|
static void output_destroy(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
struct diyac_output *output = wl_container_of(listener, output, destroy);
|
struct diyac_output *output = wl_container_of(listener, output, destroy);
|
||||||
|
|
||||||
wl_list_remove(&output->frame.link);
|
wl_list_remove(&output->frame.link);
|
||||||
@ -41,7 +45,8 @@ static void output_destroy(struct wl_listener *listener, void *data) {
|
|||||||
free(output);
|
free(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void diyac_server_new_output(struct wl_listener *listener, void *data) {
|
void diyac_server_new_output(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
/* This event is raised by the backend when a new output (aka a display or
|
/* This event is raised by the backend when a new output (aka a display or
|
||||||
* monitor) becomes available. */
|
* monitor) becomes available. */
|
||||||
struct diyac_server *server =
|
struct diyac_server *server =
|
||||||
@ -63,7 +68,8 @@ void diyac_server_new_output(struct wl_listener *listener, void *data) {
|
|||||||
* just pick the monitor's preferred mode, a more sophisticated compositor
|
* just pick the monitor's preferred mode, a more sophisticated compositor
|
||||||
* would let the user configure it. */
|
* would let the user configure it. */
|
||||||
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
|
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
|
||||||
if (mode != NULL) {
|
if (mode != NULL)
|
||||||
|
{
|
||||||
wlr_output_state_set_mode(&state, mode);
|
wlr_output_state_set_mode(&state, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +81,11 @@ void diyac_server_new_output(struct wl_listener *listener, void *data) {
|
|||||||
struct diyac_output *output = calloc(1, sizeof(*output));
|
struct diyac_output *output = calloc(1, sizeof(*output));
|
||||||
output->wlr_output = wlr_output;
|
output->wlr_output = wlr_output;
|
||||||
output->server = server;
|
output->server = server;
|
||||||
|
wlr_output->data = output;
|
||||||
|
output->usable_area.x = 0;
|
||||||
|
output->usable_area.y = 0;
|
||||||
|
output->usable_area.width = wlr_output->width;
|
||||||
|
output->usable_area.height = wlr_output->height;
|
||||||
/* Sets up a listener for the frame event. */
|
/* Sets up a listener for the frame event. */
|
||||||
output->frame.notify = output_frame;
|
output->frame.notify = output_frame;
|
||||||
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
||||||
@ -90,6 +100,46 @@ void diyac_server_new_output(struct wl_listener *listener, void *data) {
|
|||||||
|
|
||||||
wl_list_insert(&server->outputs, &output->link);
|
wl_list_insert(&server->outputs, &output->link);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create layer-trees (background, bottom, top and overlay) and
|
||||||
|
* a layer-popup-tree.
|
||||||
|
*/
|
||||||
|
output->scenes.background = wlr_scene_tree_create(&server->scene->tree);
|
||||||
|
output->scenes.bottom = wlr_scene_tree_create(&server->scene->tree);
|
||||||
|
output->scenes.top = wlr_scene_tree_create(&server->scene->tree);
|
||||||
|
output->scenes.popup = wlr_scene_tree_create(&server->scene->tree);
|
||||||
|
output->scenes.overlay = wlr_scene_tree_create(&server->scene->tree);
|
||||||
|
output->scenes.session = wlr_scene_tree_create(&server->scene->tree);
|
||||||
|
|
||||||
|
diyac_node_descriptor_create(&output->scenes.background->node, DIYAC_NODE_TREE, NULL);
|
||||||
|
diyac_node_descriptor_create(&output->scenes.bottom->node, DIYAC_NODE_TREE, NULL);
|
||||||
|
diyac_node_descriptor_create(&output->scenes.top->node, DIYAC_NODE_TREE, NULL);
|
||||||
|
diyac_node_descriptor_create(&output->scenes.popup->node, DIYAC_NODE_TREE, NULL);
|
||||||
|
diyac_node_descriptor_create(&output->scenes.overlay->node, DIYAC_NODE_TREE, NULL);
|
||||||
|
diyac_node_descriptor_create(&output->scenes.session->node, DIYAC_NODE_TREE, NULL);
|
||||||
|
|
||||||
|
output->layer_tree[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND] = output->scenes.background;
|
||||||
|
output->layer_tree[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM] = output->scenes.bottom;
|
||||||
|
output->layer_tree[ZWLR_LAYER_SHELL_V1_LAYER_TOP] = output->scenes.top;
|
||||||
|
output->layer_tree[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY] = output->scenes.overlay;
|
||||||
|
/*
|
||||||
|
* Set the z-positions to achieve the following order (from top to
|
||||||
|
* bottom):
|
||||||
|
* - session lock layer
|
||||||
|
* - layer-shell popups
|
||||||
|
* - overlay layer
|
||||||
|
* - top layer
|
||||||
|
* - views
|
||||||
|
* - bottom layer
|
||||||
|
* - background layer
|
||||||
|
*/
|
||||||
|
wlr_scene_node_lower_to_bottom(&output->scenes.bottom->node);
|
||||||
|
wlr_scene_node_lower_to_bottom(&output->scenes.background->node);
|
||||||
|
wlr_scene_node_raise_to_top(&output->scenes.top->node);
|
||||||
|
wlr_scene_node_raise_to_top(&output->scenes.overlay->node);
|
||||||
|
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
|
/* Adds this to the output layout. The add_auto function arranges outputs
|
||||||
* from left-to-right in the order they appear. A more sophisticated
|
* from left-to-right in the order they appear. A more sophisticated
|
||||||
* compositor would let the user configure the arrangement of outputs in the
|
* compositor would let the user configure the arrangement of outputs in the
|
||||||
@ -104,3 +154,50 @@ void diyac_server_new_output(struct wl_listener *listener, void *data) {
|
|||||||
struct wlr_scene_output *scene_output = wlr_scene_output_create(server->scene, 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_scene_output_layout_add_output(server->scene_layout, l_output, scene_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diyac_output_update_usable_area(struct diyac_output *output)
|
||||||
|
{
|
||||||
|
if (update_usable_area(output))
|
||||||
|
{
|
||||||
|
// regions_update_geometry(output);
|
||||||
|
diyac_arrange_all_views(output->server);
|
||||||
|
// desktop_arrange_all_views(output->server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct diyac_output *diyac_output_from_cursor(struct diyac_server *server)
|
||||||
|
{
|
||||||
|
double closest_x, closest_y;
|
||||||
|
wlr_output_layout_closest_point(server->output_layout, NULL, server->seat.cursor->x, server->seat.cursor->y,
|
||||||
|
&closest_x, &closest_y);
|
||||||
|
|
||||||
|
struct wlr_output *output = wlr_output_layout_output_at(server->output_layout,
|
||||||
|
closest_x, closest_y);
|
||||||
|
if (!output)
|
||||||
|
return NULL;
|
||||||
|
return output->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_box diyac_output_usable_area(struct diyac_output *output)
|
||||||
|
{
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
return (struct wlr_box){0};
|
||||||
|
}
|
||||||
|
struct wlr_box box = output->usable_area;
|
||||||
|
double ox = 0, oy = 0;
|
||||||
|
wlr_output_layout_output_coords(output->server->output_layout,
|
||||||
|
output->wlr_output, &ox, &oy);
|
||||||
|
box.x -= ox;
|
||||||
|
box.y -= oy;
|
||||||
|
return box;
|
||||||
|
}
|
4
output.h
4
output.h
@ -3,5 +3,7 @@
|
|||||||
#include "diyac.h"
|
#include "diyac.h"
|
||||||
|
|
||||||
void diyac_server_new_output(struct wl_listener *listener, void *data);
|
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);
|
||||||
|
struct wlr_box diyac_output_usable_area(struct diyac_output * output);
|
||||||
#endif
|
#endif
|
80
seat.c
80
seat.c
@ -1,9 +1,11 @@
|
|||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200112L
|
||||||
#include <wlr/types/wlr_input_device.h>
|
#include <wlr/types/wlr_input_device.h>
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
#include "seat.h"
|
#include "seat.h"
|
||||||
|
#include "desktop.h"
|
||||||
|
|
||||||
|
|
||||||
static void keyboard_handle_modifiers(
|
static void keyboard_handle_modifiers(
|
||||||
struct wl_listener *listener, void *data)
|
struct wl_listener *listener, void *data)
|
||||||
@ -40,13 +42,13 @@ static bool handle_keybinding(struct diyac_server *server, xkb_keysym_t sym)
|
|||||||
break;
|
break;
|
||||||
case XKB_KEY_F1:
|
case XKB_KEY_F1:
|
||||||
/* Cycle to the next toplevel */
|
/* Cycle to the next toplevel */
|
||||||
if (wl_list_length(&server->toplevels) < 2)
|
if (wl_list_length(&server->views) < 2)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
struct diyac_toplevel *next_toplevel =
|
struct diyac_view *next_toplevel =
|
||||||
wl_container_of(server->toplevels.prev, next_toplevel, link);
|
wl_container_of(server->views.prev, next_toplevel, link);
|
||||||
diyac_focus_toplevel(next_toplevel, next_toplevel->xdg_toplevel->base->surface);
|
diyac_focus_view(next_toplevel);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
@ -234,3 +236,71 @@ void diyac_init_seat(struct diyac_server *server)
|
|||||||
wl_signal_add(&server->seat.wlr_seat->events.request_set_selection,
|
wl_signal_add(&server->seat.wlr_seat->events.request_set_selection,
|
||||||
&server->seat.request_set_selection);
|
&server->seat.request_set_selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void seat_focus(struct diyac_seat *seat, struct wlr_surface *surface, bool is_lock_surface)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_INFO, "seat_focus");
|
||||||
|
/*
|
||||||
|
* Respect session lock. This check is critical, DO NOT REMOVE.
|
||||||
|
* It should also come before the !surface condition, or the
|
||||||
|
* lock screen may lose focus and become impossible to unlock.
|
||||||
|
*/
|
||||||
|
struct diyac_server *server = seat->server;
|
||||||
|
/*if (server->session_lock && !is_lock_surface)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if (!surface)
|
||||||
|
{
|
||||||
|
wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Respect input inhibit (also used by some lock screens) */
|
||||||
|
/*
|
||||||
|
if (input_inhibit_blocks_surface(seat, surface->resource)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
|
||||||
|
if (keyboard)
|
||||||
|
{
|
||||||
|
wlr_seat_keyboard_notify_enter(seat->wlr_seat, surface,
|
||||||
|
keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
struct wlr_pointer_constraint_v1 *constraint =
|
||||||
|
wlr_pointer_constraints_v1_constraint_for_surface(server->constraints,
|
||||||
|
surface, seat->seat);
|
||||||
|
constrain_cursor(server, constraint);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void diyac_seat_focus_surface(struct diyac_seat *seat, struct wlr_surface *surface)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_INFO, "diyac_seat_focus_surface");
|
||||||
|
/* Respect layer-shell exclusive keyboard-interactivity. */
|
||||||
|
if (seat->focused_layer && seat->focused_layer->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seat_focus(seat, surface, /*is_lock_surface*/ false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void diyac_seat_focus_layer(struct diyac_seat *seat, struct wlr_layer_surface_v1 *layer)
|
||||||
|
{
|
||||||
|
if (!layer)
|
||||||
|
{
|
||||||
|
seat->focused_layer = NULL;
|
||||||
|
diyac_focus_topmost_view(seat->server);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seat_focus(seat, layer->surface, /*is_lock_surface*/ false);
|
||||||
|
if (layer->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP)
|
||||||
|
{
|
||||||
|
seat->focused_layer = layer;
|
||||||
|
}
|
||||||
|
}
|
2
seat.h
2
seat.h
@ -3,4 +3,6 @@
|
|||||||
#include "diyac.h"
|
#include "diyac.h"
|
||||||
|
|
||||||
void diyac_init_seat(struct diyac_server* server);
|
void diyac_init_seat(struct diyac_server* server);
|
||||||
|
void diyac_seat_focus_surface(struct diyac_seat *seat, struct wlr_surface *surface);
|
||||||
|
void diyac_seat_focus_layer(struct diyac_seat *seat, struct wlr_layer_surface_v1 *layer);
|
||||||
#endif
|
#endif
|
224
xdg.c
224
xdg.c
@ -1,14 +1,16 @@
|
|||||||
#define _POSIX_C_SOURCE 200112L
|
#define _POSIX_C_SOURCE 200112L
|
||||||
#include <wlr/types/wlr_scene.h>
|
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
|
||||||
#include <wlr/types/wlr_xcursor_manager.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "xdg.h"
|
#include "xdg.h"
|
||||||
#include "cursor.h"
|
#include "cursor.h"
|
||||||
|
#include "node.h"
|
||||||
|
#include "desktop.h"
|
||||||
|
#include "output.h"
|
||||||
|
|
||||||
static void begin_interactive(struct diyac_toplevel *toplevel,
|
static void xdg_popup_create(struct diyac_view *view, struct wlr_xdg_popup *wlr_popup);
|
||||||
|
|
||||||
|
static void begin_interactive(struct diyac_view *toplevel,
|
||||||
enum diyac_cursor_mode mode, uint32_t edges)
|
enum diyac_cursor_mode mode, uint32_t edges)
|
||||||
{
|
{
|
||||||
/* This function sets up an interactive move or resize operation, where the
|
/* This function sets up an interactive move or resize operation, where the
|
||||||
@ -23,7 +25,7 @@ static void begin_interactive(struct diyac_toplevel *toplevel,
|
|||||||
/* Deny move/resize requests from unfocused clients. */
|
/* Deny move/resize requests from unfocused clients. */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
server->grabbed_toplevel = toplevel;
|
server->grabbed_view = toplevel;
|
||||||
server->seat.cursor_mode = mode;
|
server->seat.cursor_mode = mode;
|
||||||
|
|
||||||
if (mode == DIYAC_CURSOR_MOVE)
|
if (mode == DIYAC_CURSOR_MOVE)
|
||||||
@ -54,20 +56,20 @@ static void begin_interactive(struct diyac_toplevel *toplevel,
|
|||||||
static void xdg_toplevel_map(struct wl_listener *listener, void *data)
|
static void xdg_toplevel_map(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
/* Called when the surface is mapped, or ready to display on-screen. */
|
/* Called when the surface is mapped, or ready to display on-screen. */
|
||||||
struct diyac_toplevel *toplevel = wl_container_of(listener, toplevel, map);
|
struct diyac_view *toplevel = wl_container_of(listener, toplevel, map);
|
||||||
|
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &toplevel->current);
|
||||||
|
wl_list_insert(&toplevel->server->views, &toplevel->link);
|
||||||
|
|
||||||
wl_list_insert(&toplevel->server->toplevels, &toplevel->link);
|
diyac_focus_view(toplevel);
|
||||||
|
|
||||||
diyac_focus_toplevel(toplevel, toplevel->xdg_toplevel->base->surface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
|
static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
/* Called when the surface is unmapped, and should no longer be shown. */
|
/* Called when the surface is unmapped, and should no longer be shown. */
|
||||||
struct diyac_toplevel *toplevel = wl_container_of(listener, toplevel, unmap);
|
struct diyac_view *toplevel = wl_container_of(listener, toplevel, unmap);
|
||||||
|
|
||||||
/* Reset the cursor mode if the grabbed toplevel was unmapped. */
|
/* Reset the cursor mode if the grabbed toplevel was unmapped. */
|
||||||
if (toplevel == toplevel->server->grabbed_toplevel)
|
if (toplevel == toplevel->server->grabbed_view)
|
||||||
{
|
{
|
||||||
diyac_reset_cursor_mode(toplevel->server);
|
diyac_reset_cursor_mode(toplevel->server);
|
||||||
}
|
}
|
||||||
@ -83,7 +85,7 @@ static void xdg_toplevel_request_move(
|
|||||||
* decorations. Note that a more sophisticated compositor should check the
|
* decorations. Note that a more sophisticated compositor should check the
|
||||||
* provided serial against a list of button press serials sent to this
|
* provided serial against a list of button press serials sent to this
|
||||||
* client, to prevent the client from requesting this whenever they want. */
|
* client, to prevent the client from requesting this whenever they want. */
|
||||||
struct diyac_toplevel *toplevel = wl_container_of(listener, toplevel, request_move);
|
struct diyac_view *toplevel = wl_container_of(listener, toplevel, request_move);
|
||||||
begin_interactive(toplevel, DIYAC_CURSOR_MOVE, 0);
|
begin_interactive(toplevel, DIYAC_CURSOR_MOVE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +98,7 @@ static void xdg_toplevel_request_resize(
|
|||||||
* provided serial against a list of button press serials sent to this
|
* provided serial against a list of button press serials sent to this
|
||||||
* client, to prevent the client from requesting this whenever they want. */
|
* client, to prevent the client from requesting this whenever they want. */
|
||||||
struct wlr_xdg_toplevel_resize_event *event = data;
|
struct wlr_xdg_toplevel_resize_event *event = data;
|
||||||
struct diyac_toplevel *toplevel = wl_container_of(listener, toplevel, request_resize);
|
struct diyac_view *toplevel = wl_container_of(listener, toplevel, request_resize);
|
||||||
begin_interactive(toplevel, DIYAC_CURSOR_RESIZE, event->edges);
|
begin_interactive(toplevel, DIYAC_CURSOR_RESIZE, event->edges);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,13 +111,33 @@ static void xdg_toplevel_request_maximize(
|
|||||||
* to conform to xdg-shell protocol we still must send a configure.
|
* to conform to xdg-shell protocol we still must send a configure.
|
||||||
* wlr_xdg_surface_schedule_configure() is used to send an empty reply. */
|
* wlr_xdg_surface_schedule_configure() is used to send an empty reply. */
|
||||||
|
|
||||||
struct diyac_toplevel *toplevel =
|
struct diyac_view *toplevel =
|
||||||
wl_container_of(listener, toplevel, request_maximize);
|
wl_container_of(listener, toplevel, request_maximize);
|
||||||
// wlr_wl_output* output = get_wl_output_from_surface(struct wlr_wl_backend *wl,
|
// wlr_wl_output* output = get_wl_output_from_surface(struct wlr_wl_backend *wl,
|
||||||
// struct wl_surface *surface);
|
// struct wl_surface *surface);
|
||||||
wlr_log(WLR_ERROR, "request maximize %dx%d", toplevel->output->width, toplevel->output->height);
|
/*
|
||||||
wlr_scene_node_set_position(&toplevel->scene_tree->node,0,0);
|
struct wlr_output *output = wlr_output_layout_output_at(
|
||||||
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, toplevel->output->width, toplevel->output->height);
|
toplevel->server->output_layout, toplevel->server->seat.cursor->x,
|
||||||
|
toplevel->server->seat.cursor->y);
|
||||||
|
if (!output)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"No output available to assign layer surface");
|
||||||
|
wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct diyac_output * target_output = output->data;
|
||||||
|
*/
|
||||||
|
if(toplevel->state == DIYAC_VIEW_MAXIMIZE)
|
||||||
|
{
|
||||||
|
toplevel->state = DIYAC_VIEW_NORMAL;
|
||||||
|
// restore its default geometry
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toplevel->state = DIYAC_VIEW_MAXIMIZE;
|
||||||
|
}
|
||||||
|
diyac_view_update_geometry(toplevel, true);
|
||||||
// wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
|
// wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,15 +145,24 @@ static void xdg_toplevel_request_fullscreen(
|
|||||||
struct wl_listener *listener, void *data)
|
struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
/* Just as with request_maximize, we must send a configure here. */
|
/* Just as with request_maximize, we must send a configure here. */
|
||||||
struct diyac_toplevel *toplevel =
|
struct diyac_view *toplevel =
|
||||||
wl_container_of(listener, toplevel, request_fullscreen);
|
wl_container_of(listener, toplevel, request_fullscreen);
|
||||||
wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
|
if(toplevel->state == DIYAC_VIEW_FULL_SCREEN)
|
||||||
|
{
|
||||||
|
toplevel->state = DIYAC_VIEW_NORMAL;
|
||||||
|
// restore its default geometry
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
toplevel->state = DIYAC_VIEW_FULL_SCREEN;
|
||||||
|
}
|
||||||
|
diyac_view_update_geometry(toplevel, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
|
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
/* Called when the xdg_toplevel is destroyed. */
|
/* Called when the xdg_toplevel is destroyed. */
|
||||||
struct diyac_toplevel *toplevel = wl_container_of(listener, toplevel, destroy);
|
struct diyac_view *toplevel = wl_container_of(listener, toplevel, destroy);
|
||||||
|
|
||||||
wl_list_remove(&toplevel->map.link);
|
wl_list_remove(&toplevel->map.link);
|
||||||
wl_list_remove(&toplevel->unmap.link);
|
wl_list_remove(&toplevel->unmap.link);
|
||||||
@ -144,6 +175,124 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
|
|||||||
free(toplevel);
|
free(toplevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_xdg_popup_destroy(struct wl_listener *listener, 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);
|
||||||
|
|
||||||
|
/* Usually already removed unless there was no commit at all */
|
||||||
|
if (popup->commit.notify)
|
||||||
|
{
|
||||||
|
wl_list_remove(&popup->commit.link);
|
||||||
|
}
|
||||||
|
free(popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
popup_unconstrain(struct diyac_popup *popup)
|
||||||
|
{
|
||||||
|
struct diyac_view *view = popup->parent;
|
||||||
|
struct diyac_server *server = view->server;
|
||||||
|
struct wlr_box *popup_box = &popup->wlr_popup->current.geometry;
|
||||||
|
struct wlr_output_layout *output_layout = server->output_layout;
|
||||||
|
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||||
|
output_layout, view->current.x + popup_box->x,
|
||||||
|
view->current.y + popup_box->y);
|
||||||
|
|
||||||
|
struct wlr_box output_box;
|
||||||
|
wlr_output_layout_get_box(output_layout, wlr_output, &output_box);
|
||||||
|
|
||||||
|
struct wlr_box output_toplevel_box = {
|
||||||
|
.x = output_box.x - view->current.x,
|
||||||
|
.y = output_box.y - view->current.y,
|
||||||
|
.width = output_box.width,
|
||||||
|
.height = output_box.height,
|
||||||
|
};
|
||||||
|
wlr_xdg_popup_unconstrain_from_box(popup->wlr_popup, &output_toplevel_box);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_xdg_popup_commit(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct diyac_popup *popup = wl_container_of(listener, popup, commit);
|
||||||
|
|
||||||
|
if (popup->wlr_popup->base->initial_commit)
|
||||||
|
{
|
||||||
|
popup_unconstrain(popup);
|
||||||
|
|
||||||
|
/* Prevent getting called over and over again */
|
||||||
|
wl_list_remove(&popup->commit.link);
|
||||||
|
popup->commit.notify = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_xdg_popup_new(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct diyac_popup *popup = wl_container_of(listener, popup, new_popup);
|
||||||
|
struct wlr_xdg_popup *wlr_popup = data;
|
||||||
|
xdg_popup_create(popup->parent, wlr_popup);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xdg_popup_create(struct diyac_view *view, struct wlr_xdg_popup *wlr_popup)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_INFO, "xdg_popup_create: Creating new dialog");
|
||||||
|
struct wlr_xdg_surface *parent =
|
||||||
|
wlr_xdg_surface_try_from_wlr_surface(wlr_popup->parent);
|
||||||
|
if (!parent)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_ERROR, "parent is not a valid XDG surface");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct diyac_popup *popup = calloc(1, sizeof(*popup));
|
||||||
|
popup->parent = view;
|
||||||
|
popup->wlr_popup = wlr_popup;
|
||||||
|
|
||||||
|
popup->destroy.notify = handle_xdg_popup_destroy;
|
||||||
|
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
|
||||||
|
|
||||||
|
popup->new_popup.notify = handle_xdg_popup_new;
|
||||||
|
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
|
||||||
|
|
||||||
|
popup->commit.notify = handle_xdg_popup_commit;
|
||||||
|
wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* xdg-popups live in server->xdg_popup_tree so that they can be
|
||||||
|
* rendered above always-on-top windows
|
||||||
|
*/
|
||||||
|
struct wlr_scene_tree *parent_tree = NULL;
|
||||||
|
if (parent->role == WLR_XDG_SURFACE_ROLE_POPUP)
|
||||||
|
{
|
||||||
|
parent_tree = parent->surface->data;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent_tree = view->server->xdg_popup_tree;
|
||||||
|
wlr_scene_node_set_position(&view->server->xdg_popup_tree->node,
|
||||||
|
view->current.x, view->current.y);
|
||||||
|
}
|
||||||
|
wlr_popup->base->surface->data =
|
||||||
|
wlr_scene_xdg_surface_create(parent_tree, wlr_popup->base);
|
||||||
|
diyac_node_descriptor_create(wlr_popup->base->surface->data,
|
||||||
|
DIYAC_NODE_XDG_POPUP, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xdg_new_popup_notify(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
wlr_log(WLR_INFO, "xdg_new_popup_notify: Creating new dialog");
|
||||||
|
struct diyac_view *view =
|
||||||
|
wl_container_of(listener, view, new_popup);
|
||||||
|
struct wlr_xdg_popup *wlr_popup = data;
|
||||||
|
xdg_popup_create(view, wlr_popup);
|
||||||
|
}
|
||||||
|
|
||||||
void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
|
void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
|
||||||
{
|
{
|
||||||
/* This event is raised when wlr_xdg_shell receives a new xdg surface from a
|
/* This event is raised when wlr_xdg_shell receives a new xdg surface from a
|
||||||
@ -159,37 +308,32 @@ void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
|
|||||||
* scene node. */
|
* scene node. */
|
||||||
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP)
|
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP)
|
||||||
{
|
{
|
||||||
struct wlr_xdg_surface *parent =
|
/*struct wlr_xdg_surface *parent =
|
||||||
wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
|
wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
|
||||||
assert(parent != NULL);
|
assert(parent != NULL);
|
||||||
struct wlr_scene_tree *parent_tree = parent->data;
|
struct wlr_scene_tree *parent_tree = parent->data;
|
||||||
xdg_surface->data = wlr_scene_xdg_surface_create(
|
xdg_surface->data = wlr_scene_xdg_surface_create(
|
||||||
parent_tree, xdg_surface);
|
parent_tree, xdg_surface);
|
||||||
|
return;*/
|
||||||
|
wlr_log(WLR_INFO, "diyac_new_xdg_surface: Creating new dialog using another method");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
|
assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
|
||||||
|
wlr_log(WLR_INFO, "diyac_new_xdg_surface: Creating new application windows");
|
||||||
|
wlr_xdg_surface_ping(xdg_surface);
|
||||||
|
|
||||||
|
/* Allocate a diyac_view for this surface */
|
||||||
|
struct diyac_view *toplevel = calloc(1, sizeof(*toplevel));
|
||||||
/* Allocate a diyac_toplevel for this surface */
|
toplevel->state = DIYAC_VIEW_NORMAL;
|
||||||
struct diyac_toplevel *toplevel = calloc(1, sizeof(*toplevel));
|
|
||||||
toplevel->server = server;
|
toplevel->server = server;
|
||||||
toplevel->xdg_toplevel = xdg_surface->toplevel;
|
toplevel->xdg_toplevel = xdg_surface->toplevel;
|
||||||
|
toplevel->xdg_surface = xdg_surface;
|
||||||
|
toplevel->output = diyac_output_from_cursor(server);
|
||||||
toplevel->scene_tree = wlr_scene_xdg_surface_create(
|
toplevel->scene_tree = wlr_scene_xdg_surface_create(
|
||||||
&toplevel->server->scene->tree, toplevel->xdg_toplevel->base);
|
toplevel->server->view_tree, toplevel->xdg_toplevel->base);
|
||||||
toplevel->scene_tree->node.data = toplevel;
|
xdg_surface->data = toplevel;
|
||||||
xdg_surface->data = toplevel->scene_tree;
|
diyac_node_descriptor_create(&toplevel->scene_tree->node,
|
||||||
|
DIYAC_NODE_VIEW, toplevel);
|
||||||
struct wlr_output *output = wlr_output_layout_output_at(
|
|
||||||
server->output_layout, server->seat.cursor->x,
|
|
||||||
server->seat.cursor->y);
|
|
||||||
toplevel->output = output;
|
|
||||||
if (!output)
|
|
||||||
{
|
|
||||||
wlr_log(WLR_ERROR,
|
|
||||||
"No output available to assign layer surface");
|
|
||||||
|
|
||||||
}
|
|
||||||
/* Listen to the various events it can emit */
|
/* Listen to the various events it can emit */
|
||||||
toplevel->map.notify = xdg_toplevel_map;
|
toplevel->map.notify = xdg_toplevel_map;
|
||||||
wl_signal_add(&xdg_surface->surface->events.map, &toplevel->map);
|
wl_signal_add(&xdg_surface->surface->events.map, &toplevel->map);
|
||||||
@ -210,4 +354,6 @@ void diyac_new_xdg_surface(struct wl_listener *listener, void *data)
|
|||||||
toplevel->request_fullscreen.notify = xdg_toplevel_request_fullscreen;
|
toplevel->request_fullscreen.notify = xdg_toplevel_request_fullscreen;
|
||||||
wl_signal_add(&xdg_toplevel->events.request_fullscreen,
|
wl_signal_add(&xdg_toplevel->events.request_fullscreen,
|
||||||
&toplevel->request_fullscreen);
|
&toplevel->request_fullscreen);
|
||||||
|
toplevel->new_popup.notify = xdg_new_popup_notify;
|
||||||
|
wl_signal_add(&xdg_surface->events.new_popup, &toplevel->new_popup);
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user