diff options
author | Alexander Orzechowski <alex@ozal.ski> | 2023-11-23 10:09:48 -0500 |
---|---|---|
committer | Kirill Primak <vyivel@eclair.cafe> | 2024-01-18 18:36:54 +0300 |
commit | 5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d (patch) | |
tree | f420022ad3a48215f9182505c0060d91edcd848e /sway/input/cursor.c | |
parent | Introduce sway_text_node (diff) | |
download | sway-5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d.tar.gz sway-5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d.tar.zst sway-5b8b505af5d5925ae9e617ee8f3c7a0f9c43409d.zip |
input: Query scene graph for relevant surface/node intersections
Diffstat (limited to 'sway/input/cursor.c')
-rw-r--r-- | sway/input/cursor.c | 184 |
1 files changed, 55 insertions, 129 deletions
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 107424c9..79373e40 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -37,43 +37,6 @@ static uint32_t get_current_time_msec(void) { | |||
37 | return now.tv_sec * 1000 + now.tv_nsec / 1000000; | 37 | return now.tv_sec * 1000 + now.tv_nsec / 1000000; |
38 | } | 38 | } |
39 | 39 | ||
40 | static struct wlr_surface *layer_surface_at(struct sway_output *output, | ||
41 | struct wl_list *layer, double ox, double oy, double *sx, double *sy) { | ||
42 | struct sway_layer_surface *sway_layer; | ||
43 | wl_list_for_each_reverse(sway_layer, layer, link) { | ||
44 | double _sx = ox - sway_layer->geo.x; | ||
45 | double _sy = oy - sway_layer->geo.y; | ||
46 | struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( | ||
47 | sway_layer->layer_surface, _sx, _sy, sx, sy); | ||
48 | if (sub) { | ||
49 | return sub; | ||
50 | } | ||
51 | } | ||
52 | return NULL; | ||
53 | } | ||
54 | |||
55 | static bool surface_is_xdg_popup(struct wlr_surface *surface) { | ||
56 | struct wlr_xdg_surface *xdg_surface = | ||
57 | wlr_xdg_surface_try_from_wlr_surface(surface); | ||
58 | return xdg_surface != NULL && xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && | ||
59 | xdg_surface->popup != NULL; | ||
60 | } | ||
61 | |||
62 | static struct wlr_surface *layer_surface_popup_at(struct sway_output *output, | ||
63 | struct wl_list *layer, double ox, double oy, double *sx, double *sy) { | ||
64 | struct sway_layer_surface *sway_layer; | ||
65 | wl_list_for_each_reverse(sway_layer, layer, link) { | ||
66 | double _sx = ox - sway_layer->geo.x; | ||
67 | double _sy = oy - sway_layer->geo.y; | ||
68 | struct wlr_surface *sub = wlr_layer_surface_v1_surface_at( | ||
69 | sway_layer->layer_surface, _sx, _sy, sx, sy); | ||
70 | if (sub && surface_is_xdg_popup(sub)) { | ||
71 | return sub; | ||
72 | } | ||
73 | } | ||
74 | return NULL; | ||
75 | } | ||
76 | |||
77 | /** | 40 | /** |
78 | * Returns the node at the cursor's position. If there is a surface at that | 41 | * Returns the node at the cursor's position. If there is a surface at that |
79 | * location, it is stored in **surface (it may not be a view). | 42 | * location, it is stored in **surface (it may not be a view). |
@@ -81,116 +44,79 @@ static struct wlr_surface *layer_surface_popup_at(struct sway_output *output, | |||
81 | struct sway_node *node_at_coords( | 44 | struct sway_node *node_at_coords( |
82 | struct sway_seat *seat, double lx, double ly, | 45 | struct sway_seat *seat, double lx, double ly, |
83 | struct wlr_surface **surface, double *sx, double *sy) { | 46 | struct wlr_surface **surface, double *sx, double *sy) { |
84 | // find the output the cursor is on | 47 | struct wlr_scene_node *scene_node = NULL; |
85 | struct wlr_output *wlr_output = wlr_output_layout_output_at( | ||
86 | root->output_layout, lx, ly); | ||
87 | if (wlr_output == NULL) { | ||
88 | return NULL; | ||
89 | } | ||
90 | struct sway_output *output = wlr_output->data; | ||
91 | if (!output || !output->enabled) { | ||
92 | // output is being destroyed or is being enabled | ||
93 | return NULL; | ||
94 | } | ||
95 | double ox = lx, oy = ly; | ||
96 | wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy); | ||
97 | 48 | ||
98 | // layer surfaces on the overlay layer are rendered on top | 49 | struct wlr_scene_node *node; |
99 | if ((*surface = layer_surface_at(output, | 50 | wl_list_for_each_reverse(node, &root->layer_tree->children, link) { |
100 | &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], | 51 | struct wlr_scene_tree *layer = wlr_scene_tree_from_node(node); |
101 | ox, oy, sx, sy))) { | ||
102 | return NULL; | ||
103 | } | ||
104 | 52 | ||
105 | // check for unmanaged views | 53 | bool non_interactive = scene_descriptor_try_get(&layer->node, |
106 | #if HAVE_XWAYLAND | 54 | SWAY_SCENE_DESC_NON_INTERACTIVE); |
107 | struct wl_list *unmanaged = &root->xwayland_unmanaged; | 55 | if (non_interactive) { |
108 | struct sway_xwayland_unmanaged *unmanaged_surface; | 56 | continue; |
109 | wl_list_for_each_reverse(unmanaged_surface, unmanaged, link) { | ||
110 | struct wlr_xwayland_surface *xsurface = | ||
111 | unmanaged_surface->wlr_xwayland_surface; | ||
112 | |||
113 | double _sx = lx - unmanaged_surface->lx; | ||
114 | double _sy = ly - unmanaged_surface->ly; | ||
115 | if (wlr_surface_point_accepts_input(xsurface->surface, _sx, _sy)) { | ||
116 | *surface = xsurface->surface; | ||
117 | *sx = _sx; | ||
118 | *sy = _sy; | ||
119 | return NULL; | ||
120 | } | 57 | } |
121 | } | ||
122 | #endif | ||
123 | 58 | ||
124 | if (root->fullscreen_global) { | 59 | scene_node = wlr_scene_node_at(&layer->node, lx, ly, sx, sy); |
125 | // Try fullscreen container | 60 | if (scene_node) { |
126 | struct sway_container *con = tiling_container_at( | 61 | break; |
127 | &root->fullscreen_global->node, lx, ly, surface, sx, sy); | ||
128 | if (con) { | ||
129 | return &con->node; | ||
130 | } | 62 | } |
131 | return NULL; | ||
132 | } | 63 | } |
133 | 64 | ||
134 | // find the focused workspace on the output for this seat | 65 | if (scene_node) { |
135 | struct sway_workspace *ws = output_get_active_workspace(output); | 66 | // determine what wlr_surface we clicked on |
136 | if (!ws) { | 67 | if (scene_node->type == WLR_SCENE_NODE_BUFFER) { |
137 | return NULL; | 68 | struct wlr_scene_buffer *scene_buffer = |
138 | } | 69 | wlr_scene_buffer_from_node(scene_node); |
70 | struct wlr_scene_surface *scene_surface = | ||
71 | wlr_scene_surface_try_from_buffer(scene_buffer); | ||
72 | |||
73 | if (scene_surface) { | ||
74 | *surface = scene_surface->surface; | ||
75 | } | ||
76 | } | ||
139 | 77 | ||
140 | if (ws->fullscreen) { | 78 | // determine what container we clicked on |
141 | // Try transient containers | 79 | struct wlr_scene_node *current = scene_node; |
142 | for (int i = 0; i < ws->floating->length; ++i) { | 80 | while (true) { |
143 | struct sway_container *floater = ws->floating->items[i]; | 81 | struct sway_container *con = scene_descriptor_try_get(current, |
144 | if (container_is_transient_for(floater, ws->fullscreen)) { | 82 | SWAY_SCENE_DESC_CONTAINER); |
145 | struct sway_container *con = tiling_container_at( | 83 | if (!con) { |
146 | &floater->node, lx, ly, surface, sx, sy); | 84 | struct sway_view *view = scene_descriptor_try_get(current, |
147 | if (con) { | 85 | SWAY_SCENE_DESC_VIEW); |
86 | if (view) { | ||
87 | con = view->container; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | if (con) { | ||
92 | if (!con->view || con->view->surface) { | ||
148 | return &con->node; | 93 | return &con->node; |
149 | } | 94 | } |
150 | } | 95 | } |
96 | |||
97 | if (!current->parent) { | ||
98 | break; | ||
99 | } | ||
100 | |||
101 | current = ¤t->parent->node; | ||
151 | } | 102 | } |
152 | // Try fullscreen container | ||
153 | struct sway_container *con = | ||
154 | tiling_container_at(&ws->fullscreen->node, lx, ly, surface, sx, sy); | ||
155 | if (con) { | ||
156 | return &con->node; | ||
157 | } | ||
158 | return NULL; | ||
159 | } | ||
160 | if ((*surface = layer_surface_popup_at(output, | ||
161 | &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], | ||
162 | ox, oy, sx, sy))) { | ||
163 | return NULL; | ||
164 | } | ||
165 | if ((*surface = layer_surface_popup_at(output, | ||
166 | &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], | ||
167 | ox, oy, sx, sy))) { | ||
168 | return NULL; | ||
169 | } | ||
170 | if ((*surface = layer_surface_popup_at(output, | ||
171 | &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], | ||
172 | ox, oy, sx, sy))) { | ||
173 | return NULL; | ||
174 | } | ||
175 | if ((*surface = layer_surface_at(output, | ||
176 | &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], | ||
177 | ox, oy, sx, sy))) { | ||
178 | return NULL; | ||
179 | } | 103 | } |
180 | 104 | ||
181 | struct sway_container *c; | 105 | // if we aren't on a container, determine what workspace we are on |
182 | if ((c = container_at(ws, lx, ly, surface, sx, sy))) { | 106 | struct wlr_output *wlr_output = wlr_output_layout_output_at( |
183 | return &c->node; | 107 | root->output_layout, lx, ly); |
108 | if (wlr_output == NULL) { | ||
109 | return NULL; | ||
184 | } | 110 | } |
185 | 111 | ||
186 | if ((*surface = layer_surface_at(output, | 112 | struct sway_output *output = wlr_output->data; |
187 | &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], | 113 | if (!output || !output->enabled) { |
188 | ox, oy, sx, sy))) { | 114 | // output is being destroyed or is being enabled |
189 | return NULL; | 115 | return NULL; |
190 | } | 116 | } |
191 | if ((*surface = layer_surface_at(output, | 117 | |
192 | &output->shell_layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], | 118 | struct sway_workspace *ws = output_get_active_workspace(output); |
193 | ox, oy, sx, sy))) { | 119 | if (!ws) { |
194 | return NULL; | 120 | return NULL; |
195 | } | 121 | } |
196 | 122 | ||