2
0

shim.c 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998
  1. /*
  2. * Copyright (c) Milan Jurkulák 2026.
  3. * Contact:
  4. * e: mimoccc@gmail.com
  5. * e: mj@mjdev.org
  6. * w: https://mjdev.org
  7. *
  8. * wlroots 0.18 based compositor core, exposed to Kotlin/Native
  9. * through the flat API in shim.h. Policy (layers, focus order,
  10. * IPC) lives on the Kotlin side.
  11. */
  12. #define _POSIX_C_SOURCE 200809L
  13. #include <assert.h>
  14. #include <signal.h>
  15. #include <stdbool.h>
  16. #include <stdint.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #include <sys/wait.h>
  21. #include <time.h>
  22. #include <unistd.h>
  23. #include <wayland-server-core.h>
  24. #include <wlr/backend.h>
  25. #include <wlr/backend/session.h>
  26. #include <wlr/render/allocator.h>
  27. #include <wlr/render/wlr_renderer.h>
  28. #include <wlr/render/gles2.h>
  29. #include <wlr/render/egl.h>
  30. #include <EGL/egl.h>
  31. #include <GLES2/gl2.h>
  32. #include <wlr/types/wlr_compositor.h>
  33. #include <wlr/types/wlr_subcompositor.h>
  34. #include <wlr/types/wlr_cursor.h>
  35. #include <wlr/types/wlr_data_device.h>
  36. #include <wlr/types/wlr_input_device.h>
  37. #include <wlr/types/wlr_keyboard.h>
  38. #include <wlr/types/wlr_output.h>
  39. #include <wlr/types/wlr_output_layout.h>
  40. #include <wlr/types/wlr_pointer.h>
  41. #ifdef MJC_WITH_SCENEFX
  42. /* scenefx is a drop-in superset of the wlroots scene graph that adds backdrop blur. It replaces
  43. * (not complements) wlr/types/wlr_scene.h, the two headers must never be included together. */
  44. #include <scenefx/render/fx_renderer/fx_renderer.h>
  45. #include <scenefx/types/wlr_scene.h>
  46. #else
  47. #include <wlr/types/wlr_scene.h>
  48. #endif
  49. #include <wlr/types/wlr_seat.h>
  50. #include <wlr/types/wlr_xcursor_manager.h>
  51. #include <wlr/types/wlr_xdg_decoration_v1.h>
  52. #include <wlr/types/wlr_xdg_shell.h>
  53. #include <wlr/util/log.h>
  54. #include <wlr/xwayland.h>
  55. #include <xkbcommon/xkbcommon.h>
  56. #include "shim.h"
  57. enum mjc_cursor_mode {
  58. MJC_CURSOR_PASSTHROUGH,
  59. MJC_CURSOR_MOVE,
  60. MJC_CURSOR_RESIZE,
  61. };
  62. struct mjc_server {
  63. struct wl_display *display;
  64. struct wl_event_loop *loop;
  65. struct wlr_backend *backend;
  66. struct wlr_session *session;
  67. struct wlr_renderer *renderer;
  68. struct wlr_allocator *allocator;
  69. struct wlr_compositor *compositor;
  70. struct wlr_scene *scene;
  71. struct wlr_scene_output_layout *scene_layout;
  72. struct wlr_output_layout *output_layout;
  73. struct wlr_scene_tree *layers[5];
  74. #ifdef MJC_WITH_SCENEFX
  75. /* result of the software-GL probe (the scenefx renderer cannot be probed itself) */
  76. bool software_gl;
  77. #endif
  78. struct wlr_xdg_shell *xdg_shell;
  79. struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr;
  80. struct wlr_xwayland *xwayland;
  81. struct wlr_cursor *cursor;
  82. struct wlr_xcursor_manager *cursor_mgr;
  83. struct wlr_seat *seat;
  84. struct wl_list views; /* mjc_view.link */
  85. struct wl_list keyboards; /* mjc_keyboard.link */
  86. struct wl_list fd_sources;/* mjc_fd_source.link */
  87. struct mjc_view *focused_view;
  88. mjc_callbacks cbs;
  89. void *ud;
  90. const char *socket;
  91. uint64_t next_view_id;
  92. /* nested-output size (16:9 default); used when the backend has no mode list
  93. * (wayland/headless) and to lock the window against host-driven resizes */
  94. int output_w, output_h;
  95. /* throttle timestamp (msec) for the pointer callback */
  96. uint32_t last_pointer_ms;
  97. /* injection feedback marker (Android "show touches" style): a small white square in
  98. * the overlay layer that appears at the injected pointer and fades out after a timeout */
  99. struct wlr_scene_rect *inject_marker;
  100. struct wl_event_source *inject_fade_timer;
  101. float inject_alpha;
  102. enum mjc_cursor_mode cursor_mode;
  103. struct mjc_view *grabbed_view;
  104. double grab_x, grab_y;
  105. struct wlr_box grab_geobox;
  106. uint32_t resize_edges;
  107. struct wl_event_source *sigchld_source;
  108. /* pids spawned via mjc_spawn; sigchld must reap only these,
  109. * other children (Xwayland) belong to wlroots */
  110. pid_t spawned_pids[64];
  111. int spawned_count;
  112. struct wl_listener new_output;
  113. struct wl_listener new_xdg_toplevel;
  114. struct wl_listener new_xdg_popup;
  115. struct wl_listener new_toplevel_decoration;
  116. struct wl_listener new_xwayland_surface;
  117. struct wl_listener xwayland_ready;
  118. struct wl_listener cursor_motion;
  119. struct wl_listener cursor_motion_absolute;
  120. struct wl_listener cursor_button;
  121. struct wl_listener cursor_axis;
  122. struct wl_listener cursor_frame;
  123. struct wl_listener new_input;
  124. struct wl_listener request_cursor;
  125. struct wl_listener request_set_selection;
  126. };
  127. struct mjc_view {
  128. struct wl_list link;
  129. struct mjc_server *server;
  130. uint64_t id;
  131. bool is_xwayland;
  132. bool mapped;
  133. bool minimized;
  134. bool maximized;
  135. /* re-center once the client commits its post-unmaximize size */
  136. bool pending_center;
  137. bool focusable;
  138. /* backdrop blur requested; applied to the scene buffers whenever they exist */
  139. bool blur;
  140. mjc_layer layer;
  141. struct wlr_scene_tree *scene_tree;
  142. /* floating geometry remembered while maximized (x/y are scene coords) */
  143. struct wlr_box saved_geo;
  144. /* xdg shell */
  145. struct wlr_xdg_toplevel *xdg_toplevel;
  146. /* xwayland */
  147. struct wlr_xwayland_surface *xsurface;
  148. struct wl_listener map;
  149. struct wl_listener unmap;
  150. struct wl_listener commit;
  151. struct wl_listener destroy;
  152. struct wl_listener request_move;
  153. struct wl_listener request_resize;
  154. struct wl_listener request_maximize;
  155. struct wl_listener request_minimize;
  156. struct wl_listener request_fullscreen;
  157. struct wl_listener set_title;
  158. struct wl_listener set_app_id; /* set_class for xwayland */
  159. struct wl_listener associate;
  160. struct wl_listener dissociate;
  161. struct wl_listener request_configure;
  162. struct wl_listener set_geometry;
  163. };
  164. #ifdef MJC_WITH_SCENEFX
  165. static void view_blur_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *data) {
  166. (void) sx;
  167. (void) sy;
  168. wlr_scene_buffer_set_backdrop_blur(buffer, *(bool *) data);
  169. }
  170. /* push the requested blur state onto every scene buffer of the view (when its scene node
  171. * does not exist yet - xwayland before map - the stored flag is applied at map time) */
  172. static void view_apply_blur(struct mjc_view *view) {
  173. if (view->scene_tree == NULL) {
  174. return;
  175. }
  176. bool enabled = view->blur;
  177. wlr_scene_node_for_each_buffer(&view->scene_tree->node, view_blur_iterator, &enabled);
  178. }
  179. #else
  180. static void view_apply_blur(struct mjc_view *view) {
  181. (void) view;
  182. }
  183. #endif
  184. struct mjc_popup {
  185. struct wlr_xdg_popup *xdg_popup;
  186. struct wl_listener commit;
  187. struct wl_listener destroy;
  188. };
  189. struct mjc_decoration {
  190. struct wlr_xdg_toplevel_decoration_v1 *decoration;
  191. struct wl_listener request_mode;
  192. struct wl_listener destroy;
  193. };
  194. struct mjc_keyboard {
  195. struct wl_list link;
  196. struct mjc_server *server;
  197. struct wlr_keyboard *wlr_keyboard;
  198. struct wl_listener modifiers;
  199. struct wl_listener key;
  200. struct wl_listener destroy;
  201. };
  202. struct mjc_output {
  203. struct wl_list link;
  204. struct mjc_server *server;
  205. struct wlr_output *wlr_output;
  206. struct wl_listener frame;
  207. struct wl_listener request_state;
  208. struct wl_listener destroy;
  209. };
  210. struct mjc_fd_source {
  211. struct wl_list link;
  212. struct mjc_server *server;
  213. int fd;
  214. struct wl_event_source *source;
  215. };
  216. /* ------------------------------------------------------------------ */
  217. /* helpers */
  218. /* ------------------------------------------------------------------ */
  219. static struct wlr_surface *view_surface(struct mjc_view *view) {
  220. if (view->is_xwayland) {
  221. return view->xsurface != NULL ? view->xsurface->surface : NULL;
  222. }
  223. return view->xdg_toplevel->base->surface;
  224. }
  225. static void emit_focus_change(struct mjc_server *server) {
  226. if (server->cbs.focus_change != NULL) {
  227. server->cbs.focus_change(server->ud, server->focused_view);
  228. }
  229. }
  230. static void view_deactivate(struct mjc_view *view) {
  231. if (view->is_xwayland) {
  232. if (view->xsurface != NULL) {
  233. wlr_xwayland_surface_activate(view->xsurface, false);
  234. }
  235. } else {
  236. wlr_xdg_toplevel_set_activated(view->xdg_toplevel, false);
  237. }
  238. }
  239. static void view_focus_internal(struct mjc_view *view, bool raise) {
  240. if (view == NULL || !view->focusable || view->minimized) {
  241. return;
  242. }
  243. struct mjc_server *server = view->server;
  244. struct wlr_seat *seat = server->seat;
  245. if (server->focused_view == view) {
  246. return;
  247. }
  248. if (server->focused_view != NULL) {
  249. view_deactivate(server->focused_view);
  250. }
  251. /* focus-follows-mouse must not restack windows (no autoraise); only an explicit
  252. * focus (click / activate / unminimize) raises the view to the top */
  253. if (raise && view->scene_tree != NULL) {
  254. wlr_scene_node_raise_to_top(&view->scene_tree->node);
  255. }
  256. if (view->is_xwayland) {
  257. wlr_xwayland_surface_activate(view->xsurface, true);
  258. wlr_xwayland_surface_restack(view->xsurface, NULL, XCB_STACK_MODE_ABOVE);
  259. } else {
  260. wlr_xdg_toplevel_set_activated(view->xdg_toplevel, true);
  261. }
  262. struct wlr_surface *surface = view_surface(view);
  263. struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat);
  264. if (surface != NULL) {
  265. if (keyboard != NULL) {
  266. wlr_seat_keyboard_notify_enter(seat, surface,
  267. keyboard->keycodes, keyboard->num_keycodes, &keyboard->modifiers);
  268. } else {
  269. wlr_seat_keyboard_notify_enter(seat, surface, NULL, 0, NULL);
  270. }
  271. }
  272. server->focused_view = view;
  273. emit_focus_change(server);
  274. }
  275. void mjc_view_focus(struct mjc_view *view) {
  276. view_focus_internal(view, true);
  277. }
  278. static void clear_focus_if(struct mjc_server *server, struct mjc_view *view) {
  279. if (server->focused_view == view) {
  280. server->focused_view = NULL;
  281. emit_focus_change(server);
  282. }
  283. if (server->grabbed_view == view) {
  284. server->grabbed_view = NULL;
  285. server->cursor_mode = MJC_CURSOR_PASSTHROUGH;
  286. }
  287. }
  288. static struct mjc_view *desktop_view_at(struct mjc_server *server,
  289. double lx, double ly, struct wlr_surface **surface,
  290. double *sx, double *sy) {
  291. struct wlr_scene_node *node =
  292. wlr_scene_node_at(&server->scene->tree.node, lx, ly, sx, sy);
  293. if (node == NULL || node->type != WLR_SCENE_NODE_BUFFER) {
  294. return NULL;
  295. }
  296. struct wlr_scene_buffer *scene_buffer = wlr_scene_buffer_from_node(node);
  297. struct wlr_scene_surface *scene_surface =
  298. wlr_scene_surface_try_from_buffer(scene_buffer);
  299. if (scene_surface == NULL) {
  300. return NULL;
  301. }
  302. *surface = scene_surface->surface;
  303. struct wlr_scene_tree *tree = node->parent;
  304. while (tree != NULL && tree->node.data == NULL) {
  305. tree = tree->node.parent;
  306. }
  307. return tree != NULL ? tree->node.data : NULL;
  308. }
  309. /* ------------------------------------------------------------------ */
  310. /* outputs */
  311. /* ------------------------------------------------------------------ */
  312. static void output_frame(struct wl_listener *listener, void *data) {
  313. (void) data;
  314. struct mjc_output *output = wl_container_of(listener, output, frame);
  315. struct wlr_scene_output *scene_output = wlr_scene_get_scene_output(
  316. output->server->scene, output->wlr_output);
  317. if (scene_output == NULL) {
  318. return;
  319. }
  320. wlr_scene_output_commit(scene_output, NULL);
  321. struct timespec now;
  322. clock_gettime(CLOCK_MONOTONIC, &now);
  323. wlr_scene_output_send_frame_done(scene_output, &now);
  324. }
  325. static void output_request_state(struct wl_listener *listener, void *data) {
  326. struct mjc_output *output = wl_container_of(listener, output, request_state);
  327. const struct wlr_output_event_request_state *event = data;
  328. /* honor host-driven resizes (the user resizing the nested x11/wayland window) so the
  329. * desktop relayouts to the new size; commit the requested state and remember the new
  330. * dimensions, which the shell reads back via the wl_output geometry */
  331. wlr_output_commit_state(output->wlr_output, event->state);
  332. output->server->output_w = output->wlr_output->width;
  333. output->server->output_h = output->wlr_output->height;
  334. }
  335. static void output_destroy(struct wl_listener *listener, void *data) {
  336. (void) data;
  337. struct mjc_output *output = wl_container_of(listener, output, destroy);
  338. struct mjc_server *server = output->server;
  339. wl_list_remove(&output->frame.link);
  340. wl_list_remove(&output->request_state.link);
  341. wl_list_remove(&output->destroy.link);
  342. wl_list_remove(&output->link);
  343. free(output);
  344. /* nested backends (x11/wayland) have no session; closing the host window
  345. * destroys the output, so quit the compositor and let the run action finish.
  346. * a real (drm) session keeps running when an output is unplugged. */
  347. if (server->session == NULL) {
  348. wl_display_terminate(server->display);
  349. }
  350. }
  351. static void server_new_output(struct wl_listener *listener, void *data) {
  352. struct mjc_server *server = wl_container_of(listener, server, new_output);
  353. struct wlr_output *wlr_output = data;
  354. wlr_output_init_render(wlr_output, server->allocator, server->renderer);
  355. struct wlr_output_state state;
  356. wlr_output_state_init(&state);
  357. wlr_output_state_set_enabled(&state, true);
  358. struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
  359. if (mode != NULL) {
  360. wlr_output_state_set_mode(&state, mode);
  361. } else {
  362. /* wayland / headless backends expose no mode list, so preferred_mode is
  363. * NULL; without a mode the output has no dimensions and renders black.
  364. * pin it to the configured 16:9 size. */
  365. wlr_output_state_set_custom_mode(&state,
  366. server->output_w, server->output_h, 0);
  367. }
  368. wlr_output_commit_state(wlr_output, &state);
  369. wlr_output_state_finish(&state);
  370. struct mjc_output *output = calloc(1, sizeof(*output));
  371. output->wlr_output = wlr_output;
  372. output->server = server;
  373. output->frame.notify = output_frame;
  374. wl_signal_add(&wlr_output->events.frame, &output->frame);
  375. output->request_state.notify = output_request_state;
  376. wl_signal_add(&wlr_output->events.request_state, &output->request_state);
  377. output->destroy.notify = output_destroy;
  378. wl_signal_add(&wlr_output->events.destroy, &output->destroy);
  379. wl_list_init(&output->link);
  380. struct wlr_output_layout_output *l_output =
  381. wlr_output_layout_add_auto(server->output_layout, wlr_output);
  382. struct wlr_scene_output *scene_output =
  383. wlr_scene_output_create(server->scene, wlr_output);
  384. wlr_scene_output_layout_add_output(server->scene_layout, l_output, scene_output);
  385. }
  386. /* ------------------------------------------------------------------ */
  387. /* keyboard & input */
  388. /* ------------------------------------------------------------------ */
  389. static void keyboard_handle_modifiers(struct wl_listener *listener, void *data) {
  390. (void) data;
  391. struct mjc_keyboard *keyboard = wl_container_of(listener, keyboard, modifiers);
  392. wlr_seat_set_keyboard(keyboard->server->seat, keyboard->wlr_keyboard);
  393. wlr_seat_keyboard_notify_modifiers(keyboard->server->seat,
  394. &keyboard->wlr_keyboard->modifiers);
  395. }
  396. static void keyboard_handle_key(struct wl_listener *listener, void *data) {
  397. struct mjc_keyboard *keyboard = wl_container_of(listener, keyboard, key);
  398. struct mjc_server *server = keyboard->server;
  399. struct wlr_keyboard_key_event *event = data;
  400. uint32_t keycode = event->keycode + 8;
  401. const xkb_keysym_t *syms;
  402. int nsyms = xkb_state_key_get_syms(
  403. keyboard->wlr_keyboard->xkb_state, keycode, &syms);
  404. uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard->wlr_keyboard);
  405. bool pressed = event->state == WL_KEYBOARD_KEY_STATE_PRESSED;
  406. bool handled = false;
  407. for (int i = 0; i < nsyms; i++) {
  408. /* VT switching always works */
  409. if (pressed && syms[i] >= XKB_KEY_XF86Switch_VT_1 &&
  410. syms[i] <= XKB_KEY_XF86Switch_VT_12) {
  411. if (server->session != NULL) {
  412. wlr_session_change_vt(server->session,
  413. syms[i] - XKB_KEY_XF86Switch_VT_1 + 1);
  414. }
  415. handled = true;
  416. continue;
  417. }
  418. if (server->cbs.key != NULL &&
  419. server->cbs.key(server->ud, syms[i], modifiers, pressed)) {
  420. handled = true;
  421. }
  422. }
  423. if (!handled) {
  424. wlr_seat_set_keyboard(server->seat, keyboard->wlr_keyboard);
  425. wlr_seat_keyboard_notify_key(server->seat,
  426. event->time_msec, event->keycode, event->state);
  427. }
  428. }
  429. static void keyboard_handle_destroy(struct wl_listener *listener, void *data) {
  430. (void) data;
  431. struct mjc_keyboard *keyboard = wl_container_of(listener, keyboard, destroy);
  432. wl_list_remove(&keyboard->modifiers.link);
  433. wl_list_remove(&keyboard->key.link);
  434. wl_list_remove(&keyboard->destroy.link);
  435. wl_list_remove(&keyboard->link);
  436. free(keyboard);
  437. }
  438. static void server_new_keyboard(struct mjc_server *server,
  439. struct wlr_input_device *device) {
  440. struct wlr_keyboard *wlr_keyboard = wlr_keyboard_from_input_device(device);
  441. struct mjc_keyboard *keyboard = calloc(1, sizeof(*keyboard));
  442. keyboard->server = server;
  443. keyboard->wlr_keyboard = wlr_keyboard;
  444. struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  445. struct xkb_keymap *keymap = xkb_keymap_new_from_names(context, NULL,
  446. XKB_KEYMAP_COMPILE_NO_FLAGS);
  447. wlr_keyboard_set_keymap(wlr_keyboard, keymap);
  448. xkb_keymap_unref(keymap);
  449. xkb_context_unref(context);
  450. wlr_keyboard_set_repeat_info(wlr_keyboard, 25, 600);
  451. keyboard->modifiers.notify = keyboard_handle_modifiers;
  452. wl_signal_add(&wlr_keyboard->events.modifiers, &keyboard->modifiers);
  453. keyboard->key.notify = keyboard_handle_key;
  454. wl_signal_add(&wlr_keyboard->events.key, &keyboard->key);
  455. keyboard->destroy.notify = keyboard_handle_destroy;
  456. wl_signal_add(&device->events.destroy, &keyboard->destroy);
  457. wlr_seat_set_keyboard(server->seat, wlr_keyboard);
  458. wl_list_insert(&server->keyboards, &keyboard->link);
  459. }
  460. static void server_new_pointer(struct mjc_server *server,
  461. struct wlr_input_device *device) {
  462. wlr_cursor_attach_input_device(server->cursor, device);
  463. }
  464. static void server_new_input(struct wl_listener *listener, void *data) {
  465. struct mjc_server *server = wl_container_of(listener, server, new_input);
  466. struct wlr_input_device *device = data;
  467. switch (device->type) {
  468. case WLR_INPUT_DEVICE_KEYBOARD:
  469. server_new_keyboard(server, device);
  470. break;
  471. case WLR_INPUT_DEVICE_POINTER:
  472. server_new_pointer(server, device);
  473. break;
  474. default:
  475. break;
  476. }
  477. uint32_t caps = WL_SEAT_CAPABILITY_POINTER;
  478. if (!wl_list_empty(&server->keyboards)) {
  479. caps |= WL_SEAT_CAPABILITY_KEYBOARD;
  480. }
  481. wlr_seat_set_capabilities(server->seat, caps);
  482. }
  483. static void seat_request_cursor(struct wl_listener *listener, void *data) {
  484. struct mjc_server *server = wl_container_of(listener, server, request_cursor);
  485. struct wlr_seat_pointer_request_set_cursor_event *event = data;
  486. struct wlr_seat_client *focused_client =
  487. server->seat->pointer_state.focused_client;
  488. if (focused_client == event->seat_client) {
  489. wlr_cursor_set_surface(server->cursor, event->surface,
  490. event->hotspot_x, event->hotspot_y);
  491. }
  492. }
  493. static void seat_request_set_selection(struct wl_listener *listener, void *data) {
  494. struct mjc_server *server =
  495. wl_container_of(listener, server, request_set_selection);
  496. struct wlr_seat_request_set_selection_event *event = data;
  497. wlr_seat_set_selection(server->seat, event->source, event->serial);
  498. }
  499. /* ------------------------------------------------------------------ */
  500. /* cursor */
  501. /* ------------------------------------------------------------------ */
  502. static void view_current_geometry(struct mjc_view *view, struct wlr_box *box);
  503. static void process_cursor_move(struct mjc_server *server) {
  504. struct mjc_view *view = server->grabbed_view;
  505. if (view == NULL || view->scene_tree == NULL) {
  506. return;
  507. }
  508. int x = (int)(server->cursor->x - server->grab_x);
  509. int y = (int)(server->cursor->y - server->grab_y);
  510. wlr_scene_node_set_position(&view->scene_tree->node, x, y);
  511. if (view->is_xwayland && view->xsurface != NULL) {
  512. wlr_xwayland_surface_configure(view->xsurface,
  513. (int16_t) x, (int16_t) y,
  514. (uint16_t) view->xsurface->width, (uint16_t) view->xsurface->height);
  515. }
  516. }
  517. static void process_cursor_resize(struct mjc_server *server) {
  518. struct mjc_view *view = server->grabbed_view;
  519. if (view == NULL || view->scene_tree == NULL) {
  520. return;
  521. }
  522. double border_x = server->cursor->x - server->grab_x;
  523. double border_y = server->cursor->y - server->grab_y;
  524. int new_left = server->grab_geobox.x;
  525. int new_right = server->grab_geobox.x + server->grab_geobox.width;
  526. int new_top = server->grab_geobox.y;
  527. int new_bottom = server->grab_geobox.y + server->grab_geobox.height;
  528. if (server->resize_edges & WLR_EDGE_TOP) {
  529. new_top = (int) border_y;
  530. if (new_top >= new_bottom) {
  531. new_top = new_bottom - 1;
  532. }
  533. } else if (server->resize_edges & WLR_EDGE_BOTTOM) {
  534. new_bottom = (int) border_y;
  535. if (new_bottom <= new_top) {
  536. new_bottom = new_top + 1;
  537. }
  538. }
  539. if (server->resize_edges & WLR_EDGE_LEFT) {
  540. new_left = (int) border_x;
  541. if (new_left >= new_right) {
  542. new_left = new_right - 1;
  543. }
  544. } else if (server->resize_edges & WLR_EDGE_RIGHT) {
  545. new_right = (int) border_x;
  546. if (new_right <= new_left) {
  547. new_right = new_left + 1;
  548. }
  549. }
  550. int new_width = new_right - new_left;
  551. int new_height = new_bottom - new_top;
  552. if (view->is_xwayland && view->xsurface != NULL) {
  553. wlr_scene_node_set_position(&view->scene_tree->node, new_left, new_top);
  554. wlr_xwayland_surface_configure(view->xsurface,
  555. (int16_t) new_left, (int16_t) new_top,
  556. (uint16_t) new_width, (uint16_t) new_height);
  557. } else {
  558. struct wlr_box geo_box;
  559. wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo_box);
  560. wlr_scene_node_set_position(&view->scene_tree->node,
  561. new_left - geo_box.x, new_top - geo_box.y);
  562. wlr_xdg_toplevel_set_size(view->xdg_toplevel, new_width, new_height);
  563. }
  564. }
  565. /* 1 = focus-follows-mouse (focusable view under the pointer gets focus). The focus-clear
  566. * over the desktop is intentionally NOT done here: it made the dock reveal jam after a couple
  567. * of cycles. The dock autohide must instead be driven by pointer-leave on the shell side. */
  568. #define MJC_FOCUS_FOLLOWS_MOUSE 1
  569. static void process_cursor_motion(struct mjc_server *server, uint32_t time) {
  570. if (server->cursor_mode == MJC_CURSOR_MOVE) {
  571. process_cursor_move(server);
  572. return;
  573. } else if (server->cursor_mode == MJC_CURSOR_RESIZE) {
  574. process_cursor_resize(server);
  575. return;
  576. }
  577. double sx, sy;
  578. struct wlr_seat *seat = server->seat;
  579. struct wlr_surface *surface = NULL;
  580. struct mjc_view *view = desktop_view_at(server, server->cursor->x,
  581. server->cursor->y, &surface, &sx, &sy);
  582. if (surface == NULL) {
  583. wlr_cursor_set_xcursor(server->cursor, server->cursor_mgr, "default");
  584. }
  585. if (surface != NULL) {
  586. wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
  587. wlr_seat_pointer_notify_motion(seat, time, sx, sy);
  588. /* focus-follows-mouse: focusable view under the pointer gets keyboard focus (no
  589. * restack). Do NOT clear focus over non-focusable surfaces — that churns focus and
  590. * jams the dock reveal; autohide is handled by pointer-leave on the shell side. */
  591. if (MJC_FOCUS_FOLLOWS_MOUSE && view != NULL && view->focusable) {
  592. view_focus_internal(view, false);
  593. }
  594. } else {
  595. wlr_seat_pointer_clear_focus(seat);
  596. }
  597. // broadcast the pointer position to ipc clients (throttled), so the shell can do
  598. // edge detection without the AWT global pointer which is unreliable under nested XWayland
  599. if (server->cbs.pointer != NULL && (time - server->last_pointer_ms) >= 30u) {
  600. server->last_pointer_ms = time;
  601. server->cbs.pointer(server->ud,
  602. (int) server->cursor->x, (int) server->cursor->y);
  603. }
  604. }
  605. static void server_cursor_motion(struct wl_listener *listener, void *data) {
  606. struct mjc_server *server = wl_container_of(listener, server, cursor_motion);
  607. struct wlr_pointer_motion_event *event = data;
  608. wlr_cursor_move(server->cursor, &event->pointer->base,
  609. event->delta_x, event->delta_y);
  610. process_cursor_motion(server, event->time_msec);
  611. }
  612. static void server_cursor_motion_absolute(struct wl_listener *listener, void *data) {
  613. struct mjc_server *server =
  614. wl_container_of(listener, server, cursor_motion_absolute);
  615. struct wlr_pointer_motion_absolute_event *event = data;
  616. wlr_cursor_warp_absolute(server->cursor, &event->pointer->base,
  617. event->x, event->y);
  618. process_cursor_motion(server, event->time_msec);
  619. }
  620. static void server_cursor_button(struct wl_listener *listener, void *data) {
  621. struct mjc_server *server = wl_container_of(listener, server, cursor_button);
  622. struct wlr_pointer_button_event *event = data;
  623. wlr_seat_pointer_notify_button(server->seat,
  624. event->time_msec, event->button, event->state);
  625. if (event->state == WL_POINTER_BUTTON_STATE_RELEASED) {
  626. server->cursor_mode = MJC_CURSOR_PASSTHROUGH;
  627. server->grabbed_view = NULL;
  628. } else {
  629. double sx, sy;
  630. struct wlr_surface *surface = NULL;
  631. struct mjc_view *view = desktop_view_at(server,
  632. server->cursor->x, server->cursor->y, &surface, &sx, &sy);
  633. if (view != NULL && view->focusable) {
  634. mjc_view_focus(view);
  635. }
  636. }
  637. }
  638. static void server_cursor_axis(struct wl_listener *listener, void *data) {
  639. struct mjc_server *server = wl_container_of(listener, server, cursor_axis);
  640. struct wlr_pointer_axis_event *event = data;
  641. wlr_seat_pointer_notify_axis(server->seat,
  642. event->time_msec, event->orientation, event->delta,
  643. event->delta_discrete, event->source, event->relative_direction);
  644. }
  645. static void server_cursor_frame(struct wl_listener *listener, void *data) {
  646. (void) data;
  647. struct mjc_server *server = wl_container_of(listener, server, cursor_frame);
  648. wlr_seat_pointer_notify_frame(server->seat);
  649. }
  650. /* ------------------------------------------------------------------ */
  651. /* interactive move/resize */
  652. /* ------------------------------------------------------------------ */
  653. static void view_current_geometry(struct mjc_view *view, struct wlr_box *box) {
  654. if (view->is_xwayland && view->xsurface != NULL) {
  655. box->x = view->scene_tree != NULL ? view->scene_tree->node.x : view->xsurface->x;
  656. box->y = view->scene_tree != NULL ? view->scene_tree->node.y : view->xsurface->y;
  657. box->width = view->xsurface->width;
  658. box->height = view->xsurface->height;
  659. } else {
  660. struct wlr_box geo;
  661. wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo);
  662. box->x = view->scene_tree->node.x + geo.x;
  663. box->y = view->scene_tree->node.y + geo.y;
  664. box->width = geo.width;
  665. box->height = geo.height;
  666. }
  667. }
  668. static void begin_interactive(struct mjc_view *view,
  669. enum mjc_cursor_mode mode, uint32_t edges) {
  670. struct mjc_server *server = view->server;
  671. if (view_surface(view) !=
  672. server->seat->pointer_state.focused_surface) {
  673. /* only react to requests from the focused client */
  674. return;
  675. }
  676. server->grabbed_view = view;
  677. server->cursor_mode = mode;
  678. struct wlr_box geo_box;
  679. view_current_geometry(view, &geo_box);
  680. if (mode == MJC_CURSOR_MOVE) {
  681. server->grab_x = server->cursor->x - view->scene_tree->node.x;
  682. server->grab_y = server->cursor->y - view->scene_tree->node.y;
  683. } else {
  684. double border_x = geo_box.x +
  685. ((edges & WLR_EDGE_RIGHT) ? geo_box.width : 0);
  686. double border_y = geo_box.y +
  687. ((edges & WLR_EDGE_BOTTOM) ? geo_box.height : 0);
  688. server->grab_x = server->cursor->x - border_x;
  689. server->grab_y = server->cursor->y - border_y;
  690. server->grab_geobox = geo_box;
  691. server->resize_edges = edges;
  692. }
  693. }
  694. /* ------------------------------------------------------------------ */
  695. /* view common */
  696. /* ------------------------------------------------------------------ */
  697. /* places a freshly mapped floating view in the middle of the output */
  698. static void view_center(struct mjc_view *view) {
  699. struct mjc_server *server = view->server;
  700. if (view->scene_tree == NULL || view->maximized) {
  701. return;
  702. }
  703. struct wlr_box out;
  704. wlr_output_layout_get_box(server->output_layout, NULL, &out);
  705. struct wlr_box geo;
  706. view_current_geometry(view, &geo);
  707. if (out.width <= 0 || geo.width <= 0) {
  708. return;
  709. }
  710. int x = out.x + (out.width - geo.width) / 2;
  711. int y = out.y + (out.height - geo.height) / 2;
  712. if (x < out.x) x = out.x;
  713. if (y < out.y) y = out.y;
  714. if (view->is_xwayland) {
  715. mjc_view_set_position(view, x, y);
  716. } else {
  717. struct wlr_box off;
  718. wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &off);
  719. wlr_scene_node_set_position(&view->scene_tree->node, x - off.x, y - off.y);
  720. }
  721. }
  722. static void view_emit_new(struct mjc_view *view) {
  723. if (view->server->cbs.view_new != NULL) {
  724. view->server->cbs.view_new(view->server->ud, view, view->is_xwayland);
  725. }
  726. }
  727. static void view_emit_map(struct mjc_view *view) {
  728. if (view->server->cbs.view_map != NULL) {
  729. view->server->cbs.view_map(view->server->ud, view);
  730. }
  731. }
  732. static void view_emit_unmap(struct mjc_view *view) {
  733. if (view->server->cbs.view_unmap != NULL) {
  734. view->server->cbs.view_unmap(view->server->ud, view);
  735. }
  736. }
  737. static void view_emit_destroy(struct mjc_view *view) {
  738. if (view->server->cbs.view_destroy != NULL) {
  739. view->server->cbs.view_destroy(view->server->ud, view);
  740. }
  741. }
  742. static struct mjc_view *view_create(struct mjc_server *server, bool is_xwayland) {
  743. struct mjc_view *view = calloc(1, sizeof(*view));
  744. view->server = server;
  745. view->id = ++server->next_view_id;
  746. view->is_xwayland = is_xwayland;
  747. view->focusable = true;
  748. view->layer = MJC_LAYER_NORMAL;
  749. wl_list_insert(&server->views, &view->link);
  750. return view;
  751. }
  752. static void view_free(struct mjc_view *view) {
  753. clear_focus_if(view->server, view);
  754. view_emit_destroy(view);
  755. wl_list_remove(&view->link);
  756. free(view);
  757. }
  758. /* ------------------------------------------------------------------ */
  759. /* xdg shell views */
  760. /* ------------------------------------------------------------------ */
  761. static void xdg_toplevel_map(struct wl_listener *listener, void *data) {
  762. (void) data;
  763. struct mjc_view *view = wl_container_of(listener, view, map);
  764. view->mapped = true;
  765. view_center(view);
  766. view_emit_map(view);
  767. mjc_view_focus(view);
  768. }
  769. static void xdg_toplevel_unmap(struct wl_listener *listener, void *data) {
  770. (void) data;
  771. struct mjc_view *view = wl_container_of(listener, view, unmap);
  772. view->mapped = false;
  773. clear_focus_if(view->server, view);
  774. view_emit_unmap(view);
  775. }
  776. static void xdg_toplevel_commit(struct wl_listener *listener, void *data) {
  777. (void) data;
  778. struct mjc_view *view = wl_container_of(listener, view, commit);
  779. if (view->xdg_toplevel->base->initial_commit) {
  780. if (view->xdg_toplevel->requested.maximized) {
  781. mjc_view_set_maximized(view, true);
  782. } else {
  783. /* 0x0 lets the client pick its own (or remembered) size */
  784. wlr_xdg_toplevel_set_size(view->xdg_toplevel, 0, 0);
  785. }
  786. return;
  787. }
  788. if (view->pending_center && view->mapped && !view->maximized &&
  789. !view->xdg_toplevel->current.maximized) {
  790. struct wlr_box geo;
  791. wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &geo);
  792. if (geo.width > 0) {
  793. view->pending_center = false;
  794. if (view->saved_geo.width > 0 && view->scene_tree != NULL) {
  795. /* saved coords are visible coords, geo.x/y the offsets */
  796. wlr_scene_node_set_position(&view->scene_tree->node,
  797. view->saved_geo.x - geo.x, view->saved_geo.y - geo.y);
  798. } else {
  799. view_center(view);
  800. }
  801. }
  802. }
  803. }
  804. static void xdg_toplevel_destroy(struct wl_listener *listener, void *data) {
  805. (void) data;
  806. struct mjc_view *view = wl_container_of(listener, view, destroy);
  807. wl_list_remove(&view->map.link);
  808. wl_list_remove(&view->unmap.link);
  809. wl_list_remove(&view->commit.link);
  810. wl_list_remove(&view->destroy.link);
  811. wl_list_remove(&view->request_move.link);
  812. wl_list_remove(&view->request_resize.link);
  813. wl_list_remove(&view->request_maximize.link);
  814. wl_list_remove(&view->request_minimize.link);
  815. wl_list_remove(&view->request_fullscreen.link);
  816. wl_list_remove(&view->set_title.link);
  817. wl_list_remove(&view->set_app_id.link);
  818. view_free(view);
  819. }
  820. static void xdg_toplevel_request_move(struct wl_listener *listener, void *data) {
  821. (void) data;
  822. struct mjc_view *view = wl_container_of(listener, view, request_move);
  823. begin_interactive(view, MJC_CURSOR_MOVE, 0);
  824. }
  825. static void xdg_toplevel_request_resize(struct wl_listener *listener, void *data) {
  826. struct wlr_xdg_toplevel_resize_event *event = data;
  827. struct mjc_view *view = wl_container_of(listener, view, request_resize);
  828. begin_interactive(view, MJC_CURSOR_RESIZE, event->edges);
  829. }
  830. static void xdg_toplevel_request_maximize(struct wl_listener *listener, void *data) {
  831. (void) data;
  832. struct mjc_view *view = wl_container_of(listener, view, request_maximize);
  833. if (view->xdg_toplevel->base->initialized) {
  834. mjc_view_set_maximized(view, view->xdg_toplevel->requested.maximized);
  835. wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base);
  836. }
  837. }
  838. static void xdg_toplevel_request_minimize(struct wl_listener *listener, void *data) {
  839. (void) data;
  840. struct mjc_view *view = wl_container_of(listener, view, request_minimize);
  841. mjc_view_set_minimized(view, true);
  842. }
  843. static void xdg_toplevel_request_fullscreen(struct wl_listener *listener, void *data) {
  844. (void) data;
  845. struct mjc_view *view = wl_container_of(listener, view, request_fullscreen);
  846. if (view->xdg_toplevel->base->initialized) {
  847. wlr_xdg_surface_schedule_configure(view->xdg_toplevel->base);
  848. }
  849. }
  850. static void xdg_toplevel_set_title(struct wl_listener *listener, void *data) {
  851. (void) data;
  852. struct mjc_view *view = wl_container_of(listener, view, set_title);
  853. if (view->server->cbs.view_title != NULL) {
  854. view->server->cbs.view_title(view->server->ud, view,
  855. view->xdg_toplevel->title);
  856. }
  857. }
  858. static void xdg_toplevel_set_app_id(struct wl_listener *listener, void *data) {
  859. (void) data;
  860. struct mjc_view *view = wl_container_of(listener, view, set_app_id);
  861. if (view->server->cbs.view_app_id != NULL) {
  862. view->server->cbs.view_app_id(view->server->ud, view,
  863. view->xdg_toplevel->app_id);
  864. }
  865. }
  866. static void server_new_xdg_toplevel(struct wl_listener *listener, void *data) {
  867. struct mjc_server *server =
  868. wl_container_of(listener, server, new_xdg_toplevel);
  869. struct wlr_xdg_toplevel *xdg_toplevel = data;
  870. struct mjc_view *view = view_create(server, false);
  871. view->xdg_toplevel = xdg_toplevel;
  872. view->scene_tree = wlr_scene_xdg_surface_create(
  873. server->layers[MJC_LAYER_NORMAL], xdg_toplevel->base);
  874. view->scene_tree->node.data = view;
  875. xdg_toplevel->base->data = view->scene_tree;
  876. view_apply_blur(view);
  877. view->map.notify = xdg_toplevel_map;
  878. wl_signal_add(&xdg_toplevel->base->surface->events.map, &view->map);
  879. view->unmap.notify = xdg_toplevel_unmap;
  880. wl_signal_add(&xdg_toplevel->base->surface->events.unmap, &view->unmap);
  881. view->commit.notify = xdg_toplevel_commit;
  882. wl_signal_add(&xdg_toplevel->base->surface->events.commit, &view->commit);
  883. view->destroy.notify = xdg_toplevel_destroy;
  884. wl_signal_add(&xdg_toplevel->events.destroy, &view->destroy);
  885. view->request_move.notify = xdg_toplevel_request_move;
  886. wl_signal_add(&xdg_toplevel->events.request_move, &view->request_move);
  887. view->request_resize.notify = xdg_toplevel_request_resize;
  888. wl_signal_add(&xdg_toplevel->events.request_resize, &view->request_resize);
  889. view->request_maximize.notify = xdg_toplevel_request_maximize;
  890. wl_signal_add(&xdg_toplevel->events.request_maximize, &view->request_maximize);
  891. view->request_minimize.notify = xdg_toplevel_request_minimize;
  892. wl_signal_add(&xdg_toplevel->events.request_minimize, &view->request_minimize);
  893. view->request_fullscreen.notify = xdg_toplevel_request_fullscreen;
  894. wl_signal_add(&xdg_toplevel->events.request_fullscreen, &view->request_fullscreen);
  895. view->set_title.notify = xdg_toplevel_set_title;
  896. wl_signal_add(&xdg_toplevel->events.set_title, &view->set_title);
  897. view->set_app_id.notify = xdg_toplevel_set_app_id;
  898. wl_signal_add(&xdg_toplevel->events.set_app_id, &view->set_app_id);
  899. view_emit_new(view);
  900. }
  901. /* popups */
  902. static void xdg_popup_commit(struct wl_listener *listener, void *data) {
  903. (void) data;
  904. struct mjc_popup *popup = wl_container_of(listener, popup, commit);
  905. if (popup->xdg_popup->base->initial_commit) {
  906. wlr_xdg_surface_schedule_configure(popup->xdg_popup->base);
  907. }
  908. }
  909. static void xdg_popup_destroy(struct wl_listener *listener, void *data) {
  910. (void) data;
  911. struct mjc_popup *popup = wl_container_of(listener, popup, destroy);
  912. wl_list_remove(&popup->commit.link);
  913. wl_list_remove(&popup->destroy.link);
  914. free(popup);
  915. }
  916. static void server_new_xdg_popup(struct wl_listener *listener, void *data) {
  917. (void) listener;
  918. struct wlr_xdg_popup *xdg_popup = data;
  919. struct wlr_xdg_surface *parent =
  920. wlr_xdg_surface_try_from_wlr_surface(xdg_popup->parent);
  921. if (parent == NULL || parent->data == NULL) {
  922. return;
  923. }
  924. struct wlr_scene_tree *parent_tree = parent->data;
  925. xdg_popup->base->data =
  926. wlr_scene_xdg_surface_create(parent_tree, xdg_popup->base);
  927. struct mjc_popup *popup = calloc(1, sizeof(*popup));
  928. popup->xdg_popup = xdg_popup;
  929. popup->commit.notify = xdg_popup_commit;
  930. wl_signal_add(&xdg_popup->base->surface->events.commit, &popup->commit);
  931. popup->destroy.notify = xdg_popup_destroy;
  932. wl_signal_add(&xdg_popup->events.destroy, &popup->destroy);
  933. }
  934. /* decorations - clients draw their own buttons (CSD), the compositor
  935. * renders no frames, so server side mode is never granted */
  936. static void decoration_request_mode(struct wl_listener *listener, void *data) {
  937. (void) data;
  938. struct mjc_decoration *deco = wl_container_of(listener, deco, request_mode);
  939. if (deco->decoration->toplevel->base->initialized) {
  940. wlr_xdg_toplevel_decoration_v1_set_mode(deco->decoration,
  941. WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE);
  942. }
  943. }
  944. static void decoration_destroy(struct wl_listener *listener, void *data) {
  945. (void) data;
  946. struct mjc_decoration *deco = wl_container_of(listener, deco, destroy);
  947. wl_list_remove(&deco->request_mode.link);
  948. wl_list_remove(&deco->destroy.link);
  949. free(deco);
  950. }
  951. static void server_new_toplevel_decoration(struct wl_listener *listener,
  952. void *data) {
  953. (void) listener;
  954. struct wlr_xdg_toplevel_decoration_v1 *decoration = data;
  955. struct mjc_decoration *deco = calloc(1, sizeof(*deco));
  956. deco->decoration = decoration;
  957. deco->request_mode.notify = decoration_request_mode;
  958. wl_signal_add(&decoration->events.request_mode, &deco->request_mode);
  959. deco->destroy.notify = decoration_destroy;
  960. wl_signal_add(&decoration->events.destroy, &deco->destroy);
  961. decoration_request_mode(&deco->request_mode, NULL);
  962. }
  963. /* ------------------------------------------------------------------ */
  964. /* xwayland views */
  965. /* ------------------------------------------------------------------ */
  966. static void xwayland_surface_map(struct wl_listener *listener, void *data) {
  967. (void) data;
  968. struct mjc_view *view = wl_container_of(listener, view, map);
  969. struct mjc_server *server = view->server;
  970. struct wlr_xwayland_surface *xsurface = view->xsurface;
  971. mjc_layer layer = xsurface->override_redirect
  972. ? MJC_LAYER_OVERLAY : view->layer;
  973. view->scene_tree = wlr_scene_tree_create(server->layers[layer]);
  974. view->scene_tree->node.data = view;
  975. wlr_scene_surface_create(view->scene_tree, xsurface->surface);
  976. view_apply_blur(view);
  977. wlr_scene_node_set_position(&view->scene_tree->node,
  978. xsurface->x, xsurface->y);
  979. view->mapped = true;
  980. /* X clients that did not place themselves land at 0,0 - center those */
  981. if (!xsurface->override_redirect && xsurface->x == 0 && xsurface->y == 0) {
  982. view_center(view);
  983. }
  984. view_emit_map(view);
  985. if (!xsurface->override_redirect) {
  986. mjc_view_focus(view);
  987. }
  988. }
  989. static void xwayland_surface_unmap(struct wl_listener *listener, void *data) {
  990. (void) data;
  991. struct mjc_view *view = wl_container_of(listener, view, unmap);
  992. view->mapped = false;
  993. clear_focus_if(view->server, view);
  994. /* emit while the scene node still exists so the policy side can
  995. * read the last window geometry */
  996. view_emit_unmap(view);
  997. if (view->scene_tree != NULL) {
  998. wlr_scene_node_destroy(&view->scene_tree->node);
  999. view->scene_tree = NULL;
  1000. }
  1001. }
  1002. static void xwayland_surface_associate(struct wl_listener *listener, void *data) {
  1003. (void) data;
  1004. struct mjc_view *view = wl_container_of(listener, view, associate);
  1005. view->map.notify = xwayland_surface_map;
  1006. wl_signal_add(&view->xsurface->surface->events.map, &view->map);
  1007. view->unmap.notify = xwayland_surface_unmap;
  1008. wl_signal_add(&view->xsurface->surface->events.unmap, &view->unmap);
  1009. }
  1010. static void xwayland_surface_dissociate(struct wl_listener *listener, void *data) {
  1011. (void) data;
  1012. struct mjc_view *view = wl_container_of(listener, view, dissociate);
  1013. wl_list_remove(&view->map.link);
  1014. wl_list_remove(&view->unmap.link);
  1015. }
  1016. static void xwayland_surface_destroy(struct wl_listener *listener, void *data) {
  1017. (void) data;
  1018. struct mjc_view *view = wl_container_of(listener, view, destroy);
  1019. wl_list_remove(&view->associate.link);
  1020. wl_list_remove(&view->dissociate.link);
  1021. wl_list_remove(&view->destroy.link);
  1022. wl_list_remove(&view->request_configure.link);
  1023. wl_list_remove(&view->request_move.link);
  1024. wl_list_remove(&view->request_resize.link);
  1025. wl_list_remove(&view->request_minimize.link);
  1026. wl_list_remove(&view->request_maximize.link);
  1027. wl_list_remove(&view->set_title.link);
  1028. wl_list_remove(&view->set_app_id.link);
  1029. wl_list_remove(&view->set_geometry.link);
  1030. if (view->scene_tree != NULL) {
  1031. wlr_scene_node_destroy(&view->scene_tree->node);
  1032. view->scene_tree = NULL;
  1033. }
  1034. view_free(view);
  1035. }
  1036. static void xwayland_surface_request_configure(struct wl_listener *listener,
  1037. void *data) {
  1038. struct mjc_view *view = wl_container_of(listener, view, request_configure);
  1039. struct wlr_xwayland_surface_configure_event *event = data;
  1040. wlr_xwayland_surface_configure(view->xsurface,
  1041. event->x, event->y, event->width, event->height);
  1042. if (view->scene_tree != NULL) {
  1043. wlr_scene_node_set_position(&view->scene_tree->node, event->x, event->y);
  1044. }
  1045. }
  1046. static void xwayland_surface_set_geometry(struct wl_listener *listener,
  1047. void *data) {
  1048. (void) data;
  1049. struct mjc_view *view = wl_container_of(listener, view, set_geometry);
  1050. if (view->scene_tree != NULL && view->xsurface != NULL) {
  1051. wlr_scene_node_set_position(&view->scene_tree->node,
  1052. view->xsurface->x, view->xsurface->y);
  1053. }
  1054. }
  1055. static void xwayland_surface_request_move(struct wl_listener *listener,
  1056. void *data) {
  1057. (void) data;
  1058. struct mjc_view *view = wl_container_of(listener, view, request_move);
  1059. begin_interactive(view, MJC_CURSOR_MOVE, 0);
  1060. }
  1061. static void xwayland_surface_request_resize(struct wl_listener *listener,
  1062. void *data) {
  1063. struct mjc_view *view = wl_container_of(listener, view, request_resize);
  1064. struct wlr_xwayland_resize_event *event = data;
  1065. begin_interactive(view, MJC_CURSOR_RESIZE, event->edges);
  1066. }
  1067. static void xwayland_surface_request_minimize(struct wl_listener *listener,
  1068. void *data) {
  1069. (void) data;
  1070. struct mjc_view *view = wl_container_of(listener, view, request_minimize);
  1071. mjc_view_set_minimized(view, true);
  1072. }
  1073. static void xwayland_surface_request_maximize(struct wl_listener *listener,
  1074. void *data) {
  1075. (void) data;
  1076. struct mjc_view *view = wl_container_of(listener, view, request_maximize);
  1077. struct wlr_xwayland_surface *xsurface = view->xsurface;
  1078. if (xsurface == NULL) {
  1079. return;
  1080. }
  1081. /* the client announces the state it wants via _NET_WM_STATE */
  1082. mjc_view_set_maximized(view,
  1083. xsurface->maximized_vert && xsurface->maximized_horz);
  1084. }
  1085. static void xwayland_surface_set_title(struct wl_listener *listener, void *data) {
  1086. (void) data;
  1087. struct mjc_view *view = wl_container_of(listener, view, set_title);
  1088. if (view->server->cbs.view_title != NULL) {
  1089. view->server->cbs.view_title(view->server->ud, view,
  1090. view->xsurface->title);
  1091. }
  1092. }
  1093. static void xwayland_surface_set_class(struct wl_listener *listener, void *data) {
  1094. (void) data;
  1095. struct mjc_view *view = wl_container_of(listener, view, set_app_id);
  1096. if (view->server->cbs.view_app_id != NULL) {
  1097. view->server->cbs.view_app_id(view->server->ud, view,
  1098. view->xsurface->class);
  1099. }
  1100. }
  1101. static void server_new_xwayland_surface(struct wl_listener *listener, void *data) {
  1102. struct mjc_server *server =
  1103. wl_container_of(listener, server, new_xwayland_surface);
  1104. struct wlr_xwayland_surface *xsurface = data;
  1105. struct mjc_view *view = view_create(server, true);
  1106. view->xsurface = xsurface;
  1107. if (xsurface->override_redirect) {
  1108. view->focusable = false;
  1109. }
  1110. xsurface->data = view;
  1111. view->associate.notify = xwayland_surface_associate;
  1112. wl_signal_add(&xsurface->events.associate, &view->associate);
  1113. view->dissociate.notify = xwayland_surface_dissociate;
  1114. wl_signal_add(&xsurface->events.dissociate, &view->dissociate);
  1115. view->destroy.notify = xwayland_surface_destroy;
  1116. wl_signal_add(&xsurface->events.destroy, &view->destroy);
  1117. view->request_configure.notify = xwayland_surface_request_configure;
  1118. wl_signal_add(&xsurface->events.request_configure, &view->request_configure);
  1119. view->request_move.notify = xwayland_surface_request_move;
  1120. wl_signal_add(&xsurface->events.request_move, &view->request_move);
  1121. view->request_resize.notify = xwayland_surface_request_resize;
  1122. wl_signal_add(&xsurface->events.request_resize, &view->request_resize);
  1123. view->request_minimize.notify = xwayland_surface_request_minimize;
  1124. wl_signal_add(&xsurface->events.request_minimize, &view->request_minimize);
  1125. view->request_maximize.notify = xwayland_surface_request_maximize;
  1126. wl_signal_add(&xsurface->events.request_maximize, &view->request_maximize);
  1127. view->set_title.notify = xwayland_surface_set_title;
  1128. wl_signal_add(&xsurface->events.set_title, &view->set_title);
  1129. view->set_app_id.notify = xwayland_surface_set_class;
  1130. wl_signal_add(&xsurface->events.set_class, &view->set_app_id);
  1131. view->set_geometry.notify = xwayland_surface_set_geometry;
  1132. wl_signal_add(&xsurface->events.set_geometry, &view->set_geometry);
  1133. view_emit_new(view);
  1134. }
  1135. static void server_xwayland_ready(struct wl_listener *listener, void *data) {
  1136. (void) data;
  1137. struct mjc_server *server = wl_container_of(listener, server, xwayland_ready);
  1138. wlr_xwayland_set_seat(server->xwayland, server->seat);
  1139. }
  1140. /* ------------------------------------------------------------------ */
  1141. /* sigchld */
  1142. /* ------------------------------------------------------------------ */
  1143. static int handle_sigchld(int signal_number, void *data) {
  1144. (void) signal_number;
  1145. struct mjc_server *server = data;
  1146. for (int i = 0; i < server->spawned_count;) {
  1147. int status;
  1148. pid_t pid = waitpid(server->spawned_pids[i], &status, WNOHANG);
  1149. if (pid > 0) {
  1150. server->spawned_pids[i] =
  1151. server->spawned_pids[--server->spawned_count];
  1152. if (server->cbs.child_exit != NULL) {
  1153. server->cbs.child_exit(server->ud, (int) pid, status);
  1154. }
  1155. } else {
  1156. i++;
  1157. }
  1158. }
  1159. return 0;
  1160. }
  1161. /* True when the GLES2 renderer ended up on software rendering (llvmpipe/swrast) — i.e. there is
  1162. * no usable hardware GL. In that case the Compose shell (Skiko) cannot create an OpenGL/GLX
  1163. * context on the (also software) XWayland and must use its CPU raster backend, so the compositor
  1164. * exports SKIKO_RENDER_API=SOFTWARE for the shell. On a real GPU it returns false and the shell
  1165. * uses hardware GL. Queries GL_RENDERER via the renderer's own EGL context (surfaceless). */
  1166. static bool mjc_renderer_is_software(struct wlr_renderer *renderer) {
  1167. if (!wlr_renderer_is_gles2(renderer)) {
  1168. return false;
  1169. }
  1170. struct wlr_egl *egl = wlr_gles2_renderer_get_egl(renderer);
  1171. if (egl == NULL) {
  1172. return false;
  1173. }
  1174. EGLDisplay dpy = wlr_egl_get_display(egl);
  1175. EGLContext ctx = wlr_egl_get_context(egl);
  1176. if (dpy == EGL_NO_DISPLAY || ctx == EGL_NO_CONTEXT) {
  1177. return false;
  1178. }
  1179. if (!eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, ctx)) {
  1180. return false;
  1181. }
  1182. const char *gl_renderer = (const char *) glGetString(GL_RENDERER);
  1183. bool software = gl_renderer != NULL && (
  1184. strstr(gl_renderer, "llvmpipe") != NULL ||
  1185. strstr(gl_renderer, "softpipe") != NULL ||
  1186. strstr(gl_renderer, "swrast") != NULL ||
  1187. strstr(gl_renderer, "SWR") != NULL ||
  1188. strstr(gl_renderer, "Software") != NULL);
  1189. eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  1190. return software;
  1191. }
  1192. /* ------------------------------------------------------------------ */
  1193. /* public API */
  1194. /* ------------------------------------------------------------------ */
  1195. mjc_server *mjc_create(void) {
  1196. struct mjc_server *server = calloc(1, sizeof(*server));
  1197. wl_list_init(&server->views);
  1198. wl_list_init(&server->keyboards);
  1199. wl_list_init(&server->fd_sources);
  1200. return server;
  1201. }
  1202. bool mjc_start(mjc_server *server, const mjc_callbacks *callbacks, void *userdata) {
  1203. server->cbs = *callbacks;
  1204. server->ud = userdata;
  1205. wlr_log_init(WLR_INFO, NULL);
  1206. /* nested-output size, 16:9 default; override with MJDEVC_OUTPUT=WIDTHxHEIGHT */
  1207. server->output_w = 1280;
  1208. server->output_h = 720;
  1209. const char *out_env = getenv("MJDEVC_OUTPUT");
  1210. if (out_env != NULL) {
  1211. int w = 0, h = 0;
  1212. if (sscanf(out_env, "%dx%d", &w, &h) == 2 && w > 0 && h > 0) {
  1213. server->output_w = w;
  1214. server->output_h = h;
  1215. }
  1216. }
  1217. server->display = wl_display_create();
  1218. server->loop = wl_display_get_event_loop(server->display);
  1219. server->backend = wlr_backend_autocreate(server->loop, &server->session);
  1220. if (server->backend == NULL) {
  1221. fprintf(stderr, "mjdevc: failed to create wlr_backend\n");
  1222. return false;
  1223. }
  1224. #ifdef MJC_WITH_SCENEFX
  1225. /* The scenefx renderer is not the wlroots gles2 renderer, so the software-GL probe cannot
  1226. * run on it. Probe with a short-lived plain renderer first, then create the blur renderer. */
  1227. {
  1228. struct wlr_renderer *probe = wlr_renderer_autocreate(server->backend);
  1229. server->software_gl = probe != NULL && mjc_renderer_is_software(probe);
  1230. if (probe != NULL) {
  1231. wlr_renderer_destroy(probe);
  1232. }
  1233. }
  1234. server->renderer = fx_renderer_create(server->backend);
  1235. #else
  1236. server->renderer = wlr_renderer_autocreate(server->backend);
  1237. #endif
  1238. if (server->renderer == NULL) {
  1239. fprintf(stderr, "mjdevc: failed to create wlr_renderer\n");
  1240. return false;
  1241. }
  1242. wlr_renderer_init_wl_display(server->renderer, server->display);
  1243. server->allocator = wlr_allocator_autocreate(server->backend, server->renderer);
  1244. if (server->allocator == NULL) {
  1245. fprintf(stderr, "mjdevc: failed to create wlr_allocator\n");
  1246. return false;
  1247. }
  1248. server->compositor = wlr_compositor_create(server->display, 5, server->renderer);
  1249. wlr_subcompositor_create(server->display);
  1250. wlr_data_device_manager_create(server->display);
  1251. server->output_layout = wlr_output_layout_create(server->display);
  1252. server->new_output.notify = server_new_output;
  1253. wl_signal_add(&server->backend->events.new_output, &server->new_output);
  1254. server->scene = wlr_scene_create();
  1255. server->scene_layout =
  1256. wlr_scene_attach_output_layout(server->scene, server->output_layout);
  1257. for (int i = 0; i < 5; i++) {
  1258. server->layers[i] = wlr_scene_tree_create(&server->scene->tree);
  1259. }
  1260. /* injection feedback marker: a 16x16 white square in the overlay layer, hidden until
  1261. * input is injected, then shown at the pointer and faded out (Android show-touches style) */
  1262. const float marker_hidden[4] = {0.0f, 0.0f, 0.0f, 0.0f};
  1263. server->inject_marker = wlr_scene_rect_create(
  1264. server->layers[MJC_LAYER_OVERLAY], 16, 16, marker_hidden);
  1265. wlr_scene_node_set_enabled(&server->inject_marker->node, false);
  1266. server->xdg_shell = wlr_xdg_shell_create(server->display, 3);
  1267. server->new_xdg_toplevel.notify = server_new_xdg_toplevel;
  1268. wl_signal_add(&server->xdg_shell->events.new_toplevel, &server->new_xdg_toplevel);
  1269. server->new_xdg_popup.notify = server_new_xdg_popup;
  1270. wl_signal_add(&server->xdg_shell->events.new_popup, &server->new_xdg_popup);
  1271. server->xdg_decoration_mgr = wlr_xdg_decoration_manager_v1_create(server->display);
  1272. server->new_toplevel_decoration.notify = server_new_toplevel_decoration;
  1273. wl_signal_add(&server->xdg_decoration_mgr->events.new_toplevel_decoration,
  1274. &server->new_toplevel_decoration);
  1275. server->cursor = wlr_cursor_create();
  1276. wlr_cursor_attach_output_layout(server->cursor, server->output_layout);
  1277. server->cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
  1278. server->cursor_mode = MJC_CURSOR_PASSTHROUGH;
  1279. server->cursor_motion.notify = server_cursor_motion;
  1280. wl_signal_add(&server->cursor->events.motion, &server->cursor_motion);
  1281. server->cursor_motion_absolute.notify = server_cursor_motion_absolute;
  1282. wl_signal_add(&server->cursor->events.motion_absolute,
  1283. &server->cursor_motion_absolute);
  1284. server->cursor_button.notify = server_cursor_button;
  1285. wl_signal_add(&server->cursor->events.button, &server->cursor_button);
  1286. server->cursor_axis.notify = server_cursor_axis;
  1287. wl_signal_add(&server->cursor->events.axis, &server->cursor_axis);
  1288. server->cursor_frame.notify = server_cursor_frame;
  1289. wl_signal_add(&server->cursor->events.frame, &server->cursor_frame);
  1290. server->new_input.notify = server_new_input;
  1291. wl_signal_add(&server->backend->events.new_input, &server->new_input);
  1292. server->seat = wlr_seat_create(server->display, "seat0");
  1293. server->request_cursor.notify = seat_request_cursor;
  1294. wl_signal_add(&server->seat->events.request_set_cursor, &server->request_cursor);
  1295. server->request_set_selection.notify = seat_request_set_selection;
  1296. wl_signal_add(&server->seat->events.request_set_selection,
  1297. &server->request_set_selection);
  1298. const char *socket = wl_display_add_socket_auto(server->display);
  1299. if (socket == NULL) {
  1300. fprintf(stderr, "mjdevc: failed to create wayland socket\n");
  1301. return false;
  1302. }
  1303. server->socket = socket;
  1304. server->xwayland = wlr_xwayland_create(server->display, server->compositor, true);
  1305. if (server->xwayland != NULL) {
  1306. server->new_xwayland_surface.notify = server_new_xwayland_surface;
  1307. wl_signal_add(&server->xwayland->events.new_surface,
  1308. &server->new_xwayland_surface);
  1309. server->xwayland_ready.notify = server_xwayland_ready;
  1310. wl_signal_add(&server->xwayland->events.ready, &server->xwayland_ready);
  1311. }
  1312. server->sigchld_source = wl_event_loop_add_signal(server->loop,
  1313. SIGCHLD, handle_sigchld, server);
  1314. if (!wlr_backend_start(server->backend)) {
  1315. fprintf(stderr, "mjdevc: failed to start backend\n");
  1316. return false;
  1317. }
  1318. setenv("WAYLAND_DISPLAY", socket, true);
  1319. if (server->xwayland != NULL) {
  1320. setenv("DISPLAY", server->xwayland->display_name, true);
  1321. }
  1322. /* GPU vs software decision for the Compose shell (Skiko), exported into its environment
  1323. * before it is spawned. Software GL (VM / no GPU) -> Skiko CPU raster (else it crashes with
  1324. * "Cannot create Linux GL context"); real GPU -> leave unset so Skiko uses hardware GL. */
  1325. #ifdef MJC_WITH_SCENEFX
  1326. if (server->software_gl) {
  1327. #else
  1328. if (mjc_renderer_is_software(server->renderer)) {
  1329. #endif
  1330. setenv("SKIKO_RENDER_API", "SOFTWARE", true);
  1331. fprintf(stderr, "mjdevc: software GL renderer -> SKIKO_RENDER_API=SOFTWARE for the shell\n");
  1332. } else {
  1333. unsetenv("SKIKO_RENDER_API");
  1334. fprintf(stderr, "mjdevc: hardware GL renderer -> shell uses Skiko OpenGL\n");
  1335. }
  1336. if (server->cbs.ready != NULL) {
  1337. server->cbs.ready(server->ud);
  1338. }
  1339. return true;
  1340. }
  1341. void mjc_run(mjc_server *server) {
  1342. wl_display_run(server->display);
  1343. }
  1344. void mjc_terminate(mjc_server *server) {
  1345. wl_display_terminate(server->display);
  1346. }
  1347. void mjc_destroy(mjc_server *server) {
  1348. if (server->xwayland != NULL) {
  1349. wlr_xwayland_destroy(server->xwayland);
  1350. }
  1351. wl_display_destroy_clients(server->display);
  1352. wlr_scene_node_destroy(&server->scene->tree.node);
  1353. wlr_xcursor_manager_destroy(server->cursor_mgr);
  1354. wlr_cursor_destroy(server->cursor);
  1355. wlr_allocator_destroy(server->allocator);
  1356. wlr_renderer_destroy(server->renderer);
  1357. wlr_backend_destroy(server->backend);
  1358. wl_display_destroy(server->display);
  1359. free(server);
  1360. }
  1361. const char *mjc_socket_name(mjc_server *server) {
  1362. return server->socket;
  1363. }
  1364. const char *mjc_xwayland_display(mjc_server *server) {
  1365. return server->xwayland != NULL ? server->xwayland->display_name : NULL;
  1366. }
  1367. void mjc_output_size(mjc_server *server, int *width, int *height) {
  1368. struct wlr_box box;
  1369. wlr_output_layout_get_box(server->output_layout, NULL, &box);
  1370. *width = box.width;
  1371. *height = box.height;
  1372. }
  1373. int mjc_spawn(mjc_server *server, const char *command) {
  1374. pid_t pid = fork();
  1375. if (pid < 0) {
  1376. return -1;
  1377. }
  1378. if (pid == 0) {
  1379. setsid();
  1380. sigset_t set;
  1381. sigemptyset(&set);
  1382. sigprocmask(SIG_SETMASK, &set, NULL);
  1383. execl("/bin/sh", "/bin/sh", "-c", command, (void *) NULL);
  1384. _exit(127);
  1385. }
  1386. if (server->spawned_count <
  1387. (int) (sizeof(server->spawned_pids) / sizeof(server->spawned_pids[0]))) {
  1388. server->spawned_pids[server->spawned_count++] = pid;
  1389. }
  1390. return (int) pid;
  1391. }
  1392. /* unix socket helpers */
  1393. #include <fcntl.h>
  1394. #include <sys/socket.h>
  1395. #include <sys/un.h>
  1396. int mjc_unix_listen(const char *path, int backlog) {
  1397. int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
  1398. if (fd < 0) {
  1399. return -1;
  1400. }
  1401. struct sockaddr_un addr = {0};
  1402. addr.sun_family = AF_UNIX;
  1403. if (strlen(path) >= sizeof(addr.sun_path)) {
  1404. close(fd);
  1405. return -1;
  1406. }
  1407. strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
  1408. unlink(path);
  1409. if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) != 0 ||
  1410. listen(fd, backlog) != 0) {
  1411. close(fd);
  1412. return -1;
  1413. }
  1414. return fd;
  1415. }
  1416. int mjc_unix_accept(int server_fd) {
  1417. int fd = accept(server_fd, NULL, NULL);
  1418. if (fd >= 0) {
  1419. fcntl(fd, F_SETFL, O_NONBLOCK);
  1420. }
  1421. return fd;
  1422. }
  1423. /* fd integration */
  1424. static int handle_fd_event(int fd, uint32_t mask, void *data) {
  1425. struct mjc_fd_source *source = data;
  1426. if (source->server->cbs.fd_event != NULL) {
  1427. return source->server->cbs.fd_event(source->server->ud, fd, mask);
  1428. }
  1429. return 0;
  1430. }
  1431. bool mjc_loop_add_fd(mjc_server *server, int fd, uint32_t mask) {
  1432. struct mjc_fd_source *source = calloc(1, sizeof(*source));
  1433. source->server = server;
  1434. source->fd = fd;
  1435. source->source = wl_event_loop_add_fd(server->loop, fd, mask,
  1436. handle_fd_event, source);
  1437. if (source->source == NULL) {
  1438. free(source);
  1439. return false;
  1440. }
  1441. wl_list_insert(&server->fd_sources, &source->link);
  1442. return true;
  1443. }
  1444. void mjc_loop_remove_fd(mjc_server *server, int fd) {
  1445. struct mjc_fd_source *source, *tmp;
  1446. wl_list_for_each_safe(source, tmp, &server->fd_sources, link) {
  1447. if (source->fd == fd) {
  1448. wl_event_source_remove(source->source);
  1449. wl_list_remove(&source->link);
  1450. free(source);
  1451. return;
  1452. }
  1453. }
  1454. }
  1455. /* views */
  1456. uint64_t mjc_view_id(mjc_view *view) {
  1457. return view->id;
  1458. }
  1459. int mjc_view_pid(mjc_view *view) {
  1460. if (view->is_xwayland) {
  1461. return view->xsurface != NULL ? (int) view->xsurface->pid : 0;
  1462. }
  1463. pid_t pid = 0;
  1464. struct wlr_surface *surface = view_surface(view);
  1465. if (surface != NULL) {
  1466. struct wl_client *client = wl_resource_get_client(surface->resource);
  1467. wl_client_get_credentials(client, &pid, NULL, NULL);
  1468. }
  1469. return (int) pid;
  1470. }
  1471. const char *mjc_view_title(mjc_view *view) {
  1472. if (view->is_xwayland) {
  1473. return view->xsurface != NULL ? view->xsurface->title : NULL;
  1474. }
  1475. return view->xdg_toplevel->title;
  1476. }
  1477. const char *mjc_view_app_id(mjc_view *view) {
  1478. if (view->is_xwayland) {
  1479. return view->xsurface != NULL ? view->xsurface->class : NULL;
  1480. }
  1481. return view->xdg_toplevel->app_id;
  1482. }
  1483. bool mjc_view_is_xwayland(mjc_view *view) {
  1484. return view->is_xwayland;
  1485. }
  1486. bool mjc_view_is_mapped(mjc_view *view) {
  1487. return view->mapped;
  1488. }
  1489. bool mjc_view_is_minimized(mjc_view *view) {
  1490. return view->minimized;
  1491. }
  1492. bool mjc_view_is_maximized(mjc_view *view) {
  1493. return view->maximized;
  1494. }
  1495. bool mjc_view_is_focused(mjc_view *view) {
  1496. return view->server->focused_view == view;
  1497. }
  1498. void mjc_view_get_geometry(mjc_view *view, int *x, int *y, int *width, int *height) {
  1499. struct wlr_box box = {0};
  1500. if (view->scene_tree != NULL || !view->is_xwayland) {
  1501. view_current_geometry(view, &box);
  1502. }
  1503. *x = box.x;
  1504. *y = box.y;
  1505. *width = box.width;
  1506. *height = box.height;
  1507. }
  1508. void mjc_view_close(mjc_view *view) {
  1509. if (view->is_xwayland) {
  1510. if (view->xsurface != NULL) {
  1511. wlr_xwayland_surface_close(view->xsurface);
  1512. }
  1513. } else {
  1514. wlr_xdg_toplevel_send_close(view->xdg_toplevel);
  1515. }
  1516. }
  1517. void mjc_view_set_minimized(mjc_view *view, bool minimized) {
  1518. if (view->minimized == minimized) {
  1519. return;
  1520. }
  1521. view->minimized = minimized;
  1522. if (view->scene_tree != NULL) {
  1523. wlr_scene_node_set_enabled(&view->scene_tree->node, !minimized);
  1524. }
  1525. if (view->is_xwayland && view->xsurface != NULL) {
  1526. wlr_xwayland_surface_set_minimized(view->xsurface, minimized);
  1527. }
  1528. if (minimized) {
  1529. clear_focus_if(view->server, view);
  1530. } else {
  1531. mjc_view_focus(view);
  1532. }
  1533. }
  1534. void mjc_view_set_maximized(mjc_view *view, bool maximized) {
  1535. struct mjc_server *server = view->server;
  1536. if (view->maximized == maximized) {
  1537. return;
  1538. }
  1539. struct wlr_box box;
  1540. wlr_output_layout_get_box(server->output_layout, NULL, &box);
  1541. if (maximized && view->mapped && view->scene_tree != NULL) {
  1542. /* remember the floating geometry (visible coords) for restore */
  1543. view_current_geometry(view, &view->saved_geo);
  1544. }
  1545. view->maximized = maximized;
  1546. if (view->is_xwayland) {
  1547. if (view->xsurface == NULL) {
  1548. return;
  1549. }
  1550. wlr_xwayland_surface_set_maximized(view->xsurface, maximized);
  1551. if (maximized) {
  1552. wlr_xwayland_surface_configure(view->xsurface,
  1553. (int16_t) box.x, (int16_t) box.y,
  1554. (uint16_t) box.width, (uint16_t) box.height);
  1555. if (view->scene_tree != NULL) {
  1556. wlr_scene_node_set_position(&view->scene_tree->node, box.x, box.y);
  1557. }
  1558. } else if (view->saved_geo.width > 0) {
  1559. wlr_xwayland_surface_configure(view->xsurface,
  1560. (int16_t) view->saved_geo.x, (int16_t) view->saved_geo.y,
  1561. (uint16_t) view->saved_geo.width, (uint16_t) view->saved_geo.height);
  1562. if (view->scene_tree != NULL) {
  1563. wlr_scene_node_set_position(&view->scene_tree->node,
  1564. view->saved_geo.x, view->saved_geo.y);
  1565. }
  1566. }
  1567. } else {
  1568. wlr_xdg_toplevel_set_maximized(view->xdg_toplevel, maximized);
  1569. if (maximized) {
  1570. wlr_xdg_toplevel_set_size(view->xdg_toplevel, box.width, box.height);
  1571. if (view->scene_tree != NULL) {
  1572. wlr_scene_node_set_position(&view->scene_tree->node, box.x, box.y);
  1573. }
  1574. } else {
  1575. /* 0x0 when no remembered size - the client picks its own;
  1576. * placement happens on the commit that carries the new size,
  1577. * when the decoration offsets are known again */
  1578. wlr_xdg_toplevel_set_size(view->xdg_toplevel,
  1579. view->saved_geo.width, view->saved_geo.height);
  1580. view->pending_center = true;
  1581. }
  1582. }
  1583. }
  1584. void mjc_view_set_layer(mjc_view *view, mjc_layer layer) {
  1585. view->layer = layer;
  1586. if (view->scene_tree != NULL) {
  1587. wlr_scene_node_reparent(&view->scene_tree->node,
  1588. view->server->layers[layer]);
  1589. }
  1590. }
  1591. void mjc_view_set_focusable(mjc_view *view, bool focusable) {
  1592. view->focusable = focusable;
  1593. if (!focusable) {
  1594. clear_focus_if(view->server, view);
  1595. }
  1596. }
  1597. /* ------------------------------------------------------------------ */
  1598. /* backdrop blur (scenefx) */
  1599. /* ------------------------------------------------------------------ */
  1600. bool mjc_blur_supported(void) {
  1601. #ifdef MJC_WITH_SCENEFX
  1602. return true;
  1603. #else
  1604. return false;
  1605. #endif
  1606. }
  1607. void mjc_blur_configure(mjc_server *server, int passes, int radius, float noise,
  1608. float brightness, float contrast, float saturation) {
  1609. #ifdef MJC_WITH_SCENEFX
  1610. struct blur_data data = blur_data_get_default();
  1611. data.num_passes = passes;
  1612. data.radius = radius;
  1613. data.noise = noise;
  1614. data.brightness = brightness;
  1615. data.contrast = contrast;
  1616. data.saturation = saturation;
  1617. wlr_scene_set_blur_data(server->scene, data);
  1618. #else
  1619. (void) server; (void) passes; (void) radius; (void) noise;
  1620. (void) brightness; (void) contrast; (void) saturation;
  1621. #endif
  1622. }
  1623. void mjc_view_set_blur(mjc_view *view, bool enabled) {
  1624. view->blur = enabled;
  1625. view_apply_blur(view);
  1626. }
  1627. bool mjc_view_is_blurred(mjc_view *view) {
  1628. return view->blur;
  1629. }
  1630. void mjc_view_set_position(mjc_view *view, int x, int y) {
  1631. if (view->scene_tree != NULL) {
  1632. wlr_scene_node_set_position(&view->scene_tree->node, x, y);
  1633. }
  1634. if (view->is_xwayland && view->xsurface != NULL) {
  1635. wlr_xwayland_surface_configure(view->xsurface,
  1636. (int16_t) x, (int16_t) y,
  1637. (uint16_t) view->xsurface->width, (uint16_t) view->xsurface->height);
  1638. }
  1639. }
  1640. void mjc_view_set_geometry(mjc_view *view, int x, int y, int width, int height) {
  1641. if (width <= 0 || height <= 0) {
  1642. return;
  1643. }
  1644. if (view->maximized) {
  1645. /* keep it as the restore target for the next unmaximize */
  1646. view->saved_geo.x = x;
  1647. view->saved_geo.y = y;
  1648. view->saved_geo.width = width;
  1649. view->saved_geo.height = height;
  1650. return;
  1651. }
  1652. if (view->is_xwayland) {
  1653. if (view->xsurface != NULL) {
  1654. wlr_xwayland_surface_configure(view->xsurface,
  1655. (int16_t) x, (int16_t) y, (uint16_t) width, (uint16_t) height);
  1656. }
  1657. if (view->scene_tree != NULL) {
  1658. wlr_scene_node_set_position(&view->scene_tree->node, x, y);
  1659. }
  1660. } else {
  1661. wlr_xdg_toplevel_set_size(view->xdg_toplevel, width, height);
  1662. if (view->scene_tree != NULL) {
  1663. struct wlr_box off;
  1664. wlr_xdg_surface_get_geometry(view->xdg_toplevel->base, &off);
  1665. wlr_scene_node_set_position(&view->scene_tree->node,
  1666. x - off.x, y - off.y);
  1667. }
  1668. }
  1669. }
  1670. /* ------------------------------------------------------------------ */
  1671. /* input injection (ipc-driven, for automated/headless testing) */
  1672. /* ------------------------------------------------------------------ */
  1673. static uint32_t mjc_now_msec(void) {
  1674. struct timespec now;
  1675. clock_gettime(CLOCK_MONOTONIC, &now);
  1676. return (uint32_t) (now.tv_sec * 1000 + now.tv_nsec / 1000000);
  1677. }
  1678. #define MJC_INJECT_MARKER_SIZE 16
  1679. #define MJC_INJECT_FADE_STEP 0.08f
  1680. #define MJC_INJECT_FADE_INTERVAL_MS 40
  1681. /* step the injection marker's alpha down; disables it once fully faded */
  1682. static int inject_marker_fade(void *data) {
  1683. struct mjc_server *server = data;
  1684. if (server->inject_marker == NULL) {
  1685. return 0;
  1686. }
  1687. server->inject_alpha -= MJC_INJECT_FADE_STEP;
  1688. if (server->inject_alpha <= 0.0f) {
  1689. server->inject_alpha = 0.0f;
  1690. wlr_scene_node_set_enabled(&server->inject_marker->node, false);
  1691. return 0;
  1692. }
  1693. float a = server->inject_alpha;
  1694. const float color[4] = {a, a, a, a}; /* premultiplied white */
  1695. wlr_scene_rect_set_color(server->inject_marker, color);
  1696. if (server->inject_fade_timer != NULL) {
  1697. wl_event_source_timer_update(server->inject_fade_timer,
  1698. MJC_INJECT_FADE_INTERVAL_MS);
  1699. }
  1700. return 0;
  1701. }
  1702. /* show the injection marker at the current cursor position at full opacity and (re)arm
  1703. * the fade timer; called on every injected pointer event so it stays bright while moving */
  1704. static void inject_marker_show(struct mjc_server *server) {
  1705. if (server->inject_marker == NULL) {
  1706. return;
  1707. }
  1708. wlr_scene_node_set_position(&server->inject_marker->node,
  1709. (int) server->cursor->x - MJC_INJECT_MARKER_SIZE / 2,
  1710. (int) server->cursor->y - MJC_INJECT_MARKER_SIZE / 2);
  1711. server->inject_alpha = 1.0f;
  1712. const float color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
  1713. wlr_scene_rect_set_color(server->inject_marker, color);
  1714. wlr_scene_node_raise_to_top(&server->inject_marker->node);
  1715. wlr_scene_node_set_enabled(&server->inject_marker->node, true);
  1716. /* keep the marker persistently visible for now (behaves like a mouse cursor); the
  1717. * inactivity fadeout is disabled until we want it back */
  1718. }
  1719. void mjc_pointer_move(mjc_server *server, int x, int y) {
  1720. if (server == NULL) {
  1721. return;
  1722. }
  1723. /* warp to the closest valid layout point, then run the normal motion path so
  1724. * pointer focus, focus-follows-mouse and the ipc pointer broadcast all fire */
  1725. wlr_cursor_warp_closest(server->cursor, NULL, (double) x, (double) y);
  1726. process_cursor_motion(server, mjc_now_msec());
  1727. inject_marker_show(server);
  1728. }
  1729. void mjc_pointer_button(mjc_server *server, uint32_t button, bool pressed) {
  1730. if (server == NULL) {
  1731. return;
  1732. }
  1733. enum wl_pointer_button_state state = pressed
  1734. ? WL_POINTER_BUTTON_STATE_PRESSED
  1735. : WL_POINTER_BUTTON_STATE_RELEASED;
  1736. wlr_seat_pointer_notify_button(server->seat, mjc_now_msec(), button, state);
  1737. if (!pressed) {
  1738. server->cursor_mode = MJC_CURSOR_PASSTHROUGH;
  1739. server->grabbed_view = NULL;
  1740. } else {
  1741. double sx, sy;
  1742. struct wlr_surface *surface = NULL;
  1743. struct mjc_view *view = desktop_view_at(server,
  1744. server->cursor->x, server->cursor->y, &surface, &sx, &sy);
  1745. if (view != NULL && view->focusable) {
  1746. mjc_view_focus(view);
  1747. }
  1748. }
  1749. wlr_seat_pointer_notify_frame(server->seat);
  1750. inject_marker_show(server);
  1751. }
  1752. void mjc_key(mjc_server *server, uint32_t keycode, bool pressed) {
  1753. if (server == NULL) {
  1754. return;
  1755. }
  1756. struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(server->seat);
  1757. if (keyboard == NULL) {
  1758. if (wl_list_empty(&server->keyboards)) {
  1759. return;
  1760. }
  1761. struct mjc_keyboard *kb =
  1762. wl_container_of(server->keyboards.next, kb, link);
  1763. keyboard = kb->wlr_keyboard;
  1764. }
  1765. enum wl_keyboard_key_state state = pressed
  1766. ? WL_KEYBOARD_KEY_STATE_PRESSED
  1767. : WL_KEYBOARD_KEY_STATE_RELEASED;
  1768. /* mirror keyboard_handle_key: offer the keysym to the shell global-key hook first
  1769. * (Super/Escape toggles), and only forward to the focused client when unhandled */
  1770. uint32_t xkb_keycode = keycode + 8;
  1771. const xkb_keysym_t *syms;
  1772. int nsyms = xkb_state_key_get_syms(keyboard->xkb_state, xkb_keycode, &syms);
  1773. uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard);
  1774. bool handled = false;
  1775. if (pressed) {
  1776. for (int i = 0; i < nsyms; i++) {
  1777. if (server->cbs.key != NULL &&
  1778. server->cbs.key(server->ud, syms[i], modifiers, true)) {
  1779. handled = true;
  1780. }
  1781. }
  1782. }
  1783. if (!handled) {
  1784. wlr_seat_set_keyboard(server->seat, keyboard);
  1785. wlr_seat_keyboard_notify_key(server->seat, mjc_now_msec(), keycode, state);
  1786. }
  1787. }