wl_init.c 34 KB

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