layers.c (9537B)
1 #include <stdlib.h> 2 #include <string.h> 3 #include <wayland-server.h> 4 #include <wlr/types/wlr_layer_shell_v1.h> 5 #include "layers.h" 6 #include "server.h" 7 8 static void apply_exclusive(struct wlr_box *usable_area, 9 uint32_t anchor, int32_t exclusive, 10 int32_t margin_top, int32_t margin_right, 11 int32_t margin_bottom, int32_t margin_left) { 12 if (exclusive <= 0) { 13 return; 14 } 15 struct { 16 uint32_t anchors; 17 int *positive_axis; 18 int *negative_axis; 19 int margin; 20 } edges[] = { 21 { 22 .anchors = 23 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | 24 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | 25 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP, 26 .positive_axis = &usable_area->y, 27 .negative_axis = &usable_area->height, 28 .margin = margin_top, 29 }, 30 { 31 .anchors = 32 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | 33 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | 34 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, 35 .positive_axis = NULL, 36 .negative_axis = &usable_area->height, 37 .margin = margin_bottom, 38 }, 39 { 40 .anchors = 41 ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | 42 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | 43 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, 44 .positive_axis = &usable_area->x, 45 .negative_axis = &usable_area->width, 46 .margin = margin_left, 47 }, 48 { 49 .anchors = 50 ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT | 51 ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | 52 ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM, 53 .positive_axis = NULL, 54 .negative_axis = &usable_area->width, 55 .margin = margin_right, 56 }, 57 }; 58 for (size_t i = 0; i < sizeof(edges) / sizeof(edges[0]); ++i) { 59 if ((anchor & edges[i].anchors) == edges[i].anchors) { 60 if (edges[i].positive_axis) { 61 *edges[i].positive_axis += exclusive + edges[i].margin; 62 } 63 if (edges[i].negative_axis) { 64 *edges[i].negative_axis -= exclusive + edges[i].margin; 65 } 66 } 67 } 68 } 69 70 static void arrange_layer(struct wlr_output *output, 71 struct wl_list *list /* struct *wio_layer_surface */, 72 struct wlr_box *usable_area, bool exclusive) { 73 struct wio_layer_surface *wio_surface; 74 struct wlr_box full_area = { 0 }; 75 wlr_output_effective_resolution(output, 76 &full_area.width, &full_area.height); 77 wl_list_for_each_reverse(wio_surface, list, link) { 78 struct wlr_layer_surface_v1 *layer = wio_surface->layer_surface; 79 struct wlr_layer_surface_v1_state *state = &layer->current; 80 if (exclusive != (state->exclusive_zone > 0)) { 81 continue; 82 } 83 struct wlr_box bounds; 84 if (state->exclusive_zone == -1) { 85 bounds = full_area; 86 } else { 87 bounds = *usable_area; 88 } 89 struct wlr_box box = { 90 .width = state->desired_width, 91 .height = state->desired_height 92 }; 93 // Horizontal axis 94 const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT 95 | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; 96 if ((state->anchor & both_horiz) && box.width == 0) { 97 box.x = bounds.x; 98 box.width = bounds.width; 99 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { 100 box.x = bounds.x; 101 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { 102 box.x = bounds.x + (bounds.width - box.width); 103 } else { 104 box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); 105 } 106 // Vertical axis 107 const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP 108 | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; 109 if ((state->anchor & both_vert) && box.height == 0) { 110 box.y = bounds.y; 111 box.height = bounds.height; 112 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { 113 box.y = bounds.y; 114 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { 115 box.y = bounds.y + (bounds.height - box.height); 116 } else { 117 box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); 118 } 119 // Margin 120 if ((state->anchor & both_horiz) == both_horiz) { 121 box.x += state->margin.left; 122 box.width -= state->margin.left + state->margin.right; 123 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { 124 box.x += state->margin.left; 125 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { 126 box.x -= state->margin.right; 127 } 128 if ((state->anchor & both_vert) == both_vert) { 129 box.y += state->margin.top; 130 box.height -= state->margin.top + state->margin.bottom; 131 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { 132 box.y += state->margin.top; 133 } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { 134 box.y -= state->margin.bottom; 135 } 136 if (box.width < 0 || box.height < 0) { 137 // TODO: Bubble up a protocol error? 138 wlr_layer_surface_v1_destroy(layer); 139 continue; 140 } 141 142 // Apply 143 wio_surface->geo = box; 144 apply_exclusive(usable_area, state->anchor, state->exclusive_zone, 145 state->margin.top, state->margin.right, 146 state->margin.bottom, state->margin.left); 147 wlr_layer_surface_v1_configure(layer, box.width, box.height); 148 } 149 } 150 151 void arrange_layers(struct wio_output *output) { 152 struct wlr_box usable_area = { 0 }; 153 wlr_output_effective_resolution(output->wlr_output, 154 &usable_area.width, &usable_area.height); 155 156 // Arrange exclusive surfaces from top->bottom 157 arrange_layer(output->wlr_output, 158 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], 159 &usable_area, true); 160 arrange_layer(output->wlr_output, 161 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], 162 &usable_area, true); 163 arrange_layer(output->wlr_output, 164 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], 165 &usable_area, true); 166 arrange_layer(output->wlr_output, 167 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], 168 &usable_area, true); 169 170 // Arrange non-exlusive surfaces from top->bottom 171 arrange_layer(output->wlr_output, 172 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], 173 &usable_area, false); 174 arrange_layer(output->wlr_output, 175 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], 176 &usable_area, false); 177 arrange_layer(output->wlr_output, 178 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM], 179 &usable_area, false); 180 arrange_layer(output->wlr_output, 181 &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND], 182 &usable_area, false); 183 184 // Find topmost keyboard interactive layer, if such a layer exists 185 uint32_t layers_above_shell[] = { 186 ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, 187 ZWLR_LAYER_SHELL_V1_LAYER_TOP, 188 }; 189 size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]); 190 struct wio_layer_surface *layer, *topmost = NULL; 191 for (size_t i = 0; i < nlayers; ++i) { 192 wl_list_for_each_reverse(layer, 193 &output->layers[layers_above_shell[i]], link) { 194 if (layer->layer_surface->current.keyboard_interactive) { 195 topmost = layer; 196 break; 197 } 198 } 199 if (topmost != NULL) { 200 break; 201 } 202 } 203 204 // TODO: Focus topmost layer 205 } 206 207 static void handle_output_destroy(struct wl_listener *listener, void *data) { 208 struct wio_layer_surface *layer = 209 wl_container_of(listener, layer, output_destroy); 210 layer->layer_surface->output = NULL; 211 wl_list_remove(&layer->output_destroy.link); 212 wlr_layer_surface_v1_destroy(layer->layer_surface); 213 } 214 215 static void handle_surface_commit(struct wl_listener *listener, void *data) { 216 struct wio_layer_surface *layer = 217 wl_container_of(listener, layer, surface_commit); 218 struct wlr_layer_surface_v1 *layer_surface = layer->layer_surface; 219 struct wlr_output *wlr_output = layer_surface->output; 220 if (wlr_output != NULL) { 221 struct wio_output *output = wlr_output->data; 222 arrange_layers(output); 223 } 224 } 225 226 static void handle_destroy(struct wl_listener *listener, void *data) { 227 struct wio_layer_surface *layer = wl_container_of( 228 listener, layer, destroy); 229 wl_list_remove(&layer->link); 230 wl_list_remove(&layer->destroy.link); 231 wl_list_remove(&layer->map.link); 232 wl_list_remove(&layer->surface_commit.link); 233 if (layer->layer_surface->output) { 234 wl_list_remove(&layer->output_destroy.link); 235 arrange_layers((struct wio_output *)layer->layer_surface->output->data); 236 } 237 free(layer); 238 } 239 240 static void handle_map(struct wl_listener *listener, void *data) { 241 struct wlr_layer_surface_v1 *layer_surface = data; 242 wlr_surface_send_enter(layer_surface->surface, layer_surface->output); 243 } 244 245 void server_new_layer_surface(struct wl_listener *listener, void *data) { 246 struct wio_server *server = wl_container_of( 247 listener, server, new_layer_surface); 248 struct wlr_layer_surface_v1 *layer_surface = data; 249 if (!layer_surface->output) { 250 struct wlr_output *output = wlr_output_layout_output_at( 251 server->output_layout, server->cursor->x, server->cursor->y); 252 layer_surface->output = output; 253 } 254 255 struct wio_output *output = layer_surface->output->data; 256 struct wio_layer_surface *wio_surface = 257 calloc(1, sizeof(struct wio_layer_surface)); 258 if (!wio_surface) { 259 return; 260 } 261 wio_surface->layer_surface = layer_surface; 262 layer_surface->data = wio_surface; 263 wio_surface->server = server; 264 265 wio_surface->surface_commit.notify = handle_surface_commit; 266 wl_signal_add(&layer_surface->surface->events.commit, 267 &wio_surface->surface_commit); 268 wio_surface->output_destroy.notify = handle_output_destroy; 269 wl_signal_add(&layer_surface->output->events.destroy, 270 &wio_surface->output_destroy); 271 wio_surface->destroy.notify = handle_destroy; 272 wl_signal_add(&layer_surface->events.destroy, &wio_surface->destroy); 273 wio_surface->map.notify = handle_map; 274 wl_signal_add(&layer_surface->events.map, &wio_surface->map); 275 // TODO: popups 276 277 // TODO: Listen for subsurfaces 278 wl_list_insert(&output->layers[layer_surface->pending.layer], &wio_surface->link); 279 // Temporarily set the layer's current state to pending 280 // So that we can easily arrange it 281 struct wlr_layer_surface_v1_state old_state = layer_surface->current; 282 layer_surface->current = layer_surface->pending; 283 arrange_layers(output); 284 layer_surface->current = old_state; 285 }