feat: add support layershell protocol

This commit is contained in:
DanyLE 2024-03-31 16:09:01 +02:00
parent c1960f0438
commit 55719d6dba
15 changed files with 1404 additions and 534 deletions

View File

@ -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

View File

@ -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
View 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
View 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
View File

@ -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
View File

@ -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
View File

@ -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
View 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
View 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
View 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
View File

@ -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;
}

View File

@ -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
View File

@ -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
View File

@ -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
View File

@ -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);
} }