feat: add support layershell protocol
This commit is contained in:
226
xdg.c
226
xdg.c
@@ -1,14 +1,16 @@
|
||||
#define _POSIX_C_SOURCE 200112L
|
||||
#include <wlr/types/wlr_scene.h>
|
||||
#include <wlr/util/log.h>
|
||||
#include <wlr/types/wlr_cursor.h>
|
||||
#include <wlr/types/wlr_xcursor_manager.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "xdg.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)
|
||||
{
|
||||
/* 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. */
|
||||
return;
|
||||
}
|
||||
server->grabbed_toplevel = toplevel;
|
||||
server->grabbed_view = toplevel;
|
||||
server->seat.cursor_mode = mode;
|
||||
|
||||
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)
|
||||
{
|
||||
/* 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_toplevel(toplevel, toplevel->xdg_toplevel->base->surface);
|
||||
diyac_focus_view(toplevel);
|
||||
}
|
||||
|
||||
static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* 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. */
|
||||
if (toplevel == toplevel->server->grabbed_toplevel)
|
||||
if (toplevel == toplevel->server->grabbed_view)
|
||||
{
|
||||
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
|
||||
* provided serial against a list of button press serials sent to this
|
||||
* 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);
|
||||
}
|
||||
|
||||
@@ -96,7 +98,7 @@ static void xdg_toplevel_request_resize(
|
||||
* provided serial against a list of button press serials sent to this
|
||||
* client, to prevent the client from requesting this whenever they want. */
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -109,29 +111,58 @@ static void xdg_toplevel_request_maximize(
|
||||
* to conform to xdg-shell protocol we still must send a configure.
|
||||
* 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);
|
||||
// wlr_wl_output* output = get_wl_output_from_surface(struct wlr_wl_backend *wl,
|
||||
// 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);
|
||||
wlr_xdg_toplevel_set_size(toplevel->xdg_toplevel, toplevel->output->width, toplevel->output->height);
|
||||
//wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
|
||||
/*
|
||||
struct wlr_output *output = wlr_output_layout_output_at(
|
||||
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);
|
||||
}
|
||||
|
||||
static void xdg_toplevel_request_fullscreen(
|
||||
struct wl_listener *listener, void *data)
|
||||
{
|
||||
/* 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);
|
||||
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)
|
||||
{
|
||||
/* 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->unmap.link);
|
||||
@@ -144,6 +175,124 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
|
||||
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)
|
||||
{
|
||||
/* 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. */
|
||||
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);
|
||||
assert(parent != NULL);
|
||||
struct wlr_scene_tree *parent_tree = parent->data;
|
||||
xdg_surface->data = wlr_scene_xdg_surface_create(
|
||||
parent_tree, xdg_surface);
|
||||
return;*/
|
||||
wlr_log(WLR_INFO, "diyac_new_xdg_surface: Creating new dialog using another method");
|
||||
return;
|
||||
}
|
||||
assert(xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL);
|
||||
wlr_log(WLR_INFO, "diyac_new_xdg_surface: Creating new application windows");
|
||||
wlr_xdg_surface_ping(xdg_surface);
|
||||
|
||||
|
||||
|
||||
/* Allocate a diyac_toplevel for this surface */
|
||||
struct diyac_toplevel *toplevel = calloc(1, sizeof(*toplevel));
|
||||
/* Allocate a diyac_view for this surface */
|
||||
struct diyac_view *toplevel = calloc(1, sizeof(*toplevel));
|
||||
toplevel->state = DIYAC_VIEW_NORMAL;
|
||||
toplevel->server = server;
|
||||
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->server->scene->tree, toplevel->xdg_toplevel->base);
|
||||
toplevel->scene_tree->node.data = toplevel;
|
||||
xdg_surface->data = toplevel->scene_tree;
|
||||
|
||||
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");
|
||||
|
||||
}
|
||||
toplevel->server->view_tree, toplevel->xdg_toplevel->base);
|
||||
xdg_surface->data = toplevel;
|
||||
diyac_node_descriptor_create(&toplevel->scene_tree->node,
|
||||
DIYAC_NODE_VIEW, toplevel);
|
||||
/* Listen to the various events it can emit */
|
||||
toplevel->map.notify = xdg_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;
|
||||
wl_signal_add(&xdg_toplevel->events.request_fullscreen,
|
||||
&toplevel->request_fullscreen);
|
||||
toplevel->new_popup.notify = xdg_new_popup_notify;
|
||||
wl_signal_add(&xdg_surface->events.new_popup, &toplevel->new_popup);
|
||||
}
|
Reference in New Issue
Block a user