logo

inaban

Distrustful Wayland Compositor (inspired by XMonad and dwm) git clone https://hacktivis.me/git/inaban.git

layers.c (10399B)


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