mirror of
https://github.com/swaywm/sway.git
synced 2024-12-27 07:26:55 +01:00
input: Query scene graph for relevant surface/node intersections
This commit is contained in:
parent
946fc80945
commit
5b8b505af5
7 changed files with 93 additions and 412 deletions
|
@ -12,6 +12,9 @@
|
||||||
|
|
||||||
enum sway_scene_descriptor_type {
|
enum sway_scene_descriptor_type {
|
||||||
SWAY_SCENE_DESC_BUFFER_TIMER,
|
SWAY_SCENE_DESC_BUFFER_TIMER,
|
||||||
|
SWAY_SCENE_DESC_NON_INTERACTIVE,
|
||||||
|
SWAY_SCENE_DESC_CONTAINER,
|
||||||
|
SWAY_SCENE_DESC_VIEW,
|
||||||
SWAY_SCENE_DESC_DRAG_ICON,
|
SWAY_SCENE_DESC_DRAG_ICON,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -172,19 +172,6 @@ void container_begin_destroy(struct sway_container *con);
|
||||||
struct sway_container *container_find_child(struct sway_container *container,
|
struct sway_container *container_find_child(struct sway_container *container,
|
||||||
bool (*test)(struct sway_container *view, void *data), void *data);
|
bool (*test)(struct sway_container *view, void *data), void *data);
|
||||||
|
|
||||||
/**
|
|
||||||
* Find a container at the given coordinates. Returns the surface and
|
|
||||||
* surface-local coordinates of the given layout coordinates if the container
|
|
||||||
* is a view and the view contains a surface at those coordinates.
|
|
||||||
*/
|
|
||||||
struct sway_container *container_at(struct sway_workspace *workspace,
|
|
||||||
double lx, double ly, struct wlr_surface **surface,
|
|
||||||
double *sx, double *sy);
|
|
||||||
|
|
||||||
struct sway_container *tiling_container_at(
|
|
||||||
struct sway_node *parent, double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy);
|
|
||||||
|
|
||||||
void container_for_each_child(struct sway_container *container,
|
void container_for_each_child(struct sway_container *container,
|
||||||
void (*f)(struct sway_container *container, void *data), void *data);
|
void (*f)(struct sway_container *container, void *data), void *data);
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,10 @@ struct sway_root {
|
||||||
// staging node will be visible.
|
// staging node will be visible.
|
||||||
struct wlr_scene_tree *staging;
|
struct wlr_scene_tree *staging;
|
||||||
|
|
||||||
|
// tree containing all layers the compositor will render. Cursor handling
|
||||||
|
// will end up iterating this tree.
|
||||||
|
struct wlr_scene_tree *layer_tree;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
struct wlr_scene_tree *tiling;
|
struct wlr_scene_tree *tiling;
|
||||||
struct wlr_scene_tree *floating;
|
struct wlr_scene_tree *floating;
|
||||||
|
|
|
@ -37,43 +37,6 @@ static uint32_t get_current_time_msec(void) {
|
||||||
return now.tv_sec * 1000 + now.tv_nsec / 1000000;
|
return now.tv_sec * 1000 + now.tv_nsec / 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wlr_surface *layer_surface_at(struct sway_output *output,
|
|
||||||
struct wl_list *layer, double ox, double oy, double *sx, double *sy) {
|
|
||||||
struct sway_layer_surface *sway_layer;
|
|
||||||
wl_list_for_each_reverse(sway_layer, layer, link) {
|
|
||||||
double _sx = ox - sway_layer->geo.x;
|
|
||||||
double _sy = oy - sway_layer->geo.y;
|
|
||||||
struct wlr_surface *sub = wlr_layer_surface_v1_surface_at(
|
|
||||||
sway_layer->layer_surface, _sx, _sy, sx, sy);
|
|
||||||
if (sub) {
|
|
||||||
return sub;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool surface_is_xdg_popup(struct wlr_surface *surface) {
|
|
||||||
struct wlr_xdg_surface *xdg_surface =
|
|
||||||
wlr_xdg_surface_try_from_wlr_surface(surface);
|
|
||||||
return xdg_surface != NULL && xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP &&
|
|
||||||
xdg_surface->popup != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
|
|
||||||
struct wl_list *layer, double ox, double oy, double *sx, double *sy) {
|
|
||||||
struct sway_layer_surface *sway_layer;
|
|
||||||
wl_list_for_each_reverse(sway_layer, layer, link) {
|
|
||||||
double _sx = ox - sway_layer->geo.x;
|
|
||||||
double _sy = oy - sway_layer->geo.y;
|
|
||||||
struct wlr_surface *sub = wlr_layer_surface_v1_surface_at(
|
|
||||||
sway_layer->layer_surface, _sx, _sy, sx, sy);
|
|
||||||
if (sub && surface_is_xdg_popup(sub)) {
|
|
||||||
return sub;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the node at the cursor's position. If there is a surface at that
|
* Returns the node at the cursor's position. If there is a surface at that
|
||||||
* location, it is stored in **surface (it may not be a view).
|
* location, it is stored in **surface (it may not be a view).
|
||||||
|
@ -81,119 +44,82 @@ static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
|
||||||
struct sway_node *node_at_coords(
|
struct sway_node *node_at_coords(
|
||||||
struct sway_seat *seat, double lx, double ly,
|
struct sway_seat *seat, double lx, double ly,
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
struct wlr_surface **surface, double *sx, double *sy) {
|
||||||
// find the output the cursor is on
|
struct wlr_scene_node *scene_node = NULL;
|
||||||
|
|
||||||
|
struct wlr_scene_node *node;
|
||||||
|
wl_list_for_each_reverse(node, &root->layer_tree->children, link) {
|
||||||
|
struct wlr_scene_tree *layer = wlr_scene_tree_from_node(node);
|
||||||
|
|
||||||
|
bool non_interactive = scene_descriptor_try_get(&layer->node,
|
||||||
|
SWAY_SCENE_DESC_NON_INTERACTIVE);
|
||||||
|
if (non_interactive) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
scene_node = wlr_scene_node_at(&layer->node, lx, ly, sx, sy);
|
||||||
|
if (scene_node) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scene_node) {
|
||||||
|
// determine what wlr_surface we clicked on
|
||||||
|
if (scene_node->type == WLR_SCENE_NODE_BUFFER) {
|
||||||
|
struct wlr_scene_buffer *scene_buffer =
|
||||||
|
wlr_scene_buffer_from_node(scene_node);
|
||||||
|
struct wlr_scene_surface *scene_surface =
|
||||||
|
wlr_scene_surface_try_from_buffer(scene_buffer);
|
||||||
|
|
||||||
|
if (scene_surface) {
|
||||||
|
*surface = scene_surface->surface;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// determine what container we clicked on
|
||||||
|
struct wlr_scene_node *current = scene_node;
|
||||||
|
while (true) {
|
||||||
|
struct sway_container *con = scene_descriptor_try_get(current,
|
||||||
|
SWAY_SCENE_DESC_CONTAINER);
|
||||||
|
if (!con) {
|
||||||
|
struct sway_view *view = scene_descriptor_try_get(current,
|
||||||
|
SWAY_SCENE_DESC_VIEW);
|
||||||
|
if (view) {
|
||||||
|
con = view->container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (con) {
|
||||||
|
if (!con->view || con->view->surface) {
|
||||||
|
return &con->node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!current->parent) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = ¤t->parent->node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we aren't on a container, determine what workspace we are on
|
||||||
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
struct wlr_output *wlr_output = wlr_output_layout_output_at(
|
||||||
root->output_layout, lx, ly);
|
root->output_layout, lx, ly);
|
||||||
if (wlr_output == NULL) {
|
if (wlr_output == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sway_output *output = wlr_output->data;
|
struct sway_output *output = wlr_output->data;
|
||||||
if (!output || !output->enabled) {
|
if (!output || !output->enabled) {
|
||||||
// output is being destroyed or is being enabled
|
// output is being destroyed or is being enabled
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
double ox = lx, oy = ly;
|
|
||||||
wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
|
|
||||||
|
|
||||||
// layer surfaces on the overlay layer are rendered on top
|
|
||||||
if ((*surface = layer_surface_at(output,
|
|
||||||
&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
|
|
||||||
ox, oy, sx, sy))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for unmanaged views
|
|
||||||
#if HAVE_XWAYLAND
|
|
||||||
struct wl_list *unmanaged = &root->xwayland_unmanaged;
|
|
||||||
struct sway_xwayland_unmanaged *unmanaged_surface;
|
|
||||||
wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) {
|
|
||||||
struct wlr_xwayland_surface *xsurface =
|
|
||||||
unmanaged_surface->wlr_xwayland_surface;
|
|
||||||
|
|
||||||
double _sx = lx - unmanaged_surface->lx;
|
|
||||||
double _sy = ly - unmanaged_surface->ly;
|
|
||||||
if (wlr_surface_point_accepts_input(xsurface->surface, _sx, _sy)) {
|
|
||||||
*surface = xsurface->surface;
|
|
||||||
*sx = _sx;
|
|
||||||
*sy = _sy;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (root->fullscreen_global) {
|
|
||||||
// Try fullscreen container
|
|
||||||
struct sway_container *con = tiling_container_at(
|
|
||||||
&root->fullscreen_global->node, lx, ly, surface, sx, sy);
|
|
||||||
if (con) {
|
|
||||||
return &con->node;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the focused workspace on the output for this seat
|
|
||||||
struct sway_workspace *ws = output_get_active_workspace(output);
|
struct sway_workspace *ws = output_get_active_workspace(output);
|
||||||
if (!ws) {
|
if (!ws) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ws->fullscreen) {
|
|
||||||
// Try transient containers
|
|
||||||
for (int i = 0; i < ws->floating->length; ++i) {
|
|
||||||
struct sway_container *floater = ws->floating->items[i];
|
|
||||||
if (container_is_transient_for(floater, ws->fullscreen)) {
|
|
||||||
struct sway_container *con = tiling_container_at(
|
|
||||||
&floater->node, lx, ly, surface, sx, sy);
|
|
||||||
if (con) {
|
|
||||||
return &con->node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Try fullscreen container
|
|
||||||
struct sway_container *con =
|
|
||||||
tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy);
|
|
||||||
if (con) {
|
|
||||||
return &con->node;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if ((*surface = layer_surface_popup_at(output,
|
|
||||||
&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
|
||||||
ox, oy, sx, sy))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if ((*surface = layer_surface_popup_at(output,
|
|
||||||
&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
|
||||||
ox, oy, sx, sy))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if ((*surface = layer_surface_popup_at(output,
|
|
||||||
&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
|
||||||
ox, oy, sx, sy))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if ((*surface = layer_surface_at(output,
|
|
||||||
&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP],
|
|
||||||
ox, oy, sx, sy))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sway_container *c;
|
|
||||||
if ((c = container_at(ws, lx, ly, surface, sx, sy))) {
|
|
||||||
return &c->node;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((*surface = layer_surface_at(output,
|
|
||||||
&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM],
|
|
||||||
ox, oy, sx, sy))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if ((*surface = layer_surface_at(output,
|
|
||||||
&output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND],
|
|
||||||
ox, oy, sx, sy))) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ws->node;
|
return &ws->node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "sway/input/input-manager.h"
|
#include "sway/input/input-manager.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
#include "sway/ipc-server.h"
|
#include "sway/ipc-server.h"
|
||||||
|
#include "sway/scene_descriptor.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
#include "sway/surface.h"
|
#include "sway/surface.h"
|
||||||
|
@ -94,6 +95,11 @@ struct sway_container *container_create(struct sway_view *view) {
|
||||||
c->border.right = alloc_rect_node(c->border.tree, &failed);
|
c->border.right = alloc_rect_node(c->border.tree, &failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!failed && !scene_descriptor_assign(&c->scene_tree->node,
|
||||||
|
SWAY_SCENE_DESC_CONTAINER, c)) {
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
wlr_scene_node_destroy(&c->scene_tree->node);
|
wlr_scene_node_destroy(&c->scene_tree->node);
|
||||||
free(c);
|
free(c);
|
||||||
|
@ -239,265 +245,6 @@ struct sway_container *container_find_child(struct sway_container *container,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sway_container *surface_at_view(struct sway_container *con, double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
|
||||||
if (!sway_assert(con->view, "Expected a view")) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
struct sway_view *view = con->view;
|
|
||||||
double view_sx = lx - con->surface_x + view->geometry.x;
|
|
||||||
double view_sy = ly - con->surface_y + view->geometry.y;
|
|
||||||
|
|
||||||
double _sx, _sy;
|
|
||||||
struct wlr_surface *_surface = NULL;
|
|
||||||
switch (view->type) {
|
|
||||||
#if HAVE_XWAYLAND
|
|
||||||
case SWAY_VIEW_XWAYLAND:
|
|
||||||
_surface = wlr_surface_surface_at(view->surface,
|
|
||||||
view_sx, view_sy, &_sx, &_sy);
|
|
||||||
break;
|
|
||||||
#endif
|
|
||||||
case SWAY_VIEW_XDG_SHELL:
|
|
||||||
_surface = wlr_xdg_surface_surface_at(
|
|
||||||
view->wlr_xdg_toplevel->base,
|
|
||||||
view_sx, view_sy, &_sx, &_sy);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (_surface) {
|
|
||||||
*sx = _sx;
|
|
||||||
*sy = _sy;
|
|
||||||
*surface = _surface;
|
|
||||||
return con;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* container_at for a container with layout L_TABBED.
|
|
||||||
*/
|
|
||||||
static struct sway_container *container_at_tabbed(struct sway_node *parent,
|
|
||||||
double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
|
||||||
struct wlr_box box;
|
|
||||||
node_get_box(parent, &box);
|
|
||||||
if (lx < box.x || lx > box.x + box.width ||
|
|
||||||
ly < box.y || ly > box.y + box.height) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
struct sway_seat *seat = input_manager_current_seat();
|
|
||||||
list_t *children = node_get_children(parent);
|
|
||||||
if (!children->length) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tab titles
|
|
||||||
int title_height = container_titlebar_height();
|
|
||||||
if (ly < box.y + title_height) {
|
|
||||||
int tab_width = box.width / children->length;
|
|
||||||
int child_index = (lx - box.x) / tab_width;
|
|
||||||
if (child_index >= children->length) {
|
|
||||||
child_index = children->length - 1;
|
|
||||||
}
|
|
||||||
struct sway_container *child = children->items[child_index];
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Surfaces
|
|
||||||
struct sway_node *current = seat_get_active_tiling_child(seat, parent);
|
|
||||||
return current ? tiling_container_at(current, lx, ly, surface, sx, sy) : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* container_at for a container with layout L_STACKED.
|
|
||||||
*/
|
|
||||||
static struct sway_container *container_at_stacked(struct sway_node *parent,
|
|
||||||
double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
|
||||||
struct wlr_box box;
|
|
||||||
node_get_box(parent, &box);
|
|
||||||
if (lx < box.x || lx > box.x + box.width ||
|
|
||||||
ly < box.y || ly > box.y + box.height) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
struct sway_seat *seat = input_manager_current_seat();
|
|
||||||
list_t *children = node_get_children(parent);
|
|
||||||
|
|
||||||
// Title bars
|
|
||||||
int title_height = container_titlebar_height();
|
|
||||||
if (title_height > 0) {
|
|
||||||
int child_index = (ly - box.y) / title_height;
|
|
||||||
if (child_index < children->length) {
|
|
||||||
struct sway_container *child = children->items[child_index];
|
|
||||||
return child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Surfaces
|
|
||||||
struct sway_node *current = seat_get_active_tiling_child(seat, parent);
|
|
||||||
return current ? tiling_container_at(current, lx, ly, surface, sx, sy) : NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* container_at for a container with layout L_HORIZ or L_VERT.
|
|
||||||
*/
|
|
||||||
static struct sway_container *container_at_linear(struct sway_node *parent,
|
|
||||||
double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
|
||||||
list_t *children = node_get_children(parent);
|
|
||||||
for (int i = 0; i < children->length; ++i) {
|
|
||||||
struct sway_container *child = children->items[i];
|
|
||||||
struct sway_container *container =
|
|
||||||
tiling_container_at(&child->node, lx, ly, surface, sx, sy);
|
|
||||||
if (container) {
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sway_container *floating_container_at(double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
|
||||||
// For outputs with floating containers that overhang the output bounds,
|
|
||||||
// those at the end of the output list appear on top of floating
|
|
||||||
// containers from other outputs, so iterate the list in reverse.
|
|
||||||
for (int i = root->outputs->length - 1; i >= 0; --i) {
|
|
||||||
struct sway_output *output = root->outputs->items[i];
|
|
||||||
for (int j = 0; j < output->workspaces->length; ++j) {
|
|
||||||
struct sway_workspace *ws = output->workspaces->items[j];
|
|
||||||
if (!workspace_is_visible(ws)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
// Items at the end of the list are on top, so iterate the list in
|
|
||||||
// reverse.
|
|
||||||
for (int k = ws->floating->length - 1; k >= 0; --k) {
|
|
||||||
struct sway_container *floater = ws->floating->items[k];
|
|
||||||
struct sway_container *container =
|
|
||||||
tiling_container_at(&floater->node, lx, ly, surface, sx, sy);
|
|
||||||
if (container) {
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sway_container *view_container_content_at(struct sway_node *parent,
|
|
||||||
double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
|
||||||
if (!sway_assert(node_is_view(parent), "Expected a view")) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sway_container *container = parent->sway_container;
|
|
||||||
struct wlr_box box = {
|
|
||||||
.x = container->pending.content_x,
|
|
||||||
.y = container->pending.content_y,
|
|
||||||
.width = container->pending.content_width,
|
|
||||||
.height = container->pending.content_height,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (wlr_box_contains_point(&box, lx, ly)) {
|
|
||||||
surface_at_view(parent->sway_container, lx, ly, surface, sx, sy);
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sway_container *view_container_at(struct sway_node *parent,
|
|
||||||
double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
|
||||||
if (!sway_assert(node_is_view(parent), "Expected a view")) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sway_container *container = parent->sway_container;
|
|
||||||
struct wlr_box box = {
|
|
||||||
.x = container->pending.x,
|
|
||||||
.y = container->pending.y,
|
|
||||||
.width = container->pending.width,
|
|
||||||
.height = container->pending.height,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (wlr_box_contains_point(&box, lx, ly)) {
|
|
||||||
surface_at_view(parent->sway_container, lx, ly, surface, sx, sy);
|
|
||||||
return container;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sway_container *tiling_container_at(struct sway_node *parent,
|
|
||||||
double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
|
||||||
if (node_is_view(parent)) {
|
|
||||||
return view_container_at(parent, lx, ly, surface, sx, sy);
|
|
||||||
}
|
|
||||||
if (!node_get_children(parent)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
switch (node_get_layout(parent)) {
|
|
||||||
case L_HORIZ:
|
|
||||||
case L_VERT:
|
|
||||||
return container_at_linear(parent, lx, ly, surface, sx, sy);
|
|
||||||
case L_TABBED:
|
|
||||||
return container_at_tabbed(parent, lx, ly, surface, sx, sy);
|
|
||||||
case L_STACKED:
|
|
||||||
return container_at_stacked(parent, lx, ly, surface, sx, sy);
|
|
||||||
case L_NONE:
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool surface_is_popup(struct wlr_surface *surface) {
|
|
||||||
while (wlr_xdg_surface_try_from_wlr_surface(surface) == NULL) {
|
|
||||||
struct wlr_subsurface *subsurface =
|
|
||||||
wlr_subsurface_try_from_wlr_surface(surface);
|
|
||||||
if (subsurface == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
surface = subsurface->parent;
|
|
||||||
}
|
|
||||||
struct wlr_xdg_surface *xdg_surface =
|
|
||||||
wlr_xdg_surface_try_from_wlr_surface(surface);
|
|
||||||
return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && xdg_surface->popup != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sway_container *container_at(struct sway_workspace *workspace,
|
|
||||||
double lx, double ly,
|
|
||||||
struct wlr_surface **surface, double *sx, double *sy) {
|
|
||||||
struct sway_container *c;
|
|
||||||
|
|
||||||
struct sway_seat *seat = input_manager_current_seat();
|
|
||||||
struct sway_container *focus = seat_get_focused_container(seat);
|
|
||||||
bool is_floating = focus && container_is_floating_or_child(focus);
|
|
||||||
// Focused view's popups
|
|
||||||
if (focus && focus->view) {
|
|
||||||
c = surface_at_view(focus, lx, ly, surface, sx, sy);
|
|
||||||
if (c && surface_is_popup(*surface)) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
*surface = NULL;
|
|
||||||
}
|
|
||||||
// Floating
|
|
||||||
if ((c = floating_container_at(lx, ly, surface ,sx ,sy))) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
// Tiling (focused)
|
|
||||||
if (focus && focus->view && !is_floating) {
|
|
||||||
if ((c = view_container_content_at(&focus->node, lx, ly, surface, sx, sy))) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Tiling (non-focused)
|
|
||||||
if ((c = tiling_container_at(&workspace->node, lx, ly, surface, sx, sy))) {
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void container_for_each_child(struct sway_container *container,
|
void container_for_each_child(struct sway_container *container,
|
||||||
void (*f)(struct sway_container *container, void *data),
|
void (*f)(struct sway_container *container, void *data),
|
||||||
void *data) {
|
void *data) {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
#include "sway/ipc-server.h"
|
#include "sway/ipc-server.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
|
#include "sway/scene_descriptor.h"
|
||||||
#include "sway/tree/arrange.h"
|
#include "sway/tree/arrange.h"
|
||||||
#include "sway/tree/container.h"
|
#include "sway/tree/container.h"
|
||||||
#include "sway/tree/root.h"
|
#include "sway/tree/root.h"
|
||||||
|
@ -44,13 +45,19 @@ struct sway_root *root_create(struct wl_display *wl_display) {
|
||||||
|
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
root->staging = alloc_scene_tree(&root_scene->tree, &failed);
|
root->staging = alloc_scene_tree(&root_scene->tree, &failed);
|
||||||
|
root->layer_tree = alloc_scene_tree(&root_scene->tree, &failed);
|
||||||
|
|
||||||
root->layers.tiling = alloc_scene_tree(&root_scene->tree, &failed);
|
root->layers.tiling = alloc_scene_tree(root->layer_tree, &failed);
|
||||||
root->layers.floating = alloc_scene_tree(&root_scene->tree, &failed);
|
root->layers.floating = alloc_scene_tree(root->layer_tree, &failed);
|
||||||
root->layers.fullscreen = alloc_scene_tree(&root_scene->tree, &failed);
|
root->layers.fullscreen = alloc_scene_tree(root->layer_tree, &failed);
|
||||||
root->layers.fullscreen_global = alloc_scene_tree(&root_scene->tree, &failed);
|
root->layers.fullscreen_global = alloc_scene_tree(root->layer_tree, &failed);
|
||||||
root->layers.seat = alloc_scene_tree(&root_scene->tree, &failed);
|
root->layers.seat = alloc_scene_tree(root->layer_tree, &failed);
|
||||||
root->layers.session_lock = alloc_scene_tree(&root_scene->tree, &failed);
|
root->layers.session_lock = alloc_scene_tree(root->layer_tree, &failed);
|
||||||
|
|
||||||
|
if (!failed && !scene_descriptor_assign(&root->layers.seat->node,
|
||||||
|
SWAY_SCENE_DESC_NON_INTERACTIVE, (void *)1)) {
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
wlr_scene_node_destroy(&root_scene->tree.node);
|
wlr_scene_node_destroy(&root_scene->tree.node);
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "sway/ipc-server.h"
|
#include "sway/ipc-server.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
#include "sway/input/seat.h"
|
#include "sway/input/seat.h"
|
||||||
|
#include "sway/scene_descriptor.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
#include "sway/surface.h"
|
#include "sway/surface.h"
|
||||||
#include "sway/tree/arrange.h"
|
#include "sway/tree/arrange.h"
|
||||||
|
@ -40,6 +41,12 @@ bool view_init(struct sway_view *view, enum sway_view_type type,
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
view->scene_tree = alloc_scene_tree(root->staging, &failed);
|
view->scene_tree = alloc_scene_tree(root->staging, &failed);
|
||||||
view->content_tree = alloc_scene_tree(view->scene_tree, &failed);
|
view->content_tree = alloc_scene_tree(view->scene_tree, &failed);
|
||||||
|
|
||||||
|
if (!failed && !scene_descriptor_assign(&view->scene_tree->node,
|
||||||
|
SWAY_SCENE_DESC_VIEW, view)) {
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue