wio

a wayland wm stylised after plan9 rio - forked from git.sr.ht/~srcmpwn/wio
git clone git://src.gearsix.net/wiowio.zip
Log | Files | Refs | Atom | Submodules | README | LICENSE

input.c (raw) (17784B)


   1 #define _POSIX_C_SOURCE 200811L
   2 #include <signal.h>
   3 #include <stdlib.h>
   4 #include <sys/wait.h>
   5 #include <linux/input-event-codes.h>
   6 #include <wlr/types/wlr_cursor.h>
   7 #include <wlr/types/wlr_seat.h>
   8 #include <wlr/types/wlr_input_device.h>
   9 #include <wlr/types/wlr_keyboard.h>
  10 #include <wlr/types/wlr_pointer.h>
  11 #include <wlr/util/log.h>
  12 #include <xkbcommon/xkbcommon.h>
  13 #include <unistd.h>
  14 #include "server.h"
  15 #include "view.h"
  16 
  17 static void keyboard_handle_modifiers(
  18 		struct wl_listener *listener, void *data) {
  19 	struct wio_keyboard *keyboard =
  20 		wl_container_of(listener, keyboard, modifiers);
  21 	wlr_seat_set_keyboard(keyboard->server->seat, keyboard->device);
  22 	wlr_seat_keyboard_notify_modifiers(keyboard->server->seat,
  23 		&keyboard->device->keyboard->modifiers);
  24 }
  25 
  26 static void view_end_interactive(struct wio_server *server);
  27 static void keyboard_handle_key(
  28 		struct wl_listener *listener, void *data) {
  29 	struct wio_keyboard *keyboard =
  30 		wl_container_of(listener, keyboard, key);
  31 	struct wio_server *server = keyboard->server;
  32 	struct wlr_event_keyboard_key *event = data;
  33 	struct wlr_seat *seat = server->seat;
  34 	xkb_keycode_t keycode = event->keycode + 8;
  35 	const xkb_keysym_t *syms;
  36 	int nsyms = xkb_state_key_get_syms(
  37 		keyboard->device->keyboard->xkb_state,
  38 		keycode, &syms);
  39 
  40 	for (int i = 0; i < nsyms; i++) {
  41 		if (syms[i] == XKB_KEY_Escape) {
  42 			switch (server->input_state) {
  43 			case INPUT_STATE_NONE:
  44 			case INPUT_STATE_MENU:
  45 				break;
  46 			default:
  47 				view_end_interactive(server);
  48 				return;
  49 			}
  50 		}
  51 	}
  52 
  53 	wlr_seat_set_keyboard(seat, keyboard->device);
  54 	wlr_seat_keyboard_notify_key(seat, event->time_msec,
  55 		event->keycode, event->state);
  56 }
  57 
  58 static void server_new_keyboard(
  59 		struct wio_server *server, struct wlr_input_device *device) {
  60 	struct wio_keyboard *keyboard = calloc(1, sizeof(struct wio_keyboard));
  61 	keyboard->server = server;
  62 	keyboard->device = device;
  63 
  64 	struct xkb_rule_names rules = { 0 };
  65 	rules.rules = getenv("XKB_DEFAULT_RULES");
  66 	rules.model = getenv("XKB_DEFAULT_MODEL");
  67 	rules.layout = getenv("XKB_DEFAULT_LAYOUT");
  68 	rules.variant = getenv("XKB_DEFAULT_VARIANT");
  69 	rules.options = getenv("XKB_DEFAULT_OPTIONS");
  70 	struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
  71 	struct xkb_keymap *keymap = xkb_map_new_from_names(context, &rules,
  72 		XKB_KEYMAP_COMPILE_NO_FLAGS);
  73 
  74 	wlr_keyboard_set_keymap(device->keyboard, keymap);
  75 	xkb_keymap_unref(keymap);
  76 	xkb_context_unref(context);
  77 	wlr_keyboard_set_repeat_info(device->keyboard, 25, 600);
  78 
  79 	keyboard->modifiers.notify = keyboard_handle_modifiers;
  80 	wl_signal_add(&device->keyboard->events.modifiers, &keyboard->modifiers);
  81 	keyboard->key.notify = keyboard_handle_key;
  82 	wl_signal_add(&device->keyboard->events.key, &keyboard->key);
  83 
  84 	wlr_seat_set_keyboard(server->seat, device);
  85 	wl_list_insert(&server->keyboards, &keyboard->link);
  86 }
  87 
  88 static void server_new_pointer(
  89 		struct wio_server *server, struct wlr_input_device *device) {
  90 	wlr_cursor_attach_input_device(server->cursor, device);
  91 }
  92 
  93 void server_new_input(struct wl_listener *listener, void *data) {
  94 	struct wio_server *server = wl_container_of(listener, server, new_input);
  95 	struct wlr_input_device *device = data;
  96 	switch (device->type) {
  97 	case WLR_INPUT_DEVICE_KEYBOARD:
  98 		server_new_keyboard(server, device);
  99 		break;
 100 	case WLR_INPUT_DEVICE_POINTER:
 101 		server_new_pointer(server, device);
 102 		break;
 103 	default:
 104 		break;
 105 	}
 106 	uint32_t caps = WL_SEAT_CAPABILITY_POINTER;
 107 	if (!wl_list_empty(&server->keyboards)) {
 108 		caps |= WL_SEAT_CAPABILITY_KEYBOARD;
 109 	}
 110 	wlr_seat_set_capabilities(server->seat, caps);
 111 }
 112 
 113 static void process_cursor_motion(struct wio_server *server, uint32_t time) {
 114 	double sx, sy;
 115 	int view_area;
 116 	struct wlr_seat *seat = server->seat;
 117 	struct wlr_surface *surface = NULL;
 118 	struct wio_view *view = wio_view_at(
 119 			server, server->cursor->x, server->cursor->y, &surface, &sx, &sy,
 120 			&view_area);
 121 	if (!view) {
 122 		switch (server->input_state) {
 123 		case INPUT_STATE_MOVE_SELECT:
 124 		case INPUT_STATE_RESIZE_SELECT:
 125 		case INPUT_STATE_DELETE_SELECT:
 126 		case INPUT_STATE_HIDE_SELECT:
 127 			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 128 					"hand1", server->cursor);
 129 			break;
 130 		case INPUT_STATE_MOVE:
 131 			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 132 					"grabbing", server->cursor);
 133 			break;
 134 		case INPUT_STATE_RESIZE_START:
 135 		case INPUT_STATE_NEW_START:
 136 			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 137 					"top_left_corner", server->cursor);
 138 			break;
 139 		case INPUT_STATE_BORDER_DRAG_TOP:
 140 			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 141 					"top_side", server->cursor);
 142 			break;
 143 		case INPUT_STATE_BORDER_DRAG_RIGHT:
 144 			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 145 					"right_side", server->cursor);
 146 			break;
 147 		case INPUT_STATE_BORDER_DRAG_BOTTOM:
 148 			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 149 					"bottom_side", server->cursor);
 150 			break;
 151 		case INPUT_STATE_BORDER_DRAG_LEFT:
 152 			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 153 					"left_side", server->cursor);
 154 			break;
 155 		case INPUT_STATE_RESIZE_END:
 156 		case INPUT_STATE_NEW_END:
 157 			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 158 					"bottom_right_corner", server->cursor);
 159 			break;
 160 		default:
 161 			wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 162 					"left_ptr", server->cursor);
 163 			break;
 164 		}
 165 	}
 166 	if (surface) {
 167 		bool focus_changed = seat->pointer_state.focused_surface != surface;
 168 		wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
 169 		if (!focus_changed) {
 170 			wlr_seat_pointer_notify_motion(seat, time, sx, sy);
 171 		}
 172 	} else {
 173 		wlr_seat_pointer_clear_focus(seat);
 174 	}
 175 }
 176 
 177 void server_cursor_motion(struct wl_listener *listener, void *data) {
 178 	struct wio_server *server =
 179 		wl_container_of(listener, server, cursor_motion);
 180 	struct wlr_event_pointer_motion *event = data;
 181 	wlr_cursor_move(server->cursor, event->device,
 182 			event->delta_x, event->delta_y);
 183 	process_cursor_motion(server, event->time_msec);
 184 }
 185 
 186 void server_cursor_motion_absolute(
 187 		struct wl_listener *listener, void *data) {
 188 	struct wio_server *server =
 189 		wl_container_of(listener, server, cursor_motion_absolute);
 190 	struct wlr_event_pointer_motion_absolute *event = data;
 191 	wlr_cursor_warp_absolute(server->cursor, event->device, event->x, event->y);
 192 	process_cursor_motion(server, event->time_msec);
 193 }
 194 
 195 static void menu_handle_button(
 196 		struct wio_server *server, struct wlr_event_pointer_button *event) {
 197 	server->menu.x = server->menu.y = -1;
 198 	switch (server->menu.selected) {
 199 	case 0:
 200 		server->input_state = INPUT_STATE_NEW_START;
 201 		wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 202 				"top_left_corner", server->cursor);
 203 		break;
 204 	case 1:
 205 		server->input_state = INPUT_STATE_RESIZE_SELECT;
 206 		wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 207 				"hand1", server->cursor);
 208 		break;
 209 	case 2:
 210 		server->input_state = INPUT_STATE_MOVE_SELECT;
 211 		wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 212 				"hand1", server->cursor);
 213 		break;
 214 	case 3:
 215 		server->input_state = INPUT_STATE_DELETE_SELECT;
 216 		wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 217 				"hand1", server->cursor);
 218 		break;
 219 	default:
 220 		server->input_state = INPUT_STATE_NONE;
 221 		break;
 222 	}
 223 }
 224 
 225 static void view_begin_interactive(struct wio_view *view,
 226 		struct wlr_surface *surface, double sx, double sy,
 227 		const char *cursor, enum wio_input_state state) {
 228 	wio_view_focus(view, surface);
 229 	view->server->interactive.view = view;
 230 	view->server->interactive.sx = (int)sx;
 231 	view->server->interactive.sy = (int)sy;
 232 	view->server->input_state = state;
 233 	wlr_xcursor_manager_set_cursor_image(view->server->cursor_mgr,
 234 			cursor, view->server->cursor);
 235 }
 236 
 237 static void view_end_interactive(struct wio_server *server) {
 238 	server->input_state = INPUT_STATE_NONE;
 239 	server->interactive.view = NULL;
 240 	// TODO: Restore previous pointer?
 241 	wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
 242 			"left_ptr", server->cursor);
 243 }
 244 
 245 static void new_view(struct wio_server *server) {
 246 	int x1 = server->interactive.sx, x2 = server->cursor->x;
 247 	int y1 = server->interactive.sy, y2 = server->cursor->y;
 248 	if (x2 < x1) {
 249 		int _ = x1;
 250 		x1 = x2;
 251 		x2 = _;
 252 	}
 253 	if (y2 < y1) {
 254 		int _ = y1;
 255 		y1 = y2;
 256 		y2 = _;
 257 	}
 258 	struct wio_new_view *view = calloc(1, sizeof(struct wio_new_view));
 259 	view->box.x = x1;
 260 	view->box.y = y1;
 261 	view->box.width = x2 - x1;
 262 	view->box.height = y2 - y1;
 263 	if (view->box.width < 100){
 264 		view->box.width = 100;
 265 	}
 266 	if (view->box.height < 100){
 267 		view->box.height = 100;
 268 	}
 269 	int fd[2];
 270 	if (pipe(fd) != 0) {
 271 		wlr_log(WLR_ERROR, "Unable to create pipe for fork");
 272 		return;
 273 	}
 274 	char cmd[1024];
 275 	if (snprintf(cmd, sizeof(cmd), "%s -- %s",
 276 			server->cage, server->term) >= (int)sizeof(cmd)) {
 277 		fprintf(stderr, "New view command truncated\n");
 278 		return;
 279 	}
 280 	pid_t pid, child;
 281 	if ((pid = fork()) == 0) {
 282 		setsid();
 283 		sigset_t set;
 284 		sigemptyset(&set);
 285 		sigprocmask(SIG_SETMASK, &set, NULL);
 286 		close(fd[0]);
 287 		if ((child = fork()) == 0) {
 288 			close(fd[1]);
 289 			execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL);
 290 			_exit(0);
 291 		}
 292 		ssize_t s = 0;
 293 		while ((size_t)s < sizeof(pid_t)) {
 294 			s += write(fd[1], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
 295 		}
 296 		close(fd[1]);
 297 		_exit(0); // Close child process
 298 	} else if (pid < 0) {
 299 		close(fd[0]);
 300 		close(fd[1]);
 301 		wlr_log(WLR_ERROR, "fork failed");
 302 		return;
 303 	}
 304 	close(fd[1]); // close write
 305 	ssize_t s = 0;
 306 	while ((size_t)s < sizeof(pid_t)) {
 307 		s += read(fd[0], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
 308 	}
 309 	close(fd[0]);
 310 	waitpid(pid, NULL, 0);
 311 	if (child > 0) {
 312 		view->pid = child;
 313 		wl_list_insert(&server->new_views, &view->link);
 314 	}
 315 }
 316 
 317 static void handle_button_internal(
 318 		struct wio_server *server, struct wlr_event_pointer_button *event) {
 319 	// TODO: open menu if the client doesn't handle the button press
 320 	// will basically involve some serial hacking
 321 	struct wlr_box menu_box = {
 322 		.x = server->menu.x, .y = server->menu.y,
 323 		.width = server->menu.width, .height = server->menu.height,
 324 	};
 325 	int x1, x2, y1, y2;
 326 	uint32_t width, height;
 327 	switch (server->input_state) {
 328 	case INPUT_STATE_NONE:
 329 		if (event->state == WLR_BUTTON_PRESSED && event->button == BTN_RIGHT) {
 330 			// TODO: Open over the last-used menu item
 331 			server->input_state = INPUT_STATE_MENU;
 332 			server->menu.x = server->cursor->x;
 333 			server->menu.y = server->cursor->y;
 334 		}
 335 		break;
 336 	case INPUT_STATE_MENU:
 337 		if (wlr_box_contains_point(
 338 					&menu_box, server->cursor->x, server->cursor->y)) {
 339 			menu_handle_button(server, event);
 340 		} else {
 341 			if (event->state == WLR_BUTTON_PRESSED) {
 342 				server->input_state = INPUT_STATE_NONE;
 343 				server->menu.x = server->menu.y = -1;
 344 			}
 345 		}
 346 		break;
 347 	case INPUT_STATE_NEW_START:
 348 		if (event->state == WLR_BUTTON_PRESSED) {
 349 			server->interactive.sx = server->cursor->x;
 350 			server->interactive.sy = server->cursor->y;
 351 			server->input_state = INPUT_STATE_NEW_END;
 352 		}
 353 		break;
 354 	case INPUT_STATE_NEW_END:
 355 		new_view(server);
 356 		view_end_interactive(server);
 357 		break;
 358 	case INPUT_STATE_RESIZE_SELECT:
 359 		if (event->state == WLR_BUTTON_PRESSED) {
 360 			double sx, sy;
 361 			int view_area;
 362 			struct wlr_surface *surface = NULL;
 363 			struct wio_view *view = wio_view_at(server,
 364 					server->cursor->x, server->cursor->y, &surface, &sx, &sy,
 365 					&view_area);
 366 			if (view != NULL) {
 367 				view_begin_interactive(view, surface, sx, sy,
 368 						"bottom_right_corner", INPUT_STATE_RESIZE_START);
 369 			} else {
 370 				view_end_interactive(server);
 371 			}
 372 		}
 373 		break;
 374 	case INPUT_STATE_RESIZE_START:
 375 		if (event->state == WLR_BUTTON_PRESSED) {
 376 			server->interactive.sx = server->cursor->x;
 377 			server->interactive.sy = server->cursor->y;
 378 			server->input_state = INPUT_STATE_RESIZE_END;
 379 		}
 380 		break;
 381 	case INPUT_STATE_BORDER_DRAG_TOP:
 382 		y1 = server->interactive.view->y + server->interactive.view->xdg_surface->surface->current.height;
 383 		y2 = server->cursor->y;
 384 		x1 = server->interactive.view->x;
 385 		if (y2 < y1) {
 386 			int _ = y1;
 387 			y1 = y2;
 388 			y2 = _;
 389 		}
 390 		wio_view_move(server->interactive.view,
 391 				x1, y1);
 392 		width = server->interactive.view->xdg_surface->surface->current.width;
 393 		height = y2 - y1;
 394 		if (height < 100) {
 395 			height = 100;
 396 		}
 397 		wlr_xdg_toplevel_set_size(
 398 				server->interactive.view->xdg_surface, width, height);
 399 		view_end_interactive(server);
 400 		break;
 401 	case INPUT_STATE_BORDER_DRAG_LEFT:
 402 		x1 = server->interactive.view->x + server->interactive.view->xdg_surface->surface->current.width;
 403 		x2 = server->cursor->x;
 404 		y1 = server->interactive.view->y;
 405 		if (x2 < x1) {
 406 			int _ = x1;
 407 			x1 = x2;
 408 			x2 = _;
 409 		}
 410 		wio_view_move(server->interactive.view,
 411 				x1, y1);
 412 		width = x2 - x1;
 413 		height = server->interactive.view->xdg_surface->surface->current.height;
 414 		if (width < 100) {
 415 			width = 100;
 416 		}
 417 		wlr_xdg_toplevel_set_size(
 418 				server->interactive.view->xdg_surface, width, height);
 419 		view_end_interactive(server);
 420 		break;
 421 	case INPUT_STATE_BORDER_DRAG_BOTTOM:
 422 		x1 = server->interactive.view->x;
 423 		y1 = server->interactive.view->y, y2 = server->cursor->y;
 424 		if (y2 < y1) {
 425 			int _ = y1;
 426 			y1 = y2;
 427 			y2 = _;
 428 		}
 429 		wio_view_move(server->interactive.view,
 430 				x1, y1);
 431 		width = server->interactive.view->xdg_surface->surface->current.width;
 432 		height = y2 - y1;
 433 		if (width < 100) {
 434 			width = 100;
 435 		}
 436 		wlr_xdg_toplevel_set_size(
 437 				server->interactive.view->xdg_surface, width, height);
 438 		view_end_interactive(server);
 439 		break;
 440 	case INPUT_STATE_BORDER_DRAG_RIGHT:
 441 		x1 = server->interactive.view->x, x2 = server->cursor->x;
 442 		y1 = server->interactive.view->y;
 443 		if (x2 < x1) {
 444 			int _ = x1;
 445 			x1 = x2;
 446 			x2 = _;
 447 		}
 448 		wio_view_move(server->interactive.view,
 449 				x1, y1);
 450 		width = x2 - x1;
 451 		height = server->interactive.view->xdg_surface->surface->current.height;
 452 		if (width < 100) {
 453 			width = 100;
 454 		}
 455 		wlr_xdg_toplevel_set_size(
 456 				server->interactive.view->xdg_surface, width, height);
 457 		view_end_interactive(server);
 458 		break;
 459 	case INPUT_STATE_RESIZE_END:
 460 		x1 = server->interactive.sx, x2 = server->cursor->x;
 461 		y1 = server->interactive.sy, y2 = server->cursor->y;
 462 		if (x2 < x1) {
 463 			int _ = x1;
 464 			x1 = x2;
 465 			x2 = _;
 466 		}
 467 		if (y2 < y1) {
 468 			int _ = y1;
 469 			y1 = y2;
 470 			y2 = _;
 471 		}
 472 		wio_view_move(server->interactive.view,
 473 				x1, y1);
 474 		width = x2 - x1, height = y2 - y1;
 475 		if (width < 100) {
 476 			width = 100;
 477 		}
 478 		if (height < 100) {
 479 			height = 100;
 480 		}
 481 		wlr_xdg_toplevel_set_size(
 482 				server->interactive.view->xdg_surface, width, height);
 483 		view_end_interactive(server);
 484 		break;
 485 	case INPUT_STATE_MOVE_SELECT:
 486 		if (event->state == WLR_BUTTON_PRESSED) {
 487 			double sx, sy;
 488 			int view_area;
 489 			struct wlr_surface *surface = NULL;
 490 			struct wio_view *view = wio_view_at(server,
 491 					server->cursor->x, server->cursor->y, &surface, &sx, &sy,
 492 					&view_area);
 493 			if (view != NULL) {
 494 				view_begin_interactive(view, surface, sx, sy,
 495 						"grabbing", INPUT_STATE_MOVE);
 496 			} else {
 497 				view_end_interactive(server);
 498 			}
 499 		}
 500 		break;
 501 	case INPUT_STATE_MOVE:
 502 		wio_view_move(server->interactive.view,
 503 			server->cursor->x - server->interactive.sx,
 504 			server->cursor->y - server->interactive.sy);
 505 		view_end_interactive(server);
 506 		break;
 507 	case INPUT_STATE_DELETE_SELECT:
 508 		if (event->state == WLR_BUTTON_PRESSED) {
 509 			double sx, sy;
 510 			int view_area;
 511 			struct wlr_surface *surface = NULL;
 512 			struct wio_view *view = wio_view_at(server,
 513 					server->cursor->x, server->cursor->y, &surface, &sx, &sy,
 514 					&view_area);
 515 			if (view != NULL) {
 516 				wlr_xdg_toplevel_send_close(view->xdg_surface);
 517 			}
 518 			view_end_interactive(server);
 519 		}
 520 		break;
 521 	default:
 522 		// TODO
 523 		break;
 524 	}
 525 }
 526 
 527 void server_cursor_button(struct wl_listener *listener, void *data) {
 528 	struct wio_server *server =
 529 		wl_container_of(listener, server, cursor_button);
 530 	struct wlr_event_pointer_button *event = data;
 531 	double sx, sy;
 532 	struct wlr_surface *surface = NULL;
 533 	int view_area;
 534 	struct wio_view *view = wio_view_at(
 535 			server, server->cursor->x, server->cursor->y, &surface, &sx, &sy,
 536 			&view_area);
 537 	if (server->input_state == INPUT_STATE_NONE && view) {
 538 		wio_view_focus(view, surface);
 539 		switch (view_area) {
 540 		case VIEW_AREA_SURFACE:
 541 			wlr_seat_pointer_notify_button(server->seat,
 542 					event->time_msec, event->button, event->state);
 543 			break;
 544 		case VIEW_AREA_BORDER_TOP:
 545 			view_begin_interactive(view, surface, view->x, view->y,
 546 					"top_side", INPUT_STATE_BORDER_DRAG_TOP);
 547 			break;
 548 		case VIEW_AREA_BORDER_RIGHT:
 549 			view_begin_interactive(view, surface, view->x, view->y,
 550 					"right_side", INPUT_STATE_BORDER_DRAG_RIGHT);
 551 			break;
 552 		case VIEW_AREA_BORDER_BOTTOM:
 553 			view_begin_interactive(view, surface, view->x, view->y,
 554 					"bottom_side", INPUT_STATE_BORDER_DRAG_BOTTOM);
 555 			break;
 556 		case VIEW_AREA_BORDER_LEFT:
 557 			view_begin_interactive(view, surface, view->x, view->y,
 558 					"left_side", INPUT_STATE_BORDER_DRAG_LEFT);
 559 			break;
 560 		}
 561 	} else {
 562 		handle_button_internal(server, event);
 563 	}
 564 }
 565 
 566 void server_cursor_axis(struct wl_listener *listener, void *data) {
 567 	struct wio_server *server = wl_container_of(listener, server, cursor_axis);
 568 	struct wlr_event_pointer_axis *event = data;
 569 	wlr_seat_pointer_notify_axis(server->seat,
 570 			event->time_msec, event->orientation, event->delta,
 571 			event->delta_discrete, event->source);
 572 }
 573 
 574 void server_cursor_frame(struct wl_listener *listener, void *data) {
 575 	struct wio_server *server =
 576 		wl_container_of(listener, server, cursor_frame);
 577 	wlr_seat_pointer_notify_frame(server->seat);
 578 }
 579 
 580 void seat_request_cursor(struct wl_listener *listener, void *data) {
 581 	struct wio_server *server = wl_container_of(
 582 			listener, server, request_cursor);
 583 	struct wlr_seat_pointer_request_set_cursor_event *event = data;
 584 	struct wlr_seat_client *focused_client =
 585 		server->seat->pointer_state.focused_client;
 586 	if (focused_client == event->seat_client
 587 			&& server->input_state == INPUT_STATE_NONE) {
 588 		wlr_cursor_set_surface(server->cursor, event->surface,
 589 				event->hotspot_x, event->hotspot_y);
 590 	}
 591 }