feat: add wlr_foreign_toplevel support
This commit is contained in:
parent
bca498f387
commit
dced6db8b2
1
Makefile
1
Makefile
@ -12,6 +12,7 @@ OBJS=\
|
||||
seat.c \
|
||||
node.c \
|
||||
view.c \
|
||||
foreign.c \
|
||||
xdg.c \
|
||||
xdg-shell-protocol.c \
|
||||
layer.c \
|
||||
|
3
cursor.c
3
cursor.c
@ -22,6 +22,8 @@ void diyac_cursor_focus(struct diyac_server *server)
|
||||
switch (desc->type)
|
||||
{
|
||||
case DIYAC_NODE_VIEW:
|
||||
diyac_focus_view(desc->data, true);
|
||||
/*
|
||||
root = diyac_get_root_view(desc->data);
|
||||
if (root)
|
||||
{
|
||||
@ -31,6 +33,7 @@ void diyac_cursor_focus(struct diyac_server *server)
|
||||
{
|
||||
diyac_focus_view(desc->data, true);
|
||||
}
|
||||
*/
|
||||
break;
|
||||
case DIYAC_NODE_LAYER_SURFACE:
|
||||
layer = desc->data;
|
||||
|
2
diyac.c
2
diyac.c
@ -142,6 +142,8 @@ int main(int argc, char *argv[])
|
||||
* let us know when new input devices are available on the backend.
|
||||
*/
|
||||
wl_list_init(&server.seat.keyboards);
|
||||
/* foreign toplevel manager for create shell panel for application control */
|
||||
server.foreign_toplevel_manager = wlr_foreign_toplevel_manager_v1_create(server.wl_display);
|
||||
diyac_init_seat(&server);
|
||||
|
||||
/* Add a Unix socket to the Wayland display. */
|
||||
|
15
diyac.h
15
diyac.h
@ -15,6 +15,7 @@
|
||||
#include <wlr/types/wlr_primary_selection_v1.h>
|
||||
#include <wlr/types/wlr_primary_selection.h>
|
||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
|
||||
|
||||
#define LAYER_TREE_SZ 4
|
||||
/* For brevity's sake, struct members are annotated where they are used. */
|
||||
@ -113,6 +114,8 @@ struct diyac_server
|
||||
struct wl_listener new_xdg_surface;
|
||||
struct wl_listener new_layer_surface;
|
||||
struct wl_list views;
|
||||
struct diyac_view * active_view;
|
||||
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
|
||||
|
||||
/*
|
||||
* Popups need to be rendered above always-on-top views, so we reparent
|
||||
@ -162,6 +165,17 @@ struct diyac_output
|
||||
struct wlr_scene_tree *layer_tree[LAYER_TREE_SZ];
|
||||
};
|
||||
|
||||
struct foreign_toplevel
|
||||
{
|
||||
struct wlr_foreign_toplevel_handle_v1 *handle;
|
||||
struct wl_listener maximize;
|
||||
struct wl_listener minimize;
|
||||
struct wl_listener fullscreen;
|
||||
struct wl_listener activate;
|
||||
struct wl_listener close;
|
||||
struct wl_listener destroy;
|
||||
};
|
||||
|
||||
struct diyac_view
|
||||
{
|
||||
struct wl_list link;
|
||||
@ -191,6 +205,7 @@ struct diyac_view
|
||||
|
||||
struct wl_listener set_app_id; // only useful when using SSD
|
||||
struct wl_listener new_popup;
|
||||
struct foreign_toplevel toplevel;
|
||||
};
|
||||
|
||||
struct diyac_keyboard
|
||||
|
97
foreign.c
Normal file
97
foreign.c
Normal file
@ -0,0 +1,97 @@
|
||||
#include "foreign.h"
|
||||
#include "view.h"
|
||||
#include <wlr/util/log.h>
|
||||
|
||||
static void handle_request_minimize(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_view *view = wl_container_of(listener, view, toplevel.minimize);
|
||||
struct wlr_foreign_toplevel_handle_v1_minimized_event *event = data;
|
||||
// view_minimize(view, event->minimized);
|
||||
diyac_view_set_mimimize(view, event->minimized);
|
||||
wlr_log(WLR_INFO, "foreign: request minimize");
|
||||
|
||||
}
|
||||
|
||||
static void handle_request_maximize(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_view *view = wl_container_of(listener, view, toplevel.maximize);
|
||||
struct wlr_foreign_toplevel_handle_v1_maximized_event *event = data;
|
||||
// view_maximize(view, event->maximized ? VIEW_AXIS_BOTH : VIEW_AXIS_NONE,
|
||||
// /*store_natural_geometry*/ true);
|
||||
diyac_view_set_maximize(view, event->maximized);
|
||||
wlr_log(WLR_INFO, "foreign: request maximize");
|
||||
}
|
||||
|
||||
static void handle_request_fullscreen(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_view *view = wl_container_of(listener, view, toplevel.fullscreen);
|
||||
struct wlr_foreign_toplevel_handle_v1_fullscreen_event *event = data;
|
||||
// view_set_fullscreen(view, event->fullscreen);
|
||||
diyac_view_set_fullscreen(view, event->fullscreen);
|
||||
wlr_log(WLR_INFO, "foreign: request fullscreen");
|
||||
}
|
||||
|
||||
static void handle_request_activate(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_view *view = wl_container_of(listener, view, toplevel.activate);
|
||||
// struct wlr_foreign_toplevel_handle_v1_activated_event *event = data;
|
||||
/* In a multi-seat world we would select seat based on event->seat here. */
|
||||
// desktop_focus_view(view, /*raise*/ true);
|
||||
diyac_focus_view(view,true);
|
||||
wlr_log(WLR_INFO, "foreign: request activate");
|
||||
}
|
||||
|
||||
static void
|
||||
handle_request_close(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_view *view = wl_container_of(listener, view, toplevel.close);
|
||||
//view_close(view);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_destroy(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_view *view = wl_container_of(listener, view, toplevel.destroy);
|
||||
struct foreign_toplevel *toplevel = &view->toplevel;
|
||||
wl_list_remove(&toplevel->maximize.link);
|
||||
wl_list_remove(&toplevel->minimize.link);
|
||||
wl_list_remove(&toplevel->fullscreen.link);
|
||||
wl_list_remove(&toplevel->activate.link);
|
||||
wl_list_remove(&toplevel->close.link);
|
||||
wl_list_remove(&toplevel->destroy.link);
|
||||
toplevel->handle = NULL;
|
||||
}
|
||||
|
||||
void diyac_init_foreign_toplevel(struct diyac_view *view)
|
||||
{
|
||||
struct foreign_toplevel *toplevel = &view->toplevel;
|
||||
toplevel->handle = wlr_foreign_toplevel_handle_v1_create(
|
||||
view->server->foreign_toplevel_manager);
|
||||
if (!toplevel->handle)
|
||||
{
|
||||
wlr_log(WLR_ERROR, "cannot create foreign toplevel handle");
|
||||
return;
|
||||
}
|
||||
toplevel->maximize.notify = handle_request_maximize;
|
||||
wl_signal_add(&toplevel->handle->events.request_maximize,
|
||||
&toplevel->maximize);
|
||||
|
||||
toplevel->minimize.notify = handle_request_minimize;
|
||||
wl_signal_add(&toplevel->handle->events.request_minimize,
|
||||
&toplevel->minimize);
|
||||
|
||||
toplevel->fullscreen.notify = handle_request_fullscreen;
|
||||
wl_signal_add(&toplevel->handle->events.request_fullscreen,
|
||||
&toplevel->fullscreen);
|
||||
|
||||
toplevel->activate.notify = handle_request_activate;
|
||||
wl_signal_add(&toplevel->handle->events.request_activate,
|
||||
&toplevel->activate);
|
||||
|
||||
toplevel->close.notify = handle_request_close;
|
||||
wl_signal_add(&toplevel->handle->events.request_close,
|
||||
&toplevel->close);
|
||||
|
||||
toplevel->destroy.notify = handle_destroy;
|
||||
wl_signal_add(&toplevel->handle->events.destroy, &toplevel->destroy);
|
||||
}
|
6
foreign.h
Normal file
6
foreign.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef DIYAC_FOREIGN_H
|
||||
#define DIYAC_FOREIGN_H
|
||||
#include "diyac.h"
|
||||
|
||||
void diyac_init_foreign_toplevel(struct diyac_view* view);
|
||||
#endif
|
93
view.c
93
view.c
@ -5,6 +5,25 @@
|
||||
#include "node.h"
|
||||
#include "seat.h"
|
||||
#include "output.h"
|
||||
#include "cursor.h"
|
||||
|
||||
static void diyac_view_set_activated(struct diyac_view * view, bool activated)
|
||||
{
|
||||
struct diyac_server *server = view->server;
|
||||
wlr_xdg_toplevel_set_activated(view->xdg_toplevel, activated);
|
||||
if(view->toplevel.handle)
|
||||
{
|
||||
wlr_foreign_toplevel_handle_v1_set_activated(view->toplevel.handle, activated);
|
||||
}
|
||||
server->active_view = NULL;
|
||||
if(activated)
|
||||
{
|
||||
|
||||
diyac_seat_focus_surface(&server->seat, view->xdg_toplevel->base->surface);
|
||||
server->active_view = view;
|
||||
}
|
||||
}
|
||||
|
||||
static void raise_to_front(struct diyac_view *view)
|
||||
{
|
||||
/* Move the toplevel to the front */
|
||||
@ -12,8 +31,8 @@ static void raise_to_front(struct diyac_view *view)
|
||||
wl_list_remove(&view->link);
|
||||
wl_list_insert(&view->server->views, &view->link);
|
||||
/* Activate the new surface */
|
||||
wlr_xdg_toplevel_set_activated(view->xdg_toplevel, true);
|
||||
}
|
||||
|
||||
void diyac_focus_view(struct diyac_view *toplevel, bool raise)
|
||||
{
|
||||
/* Note: this function only deals with keyboard focus. */
|
||||
@ -26,27 +45,15 @@ void diyac_focus_view(struct diyac_view *toplevel, bool raise)
|
||||
// dont focus unmapped view
|
||||
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)
|
||||
if(toplevel == toplevel->server->active_view)
|
||||
{
|
||||
// Don't re-focus an already focused surface.
|
||||
wlr_log(WLR_DEBUG, "Don't re-focus an already focused surface");
|
||||
return;
|
||||
}
|
||||
if (prev_surface)
|
||||
if(toplevel->server->active_view)
|
||||
{
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
diyac_view_set_activated(toplevel->server->active_view, false);
|
||||
}
|
||||
raise_to_front(toplevel);
|
||||
if (raise)
|
||||
@ -61,13 +68,12 @@ void diyac_focus_view(struct diyac_view *toplevel, bool raise)
|
||||
}
|
||||
wl_array_release(&subviews);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
diyac_view_set_activated(toplevel, true);
|
||||
//diyac_seat_focus_surface(&server->seat, toplevel->xdg_toplevel->base->surface);
|
||||
/*if(toplevel->toplevel.handle)
|
||||
{
|
||||
wlr_foreign_toplevel_handle_v1_set_activated(toplevel->toplevel.handle, true);
|
||||
}*/
|
||||
}
|
||||
|
||||
struct diyac_view *diyac_view_at(
|
||||
@ -100,6 +106,7 @@ void diyac_focus_topmost_view(struct diyac_server *server, bool raise)
|
||||
}
|
||||
else
|
||||
{
|
||||
wlr_log(WLR_INFO, "No view found");
|
||||
/*
|
||||
* Defocus previous focused surface/view if no longer
|
||||
* focusable (e.g. unmapped or on a different workspace).
|
||||
@ -124,7 +131,6 @@ struct diyac_view *diyac_topmost_focusable_view(struct diyac_server *server)
|
||||
continue;
|
||||
}
|
||||
view = diyac_view_from_node(node);
|
||||
return view;
|
||||
|
||||
if (view->mapped /*&& view_is_focusable_from(view, prev)*/)
|
||||
{
|
||||
@ -181,12 +187,20 @@ bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed)
|
||||
if(view->state.fullscreen && !view->requested.fullscreen)
|
||||
{
|
||||
wlr_xdg_toplevel_set_fullscreen(view->xdg_toplevel, false);
|
||||
if(view->toplevel.handle)
|
||||
{
|
||||
wlr_foreign_toplevel_handle_v1_set_fullscreen(view->toplevel.handle, false);
|
||||
}
|
||||
wlr_scene_node_set_enabled(&view->output->scenes.top->node, true);
|
||||
view->state.fullscreen = false;
|
||||
}
|
||||
if(view->state.maximized && !view->requested.maximized)
|
||||
{
|
||||
wlr_xdg_toplevel_set_maximized(view->xdg_toplevel, false);
|
||||
if(view->toplevel.handle)
|
||||
{
|
||||
wlr_foreign_toplevel_handle_v1_set_maximized(view->toplevel.handle, false);
|
||||
}
|
||||
view->state.maximized = false;
|
||||
}
|
||||
view->state = view->requested;
|
||||
@ -202,6 +216,10 @@ bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed)
|
||||
wlr_scene_node_set_position(&view->scene_tree->node, 0, 0);
|
||||
wlr_xdg_toplevel_set_size(view->xdg_toplevel, view->output->wlr_output->width, view->output->wlr_output->height);
|
||||
wlr_xdg_toplevel_set_fullscreen(view->xdg_toplevel, false);
|
||||
if(view->toplevel.handle)
|
||||
{
|
||||
wlr_foreign_toplevel_handle_v1_set_fullscreen(view->toplevel.handle, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else if(view->requested.maximized)
|
||||
@ -209,6 +227,10 @@ bool diyac_view_update_geometry(struct diyac_view *view, bool grabbed)
|
||||
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);
|
||||
wlr_xdg_toplevel_set_maximized(view->xdg_toplevel, true);
|
||||
if(view->toplevel.handle)
|
||||
{
|
||||
wlr_foreign_toplevel_handle_v1_set_maximized(view->toplevel.handle, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@ -305,3 +327,26 @@ struct wlr_box diyac_view_get_geometry(struct diyac_view *view)
|
||||
}
|
||||
return view->original;
|
||||
}
|
||||
|
||||
void diyac_view_set_maximize(struct diyac_view * view, bool activated)
|
||||
{
|
||||
view->requested.maximized = activated;
|
||||
diyac_reset_cursor_mode(view->server);
|
||||
diyac_view_update_geometry(view, false);
|
||||
}
|
||||
void diyac_view_set_fullscreen(struct diyac_view * view, bool activated)
|
||||
{
|
||||
view->requested.fullscreen = activated;
|
||||
/**
|
||||
* TODO: use client specific output for fullscreen
|
||||
* toplevel->xdg_toplevel->requested.fullscreen_output
|
||||
*/
|
||||
diyac_reset_cursor_mode(view->server);
|
||||
diyac_view_update_geometry(view, false);
|
||||
}
|
||||
void diyac_view_set_mimimize(struct diyac_view * view, bool activated)
|
||||
{
|
||||
// view->requested.minimized = activated;
|
||||
//TODO implement minimize
|
||||
wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base);
|
||||
}
|
3
view.h
3
view.h
@ -15,4 +15,7 @@ void diyac_arrange_all_views(struct diyac_server *server);
|
||||
struct diyac_view *diyac_get_root_view(struct diyac_view *view);
|
||||
void diyac_get_children_views(struct diyac_view *view, struct wl_array *children);
|
||||
struct wlr_box diyac_view_get_geometry(struct diyac_view *view);
|
||||
void diyac_view_set_maximize(struct diyac_view * view, bool activated);
|
||||
void diyac_view_set_fullscreen(struct diyac_view * view, bool activated);
|
||||
void diyac_view_set_mimimize(struct diyac_view * view, bool activated);
|
||||
#endif
|
48
xdg.c
48
xdg.c
@ -7,6 +7,7 @@
|
||||
#include "node.h"
|
||||
#include "view.h"
|
||||
#include "output.h"
|
||||
#include "foreign.h"
|
||||
|
||||
static void xdg_popup_create(struct diyac_view *view, struct wlr_xdg_popup *wlr_popup);
|
||||
|
||||
@ -58,6 +59,10 @@ 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_view *toplevel = wl_container_of(listener, toplevel, map);
|
||||
if(toplevel->mapped)
|
||||
{
|
||||
return;
|
||||
}
|
||||
/*
|
||||
wlr_xdg_toplevel_set_wm_capabilities(toplevel->xdg_toplevel,
|
||||
WLR_XDG_TOPLEVEL_WM_CAPABILITIES_MAXIMIZE |
|
||||
@ -67,6 +72,7 @@ static void xdg_toplevel_map(struct wl_listener *listener, void *data)
|
||||
wlr_xdg_surface_get_geometry(toplevel->xdg_toplevel->base, &toplevel->original);
|
||||
wlr_scene_node_set_enabled(&toplevel->scene_tree->node, true);
|
||||
toplevel->mapped = true;
|
||||
diyac_init_foreign_toplevel(toplevel);
|
||||
wl_list_insert(&toplevel->server->views, &toplevel->link);
|
||||
toplevel->original.x = (toplevel->output->usable_area.width - toplevel->original.width) / 2;
|
||||
toplevel->original.y = (toplevel->output->usable_area.height - toplevel->original.height) / 2;
|
||||
@ -100,6 +106,22 @@ static void xdg_toplevel_unmap(struct wl_listener *listener, void *data)
|
||||
*/
|
||||
wlr_scene_node_set_enabled(&toplevel->output->scenes.top->node, true);
|
||||
}
|
||||
if(toplevel->server->active_view == toplevel)
|
||||
{
|
||||
toplevel->server->active_view = NULL;
|
||||
}
|
||||
struct diyac_view *root = diyac_get_root_view(toplevel);
|
||||
if (root && root->mapped)
|
||||
{
|
||||
diyac_focus_view(root, true);
|
||||
//wlr_log(WLR_INFO, "focus root");
|
||||
}
|
||||
else
|
||||
{
|
||||
//wlr_log(WLR_INFO, "focus topmost");
|
||||
diyac_focus_topmost_view(toplevel->server, true);
|
||||
}
|
||||
|
||||
wl_list_remove(&toplevel->link);
|
||||
}
|
||||
|
||||
@ -140,31 +162,21 @@ static void xdg_toplevel_request_maximize(
|
||||
|
||||
struct diyac_view *toplevel =
|
||||
wl_container_of(listener, toplevel, request_maximize);
|
||||
toplevel->requested.maximized = toplevel->xdg_toplevel->requested.maximized;
|
||||
diyac_reset_cursor_mode(toplevel->server);
|
||||
diyac_view_update_geometry(toplevel, false);
|
||||
diyac_view_set_maximize(toplevel, toplevel->xdg_toplevel->requested.maximized);
|
||||
}
|
||||
|
||||
static void xdg_toplevel_request_fullscreen(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_view *toplevel =
|
||||
wl_container_of(listener, toplevel, request_fullscreen);
|
||||
toplevel->requested.fullscreen = toplevel->xdg_toplevel->requested.fullscreen;
|
||||
/**
|
||||
* TODO: use client specific output for fullscreen
|
||||
* toplevel->xdg_toplevel->requested.fullscreen_output
|
||||
*/
|
||||
diyac_reset_cursor_mode(toplevel->server);
|
||||
diyac_view_update_geometry(toplevel, false);
|
||||
diyac_view_set_fullscreen(toplevel,toplevel->xdg_toplevel->requested.fullscreen);
|
||||
}
|
||||
|
||||
static void xdg_toplevel_request_minimize(struct wl_listener *listener, void *data)
|
||||
{
|
||||
struct diyac_view *toplevel =
|
||||
wl_container_of(listener, toplevel, request_minimize);
|
||||
toplevel->requested.minimized = toplevel->xdg_toplevel->requested.minimized;
|
||||
//TODO implement minimize
|
||||
wlr_xdg_surface_schedule_configure(toplevel->xdg_toplevel->base);
|
||||
diyac_view_set_mimimize(toplevel, toplevel->xdg_toplevel->requested.minimized);
|
||||
}
|
||||
|
||||
static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
|
||||
@ -172,16 +184,6 @@ static void xdg_toplevel_destroy(struct wl_listener *listener, void *data)
|
||||
/* Called when the xdg_toplevel is destroyed. */
|
||||
struct diyac_view *toplevel = wl_container_of(listener, toplevel, destroy);
|
||||
|
||||
struct diyac_view *root = diyac_get_root_view(toplevel);
|
||||
if (root && root->mapped)
|
||||
{
|
||||
diyac_focus_view(root, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
diyac_focus_topmost_view(toplevel->server, true);
|
||||
}
|
||||
|
||||
wl_list_remove(&toplevel->map.link);
|
||||
wl_list_remove(&toplevel->unmap.link);
|
||||
wl_list_remove(&toplevel->destroy.link);
|
||||
|
Loading…
Reference in New Issue
Block a user