tsp:kp.c - spkp - Stacking wayland compositor
 (HTM) git clone git://git.z3bra.org/spkp.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       tsp: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 }