spkp

Stacking wayland compositor
git clone git://git.z3bra.org/spkp.git
Log | Files | Refs

sp:kp.c (32874B)


      1 #include <signal.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <time.h>
      5 #include <unistd.h>
      6 
      7 #include <sys/types.h>
      8 
      9 #include <wayland-server.h>
     10 #include <wlr/backend.h>
     11 #include <wlr/render/wlr_renderer.h>
     12 #include <wlr/types/wlr_compositor.h>
     13 #include <wlr/types/wlr_cursor.h>
     14 #include <wlr/types/wlr_data_control_v1.h>
     15 #include <wlr/types/wlr_data_device.h>
     16 #include <wlr/types/wlr_gamma_control_v1.h>
     17 #include <wlr/types/wlr_idle.h>
     18 #include <wlr/types/wlr_keyboard.h>
     19 #include <wlr/types/wlr_matrix.h>
     20 #include <wlr/types/wlr_output.h>
     21 #include <wlr/types/wlr_output_layout.h>
     22 #include <wlr/types/wlr_primary_selection_v1.h>
     23 #include <wlr/types/wlr_server_decoration.h>
     24 #include <wlr/types/wlr_screencopy_v1.h>
     25 #include <wlr/types/wlr_xcursor_manager.h>
     26 #include <wlr/types/wlr_xdg_decoration_v1.h>
     27 #include <wlr/types/wlr_xdg_output_v1.h>
     28 #include <wlr/types/wlr_xdg_shell.h>
     29 
     30 #include <linux/input-event-codes.h>
     31 
     32 #include "arg.h"
     33 
     34 #define MAX(a,b) ((a)>(b)?(a):(b))
     35 #define MIN(a,b) ((a)<(b)?(a):(b))
     36 #define DELTA(a,b) ((a)>(b)?(a)-(b):(b)-(a))
     37 
     38 #define CLEANMASK(mask) (mask & ~(WLR_MODIFIER_CAPS|WLR_MODIFIER_SHIFT))
     39 
     40 enum {
     41 	NORMAL,
     42 	UNGRAB,
     43 	MOVE,
     44 	RESIZE,
     45 };
     46 
     47 /* Internal compositor state */
     48 struct spkp {
     49 	struct wl_display *dpy;
     50 	struct wlr_backend *backend;
     51 	struct wlr_renderer *renderer;
     52 	struct wlr_xdg_shell *shell;
     53 	struct wlr_output_layout *layout;
     54 
     55 	struct wlr_seat *seat;
     56 
     57 	int desktop; /* wether desktop is visible */
     58 
     59 	struct {
     60 		int mode;
     61 		struct wlr_box box;
     62 		struct window *window;
     63 	} grab;
     64 
     65 	struct wlr_cursor *cursor;
     66 	struct wlr_xcursor_manager *cursor_mgr;
     67 	struct wlr_xdg_decoration_manager_v1 *chrome_mgr;
     68 
     69 	struct wl_listener new_input;
     70 	struct wl_listener new_output;
     71 	struct wl_listener new_window;
     72 	struct wl_listener new_chrome;
     73 	struct wl_listener copy;
     74 
     75 	/* cursor related events */
     76 	struct wl_listener req_cursor;
     77 	struct wl_listener motion_relative;
     78 	struct wl_listener motion_absolute;
     79 	struct wl_listener click;
     80 	struct wl_listener scroll;
     81 	struct wl_listener paint_cursor;
     82 
     83 	struct wl_list outputs;
     84 	struct wl_list windows;
     85 	struct wl_list keyboards;
     86 };
     87 
     88 /* Display output (usually a monitor) */
     89 struct output {
     90 	struct spkp *server;
     91 	struct wlr_output *wlr_output;
     92 
     93 	struct wl_listener destroy;
     94 	struct wl_listener frame;
     95 	struct wl_listener window;
     96 
     97 	/* pointer to the next output */
     98 	struct wl_list link;
     99 };
    100 
    101 /* Client surface window */
    102 struct window {
    103 	struct spkp *server;
    104 	struct wlr_surface *surface;
    105 	struct wlr_xdg_surface *xdg;
    106 	struct wlr_xdg_toplevel_decoration_v1 decoration;
    107 	double x, y;
    108 
    109 	double sx, sy;
    110 
    111 	struct wl_listener map;
    112 	struct wl_listener destroy;
    113 
    114 	/* pointer to the next client */
    115 	struct wl_list link;
    116 };
    117 
    118 struct keyboard {
    119 	struct spkp *server;
    120 	struct wlr_input_device *device;
    121 	struct wl_listener destroy;
    122 
    123 	struct wl_listener key;
    124 	struct wl_listener modifiers;
    125 
    126 	/* pointer to the next keyboard */
    127 	struct wl_list link;
    128 };
    129 
    130 struct chrome {
    131 	struct spkp *server;
    132 	struct wlr_xdg_toplevel_decoration_v1 *decoration;
    133 
    134 	struct wl_listener destroy;
    135 	struct wl_listener mode;
    136 };
    137 
    138 /* Optional argument to pass down to a keybinding function */
    139 union keyarg {
    140 	int i;
    141 	float f;
    142 	const void *v;
    143 };
    144 
    145 /* Keybindig to function association, see config.h */
    146 struct key {
    147 	uint32_t mod;
    148 	uint32_t key;
    149 	void (*func)(struct spkp *, union keyarg *);
    150 	union keyarg arg;
    151 };
    152 
    153 /* Rendering data, used to render window's surfaces */
    154 struct rdata {
    155 	struct wlr_output *output;
    156 	struct window *window;
    157 	struct wlr_renderer *renderer;
    158 	struct timespec when;
    159 };
    160 
    161 
    162 static void usage(char *);
    163 
    164 /* callback functions triggered when a new event occur */
    165 static void cb_new_input(struct wl_listener *, void *);
    166 static void cb_new_output(struct wl_listener *, void *);
    167 static void cb_destroy_output(struct wl_listener *, void *);
    168 static void cb_frame_output(struct wl_listener *, void *);
    169 static void cb_new_window(struct wl_listener *, void *);
    170 static void cb_new_decoration(struct wl_listener *, void *);
    171 static void cb_copy(struct wl_listener *, void *);
    172 
    173 static void cb_map_window(struct wl_listener *, void *);
    174 static void cb_destroy_window(struct wl_listener *, void *);
    175 static void cb_set_chrome(struct wl_listener *, void *);
    176 static void cb_destroy_chrome(struct wl_listener *, void *);
    177 
    178 static void cb_kb_mod(struct wl_listener *, void *);
    179 static void cb_kb_key(struct wl_listener *, void *);
    180 
    181 static void cb_motion(struct spkp *, uint32_t);
    182 static void cb_motion_relative(struct wl_listener *, void *);
    183 static void cb_motion_absolute(struct wl_listener *, void *);
    184 static void cb_click(struct wl_listener *, void *);
    185 static void cb_click_press(struct spkp *, struct wlr_event_pointer_button *);
    186 static void cb_click_release(struct spkp *, struct wlr_event_pointer_button *);
    187 static void cb_scroll(struct wl_listener *, void *);
    188 static void cb_paint_cursor(struct wl_listener *, void *);
    189 
    190 /* helper functions, used inside callbacks */
    191 static void add_keyboard(struct spkp *, struct wlr_input_device *);
    192 static void add_pointer(struct spkp *, struct wlr_input_device *);
    193 static void render(struct wlr_surface *, int, int, void *);
    194 static void render_border(struct wlr_box *, struct rdata *, float *);
    195 static void focus(struct window *);
    196 static void grab(struct window *, int, const char *);
    197 
    198 static int dropprivilege();
    199 static int keybinding(struct spkp *, uint32_t, uint32_t, enum wlr_key_state);
    200 static struct window *underneath(struct spkp *, double, double);
    201 
    202 /* keybinding functions, see config.h */
    203 static void kb_terminate(struct spkp *, union keyarg *);
    204 static void kb_alttab(struct spkp *, union keyarg *);
    205 static void kb_exec(struct spkp *, union keyarg *);
    206 static void kb_desktop(struct spkp *, union keyarg *);
    207 
    208 #include "config.h"
    209 
    210 void
    211 usage(char *pgm)
    212 {
    213 	fprintf(stderr, "usage: %s [-h]\n", pgm);
    214 }
    215 
    216 /*
    217  * A new input device is available. Each new input type is added to the
    218  * capabilities of the seat.
    219  */
    220 void
    221 cb_new_input(struct wl_listener *listener, void *data)
    222 {
    223 	uint32_t cap = 0;
    224 	struct spkp *server;
    225 	struct wlr_input_device *device;
    226 
    227 	server = wl_container_of(listener, server, new_input);
    228 	device = data;
    229 
    230 	cap = server->seat->capabilities;
    231 
    232 	switch(device->type) {
    233 	case WLR_INPUT_DEVICE_KEYBOARD:
    234 		cap |= WL_SEAT_CAPABILITY_KEYBOARD;
    235 		add_keyboard(server, device);
    236 		break;
    237 	case WLR_INPUT_DEVICE_POINTER:
    238 		cap |= WL_SEAT_CAPABILITY_POINTER;
    239 		add_pointer(server, device);
    240 		break;
    241 	default:
    242 		break;
    243 	}
    244 
    245 	wlr_seat_set_capabilities(server->seat, cap);
    246 }
    247 
    248 /*
    249  * Triggered whenever a new output (eg, monitor) is connected to the
    250  * compositor. This output is configured (set "mode" if needed) and
    251  * added to the outputs list.
    252  * Listeners are setup on this output for when stuff needs to get
    253  * rendered, or when output is disconnected.
    254  */
    255 void
    256 cb_new_output(struct wl_listener *listener, void *data)
    257 {
    258 	struct spkp *server;
    259 	struct output *output;
    260 	struct wlr_output *wlr_output;
    261 	struct wlr_output_mode *mode;
    262 
    263 	server = wl_container_of(listener, server, new_output);
    264 	wlr_output = data;
    265 
    266 	/*
    267 	 * Configure output mode when advertized. This is only needed
    268 	 * for DRM backend, as other backends don't have such thing as an
    269 	 * "output" or "mode". They simply run within a window, and thus
    270 	 * have nothing to configure on their own.
    271 	 */
    272 	if (!wl_list_empty(&wlr_output->modes)) {
    273 		mode = wl_container_of(wlr_output->modes.prev, mode, link);
    274 		wlr_output_set_mode(wlr_output, mode);
    275 		wlr_output_enable(wlr_output, true);
    276 		if (!wlr_output_commit(wlr_output))
    277 			return;
    278 	}
    279 
    280 	output = calloc(1, sizeof(*output));
    281 	output->server = server;
    282 	output->wlr_output = wlr_output;
    283 
    284 	wl_list_insert(&server->outputs, &output->link);
    285 
    286 	/* setup callbacks for our output */
    287 	output->destroy.notify = cb_destroy_output;
    288 	output->frame.notify = cb_frame_output;
    289 
    290 	/* setup signals for above notifies */
    291 	wl_signal_add(&wlr_output->events.destroy, &output->destroy);
    292 	wl_signal_add(&wlr_output->events.frame, &output->frame);
    293 
    294 	/* create global and arrange outputs from left to right */
    295 	wlr_output_layout_add_auto(server->layout, wlr_output);
    296 }
    297 
    298 /*
    299  * Output gets disconnected. Remove it from the list and release memory.
    300  */
    301 void
    302 cb_destroy_output(struct wl_listener *listener, void *data)
    303 {
    304 	(void)data;
    305 	struct output *output;
    306 
    307 	output = wl_container_of(listener, output, destroy);
    308 
    309 	wl_list_remove(&output->link);
    310 	wl_list_remove(&output->destroy.link);
    311 	wl_list_remove(&output->frame.link);
    312 
    313 	free(output);
    314 }
    315 
    316 /*
    317  * Output is displaying a frame. This would be called 60 times per
    318  * seconds on a 60Hz monitor.
    319  * Windows will be rendered on top of each others, starting from the
    320  * bottom of the window list.
    321  *
    322  * TODO: damage tracking
    323  */
    324 void
    325 cb_frame_output(struct wl_listener *listener, void *data)
    326 {
    327 	struct spkp *server;
    328 	struct output *output;
    329 	struct window *window;
    330 	struct rdata rdata;
    331 	struct wlr_output *wlr_output;
    332 	struct wlr_renderer *renderer;
    333 
    334 	output = wl_container_of(listener, output, frame);
    335 	server = output->server;
    336 	renderer = output->server->renderer;
    337 	wlr_output = data;
    338 
    339 	if (!wlr_output->enabled)
    340 		return;
    341 
    342 	if (!wlr_output_attach_render(wlr_output, NULL))
    343 		return;
    344 
    345 	/* Update output resolution with current values */
    346 	wlr_output_effective_resolution(wlr_output, &wlr_output->width, &wlr_output->height);
    347 
    348 	/* Paint whole output surface with the background color */
    349 	wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height);
    350 	wlr_renderer_clear(renderer, background);
    351 
    352 	rdata.output = wlr_output;
    353 	rdata.renderer = renderer;
    354 
    355 	wl_list_for_each_reverse(window, &output->server->windows, link) {
    356 		if (!window->xdg->mapped)
    357 			continue;
    358 
    359 		rdata.window = window;
    360 		clock_gettime(CLOCK_MONOTONIC, &rdata.when);
    361 		wlr_xdg_surface_for_each_surface(window->xdg, render, &rdata);
    362 	}
    363 
    364 	if (server->grab.mode != NORMAL)
    365 		render_border(&server->grab.box, &rdata, drawcolor);
    366 
    367 	/* render cursor by software in case the GPU doesn't handle it */
    368 	wlr_output_render_software_cursors(wlr_output, NULL);
    369 
    370 	/* commit changes made to output */
    371 	wlr_renderer_end(renderer);
    372 	wlr_output_commit(wlr_output);
    373 }
    374 
    375 /*
    376  * A new application window is created. Only top-level windows are
    377  * supported and rendered.
    378  *
    379  * TODO: better window placement
    380  * TODO: client size/position hint support
    381  */
    382 void
    383 cb_new_window(struct wl_listener *listener, void *data)
    384 {
    385 	struct spkp *server;
    386 	struct wlr_xdg_surface *surface;
    387 	struct window *window;
    388 
    389 	server = wl_container_of(listener, server, new_window);
    390 	surface = data;
    391 
    392 	/* only register top level windows */
    393 	if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL)
    394 		return;
    395 
    396 	window = calloc(1, sizeof(*window));
    397 	window->server = server;
    398 	window->xdg = surface;
    399 
    400 	window->x = -1;
    401 	window->y = -1;
    402 
    403 	window->map.notify = cb_map_window;
    404 	window->destroy.notify = cb_destroy_window;
    405 
    406 	/* have the client consider itself "tiled", to constrain it */
    407 	wlr_xdg_toplevel_set_tiled(window->xdg,
    408                 WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP | WLR_EDGE_BOTTOM);
    409 
    410 
    411 	wl_signal_add(&surface->events.map, &window->map);
    412 	wl_signal_add(&surface->events.destroy, &window->destroy);
    413 
    414 	wl_list_insert(&server->windows, &window->link);
    415 }
    416 
    417 /*
    418  * Top level window request to add decorations
    419  */
    420 void
    421 cb_new_decoration(struct wl_listener *listener, void *data)
    422 {
    423 	struct spkp *server;
    424 	struct chrome *chrome;
    425 	struct wlr_xdg_toplevel_decoration_v1 *decoration;
    426 
    427 	server = wl_container_of(listener, server, new_chrome);
    428 	decoration = data;
    429 
    430 	chrome = calloc(1, sizeof(*chrome));
    431 	if (!chrome)
    432 		return;
    433 
    434 	chrome->decoration = decoration;
    435 	chrome->server = server;
    436 
    437 	chrome->mode.notify = cb_set_chrome;
    438 	chrome->destroy.notify = cb_destroy_chrome;
    439 
    440 	wl_signal_add(&decoration->events.request_mode, &chrome->mode);
    441 	wl_signal_add(&decoration->events.destroy, &chrome->destroy);
    442 }
    443 
    444 /*
    445  * Request setting selection from the client. This happens when the user
    446  * copies something from a client window.
    447  */
    448 void
    449 cb_copy(struct wl_listener *listener, void *data)
    450 {
    451         struct spkp *server;
    452 	struct wlr_seat_request_set_selection_event *ev;
    453 
    454 	server = wl_container_of(listener, server, copy);
    455         ev = data;
    456         wlr_seat_set_selection(server->seat, ev->source, ev->serial);
    457 }
    458 
    459 /*
    460  * Request from a client to be mapped on-screen.
    461  */
    462 void
    463 cb_map_window(struct wl_listener *listener, void *data)
    464 {
    465 	(void)data;
    466 	int ow, oh;
    467 	struct window *w;
    468 	struct wlr_output *output;
    469 	struct spkp *server;
    470 	struct wlr_output_layout_output *layer;
    471 	struct wlr_box geom;
    472 
    473 	w = wl_container_of(listener, w, map);
    474 	server = w->server;
    475 
    476 	/*
    477 	 * New windows are created with no specific position on
    478 	 * screen. In this case, they're put in the middle of the output,
    479 	 * and eventually resized if they're bigger than said output.
    480 	 */
    481 	if (w->x < 0 || w->y < 0) {
    482 		output = wlr_output_layout_output_at(server->layout,
    483 			server->cursor->x, server->cursor->y);
    484 		layer = wlr_output_layout_get(server->layout, output);
    485 
    486 		wlr_output_effective_resolution(output, &ow, &oh);
    487 		wlr_xdg_surface_get_geometry(w->xdg, &geom);
    488 
    489 		if (geom.width > ow || geom.height > oh) {
    490 			geom.width = MIN(ow - 2 * bordersize, geom.width);
    491 			geom.height = MIN(oh - 2 * bordersize, geom.height);
    492 			wlr_xdg_toplevel_set_size(w->xdg, geom.width, geom.height);
    493 		}
    494 
    495 		w->x = layer->x + ow/2 - geom.width/2;
    496 		w->y = layer->y + oh/2 - geom.height/2;
    497 
    498 		focus(w);
    499 	}
    500 }
    501 
    502 /*
    503  * Release all resources associated to a window.
    504  */
    505 void
    506 cb_destroy_window(struct wl_listener *listener, void *data)
    507 {
    508 	(void)data;
    509 	struct window *w;
    510 
    511 	w = wl_container_of(listener, w, destroy);
    512 	wl_list_remove(&w->link);
    513 	free(w);
    514 }
    515 
    516 /*
    517  * Ask wether to use client-side or server-side decorations.
    518  * We always to server-side.
    519  */
    520 void
    521 cb_set_chrome(struct wl_listener *listener, void *data)
    522 {
    523 	(void)data;
    524 	struct chrome *chrome;
    525 
    526 	chrome = wl_container_of(listener, chrome, mode);
    527 	wlr_xdg_toplevel_decoration_v1_set_mode(chrome->decoration,
    528 		WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE);
    529 }
    530 
    531 /*
    532  * Destroy chrome associated to a window
    533  */
    534 void
    535 cb_destroy_chrome(struct wl_listener *listener, void *data)
    536 {
    537 	(void)data;
    538 	struct chrome *chrome;
    539 
    540 	chrome = wl_container_of(listener, chrome, destroy);
    541 
    542 	wl_list_remove(&chrome->destroy.link);
    543 	wl_list_remove(&chrome->mode.link);
    544 	free(chrome);
    545 }
    546 
    547 /*
    548  * A modifier key is pressed, or depressed.
    549  */
    550 void
    551 cb_kb_mod(struct wl_listener *listener, void *data)
    552 {
    553 	(void)data;
    554 	struct keyboard *kb;
    555 
    556 	kb = wl_container_of(listener, kb, modifiers);
    557 
    558 	wlr_seat_set_keyboard(kb->server->seat, kb->device);
    559 	wlr_seat_keyboard_notify_modifiers(kb->server->seat, &kb->device->keyboard->modifiers);
    560 }
    561 
    562 /*
    563  * A key is pressed, or depressed.
    564  */
    565 void
    566 cb_kb_key(struct wl_listener *listener, void *data)
    567 {
    568 	struct spkp *server;
    569 	struct keyboard *kb;
    570 	struct wlr_event_keyboard_key *ev;
    571 	struct wlr_seat *seat;
    572 
    573 	int nsym;
    574 	uint32_t kc, mod;
    575 	xkb_layout_index_t layout;
    576 	struct xkb_keymap *keymap;
    577 	const xkb_keysym_t *syms;
    578 
    579 	ev = data;
    580 	kb = wl_container_of(listener, kb, key);
    581 	server = kb->server;
    582 	seat = server->seat;
    583 
    584 	/* translate libinput keycode to xkbcommon */
    585 	kc = ev->keycode + 8;
    586 
    587 	/* get keysym as if no modifier was held (level 0) */
    588 	keymap = xkb_state_get_keymap(kb->device->keyboard->xkb_state);
    589 	layout = xkb_state_key_get_layout(kb->device->keyboard->xkb_state, kc);
    590 	nsym = xkb_keymap_key_get_syms_by_level(keymap, kc, layout, 0, &syms);
    591 
    592 	mod = wlr_keyboard_get_modifiers(kb->device->keyboard);
    593 
    594 	for (int i = 0; i < nsym; i++) {
    595 		if (keybinding(server, mod, syms[i], ev->state))
    596 			continue;
    597 
    598 		/* pass it onto the underlying client */
    599 		wlr_seat_set_keyboard(seat, kb->device);
    600 		wlr_seat_keyboard_notify_key(seat, ev->time_msec, ev->keycode, ev->state);
    601 	}
    602 }
    603 
    604 /*
    605  * Client request to change the cursor frame.
    606  */
    607 void
    608 cb_req_cursor(struct wl_listener *listener, void *data)
    609 {
    610 	struct spkp *server;
    611 	struct wlr_seat_pointer_request_set_cursor_event *ev;
    612 	struct wlr_seat_client *focus;
    613 
    614 	server = wl_container_of(listener, server, req_cursor);
    615 	ev = data;
    616 
    617 	focus = server->seat->pointer_state.focused_client;
    618 	if (focus == ev->seat_client)
    619 		wlr_cursor_set_surface(server->cursor, ev->surface, ev->hotspot_x, ev->hotspot_y);
    620 }
    621 
    622 /*
    623  * Generic callback for pointer motion (relative or absolute).
    624  * Depending on the server grab mode, windows will be moved or resized.
    625  * If no grab mode is set, motion events are simply passed down to
    626  * the client underneath the pointer.
    627  */
    628 void
    629 cb_motion(struct spkp *server, uint32_t time)
    630 {
    631 	struct window *w;
    632 	struct wlr_seat *seat;
    633 
    634 	seat = server->seat;
    635 
    636 	/*
    637 	 * reset focus and cursor image when no window is under the
    638 	 * pointer
    639 	 */
    640 	switch(server->grab.mode) {
    641 	case MOVE:
    642 		server->grab.box.x = server->cursor->x - server->grab.window->sx;
    643 		server->grab.box.y = server->cursor->y - server->grab.window->sy;
    644 		break;
    645 	case RESIZE:
    646 		server->grab.box.width = MAX(server->cursor->x - server->grab.box.x, 1);
    647 		server->grab.box.height = MAX(server->cursor->y - server->grab.box.y, 1);
    648 		break;
    649 	case NORMAL:
    650 		wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
    651 			"left_ptr", server->cursor);
    652 		w = underneath(server, server->cursor->x, server->cursor->y);
    653 		if (!w) {
    654 			wlr_seat_pointer_clear_focus(seat);
    655 			return;
    656 		}
    657 
    658 		/* focus pointer when moving to a different surface */
    659 		if (seat->pointer_state.focused_surface != w->surface)
    660 			wlr_seat_pointer_notify_enter(seat, w->surface, w->sx, w->sy);
    661 
    662 		wlr_seat_pointer_notify_motion(seat, time, w->sx, w->sy);
    663 	}
    664 }
    665 
    666 /*
    667  * Move the cursor according to input device request. This event is
    668  * triggered when the cursor is moving from a relative offset from its
    669  * current position.
    670  */
    671 void
    672 cb_motion_relative(struct wl_listener *listener, void *data)
    673 {
    674 	struct spkp *server;
    675 	struct wlr_event_pointer_motion *ev;
    676 
    677 	server = wl_container_of(listener, server, motion_relative);
    678 	ev = data;
    679 
    680 	wlr_cursor_move(server->cursor, ev->device, ev->delta_x, ev->delta_y);
    681 	cb_motion(server, ev->time_msec);
    682 }
    683 
    684 /*
    685  * Move the cursor according to input device request. This event is
    686  * triggered when the cursor is given an absolute position to move to.
    687  */
    688 void
    689 cb_motion_absolute(struct wl_listener *listener, void *data)
    690 {
    691 	struct spkp *server;
    692 	struct wlr_event_pointer_motion_absolute *ev;
    693 
    694 	server = wl_container_of(listener, server, motion_absolute);
    695 	ev = data;
    696 
    697 	wlr_cursor_warp_absolute(server->cursor, ev->device, ev->x, ev->y);
    698 	cb_motion(server, ev->time_msec);
    699 }
    700 
    701 /*
    702  * A mouse button is pressed, or released. If the given modifiers are
    703  * pressed wilst pressing the button, the underlying window (if any!) will
    704  * be moved or resized.
    705  * Any mouse event will be ignored until the button is released.
    706  *
    707  * TODO: refactor grab mode
    708  */
    709 void
    710 cb_click(struct wl_listener *listener, void *data)
    711 {
    712 	struct spkp *server;
    713 	struct wlr_event_pointer_button *ev;
    714 
    715 	server = wl_container_of(listener, server, click);
    716 	ev = data;
    717 
    718 	switch (ev->state) {
    719 	case WLR_BUTTON_RELEASED:
    720 		cb_click_release(server, ev);
    721 		break;
    722 	case WLR_BUTTON_PRESSED:
    723 		cb_click_press(server, ev);
    724 		break;
    725 	}
    726 }
    727 
    728 /*
    729  * Mouse button was released. There are only 2 different use cases:
    730  * either we where grabbing a window to move/resize it, or not.
    731  * In the first case, it means the operation is over, so me must
    732  * move/resize the window.
    733  * When it's not, the event is simply passed down to the focused window.
    734  */
    735 void
    736 cb_click_release(struct spkp *server, struct wlr_event_pointer_button *ev)
    737 {
    738 	switch(server->grab.mode) {
    739 	case RESIZE:
    740 		wlr_xdg_toplevel_set_size(server->grab.window->xdg,
    741 			server->grab.box.width,
    742 			server->grab.box.height);
    743 		break;
    744 	case MOVE:
    745 		server->grab.window->x = server->grab.box.x;
    746 		server->grab.window->y = server->grab.box.y;
    747 		break;
    748 	default:
    749 		/* pass down event when not grabbing a window */
    750 		wlr_seat_pointer_notify_button(server->seat,
    751 			ev->time_msec, ev->button, ev->state);
    752 		return;
    753 	}
    754 
    755 	if (server->grab.mode != NORMAL)
    756 		grab(server->grab.window, UNGRAB, "left_ptr");
    757 }
    758 
    759 /*
    760  * Mouse button was pressed. If the modifier key is held down, we enter
    761  * the "grab mode", which will move and/or resize the clicked or focused
    762  * window, and will terminate when the button is released.
    763  */
    764 void
    765 cb_click_press(struct spkp *server, struct wlr_event_pointer_button *ev)
    766 {
    767 	struct window *w;
    768 	struct wlr_keyboard *kb;
    769 
    770 	/* Ignore all press events when a window is grabbed */
    771 	if (server->grab.mode != NORMAL)
    772 		return;
    773 
    774 	kb = wlr_seat_get_keyboard(server->seat);
    775 
    776 	w = underneath(server, server->cursor->x, server->cursor->y);
    777 	if (!w)
    778 		return;
    779 
    780 	/* bring window to the front */
    781 	wl_list_remove(&w->link);
    782 	wl_list_insert(&server->windows, &w->link);
    783 
    784 	focus(w);
    785 
    786 	if (kb->modifiers.depressed != mousemod) {
    787 		wlr_seat_pointer_notify_button(server->seat,
    788 			ev->time_msec, ev->button, ev->state);
    789 
    790 		return;
    791 	}
    792 
    793 	switch (ev->button) {
    794 	case BTN_LEFT:
    795 		grab(w, MOVE, "hand2");
    796 		break;
    797 	case BTN_RIGHT:
    798 		grab(w, RESIZE, "bottom_right_corner");
    799 		break;
    800 	}
    801 }
    802 
    803 /*
    804  * Mouse scroll. Passed down to the underlying client.
    805  */
    806 void
    807 cb_scroll(struct wl_listener *listener, void *data)
    808 {
    809 	struct spkp *server;
    810 	struct wlr_event_pointer_axis *ev;
    811 
    812 
    813 	server = wl_container_of(listener, server, scroll);
    814 	ev = data;
    815 
    816 	/* Ignore all scrolling events when a window is grabbed */
    817 	if (server->grab.mode != NORMAL)
    818 		return;
    819 
    820 	wlr_seat_pointer_notify_axis(server->seat, ev->time_msec,
    821 		ev->orientation, ev->delta, ev->delta_discrete, ev->source);
    822 }
    823 
    824 /*
    825  * Request to re-paint the cursor.
    826  */
    827 void
    828 cb_paint_cursor(struct wl_listener *listener, void *data)
    829 {
    830 	(void)data;
    831 	struct spkp *server;
    832 
    833 	server = wl_container_of(listener, server, paint_cursor);
    834 
    835 	wlr_seat_pointer_notify_frame(server->seat);
    836 }
    837 
    838 /*
    839  * Configure a newly added keyboard.
    840  */
    841 void
    842 add_keyboard(struct spkp *server, struct wlr_input_device *device)
    843 {
    844 	struct keyboard *kb;
    845 	struct xkb_context *context;
    846 	struct xkb_keymap *keymap;
    847 	struct xkb_rule_names rules = { 0 };
    848 
    849 	kb = calloc(1, sizeof(*kb));
    850 
    851 	kb->server = server;
    852 	kb->device = device;
    853 
    854 	rules.rules = getenv("XKB_DEFAULT_RULES");
    855 	rules.model = getenv("XKB_DEFAULT_MODEL");
    856 	rules.layout = getenv("XKB_DEFAULT_LAYOUT");
    857 	rules.variant = getenv("XKB_DEFAULT_VARIANT");
    858 	rules.options = getenv("XKB_DEFAULT_OPTIONS");
    859 
    860 	context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
    861 	keymap = xkb_map_new_from_names(context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
    862 
    863 	wlr_keyboard_set_keymap(device->keyboard, keymap);
    864 	xkb_keymap_unref(keymap);
    865 	xkb_context_unref(context);
    866 	wlr_keyboard_set_repeat_info(device->keyboard, 25, 600);
    867 
    868 	kb->key.notify = cb_kb_key;
    869 	kb->modifiers.notify = cb_kb_mod;
    870 
    871 	wl_signal_add(&device->keyboard->events.key, &kb->key);
    872 	wl_signal_add(&device->keyboard->events.modifiers, &kb->modifiers);
    873 
    874 	wlr_seat_set_keyboard(server->seat, device);
    875 
    876 	wl_list_insert(&server->keyboards, &kb->link);
    877 }
    878 
    879 /*
    880  * Configure a newly added pointer device.
    881  */
    882 void
    883 add_pointer(struct spkp *server, struct wlr_input_device *device)
    884 {
    885 	/* no special configuration required (eg, accel, …) */
    886 	wlr_cursor_attach_input_device(server->cursor, device);
    887 }
    888 
    889 /*
    890  * Render a full surface on-screen, at the given position.
    891  */
    892 void
    893 render(struct wlr_surface *surface, int x, int y, void *data)
    894 {
    895 	float matrix[9];
    896 	struct rdata *rdata;
    897 	struct window *window;
    898 	struct wlr_output *output;
    899 	struct wlr_surface *focus;
    900 	struct wlr_texture *texture;
    901 	struct wlr_box box;
    902 	enum wl_output_transform transform;
    903 
    904 	rdata = data;
    905 	window = rdata->window;
    906 	output = rdata->output;
    907 
    908 	texture = wlr_surface_get_texture(surface);
    909 	if (!texture)
    910 		return;
    911 
    912 	transform = wlr_output_transform_invert(surface->current.transform);
    913 
    914 	box.x = window->x + x;
    915 	box.y = window->y + y;
    916 	box.width = surface->current.width;
    917 	box.height = surface->current.height;
    918 
    919 	focus = window->server->seat->keyboard_state.focused_surface;
    920 	if (surface == window->xdg->surface)
    921 		render_border(&box, rdata, (surface == focus) ? activecolor : bordercolor);
    922 
    923 	wlr_matrix_project_box(matrix, &box, transform, 0, output->transform_matrix);
    924 	wlr_render_texture_with_matrix(rdata->renderer, texture, matrix, 1);
    925 	wlr_surface_send_frame_done(surface, &rdata->when);
    926 }
    927 
    928 void
    929 render_border(struct wlr_box *content, struct rdata *rdata, float *color)
    930 {
    931 	struct wlr_box box;
    932 
    933 	/* top */
    934 	box.x = content->x - bordersize;
    935 	box.y = content->y - bordersize;
    936 	box.width = bordersize * 2 + content->width;
    937 	box.height = bordersize;
    938 	wlr_render_rect(rdata->renderer, &box, color, rdata->output->transform_matrix);
    939 
    940 	/* bottom */
    941 	box.x = content->x - bordersize;
    942 	box.y = content->y + content->height;
    943 	box.width = bordersize * 2 + content->width;
    944 	box.height = bordersize;
    945 	wlr_render_rect(rdata->renderer, &box, color, rdata->output->transform_matrix);
    946 
    947 	/* left */
    948 	box.x = content->x - bordersize;
    949 	box.y = content->y;
    950 	box.width = bordersize;
    951 	box.height = content->height;
    952 	wlr_render_rect(rdata->renderer, &box, color, rdata->output->transform_matrix);
    953 
    954 	/* right */
    955 	box.x = content->x + content->width;
    956 	box.y = content->y;
    957 	box.width = bordersize;
    958 	box.height = content->height;
    959 	wlr_render_rect(rdata->renderer, &box, color, rdata->output->transform_matrix);
    960 }
    961 
    962 /*
    963  * Set keyboard focus on the given top-level window.
    964  */
    965 void
    966 focus(struct window *window)
    967 {
    968 	struct spkp *server;
    969 	struct wlr_seat *seat;
    970 	struct wlr_keyboard *kb;
    971 	struct wlr_surface *focus;
    972 	struct wlr_xdg_surface *toplevel;
    973 
    974 	server = window->server;
    975 	seat = server->seat;
    976 	kb = wlr_seat_get_keyboard(seat);
    977 	focus = seat->keyboard_state.focused_surface;
    978 
    979 	/* skip if window is already focused */
    980 	if (focus == window->surface)
    981 		return;
    982 
    983 	/* deactivate currently focused window */
    984 	if (focus) {
    985 		toplevel = wlr_xdg_surface_from_wlr_surface(focus);
    986 		wlr_xdg_toplevel_set_activated(toplevel, false);
    987 	}
    988 
    989 	/* give keyboard focus to the toplevel window */
    990 	wlr_seat_keyboard_notify_enter(seat, window->xdg->surface,
    991 		kb->keycodes, kb->num_keycodes, &kb->modifiers);
    992 }
    993 
    994 void
    995 grab(struct window *window, int mode, const char *cursor)
    996 {
    997 	struct spkp *server;
    998 
    999 	server = window->server;
   1000 
   1001 	if (mode == UNGRAB) {
   1002 		server->grab.mode = NORMAL;
   1003 		server->grab.window = NULL;
   1004 		wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
   1005 			cursor, server->cursor);
   1006 		return;
   1007 	}
   1008 
   1009 	if (server->grab.mode != NORMAL)
   1010 		return;
   1011 
   1012 	server->grab.mode = mode;
   1013 	server->grab.window = window;
   1014 	wlr_xcursor_manager_set_cursor_image(server->cursor_mgr,
   1015 		cursor, server->cursor);
   1016 
   1017 	switch (mode) {
   1018 	case MOVE:
   1019 		wlr_xdg_surface_get_geometry(window->xdg, &(server->grab.box));
   1020 		server->grab.box.x = window->x;
   1021 		server->grab.box.y = window->y;
   1022 		break;
   1023 	case RESIZE:
   1024 		server->grab.box.x = window->x;
   1025 		server->grab.box.y = window->y;
   1026 		break;
   1027 	}
   1028 }
   1029 
   1030 /*
   1031  * Drop current privileges to run as current user.
   1032  */
   1033 int
   1034 dropprivilege()
   1035 {
   1036 	if (getuid() == geteuid() && getgid() == getegid())
   1037 		return 1;
   1038 
   1039 	if (!setgid(getgid()) && !setuid(getuid()))
   1040 		return 1;
   1041 
   1042 	return 0;
   1043 }
   1044 
   1045 
   1046 /*
   1047  * Execute specific functions when an modifier/key combination is pressed.
   1048  */
   1049 int
   1050 keybinding(struct spkp *server, uint32_t mod, uint32_t key, enum wlr_key_state state)
   1051 {
   1052 	ssize_t i, nkey;
   1053 
   1054 	nkey = sizeof(keys)/sizeof(*keys);
   1055 
   1056 	for (i=0; i<nkey; i++) {
   1057 		if (keys[i].mod == CLEANMASK(mod) && keys[i].key == key) {
   1058 			if (state == WLR_KEY_PRESSED)
   1059 				keys[i].func(server, &(keys[i].arg));
   1060 
   1061 			return 1;
   1062 		}
   1063 	}
   1064 
   1065 	return 0;
   1066 }
   1067 
   1068 /*
   1069  * Returns a pointer to the toplevel window at the given position.
   1070  * If a toplevel window is found, the topmost surface pertaining to this
   1071  * toplevel window will be saved, as well as the pointer coordinates
   1072  * relative to that surface.
   1073  * These informations are needed to relay pointer events to the window.
   1074  */
   1075 struct window *
   1076 underneath(struct spkp *server, double x, double y)
   1077 {
   1078 	struct window *w;
   1079 
   1080 	wl_list_for_each(w, &server->windows, link) {
   1081 		/*
   1082 		 * retrieve the subsurface at the given coordinates.
   1083 		 * coordinates are given relatively to the top level
   1084 		 * window coordinates on the output. Subsurfaces can
   1085 		 * however exist outside the bounds of the top level
   1086 		 * window, and thus have negative coordinates for example
   1087 		 *
   1088 		 * sx, sy will be updated with the pointer coordinates
   1089 		 * within the subsurface (always positive).
   1090 		 */
   1091 		w->surface = wlr_xdg_surface_surface_at(w->xdg,
   1092 			x - w->x, y - w->y, &w->sx, &w->sy);
   1093 
   1094 		if (w->surface)
   1095 			return w;
   1096 	}
   1097 
   1098 	return NULL;
   1099 }
   1100 
   1101 /*
   1102  * Keybind: Terminate the wayland compositor
   1103  */
   1104 void
   1105 kb_terminate(struct spkp *server, union keyarg *arg)
   1106 {
   1107 	(void)arg;
   1108 	wl_display_terminate(server->dpy);
   1109 }
   1110 
   1111 /*
   1112  * Cycle windows.
   1113  */
   1114 void
   1115 kb_alttab(struct spkp *server, union keyarg *arg)
   1116 {
   1117 	int reverse;
   1118 	struct window *w;
   1119 	struct wl_list *list, *elm;
   1120 
   1121 	if (wl_list_empty(&server->windows))
   1122 		return;
   1123 
   1124 	reverse = arg->i;
   1125 
   1126 	list = &server->windows;
   1127 	elm = list->prev;
   1128 
   1129 	if (reverse) {
   1130 		elm = list->next;
   1131 		list = list->prev;
   1132 	}
   1133 
   1134 	wl_list_remove(elm);
   1135 	wl_list_insert(list, elm);
   1136 
   1137 	w = wl_container_of(elm, w, link);
   1138 
   1139 	focus(w);
   1140 }
   1141 
   1142 /*
   1143  * Run the given command
   1144  */
   1145 void
   1146 kb_exec(struct spkp *server, union keyarg *arg)
   1147 {
   1148 	(void)server;
   1149 	if (!fork()) {
   1150 		setsid();
   1151 		sigset_t set;
   1152 		sigemptyset(&set);
   1153 		sigprocmask(SIG_SETMASK, &set, NULL);
   1154 		close(1);
   1155 		close(2);
   1156 		execl("/bin/sh", "/bin/sh", "-c", (char *)arg->v, (void *)NULL);
   1157 		exit(1); /* NOTREACHED */
   1158 	}
   1159 }
   1160 
   1161 /*
   1162  * Hide/show all windows on the desktop
   1163  */
   1164 void
   1165 kb_desktop(struct spkp *server, union keyarg *arg)
   1166 {
   1167 	(void)arg;
   1168 	struct window *w;
   1169 
   1170 	server->desktop = !server->desktop;
   1171 	wl_list_for_each(w, &server->windows, link)
   1172 		w->xdg->mapped = !server->desktop;
   1173 
   1174 }
   1175 
   1176 int
   1177 main(int argc, char *argv[])
   1178 {
   1179 	char *argv0;
   1180 	const char *socket;
   1181 	struct spkp server;
   1182 	struct wlr_server_decoration_manager *decorations;
   1183 
   1184 	ARGBEGIN {
   1185 	case 'h':
   1186 	default:
   1187 		usage(argv0);
   1188 		return -1;
   1189 		break; /* NOTREACHED */
   1190 	} ARGEND;
   1191 
   1192 	/*
   1193 	 * create server side resources
   1194 	 */
   1195 	server.dpy = wl_display_create();
   1196 	server.backend = wlr_backend_autocreate(server.dpy, NULL);
   1197 
   1198 	if (!dropprivilege())
   1199 		return -1;
   1200 
   1201 	server.seat = wlr_seat_create(server.dpy, "seat0");
   1202 	server.shell = wlr_xdg_shell_create(server.dpy);
   1203 	server.layout = wlr_output_layout_create();
   1204 	server.renderer = wlr_backend_get_renderer(server.backend);
   1205 	server.chrome_mgr = wlr_xdg_decoration_manager_v1_create(server.dpy);
   1206 
   1207 	server.cursor = wlr_cursor_create();
   1208 	server.cursor_mgr = wlr_xcursor_manager_create(NULL, 24);
   1209 	server.grab.mode = NORMAL;
   1210 
   1211 	wl_list_init(&server.outputs);
   1212 	wl_list_init(&server.windows);
   1213 	wl_list_init(&server.keyboards);
   1214 
   1215 	wl_display_init_shm(server.dpy);
   1216 	wlr_renderer_init_wl_display(server.renderer, server.dpy);
   1217 
   1218 	wlr_xcursor_manager_load(server.cursor_mgr, 1);
   1219 	wlr_cursor_attach_output_layout(server.cursor, server.layout);
   1220 
   1221 	wlr_compositor_create(server.dpy, server.renderer);
   1222 	wlr_data_device_manager_create(server.dpy);
   1223 
   1224 	wlr_gamma_control_manager_v1_create(server.dpy);
   1225 	wlr_screencopy_manager_v1_create(server.dpy);
   1226 	wlr_primary_selection_v1_device_manager_create(server.dpy);
   1227 	wlr_xdg_output_manager_v1_create(server.dpy, server.layout);
   1228 	wlr_idle_create(server.dpy);
   1229 
   1230 	/*
   1231 	 * Legacy protocol to negotiate decorations. Still used by GTK…
   1232 	 */
   1233 	decorations = wlr_server_decoration_manager_create(server.dpy);
   1234 	wlr_server_decoration_manager_set_default_mode(decorations,
   1235 		WLR_SERVER_DECORATION_MANAGER_MODE_SERVER);
   1236 
   1237 	/*
   1238 	 * Setup callbacks for server-side events
   1239 	 */
   1240 	server.new_window.notify = cb_new_window;
   1241 	server.new_input.notify = cb_new_input;
   1242 	server.new_output.notify = cb_new_output;
   1243 	server.new_chrome.notify = cb_new_decoration;
   1244 	server.copy.notify = cb_copy;
   1245 
   1246 	server.click.notify = cb_click;
   1247 	server.scroll.notify = cb_scroll;
   1248 	server.paint_cursor.notify = cb_paint_cursor;
   1249 	server.motion_relative.notify = cb_motion_relative;
   1250 	server.motion_absolute.notify = cb_motion_absolute;
   1251 	server.req_cursor.notify = cb_req_cursor;
   1252 
   1253 	wl_signal_add(&server.backend->events.new_output, &server.new_output);
   1254 	wl_signal_add(&server.shell->events.new_surface, &server.new_window);
   1255 	wl_signal_add(&server.backend->events.new_input, &server.new_input);
   1256 	wl_signal_add(&server.chrome_mgr->events.new_toplevel_decoration, &server.new_chrome);
   1257 	wl_signal_add(&server.seat->events.request_set_selection, &server.copy);
   1258 
   1259 	wl_signal_add(&server.cursor->events.button, &server.click);
   1260 	wl_signal_add(&server.cursor->events.axis, &server.scroll);
   1261 	wl_signal_add(&server.cursor->events.frame, &server.paint_cursor);
   1262 	wl_signal_add(&server.cursor->events.motion, &server.motion_relative);
   1263 	wl_signal_add(&server.cursor->events.motion_absolute, &server.motion_absolute);
   1264 	wl_signal_add(&server.seat->events.request_set_cursor, &server.req_cursor);
   1265 
   1266 	socket = wl_display_add_socket_auto(server.dpy);
   1267 	setenv("WAYLAND_DISPLAY", socket, 1);
   1268 
   1269 	if (!wlr_backend_start(server.backend)) {
   1270 		fprintf(stderr, "Failed to start backend\n");
   1271 		wlr_backend_destroy(server.backend);
   1272 		wl_display_destroy(server.dpy);
   1273 		return -1;
   1274 	}
   1275 
   1276 	/* all these interfaces are managed internally by wlroots */
   1277 	/* trigger internal event loop */
   1278 	wl_display_run(server.dpy);
   1279 	wl_display_destroy_clients(server.dpy);
   1280 	wl_display_destroy(server.dpy);
   1281 
   1282 	return 0;
   1283 }