226 lines
7.4 KiB
C
226 lines
7.4 KiB
C
|
#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;
|
||
|
}
|
||
|
}
|