wl_init.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890
  1. //========================================================================
  2. // GLFW 3.4 Wayland - www.glfw.org
  3. //------------------------------------------------------------------------
  4. // Copyright (c) 2014 Jonas Ådahl <jadahl@gmail.com>
  5. //
  6. // This software is provided 'as-is', without any express or implied
  7. // warranty. In no event will the authors be held liable for any damages
  8. // arising from the use of this software.
  9. //
  10. // Permission is granted to anyone to use this software for any purpose,
  11. // including commercial applications, and to alter it and redistribute it
  12. // freely, subject to the following restrictions:
  13. //
  14. // 1. The origin of this software must not be misrepresented; you must not
  15. // claim that you wrote the original software. If you use this software
  16. // in a product, an acknowledgment in the product documentation would
  17. // be appreciated but is not required.
  18. //
  19. // 2. Altered source versions must be plainly marked as such, and must not
  20. // be misrepresented as being the original software.
  21. //
  22. // 3. This notice may not be removed or altered from any source
  23. // distribution.
  24. //
  25. //========================================================================
  26. // It is fine to use C99 in this file because it will not be built with VS
  27. //========================================================================
  28. #define _GNU_SOURCE
  29. #include "internal.h"
  30. #include "backend_utils.h"
  31. #include "wl_client_side_decorations.h"
  32. #include "linux_desktop_settings.h"
  33. #include "../kitty/monotonic.h"
  34. #include "wl_text_input.h"
  35. #include "wayland-text-input-unstable-v3-client-protocol.h"
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. #include <string.h>
  39. #include <sys/mman.h>
  40. #include <unistd.h>
  41. #include <fcntl.h>
  42. #include <sys/socket.h>
  43. #include <wayland-client.h>
  44. #include <stdio.h>
  45. // Needed for the BTN_* defines
  46. #ifdef __has_include
  47. #if __has_include(<linux/input.h>)
  48. #include <linux/input.h>
  49. #elif __has_include(<dev/evdev/input.h>)
  50. #include <dev/evdev/input.h>
  51. #endif
  52. #else
  53. #include <linux/input.h>
  54. #endif
  55. #define debug debug_rendering
  56. #define x window->wl.allCursorPosX
  57. #define y window->wl.allCursorPosY
  58. static _GLFWwindow*
  59. get_window_from_surface(struct wl_surface* surface) {
  60. if (!surface) return NULL;
  61. _GLFWwindow *ans = wl_surface_get_user_data(surface);
  62. if (ans) {
  63. const _GLFWwindow *w = _glfw.windowListHead;
  64. while (w) {
  65. if (w == ans) return ans;
  66. w = w->next;
  67. }
  68. }
  69. return NULL;
  70. }
  71. static void
  72. pointerHandleEnter(
  73. void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t serial, struct wl_surface* surface,
  74. wl_fixed_t sx, wl_fixed_t sy
  75. ) {
  76. _GLFWwindow* window = get_window_from_surface(surface);
  77. if (!window) return;
  78. _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.pointer_serial = serial; _glfw.wl.pointer_enter_serial = serial;
  79. _glfw.wl.pointerFocus = window;
  80. window->wl.allCursorPosX = wl_fixed_to_double(sx);
  81. window->wl.allCursorPosY = wl_fixed_to_double(sy);
  82. if (surface != window->wl.surface) {
  83. csd_handle_pointer_event(window, -2, -2, surface);
  84. } else {
  85. window->wl.decorations.focus = CENTRAL_WINDOW;
  86. window->wl.hovered = true;
  87. window->wl.cursorPosX = x;
  88. window->wl.cursorPosY = y;
  89. _glfwPlatformSetCursor(window, window->wl.currentCursor);
  90. _glfwInputCursorEnter(window, true);
  91. }
  92. }
  93. static void
  94. pointerHandleLeave(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t serial, struct wl_surface* surface) {
  95. _GLFWwindow* window = _glfw.wl.pointerFocus;
  96. if (!window) return;
  97. _glfw.wl.serial = serial;
  98. _glfw.wl.pointerFocus = NULL;
  99. if (window->wl.surface == surface) {
  100. window->wl.hovered = false;
  101. _glfwInputCursorEnter(window, false);
  102. _glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
  103. } else csd_handle_pointer_event(window, -3, -3, surface);
  104. }
  105. static void
  106. pointerHandleMotion(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t time UNUSED, wl_fixed_t sx, wl_fixed_t sy) {
  107. _GLFWwindow* window = _glfw.wl.pointerFocus;
  108. if (!window || window->cursorMode == GLFW_CURSOR_DISABLED) return;
  109. window->wl.allCursorPosX = wl_fixed_to_double(sx);
  110. window->wl.allCursorPosY = wl_fixed_to_double(sy);
  111. if (window->wl.decorations.focus != CENTRAL_WINDOW) {
  112. csd_handle_pointer_event(window, -1, -1, NULL);
  113. } else {
  114. window->wl.cursorPosX = x;
  115. window->wl.cursorPosY = y;
  116. _glfwInputCursorPos(window, x, y);
  117. _glfw.wl.cursorPreviousShape = GLFW_INVALID_CURSOR;
  118. }
  119. }
  120. static void pointerHandleButton(void* data UNUSED,
  121. struct wl_pointer* pointer UNUSED,
  122. uint32_t serial,
  123. uint32_t time UNUSED,
  124. uint32_t button,
  125. uint32_t state)
  126. {
  127. _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.pointer_serial = serial;
  128. _GLFWwindow* window = _glfw.wl.pointerFocus;
  129. if (!window) return;
  130. if (window->wl.decorations.focus != CENTRAL_WINDOW) {
  131. csd_handle_pointer_event(window, button, state, NULL);
  132. return;
  133. }
  134. /* Makes left, right and middle 0, 1 and 2. Overall order follows evdev
  135. * codes. */
  136. int glfwButton = button - BTN_LEFT;
  137. _glfwInputMouseClick(
  138. window, glfwButton, state == WL_POINTER_BUTTON_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE, _glfw.wl.xkb.states.modifiers);
  139. }
  140. #undef x
  141. #undef y
  142. #define info (window->wl.pointer_curr_axis_info)
  143. static void
  144. pointer_handle_axis_common(enum _GLFWWaylandAxisEvent type, uint32_t axis, wl_fixed_t value) {
  145. _GLFWwindow* window = _glfw.wl.pointerFocus;
  146. if (!window || window->wl.decorations.focus != CENTRAL_WINDOW) return;
  147. float fval = (float) wl_fixed_to_double(value);
  148. #define CASE(type, type_const, axis, fval) \
  149. case type_const: \
  150. if (info.type.axis##_axis_type == AXIS_EVENT_UNKNOWN) { \
  151. info.type.axis##_axis_type = type_const; info.type.axis = 0.f; } \
  152. info.type.axis += fval; break;
  153. if (window) {
  154. switch ((enum wl_pointer_axis)axis) {
  155. case WL_POINTER_AXIS_VERTICAL_SCROLL:
  156. switch (type) {
  157. case AXIS_EVENT_UNKNOWN: break;
  158. CASE(discrete, AXIS_EVENT_DISCRETE, y, -fval); // wheel event
  159. CASE(discrete, AXIS_EVENT_VALUE120, y, -fval); // wheel event higher res than plain discrete
  160. CASE(continuous, AXIS_EVENT_CONTINUOUS, y, -fval); // touchpad, etc. high res
  161. }
  162. break;
  163. case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
  164. switch (type) {
  165. case AXIS_EVENT_UNKNOWN: break;
  166. CASE(discrete, AXIS_EVENT_DISCRETE, x, fval); // wheel event
  167. CASE(discrete, AXIS_EVENT_VALUE120, x, fval); // wheel event higher res than plain discrete
  168. CASE(continuous, AXIS_EVENT_CONTINUOUS, x, fval); // touchpad, etc. high res
  169. }
  170. break;
  171. }
  172. }
  173. #undef CASE
  174. }
  175. static void
  176. pointer_handle_axis(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t time, uint32_t axis, wl_fixed_t value) {
  177. _GLFWwindow* window = _glfw.wl.pointerFocus;
  178. if (!window) return;
  179. if (!info.timestamp_ns) info.timestamp_ns = ms_to_monotonic_t(time);
  180. pointer_handle_axis_common(AXIS_EVENT_CONTINUOUS, axis, value);
  181. }
  182. static void
  183. pointer_handle_frame(void *data UNUSED, struct wl_pointer *pointer UNUSED) {
  184. _GLFWwindow* window = _glfw.wl.pointerFocus;
  185. if (!window) return;
  186. float x = 0, y = 0;
  187. int highres = 0;
  188. if (info.discrete.y_axis_type != AXIS_EVENT_UNKNOWN) {
  189. y = info.discrete.y;
  190. if (info.discrete.y_axis_type == AXIS_EVENT_VALUE120) y /= 120.f;
  191. } else if (info.continuous.y_axis_type != AXIS_EVENT_UNKNOWN) {
  192. highres = 1;
  193. y = info.continuous.y;
  194. }
  195. if (info.discrete.x_axis_type != AXIS_EVENT_UNKNOWN) {
  196. x = info.discrete.x;
  197. if (info.discrete.x_axis_type == AXIS_EVENT_VALUE120) x /= 120.f;
  198. } else if (info.continuous.x_axis_type != AXIS_EVENT_UNKNOWN) {
  199. highres = 1;
  200. x = info.continuous.x;
  201. }
  202. /* clear pointer_curr_axis_info for next frame */
  203. memset(&info, 0, sizeof(info));
  204. if (x != 0.0f || y != 0.0f) {
  205. float scale = (float)_glfwWaylandWindowScale(window);
  206. y *= scale; x *= scale;
  207. _glfwInputScroll(window, -x, y, highres, _glfw.wl.xkb.states.modifiers);
  208. }
  209. }
  210. static void
  211. pointer_handle_axis_source(void* data UNUSED, struct wl_pointer* pointer UNUSED, uint32_t source UNUSED) { }
  212. static void
  213. pointer_handle_axis_stop(void *data UNUSED, struct wl_pointer *wl_pointer UNUSED, uint32_t time UNUSED, uint32_t axis UNUSED) { }
  214. static void
  215. pointer_handle_axis_discrete(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t axis, int32_t discrete) {
  216. pointer_handle_axis_common(AXIS_EVENT_DISCRETE, axis, wl_fixed_from_int(discrete));
  217. }
  218. static void
  219. pointer_handle_axis_value120(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t axis, int32_t value120) {
  220. pointer_handle_axis_common(AXIS_EVENT_VALUE120, axis, wl_fixed_from_int(value120));
  221. }
  222. static void
  223. pointer_handle_axis_relative_direction(void *data UNUSED, struct wl_pointer *pointer UNUSED, uint32_t axis UNUSED, uint32_t axis_relative_direction UNUSED) { }
  224. #undef info
  225. static const struct wl_pointer_listener pointerListener = {
  226. .enter = pointerHandleEnter,
  227. .leave = pointerHandleLeave,
  228. .motion = pointerHandleMotion,
  229. .button = pointerHandleButton,
  230. .axis = pointer_handle_axis,
  231. .frame = pointer_handle_frame,
  232. .axis_source = pointer_handle_axis_source,
  233. .axis_stop = pointer_handle_axis_stop,
  234. .axis_discrete = pointer_handle_axis_discrete,
  235. #ifdef WL_POINTER_AXIS_VALUE120_SINCE_VERSION
  236. .axis_value120 = pointer_handle_axis_value120,
  237. #endif
  238. #ifdef WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION
  239. .axis_relative_direction = pointer_handle_axis_relative_direction,
  240. #endif
  241. };
  242. static void keyboardHandleKeymap(void* data UNUSED,
  243. struct wl_keyboard* keyboard UNUSED,
  244. uint32_t format,
  245. int fd,
  246. uint32_t size)
  247. {
  248. char* mapStr;
  249. if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
  250. {
  251. _glfwInputError(GLFW_PLATFORM_ERROR, "Unknown keymap format: %u", format);
  252. close(fd);
  253. return;
  254. }
  255. mapStr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
  256. if (mapStr == MAP_FAILED) {
  257. close(fd);
  258. _glfwInputError(GLFW_PLATFORM_ERROR, "Mapping of keymap file descriptor failed: %u", format);
  259. return;
  260. }
  261. glfw_xkb_compile_keymap(&_glfw.wl.xkb, mapStr);
  262. munmap(mapStr, size);
  263. close(fd);
  264. }
  265. static void keyboardHandleEnter(void* data UNUSED,
  266. struct wl_keyboard* keyboard UNUSED,
  267. uint32_t serial,
  268. struct wl_surface* surface,
  269. struct wl_array* keys)
  270. {
  271. _GLFWwindow* window = get_window_from_surface(surface);
  272. if (!window) return;
  273. _glfw.wl.serial = serial; _glfw.wl.input_serial = serial; _glfw.wl.keyboard_enter_serial = serial;
  274. _glfw.wl.keyboardFocusId = window->id;
  275. _glfwInputWindowFocus(window, true);
  276. uint32_t* key;
  277. if (keys && _glfw.wl.keyRepeatInfo.key) {
  278. wl_array_for_each(key, keys) {
  279. if (*key == _glfw.wl.keyRepeatInfo.key) {
  280. toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
  281. break;
  282. }
  283. }
  284. }
  285. }
  286. static void keyboardHandleLeave(void* data UNUSED,
  287. struct wl_keyboard* keyboard UNUSED,
  288. uint32_t serial,
  289. struct wl_surface* surface UNUSED)
  290. {
  291. _GLFWwindow* window = _glfwWindowForId(_glfw.wl.keyboardFocusId);
  292. if (!window)
  293. return;
  294. _glfw.wl.serial = serial;
  295. _glfw.wl.keyboardFocusId = 0;
  296. _glfwInputWindowFocus(window, false);
  297. toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
  298. }
  299. static void
  300. dispatchPendingKeyRepeats(id_type timer_id UNUSED, void *data UNUSED) {
  301. if (_glfw.wl.keyRepeatInfo.keyboardFocusId != _glfw.wl.keyboardFocusId || _glfw.wl.keyboardRepeatRate == 0) return;
  302. _GLFWwindow* window = _glfwWindowForId(_glfw.wl.keyboardFocusId);
  303. if (!window) return;
  304. glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, _glfw.wl.keyRepeatInfo.key, GLFW_REPEAT);
  305. changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, (s_to_monotonic_t(1ll) / (monotonic_t)_glfw.wl.keyboardRepeatRate));
  306. toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
  307. }
  308. static void keyboardHandleKey(void* data UNUSED,
  309. struct wl_keyboard* keyboard UNUSED,
  310. uint32_t serial,
  311. uint32_t time UNUSED,
  312. uint32_t key,
  313. uint32_t state)
  314. {
  315. _GLFWwindow* window = _glfwWindowForId(_glfw.wl.keyboardFocusId);
  316. if (!window)
  317. return;
  318. int action = state == WL_KEYBOARD_KEY_STATE_PRESSED ? GLFW_PRESS : GLFW_RELEASE;
  319. _glfw.wl.serial = serial; _glfw.wl.input_serial = serial;
  320. glfw_xkb_handle_key_event(window, &_glfw.wl.xkb, key, action);
  321. if (action == GLFW_PRESS && _glfw.wl.keyboardRepeatRate > 0 && glfw_xkb_should_repeat(&_glfw.wl.xkb, key))
  322. {
  323. _glfw.wl.keyRepeatInfo.key = key;
  324. _glfw.wl.keyRepeatInfo.keyboardFocusId = window->id;
  325. changeTimerInterval(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, _glfw.wl.keyboardRepeatDelay);
  326. toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 1);
  327. } else if (action == GLFW_RELEASE && key == _glfw.wl.keyRepeatInfo.key) {
  328. _glfw.wl.keyRepeatInfo.key = 0;
  329. toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
  330. }
  331. }
  332. static void keyboardHandleModifiers(void* data UNUSED,
  333. struct wl_keyboard* keyboard UNUSED,
  334. uint32_t serial,
  335. uint32_t modsDepressed,
  336. uint32_t modsLatched,
  337. uint32_t modsLocked,
  338. uint32_t group)
  339. {
  340. _glfw.wl.serial = serial; _glfw.wl.input_serial = serial;
  341. glfw_xkb_update_modifiers(&_glfw.wl.xkb, modsDepressed, modsLatched, modsLocked, 0, 0, group);
  342. }
  343. static void keyboardHandleRepeatInfo(void* data UNUSED,
  344. struct wl_keyboard* keyboard,
  345. int32_t rate,
  346. int32_t delay)
  347. {
  348. if (keyboard != _glfw.wl.keyboard)
  349. return;
  350. _glfw.wl.keyboardRepeatRate = rate;
  351. _glfw.wl.keyboardRepeatDelay = ms_to_monotonic_t(delay);
  352. }
  353. static const struct wl_keyboard_listener keyboardListener = {
  354. keyboardHandleKeymap,
  355. keyboardHandleEnter,
  356. keyboardHandleLeave,
  357. keyboardHandleKey,
  358. keyboardHandleModifiers,
  359. keyboardHandleRepeatInfo,
  360. };
  361. static void seatHandleCapabilities(void* data UNUSED,
  362. struct wl_seat* seat,
  363. enum wl_seat_capability caps)
  364. {
  365. if ((caps & WL_SEAT_CAPABILITY_POINTER) && !_glfw.wl.pointer)
  366. {
  367. _glfw.wl.pointer = wl_seat_get_pointer(seat);
  368. wl_pointer_add_listener(_glfw.wl.pointer, &pointerListener, NULL);
  369. if (_glfw.wl.wp_cursor_shape_manager_v1) {
  370. if (_glfw.wl.wp_cursor_shape_device_v1) wp_cursor_shape_device_v1_destroy(_glfw.wl.wp_cursor_shape_device_v1);
  371. _glfw.wl.wp_cursor_shape_device_v1 = NULL;
  372. _glfw.wl.wp_cursor_shape_device_v1 = wp_cursor_shape_manager_v1_get_pointer(_glfw.wl.wp_cursor_shape_manager_v1, _glfw.wl.pointer);
  373. }
  374. }
  375. else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && _glfw.wl.pointer)
  376. {
  377. if (_glfw.wl.wp_cursor_shape_device_v1) wp_cursor_shape_device_v1_destroy(_glfw.wl.wp_cursor_shape_device_v1);
  378. _glfw.wl.wp_cursor_shape_device_v1 = NULL;
  379. wl_pointer_destroy(_glfw.wl.pointer);
  380. _glfw.wl.pointer = NULL;
  381. if (_glfw.wl.cursorAnimationTimer) toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.cursorAnimationTimer, 0);
  382. }
  383. if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !_glfw.wl.keyboard)
  384. {
  385. _glfw.wl.keyboard = wl_seat_get_keyboard(seat);
  386. wl_keyboard_add_listener(_glfw.wl.keyboard, &keyboardListener, NULL);
  387. }
  388. else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && _glfw.wl.keyboard)
  389. {
  390. wl_keyboard_destroy(_glfw.wl.keyboard);
  391. _glfw.wl.keyboard = NULL;
  392. _glfw.wl.keyboardFocusId = 0;
  393. if (_glfw.wl.keyRepeatInfo.keyRepeatTimer) toggleTimer(&_glfw.wl.eventLoopData, _glfw.wl.keyRepeatInfo.keyRepeatTimer, 0);
  394. }
  395. }
  396. static void seatHandleName(void* data UNUSED,
  397. struct wl_seat* seat UNUSED,
  398. const char* name UNUSED)
  399. {
  400. }
  401. static const struct wl_seat_listener seatListener = {
  402. seatHandleCapabilities,
  403. seatHandleName,
  404. };
  405. static void wmBaseHandlePing(void* data UNUSED,
  406. struct xdg_wm_base* wmBase,
  407. uint32_t serial)
  408. {
  409. xdg_wm_base_pong(wmBase, serial);
  410. }
  411. static const struct xdg_wm_base_listener wmBaseListener = {
  412. wmBaseHandlePing
  413. };
  414. static void registryHandleGlobal(void* data UNUSED,
  415. struct wl_registry* registry,
  416. uint32_t name,
  417. const char* interface,
  418. uint32_t version)
  419. {
  420. #define is(x) strcmp(interface, x##_interface.name) == 0
  421. if (is(wl_compositor))
  422. {
  423. #ifdef WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION
  424. _glfw.wl.compositorVersion = MIN(WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION, (int)version);
  425. _glfw.wl.has_preferred_buffer_scale = _glfw.wl.compositorVersion >= WL_SURFACE_PREFERRED_BUFFER_SCALE_SINCE_VERSION;
  426. #else
  427. _glfw.wl.compositorVersion = MIN(3, (int)version);
  428. #endif
  429. _glfw.wl.compositor = wl_registry_bind(registry, name, &wl_compositor_interface, _glfw.wl.compositorVersion);
  430. }
  431. else if (is(wl_subcompositor))
  432. {
  433. _glfw.wl.subcompositor =
  434. wl_registry_bind(registry, name, &wl_subcompositor_interface, 1);
  435. }
  436. else if (is(wl_shm))
  437. {
  438. _glfw.wl.shm =
  439. wl_registry_bind(registry, name, &wl_shm_interface, 1);
  440. }
  441. else if (is(wl_output))
  442. {
  443. _glfwAddOutputWayland(name, version);
  444. }
  445. else if (is(wl_seat))
  446. {
  447. if (!_glfw.wl.seat)
  448. {
  449. #ifdef WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION
  450. _glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_RELATIVE_DIRECTION_SINCE_VERSION, (int)version);
  451. #elif defined(WL_POINTER_AXIS_VALUE120_SINCE_VERSION)
  452. _glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_VALUE120_SINCE_VERSION, (int)version);
  453. #else
  454. _glfw.wl.seatVersion = MIN(WL_POINTER_AXIS_DISCRETE_SINCE_VERSION, version);
  455. #endif
  456. _glfw.wl.seat =
  457. wl_registry_bind(registry, name, &wl_seat_interface,
  458. _glfw.wl.seatVersion);
  459. wl_seat_add_listener(_glfw.wl.seat, &seatListener, NULL);
  460. }
  461. if (_glfw.wl.seat) {
  462. if (_glfw.wl.dataDeviceManager && !_glfw.wl.dataDevice) _glfwSetupWaylandDataDevice();
  463. if (_glfw.wl.primarySelectionDeviceManager && !_glfw.wl.primarySelectionDevice) {
  464. _glfwSetupWaylandPrimarySelectionDevice();
  465. }
  466. }
  467. }
  468. else if (is(xdg_wm_base))
  469. {
  470. _glfw.wl.xdg_wm_base_version = 1;
  471. #ifdef XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION
  472. _glfw.wl.xdg_wm_base_version = MIN(XDG_TOPLEVEL_STATE_SUSPENDED_SINCE_VERSION, (int)version);
  473. #elif defined(XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION)
  474. _glfw.wl.xdg_wm_base_version = MIN(XDG_TOPLEVEL_WM_CAPABILITIES_SINCE_VERSION, (int)version);
  475. #endif
  476. _glfw.wl.wmBase = wl_registry_bind(registry, name, &xdg_wm_base_interface, _glfw.wl.xdg_wm_base_version);
  477. xdg_wm_base_add_listener(_glfw.wl.wmBase, &wmBaseListener, NULL);
  478. }
  479. else if (is(zxdg_decoration_manager_v1))
  480. {
  481. _glfw.wl.decorationManager =
  482. wl_registry_bind(registry, name,
  483. &zxdg_decoration_manager_v1_interface, 1);
  484. }
  485. else if (is(zwp_relative_pointer_manager_v1))
  486. {
  487. _glfw.wl.relativePointerManager =
  488. wl_registry_bind(registry, name,
  489. &zwp_relative_pointer_manager_v1_interface,
  490. 1);
  491. }
  492. else if (is(zwp_pointer_constraints_v1))
  493. {
  494. _glfw.wl.pointerConstraints =
  495. wl_registry_bind(registry, name,
  496. &zwp_pointer_constraints_v1_interface,
  497. 1);
  498. }
  499. else if (is(zwp_text_input_manager_v3))
  500. {
  501. _glfwWaylandBindTextInput(registry, name);
  502. }
  503. else if (is(wl_data_device_manager))
  504. {
  505. _glfw.wl.dataDeviceManager =
  506. wl_registry_bind(registry, name,
  507. &wl_data_device_manager_interface,
  508. 1);
  509. if (_glfw.wl.seat && _glfw.wl.dataDeviceManager && !_glfw.wl.dataDevice) {
  510. _glfwSetupWaylandDataDevice();
  511. }
  512. }
  513. else if (is(zwp_primary_selection_device_manager_v1))
  514. {
  515. _glfw.wl.primarySelectionDeviceManager =
  516. wl_registry_bind(registry, name,
  517. &zwp_primary_selection_device_manager_v1_interface,
  518. 1);
  519. if (_glfw.wl.seat && _glfw.wl.primarySelectionDeviceManager && !_glfw.wl.primarySelectionDevice) {
  520. _glfwSetupWaylandPrimarySelectionDevice();
  521. }
  522. }
  523. else if (is(wp_single_pixel_buffer_manager_v1)) {
  524. _glfw.wl.wp_single_pixel_buffer_manager_v1 = wl_registry_bind(registry, name, &wp_single_pixel_buffer_manager_v1_interface, 1);
  525. }
  526. else if (is(xdg_activation_v1)) {
  527. _glfw.wl.xdg_activation_v1 = wl_registry_bind(registry, name, &xdg_activation_v1_interface, 1);
  528. }
  529. else if (is(wp_cursor_shape_manager_v1)) {
  530. _glfw.wl.wp_cursor_shape_manager_v1 = wl_registry_bind(registry, name, &wp_cursor_shape_manager_v1_interface, 1);
  531. }
  532. else if (is(wp_fractional_scale_manager_v1)) {
  533. _glfw.wl.wp_fractional_scale_manager_v1 = wl_registry_bind(registry, name, &wp_fractional_scale_manager_v1_interface, 1);
  534. }
  535. else if (is(wp_viewporter)) {
  536. _glfw.wl.wp_viewporter = wl_registry_bind(registry, name, &wp_viewporter_interface, 1);
  537. }
  538. else if (is(org_kde_kwin_blur_manager)) {
  539. _glfw.wl.org_kde_kwin_blur_manager = wl_registry_bind(registry, name, &org_kde_kwin_blur_manager_interface, 1);
  540. }
  541. else if (is(zwlr_layer_shell_v1)) {
  542. if (version >= 4) {
  543. _glfw.wl.zwlr_layer_shell_v1_version = version;
  544. _glfw.wl.zwlr_layer_shell_v1 = wl_registry_bind(registry, name, &zwlr_layer_shell_v1_interface, version);
  545. }
  546. }
  547. #undef is
  548. }
  549. static void registryHandleGlobalRemove(void *data UNUSED,
  550. struct wl_registry *registry UNUSED,
  551. uint32_t name)
  552. {
  553. _GLFWmonitor* monitor;
  554. for (int i = 0; i < _glfw.monitorCount; ++i)
  555. {
  556. monitor = _glfw.monitors[i];
  557. if (monitor->wl.name == name)
  558. {
  559. for (_GLFWwindow *window = _glfw.windowListHead; window; window = window->next) {
  560. for (int m = window->wl.monitorsCount - 1; m >= 0; m--) {
  561. if (window->wl.monitors[m] == monitor) {
  562. remove_i_from_array(window->wl.monitors, m, window->wl.monitorsCount);
  563. }
  564. }
  565. }
  566. _glfwInputMonitor(monitor, GLFW_DISCONNECTED, 0);
  567. return;
  568. }
  569. }
  570. }
  571. static const struct wl_registry_listener registryListener = {
  572. registryHandleGlobal,
  573. registryHandleGlobalRemove
  574. };
  575. GLFWAPI GLFWColorScheme glfwGetCurrentSystemColorTheme(void) {
  576. return glfw_current_system_color_theme();
  577. }
  578. static pid_t
  579. get_socket_peer_pid(int fd) {
  580. #ifdef __linux__
  581. struct ucred ucred;
  582. socklen_t len = sizeof(struct ucred);
  583. return (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1) ? -1 : ucred.pid;
  584. #elif defined(LOCAL_PEERCRED) && defined(XUCRED_VERSION)
  585. struct xucred peercred;
  586. socklen_t peercredlen = sizeof(peercred);
  587. return (getsockopt(c->fd, LOCAL_PEERCRED, 1, (void *)&peercred, &peercredlen) == 0 && peercred.cr_version == XUCRED_VERSION) ? peercred.cr_pid : -1;
  588. #elif defined(LOCAL_PEERPID)
  589. pid_t pid;
  590. socklen_t pid_size = sizeof(pid);
  591. return getsockopt(client, SOL_LOCAL, LOCAL_PEERPID, &pid, &pid_size) == -1 ? -1 : pid;
  592. #else
  593. errno = ENOSYS;
  594. return -1;
  595. #endif
  596. }
  597. GLFWAPI pid_t glfwWaylandCompositorPID(void) {
  598. if (!_glfw.wl.display) return -1;
  599. int fd = wl_display_get_fd(_glfw.wl.display);
  600. if (fd < 0) return -1;
  601. return get_socket_peer_pid(fd);
  602. }
  603. //////////////////////////////////////////////////////////////////////////
  604. ////// GLFW platform API //////
  605. //////////////////////////////////////////////////////////////////////////
  606. static const char*
  607. get_compositor_missing_capabilities(void) {
  608. #define C(title, x) if (!_glfw.wl.x) p += snprintf(buf, sizeof(buf) - (p - buf), "%s", #title);
  609. static char buf[256];
  610. char *p = buf;
  611. *p = 0;
  612. C(viewporter, wp_viewporter); C(fractional_scale, wp_fractional_scale_manager_v1);
  613. C(blur, org_kde_kwin_blur_manager); C(server_side_decorations, decorationManager);
  614. C(cursor_shape, wp_cursor_shape_manager_v1); C(layer_shell, zwlr_layer_shell_v1);
  615. C(single_pixel_buffer, wp_single_pixel_buffer_manager_v1); C(preferred_scale, has_preferred_buffer_scale);
  616. #undef C
  617. return buf;
  618. }
  619. GLFWAPI const char* glfwWaylandMissingCapabilities(void) { return get_compositor_missing_capabilities(); }
  620. int _glfwPlatformInit(void)
  621. {
  622. int i;
  623. _GLFWmonitor* monitor;
  624. _glfw.wl.cursor.handle = _glfw_dlopen("libwayland-cursor.so.0");
  625. if (!_glfw.wl.cursor.handle)
  626. {
  627. _glfwInputError(GLFW_PLATFORM_ERROR,
  628. "Wayland: Failed to open libwayland-cursor");
  629. return false;
  630. }
  631. glfw_dlsym(_glfw.wl.cursor.theme_load, _glfw.wl.cursor.handle, "wl_cursor_theme_load");
  632. glfw_dlsym(_glfw.wl.cursor.theme_destroy, _glfw.wl.cursor.handle, "wl_cursor_theme_destroy");
  633. glfw_dlsym(_glfw.wl.cursor.theme_get_cursor, _glfw.wl.cursor.handle, "wl_cursor_theme_get_cursor");
  634. glfw_dlsym(_glfw.wl.cursor.image_get_buffer, _glfw.wl.cursor.handle, "wl_cursor_image_get_buffer");
  635. _glfw.wl.egl.handle = _glfw_dlopen("libwayland-egl.so.1");
  636. if (!_glfw.wl.egl.handle)
  637. {
  638. _glfwInputError(GLFW_PLATFORM_ERROR,
  639. "Wayland: Failed to open libwayland-egl");
  640. return false;
  641. }
  642. glfw_dlsym(_glfw.wl.egl.window_create, _glfw.wl.egl.handle, "wl_egl_window_create");
  643. glfw_dlsym(_glfw.wl.egl.window_destroy, _glfw.wl.egl.handle, "wl_egl_window_destroy");
  644. glfw_dlsym(_glfw.wl.egl.window_resize, _glfw.wl.egl.handle, "wl_egl_window_resize");
  645. _glfw.wl.display = wl_display_connect(NULL);
  646. if (!_glfw.wl.display)
  647. {
  648. _glfwInputError(GLFW_PLATFORM_ERROR,
  649. "Wayland: Failed to connect to display");
  650. return false;
  651. }
  652. if (!initPollData(&_glfw.wl.eventLoopData, wl_display_get_fd(_glfw.wl.display))) {
  653. _glfwInputError(GLFW_PLATFORM_ERROR,
  654. "Wayland: Failed to initialize event loop data");
  655. }
  656. glfw_dbus_init(&_glfw.wl.dbus, &_glfw.wl.eventLoopData);
  657. glfw_initialize_desktop_settings();
  658. _glfw.wl.keyRepeatInfo.keyRepeatTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-key-repeat", ms_to_monotonic_t(500ll), 0, true, dispatchPendingKeyRepeats, NULL, NULL);
  659. _glfw.wl.cursorAnimationTimer = addTimer(&_glfw.wl.eventLoopData, "wayland-cursor-animation", ms_to_monotonic_t(500ll), 0, true, animateCursorImage, NULL, NULL);
  660. _glfw.wl.registry = wl_display_get_registry(_glfw.wl.display);
  661. wl_registry_add_listener(_glfw.wl.registry, &registryListener, NULL);
  662. if (!glfw_xkb_create_context(&_glfw.wl.xkb)) return false;
  663. // Sync so we got all registry objects
  664. wl_display_roundtrip(_glfw.wl.display);
  665. _glfwWaylandInitTextInput();
  666. // Sync so we got all initial output events
  667. wl_display_roundtrip(_glfw.wl.display);
  668. for (i = 0; i < _glfw.monitorCount; ++i)
  669. {
  670. monitor = _glfw.monitors[i];
  671. if (monitor->widthMM <= 0 || monitor->heightMM <= 0)
  672. {
  673. // If Wayland does not provide a physical size, assume the default 96 DPI
  674. monitor->widthMM = (int) (monitor->modes[monitor->wl.currentMode].width * 25.4f / 96.f);
  675. monitor->heightMM = (int) (monitor->modes[monitor->wl.currentMode].height * 25.4f / 96.f);
  676. }
  677. }
  678. if (!_glfw.wl.wmBase)
  679. {
  680. _glfwInputError(GLFW_PLATFORM_ERROR,
  681. "Wayland: Failed to find xdg-shell in your compositor");
  682. return false;
  683. }
  684. if (_glfw.wl.shm)
  685. {
  686. _glfw.wl.cursorSurface =
  687. wl_compositor_create_surface(_glfw.wl.compositor);
  688. }
  689. else
  690. {
  691. _glfwInputError(GLFW_PLATFORM_ERROR,
  692. "Wayland: Failed to find Wayland SHM");
  693. return false;
  694. }
  695. if (_glfw.hints.init.debugRendering) {
  696. const char *mc = get_compositor_missing_capabilities();
  697. if (mc && mc[0]) debug("Compositor missing capabilities: %s\n", mc);
  698. }
  699. return true;
  700. }
  701. void _glfwPlatformTerminate(void)
  702. {
  703. if (_glfw.wl.activation_requests.array) {
  704. for (size_t i=0; i < _glfw.wl.activation_requests.sz; i++) {
  705. glfw_wl_xdg_activation_request *r = _glfw.wl.activation_requests.array + i;
  706. if (r->callback) r->callback(NULL, NULL, r->callback_data);
  707. xdg_activation_token_v1_destroy(r->token);
  708. }
  709. free(_glfw.wl.activation_requests.array);
  710. }
  711. _glfwTerminateEGL();
  712. if (_glfw.wl.egl.handle)
  713. {
  714. _glfw_dlclose(_glfw.wl.egl.handle);
  715. _glfw.wl.egl.handle = NULL;
  716. }
  717. glfw_xkb_release(&_glfw.wl.xkb);
  718. glfw_dbus_terminate(&_glfw.wl.dbus);
  719. glfw_wlc_destroy();
  720. if (_glfw.wl.cursor.handle)
  721. {
  722. _glfw_dlclose(_glfw.wl.cursor.handle);
  723. _glfw.wl.cursor.handle = NULL;
  724. }
  725. if (_glfw.wl.cursorSurface)
  726. wl_surface_destroy(_glfw.wl.cursorSurface);
  727. if (_glfw.wl.subcompositor)
  728. wl_subcompositor_destroy(_glfw.wl.subcompositor);
  729. if (_glfw.wl.compositor)
  730. wl_compositor_destroy(_glfw.wl.compositor);
  731. if (_glfw.wl.shm)
  732. wl_shm_destroy(_glfw.wl.shm);
  733. if (_glfw.wl.decorationManager)
  734. zxdg_decoration_manager_v1_destroy(_glfw.wl.decorationManager);
  735. if (_glfw.wl.wmBase)
  736. xdg_wm_base_destroy(_glfw.wl.wmBase);
  737. if (_glfw.wl.pointer)
  738. wl_pointer_destroy(_glfw.wl.pointer);
  739. if (_glfw.wl.keyboard)
  740. wl_keyboard_destroy(_glfw.wl.keyboard);
  741. if (_glfw.wl.seat)
  742. wl_seat_destroy(_glfw.wl.seat);
  743. if (_glfw.wl.relativePointerManager)
  744. zwp_relative_pointer_manager_v1_destroy(_glfw.wl.relativePointerManager);
  745. if (_glfw.wl.pointerConstraints)
  746. zwp_pointer_constraints_v1_destroy(_glfw.wl.pointerConstraints);
  747. _glfwWaylandDestroyTextInput();
  748. if (_glfw.wl.dataSourceForClipboard)
  749. wl_data_source_destroy(_glfw.wl.dataSourceForClipboard);
  750. if (_glfw.wl.dataSourceForPrimarySelection)
  751. zwp_primary_selection_source_v1_destroy(_glfw.wl.dataSourceForPrimarySelection);
  752. for (size_t doi=0; doi < arraysz(_glfw.wl.dataOffers); doi++) {
  753. if (_glfw.wl.dataOffers[doi].id) {
  754. destroy_data_offer(&_glfw.wl.dataOffers[doi]);
  755. }
  756. }
  757. if (_glfw.wl.dataDevice)
  758. wl_data_device_destroy(_glfw.wl.dataDevice);
  759. if (_glfw.wl.dataDeviceManager)
  760. wl_data_device_manager_destroy(_glfw.wl.dataDeviceManager);
  761. if (_glfw.wl.primarySelectionDevice)
  762. zwp_primary_selection_device_v1_destroy(_glfw.wl.primarySelectionDevice);
  763. if (_glfw.wl.primarySelectionDeviceManager)
  764. zwp_primary_selection_device_manager_v1_destroy(_glfw.wl.primarySelectionDeviceManager);
  765. if (_glfw.wl.xdg_activation_v1)
  766. xdg_activation_v1_destroy(_glfw.wl.xdg_activation_v1);
  767. if (_glfw.wl.wp_single_pixel_buffer_manager_v1)
  768. wp_single_pixel_buffer_manager_v1_destroy(_glfw.wl.wp_single_pixel_buffer_manager_v1);
  769. if (_glfw.wl.wp_cursor_shape_manager_v1)
  770. wp_cursor_shape_manager_v1_destroy(_glfw.wl.wp_cursor_shape_manager_v1);
  771. if (_glfw.wl.wp_viewporter)
  772. wp_viewporter_destroy(_glfw.wl.wp_viewporter);
  773. if (_glfw.wl.wp_fractional_scale_manager_v1)
  774. wp_fractional_scale_manager_v1_destroy(_glfw.wl.wp_fractional_scale_manager_v1);
  775. if (_glfw.wl.org_kde_kwin_blur_manager)
  776. org_kde_kwin_blur_manager_destroy(_glfw.wl.org_kde_kwin_blur_manager);
  777. if (_glfw.wl.zwlr_layer_shell_v1)
  778. zwlr_layer_shell_v1_destroy(_glfw.wl.zwlr_layer_shell_v1);
  779. if (_glfw.wl.registry)
  780. wl_registry_destroy(_glfw.wl.registry);
  781. if (_glfw.wl.display)
  782. {
  783. wl_display_flush(_glfw.wl.display);
  784. wl_display_disconnect(_glfw.wl.display);
  785. }
  786. finalizePollData(&_glfw.wl.eventLoopData);
  787. }
  788. #define GLFW_LOOP_BACKEND wl
  789. #include "main_loop.h"
  790. const char* _glfwPlatformGetVersionString(void)
  791. {
  792. (void)keep_going;
  793. return _GLFW_VERSION_NUMBER " Wayland EGL OSMesa"
  794. #if defined(_POSIX_TIMERS) && defined(_POSIX_MONOTONIC_CLOCK)
  795. " clock_gettime"
  796. #else
  797. " gettimeofday"
  798. #endif
  799. " evdev"
  800. #if defined(_GLFW_BUILD_DLL)
  801. " shared"
  802. #endif
  803. ;
  804. }