gimp but for windows: a wayland compositor
git clone https://github.com/m-col/wimp
Files | Refs | Readme

-rw-r--r-- src/layer_shell.c


      1 #include <wlr/types/wlr_layer_shell_v1.h>
      2 #include <wlr/types/wlr_output_damage.h>
      3 
      4 #include "layer_shell.h"
      5 #include "output.h"
      6 #include "shell.h"
      7 
      8 
      9 static void layer(struct output *output) {
     10     struct layer_view *lview;
     11     struct wlr_layer_surface_v1 *surface;
     12     struct wlr_layer_surface_v1_state *state;
     13     int width, height;
     14     wlr_output_effective_resolution(output->wlr_output, &width, &height);
     15 
     16     for (int i = 0; i < 4; i++) {
     17 	wl_list_for_each(lview, &output->layer_views[i], link) {
     18 	    surface = lview->surface;
     19 	    state = &surface->current;
     20 	    struct wlr_box box = {
     21 		.width = state->desired_width,
     22 		.height = state->desired_height
     23 	    };
     24 	    // Horizontal axis
     25 	    const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
     26 		| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
     27 	    if ((state->anchor & both_horiz) && box.width == 0) {
     28 		box.x = state->margin.left;
     29 		box.width = width - state->margin.left - state->margin.right;
     30 	    } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) {
     31 		box.x = state->margin.left;
     32 	    } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) {
     33 		box.x = width - box.width - state->margin.right;
     34 	    } else {
     35 		box.x = width / 2 - box.width / 2;
     36 	    }
     37 	    // Vertical axis
     38 	    const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP
     39 		    | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
     40 	    if ((state->anchor & both_vert) && box.height == 0) {
     41 		box.y = state->margin.top;
     42 		box.height = height - state->margin.top - state->margin.bottom;
     43 	    } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) {
     44 		box.y = state->margin.top;
     45 	    } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) {
     46 		box.y = height - box.height - state->margin.bottom;
     47 	    } else {
     48 		box.y = height / 2 - box.height / 2;
     49 	    }
     50 	    if (box.width < 0 || box.height < 0) {
     51 		wlr_layer_surface_v1_close(surface);
     52 		continue;
     53 	    }
     54 	    memcpy(&lview->geo, &box, sizeof(struct wlr_box));
     55 	    wlr_layer_surface_v1_configure(surface, box.width, box.height);
     56 	}
     57     }
     58 
     59     // Find topmost keyboard interactive layer, if such a layer exists
     60     uint32_t layers_above_shell[] = {
     61 	ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY,
     62 	ZWLR_LAYER_SHELL_V1_LAYER_TOP,
     63     };
     64     size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
     65     bool found = false;
     66     for (size_t i = 0; i < nlayers; ++i) {
     67 	wl_list_for_each_reverse(lview, &output->layer_views[layers_above_shell[i]], link) {
     68 	    if (lview->surface->current.keyboard_interactive && lview->surface->mapped) {
     69 		focus(lview, NULL, true);
     70 		found = true;
     71 		break;
     72 	    }
     73 	}
     74 	if (found) {
     75 	    break;
     76 	}
     77     }
     78 
     79     wlr_output_damage_add_whole(output->wlr_output_damage);
     80 }
     81 
     82 
     83 static void on_destroy(struct wl_listener *listener, void *data) {
     84     struct layer_view *lview = wl_container_of(listener, lview, destroy_listener);
     85     struct output *output = lview->output;
     86 
     87     wl_list_remove(&lview->destroy_listener.link);
     88     wl_list_remove(&lview->map_listener.link);
     89     wl_list_remove(&lview->unmap_listener.link);
     90     wl_list_remove(&lview->link);
     91     free(lview);
     92     layer(output);
     93 }
     94 
     95 
     96 static void on_commit(struct wl_listener *listener, void *data) {
     97     struct layer_view *lview = wl_container_of(listener, lview, commit_listener);
     98     damage_by_lview(lview);
     99 }
    100 
    101 
    102 static void on_unmap(struct wl_listener *listener, void *data) {
    103     struct layer_view *lview = wl_container_of(listener, lview, unmap_listener);
    104     lview->surface->mapped = false;
    105     layer(lview->output);
    106     if (wimp.focussed_layer_view == lview) {
    107 	wimp.focussed_layer_view = NULL;
    108 	find_focus();
    109     }
    110 }
    111 
    112 
    113 static void on_map(struct wl_listener *listener, void *data) {
    114     struct layer_view *lview = wl_container_of(listener, lview, map_listener);
    115     lview->surface->mapped = true;
    116     layer(lview->output);
    117     wlr_surface_send_enter(lview->surface->surface, lview->surface->output);
    118 }
    119 
    120 
    121 static void on_new_surface(struct wl_listener *listener, void *data) {
    122     struct wlr_layer_surface_v1 *surface = data;
    123 
    124     struct layer_view *lview = calloc(1, sizeof(struct view));
    125     lview->surface = surface;
    126     surface->data = lview;
    127 
    128     lview->map_listener.notify = on_map;
    129     lview->unmap_listener.notify = on_unmap;
    130     lview->destroy_listener.notify = on_destroy;
    131     lview->commit_listener.notify = on_commit;
    132     wl_signal_add(&surface->events.map, &lview->map_listener);
    133     wl_signal_add(&surface->events.unmap, &lview->unmap_listener);
    134     wl_signal_add(&surface->events.destroy, &lview->destroy_listener);
    135     wl_signal_add(&surface->surface->events.commit, &lview->commit_listener);
    136 
    137     if (!surface->output) {
    138 	surface->output = wlr_output_layout_output_at(
    139 	    wimp.output_layout, wimp.cursor->x, wimp.cursor->y
    140 	);
    141     }
    142     struct output *output = surface->output->data;
    143     lview->output = output;
    144     wl_list_insert(&output->layer_views[surface->client_pending.layer], &lview->link);
    145     layer(lview->output);
    146 }
    147 
    148 
    149 void set_up_layer_shell() {
    150     wimp.layer_shell = wlr_layer_shell_v1_create(wimp.display);
    151     wimp.layer_shell_surface_listener.notify = on_new_surface;
    152     wl_signal_add(&wimp.layer_shell->events.new_surface, &wimp.layer_shell_surface_listener);
    153 }
    154