diyac/desktop.c

226 lines
7.4 KiB
C
Raw Normal View History

2024-03-31 16:09:01 +02:00
#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;
}
}