client.h 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. * Attempt to consolidate unavoidable suck into one file, away from dwl.c. This
  3. * file is not meant to be pretty. We use a .h file with static inline
  4. * functions instead of a separate .c module, or function pointers like sway, so
  5. * that they will simply compile out if the chosen #defines leave them unused.
  6. */
  7. /* Leave these functions first; they're used in the others */
  8. static inline int
  9. client_is_x11(Client *c)
  10. {
  11. #ifdef XWAYLAND
  12. return c->type == X11;
  13. #endif
  14. return 0;
  15. }
  16. static inline struct wlr_surface *
  17. client_surface(Client *c)
  18. {
  19. #ifdef XWAYLAND
  20. if (client_is_x11(c))
  21. return c->surface.xwayland->surface;
  22. #endif
  23. return c->surface.xdg->surface;
  24. }
  25. static inline int
  26. toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, LayerSurface **pl)
  27. {
  28. struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface;
  29. struct wlr_surface *root_surface;
  30. struct wlr_layer_surface_v1 *layer_surface;
  31. Client *c = NULL;
  32. LayerSurface *l = NULL;
  33. int type = -1;
  34. #ifdef XWAYLAND
  35. struct wlr_xwayland_surface *xsurface;
  36. #endif
  37. if (!s)
  38. return -1;
  39. root_surface = wlr_surface_get_root_surface(s);
  40. #ifdef XWAYLAND
  41. if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(root_surface))) {
  42. c = xsurface->data;
  43. type = c->type;
  44. goto end;
  45. }
  46. #endif
  47. if ((layer_surface = wlr_layer_surface_v1_try_from_wlr_surface(root_surface))) {
  48. l = layer_surface->data;
  49. type = LayerShell;
  50. goto end;
  51. }
  52. xdg_surface = wlr_xdg_surface_try_from_wlr_surface(root_surface);
  53. while (xdg_surface) {
  54. tmp_xdg_surface = NULL;
  55. switch (xdg_surface->role) {
  56. case WLR_XDG_SURFACE_ROLE_POPUP:
  57. if (!xdg_surface->popup || !xdg_surface->popup->parent)
  58. return -1;
  59. tmp_xdg_surface = wlr_xdg_surface_try_from_wlr_surface(xdg_surface->popup->parent);
  60. if (!tmp_xdg_surface)
  61. return toplevel_from_wlr_surface(xdg_surface->popup->parent, pc, pl);
  62. xdg_surface = tmp_xdg_surface;
  63. break;
  64. case WLR_XDG_SURFACE_ROLE_TOPLEVEL:
  65. c = xdg_surface->data;
  66. type = c->type;
  67. goto end;
  68. case WLR_XDG_SURFACE_ROLE_NONE:
  69. return -1;
  70. }
  71. }
  72. end:
  73. if (pl)
  74. *pl = l;
  75. if (pc)
  76. *pc = c;
  77. return type;
  78. }
  79. /* The others */
  80. static inline void
  81. client_activate_surface(struct wlr_surface *s, int activated)
  82. {
  83. struct wlr_xdg_toplevel *toplevel;
  84. #ifdef XWAYLAND
  85. struct wlr_xwayland_surface *xsurface;
  86. if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(s))) {
  87. wlr_xwayland_surface_activate(xsurface, activated);
  88. return;
  89. }
  90. #endif
  91. if ((toplevel = wlr_xdg_toplevel_try_from_wlr_surface(s)))
  92. wlr_xdg_toplevel_set_activated(toplevel, activated);
  93. }
  94. static inline uint32_t
  95. client_set_bounds(Client *c, int32_t width, int32_t height)
  96. {
  97. #ifdef XWAYLAND
  98. if (client_is_x11(c))
  99. return 0;
  100. #endif
  101. if (wl_resource_get_version(c->surface.xdg->toplevel->resource) >=
  102. XDG_TOPLEVEL_CONFIGURE_BOUNDS_SINCE_VERSION && width >= 0 && height >= 0
  103. && (c->bounds.width != width || c->bounds.height != height)) {
  104. c->bounds.width = width;
  105. c->bounds.height = height;
  106. return wlr_xdg_toplevel_set_bounds(c->surface.xdg->toplevel, width, height);
  107. }
  108. return 0;
  109. }
  110. static inline const char *
  111. client_get_appid(Client *c)
  112. {
  113. #ifdef XWAYLAND
  114. if (client_is_x11(c))
  115. return c->surface.xwayland->class;
  116. #endif
  117. return c->surface.xdg->toplevel->app_id;
  118. }
  119. static inline void
  120. client_get_clip(Client *c, struct wlr_box *clip)
  121. {
  122. struct wlr_box xdg_geom = {0};
  123. *clip = (struct wlr_box){
  124. .x = 0,
  125. .y = 0,
  126. .width = c->geom.width - c->bw,
  127. .height = c->geom.height - c->bw,
  128. };
  129. #ifdef XWAYLAND
  130. if (client_is_x11(c))
  131. return;
  132. #endif
  133. wlr_xdg_surface_get_geometry(c->surface.xdg, &xdg_geom);
  134. clip->x = xdg_geom.x;
  135. clip->y = xdg_geom.y;
  136. }
  137. static inline void
  138. client_get_geometry(Client *c, struct wlr_box *geom)
  139. {
  140. #ifdef XWAYLAND
  141. if (client_is_x11(c)) {
  142. geom->x = c->surface.xwayland->x;
  143. geom->y = c->surface.xwayland->y;
  144. geom->width = c->surface.xwayland->width;
  145. geom->height = c->surface.xwayland->height;
  146. return;
  147. }
  148. #endif
  149. wlr_xdg_surface_get_geometry(c->surface.xdg, geom);
  150. }
  151. static inline Client *
  152. client_get_parent(Client *c)
  153. {
  154. Client *p = NULL;
  155. #ifdef XWAYLAND
  156. if (client_is_x11(c)) {
  157. if (c->surface.xwayland->parent)
  158. toplevel_from_wlr_surface(c->surface.xwayland->parent->surface, &p, NULL);
  159. return p;
  160. }
  161. #endif
  162. if (c->surface.xdg->toplevel->parent)
  163. toplevel_from_wlr_surface(c->surface.xdg->toplevel->parent->base->surface, &p, NULL);
  164. return p;
  165. }
  166. static inline int
  167. client_has_children(Client *c)
  168. {
  169. #ifdef XWAYLAND
  170. if (client_is_x11(c))
  171. return !wl_list_empty(&c->surface.xwayland->children);
  172. #endif
  173. /* surface.xdg->link is never empty because it always contains at least the
  174. * surface itself. */
  175. return wl_list_length(&c->surface.xdg->link) > 1;
  176. }
  177. static inline const char *
  178. client_get_title(Client *c)
  179. {
  180. #ifdef XWAYLAND
  181. if (client_is_x11(c))
  182. return c->surface.xwayland->title;
  183. #endif
  184. return c->surface.xdg->toplevel->title;
  185. }
  186. static inline int
  187. client_is_float_type(Client *c)
  188. {
  189. struct wlr_xdg_toplevel *toplevel;
  190. struct wlr_xdg_toplevel_state state;
  191. #ifdef XWAYLAND
  192. if (client_is_x11(c)) {
  193. struct wlr_xwayland_surface *surface = c->surface.xwayland;
  194. xcb_size_hints_t *size_hints = surface->size_hints;
  195. size_t i;
  196. if (surface->modal)
  197. return 1;
  198. for (i = 0; i < surface->window_type_len; i++)
  199. if (surface->window_type[i] == netatom[NetWMWindowTypeDialog]
  200. || surface->window_type[i] == netatom[NetWMWindowTypeSplash]
  201. || surface->window_type[i] == netatom[NetWMWindowTypeToolbar]
  202. || surface->window_type[i] == netatom[NetWMWindowTypeUtility])
  203. return 1;
  204. return size_hints && size_hints->min_width > 0 && size_hints->min_height > 0
  205. && (size_hints->max_width == size_hints->min_width
  206. || size_hints->max_height == size_hints->min_height);
  207. }
  208. #endif
  209. toplevel = c->surface.xdg->toplevel;
  210. state = toplevel->current;
  211. return toplevel->parent || (state.min_width != 0 && state.min_height != 0
  212. && (state.min_width == state.max_width
  213. || state.min_height == state.max_height));
  214. }
  215. static inline int
  216. client_is_rendered_on_mon(Client *c, Monitor *m)
  217. {
  218. /* This is needed for when you don't want to check formal assignment,
  219. * but rather actual displaying of the pixels.
  220. * Usually VISIBLEON suffices and is also faster. */
  221. struct wlr_surface_output *s;
  222. int unused_lx, unused_ly;
  223. if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly))
  224. return 0;
  225. wl_list_for_each(s, &client_surface(c)->current_outputs, link)
  226. if (s->output == m->wlr_output)
  227. return 1;
  228. return 0;
  229. }
  230. static inline int
  231. client_is_stopped(Client *c)
  232. {
  233. int pid;
  234. siginfo_t in = {0};
  235. #ifdef XWAYLAND
  236. if (client_is_x11(c))
  237. return 0;
  238. #endif
  239. wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
  240. if (waitid(P_PID, pid, &in, WNOHANG|WCONTINUED|WSTOPPED|WNOWAIT) < 0) {
  241. /* This process is not our child process, while is very unluckely that
  242. * it is stopped, in order to do not skip frames assume that it is. */
  243. if (errno == ECHILD)
  244. return 1;
  245. } else if (in.si_pid) {
  246. if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
  247. return 1;
  248. if (in.si_code == CLD_CONTINUED)
  249. return 0;
  250. }
  251. return 0;
  252. }
  253. static inline int
  254. client_is_unmanaged(Client *c)
  255. {
  256. #ifdef XWAYLAND
  257. if (client_is_x11(c))
  258. return c->surface.xwayland->override_redirect;
  259. #endif
  260. return 0;
  261. }
  262. static inline void
  263. client_notify_enter(struct wlr_surface *s, struct wlr_keyboard *kb)
  264. {
  265. if (kb)
  266. wlr_seat_keyboard_notify_enter(seat, s, kb->keycodes,
  267. kb->num_keycodes, &kb->modifiers);
  268. else
  269. wlr_seat_keyboard_notify_enter(seat, s, NULL, 0, NULL);
  270. }
  271. static inline void
  272. client_restack_surface(Client *c)
  273. {
  274. #ifdef XWAYLAND
  275. if (client_is_x11(c))
  276. wlr_xwayland_surface_restack(c->surface.xwayland, NULL,
  277. XCB_STACK_MODE_ABOVE);
  278. #endif
  279. return;
  280. }
  281. static inline void
  282. client_send_close(Client *c)
  283. {
  284. #ifdef XWAYLAND
  285. if (client_is_x11(c)) {
  286. wlr_xwayland_surface_close(c->surface.xwayland);
  287. return;
  288. }
  289. #endif
  290. wlr_xdg_toplevel_send_close(c->surface.xdg->toplevel);
  291. }
  292. static inline void
  293. client_set_border_color(Client *c, const float color[static 4])
  294. {
  295. int i;
  296. for (i = 0; i < 4; i++)
  297. wlr_scene_rect_set_color(c->border[i], color);
  298. }
  299. static inline void
  300. client_set_fullscreen(Client *c, int fullscreen)
  301. {
  302. #ifdef XWAYLAND
  303. if (client_is_x11(c)) {
  304. wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen);
  305. return;
  306. }
  307. #endif
  308. wlr_xdg_toplevel_set_fullscreen(c->surface.xdg->toplevel, fullscreen);
  309. }
  310. static inline uint32_t
  311. client_set_size(Client *c, uint32_t width, uint32_t height)
  312. {
  313. #ifdef XWAYLAND
  314. if (client_is_x11(c)) {
  315. wlr_xwayland_surface_configure(c->surface.xwayland,
  316. c->geom.x + c->bw, c->geom.y + c->bw, width, height);
  317. return 0;
  318. }
  319. #endif
  320. if ((int32_t)width == c->surface.xdg->toplevel->current.width
  321. && (int32_t)height == c->surface.xdg->toplevel->current.height)
  322. return 0;
  323. return wlr_xdg_toplevel_set_size(c->surface.xdg->toplevel, (int32_t)width, (int32_t)height);
  324. }
  325. static inline void
  326. client_set_tiled(Client *c, uint32_t edges)
  327. {
  328. #ifdef XWAYLAND
  329. if (client_is_x11(c))
  330. return;
  331. #endif
  332. if (wl_resource_get_version(c->surface.xdg->toplevel->resource)
  333. >= XDG_TOPLEVEL_STATE_TILED_RIGHT_SINCE_VERSION) {
  334. wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
  335. } else {
  336. wlr_xdg_toplevel_set_maximized(c->surface.xdg->toplevel, edges != WLR_EDGE_NONE);
  337. }
  338. }
  339. static inline void
  340. client_set_suspended(Client *c, int suspended)
  341. {
  342. #ifdef XWAYLAND
  343. if (client_is_x11(c))
  344. return;
  345. #endif
  346. wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended);
  347. }
  348. static inline int
  349. client_wants_focus(Client *c)
  350. {
  351. #ifdef XWAYLAND
  352. return client_is_unmanaged(c)
  353. && wlr_xwayland_or_surface_wants_focus(c->surface.xwayland)
  354. && wlr_xwayland_icccm_input_model(c->surface.xwayland) != WLR_ICCCM_INPUT_MODEL_NONE;
  355. #endif
  356. return 0;
  357. }
  358. static inline int
  359. client_wants_fullscreen(Client *c)
  360. {
  361. #ifdef XWAYLAND
  362. if (client_is_x11(c))
  363. return c->surface.xwayland->fullscreen;
  364. #endif
  365. return c->surface.xdg->toplevel->requested.fullscreen;
  366. }