swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

xdg_shell.c (14422B)


      1 /* swc: libswc/xdg_shell.c
      2  *
      3  * Copyright (c) 2014, 2018 Michael Forney
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a copy
      6  * of this software and associated documentation files (the "Software"), to deal
      7  * in the Software without restriction, including without limitation the rights
      8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9  * copies of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice shall be included in
     13  * all copies or substantial portions of the Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     21  * SOFTWARE.
     22  */
     23 
     24 #include "xdg_shell.h"
     25 #include "internal.h"
     26 #include "seat.h"
     27 #include "surface.h"
     28 #include "util.h"
     29 #include "window.h"
     30 
     31 #include <assert.h>
     32 #include <stdlib.h>
     33 #include <wayland-server.h>
     34 #include "xdg-shell-server-protocol.h"
     35 
     36 struct xdg_surface {
     37 	struct wl_resource *resource, *role;
     38 	struct surface *surface;
     39 	struct wl_listener surface_destroy_listener, role_destroy_listener;
     40 	uint32_t configure_serial;
     41 };
     42 
     43 struct xdg_positioner {
     44 	struct wl_resource *resource;
     45 };
     46 
     47 struct xdg_toplevel {
     48 	struct window window;
     49 	struct wl_resource *resource;
     50 	struct wl_array states;
     51 	struct xdg_surface *xdg_surface;
     52 };
     53 
     54 /* xdg_positioner */
     55 static void
     56 destroy_positioner(struct wl_resource *resource)
     57 {
     58 	struct xdg_positioner *positioner = wl_resource_get_user_data(resource);
     59 
     60 	free(positioner);
     61 }
     62 
     63 static void
     64 set_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height)
     65 {
     66 }
     67 
     68 static void
     69 set_anchor_rect(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
     70 {
     71 }
     72 
     73 static void
     74 set_anchor(struct wl_client *client, struct wl_resource *resource, uint32_t anchor)
     75 {
     76 }
     77 
     78 static void
     79 set_gravity(struct wl_client *client, struct wl_resource *resource, uint32_t gravity)
     80 {
     81 }
     82 
     83 static void
     84 set_constraint_adjustment(struct wl_client *client, struct wl_resource *resource, uint32_t adjustment)
     85 {
     86 }
     87 
     88 static void
     89 set_offset(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y)
     90 {
     91 }
     92 
     93 static const struct xdg_positioner_interface positioner_impl = {
     94 	.destroy = destroy_resource,
     95 	.set_size = set_size,
     96 	.set_anchor_rect = set_anchor_rect,
     97 	.set_anchor = set_anchor,
     98 	.set_gravity = set_gravity,
     99 	.set_constraint_adjustment = set_constraint_adjustment,
    100 	.set_offset = set_offset,
    101 };
    102 
    103 /* xdg_toplevel */
    104 static void
    105 destroy_toplevel(struct wl_resource *resource)
    106 {
    107 	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
    108 
    109 	window_finalize(&toplevel->window);
    110 	free(toplevel);
    111 }
    112 
    113 static bool
    114 add_state(struct xdg_toplevel *toplevel, uint32_t state)
    115 {
    116 	uint32_t *current_state;
    117 
    118 	wl_array_for_each (current_state, &toplevel->states) {
    119 		if (*current_state == state)
    120 			return false;
    121 	}
    122 
    123 	if (!(current_state = wl_array_add(&toplevel->states, sizeof(state)))) {
    124 		WARNING("xdg_toplevel: Failed to allocate new state\n");
    125 		return false;
    126 	}
    127 
    128 	*current_state = state;
    129 	return true;
    130 }
    131 
    132 static bool
    133 remove_state(struct xdg_toplevel *toplevel, uint32_t state)
    134 {
    135 	uint32_t *current_state;
    136 
    137 	wl_array_for_each (current_state, &toplevel->states) {
    138 		if (*current_state == state) {
    139 			array_remove(&toplevel->states, current_state, sizeof(state));
    140 			return true;
    141 		}
    142 	}
    143 
    144 	return false;
    145 }
    146 
    147 static uint32_t
    148 send_configure(struct xdg_toplevel *toplevel, int32_t width, int32_t height) {
    149 	uint32_t serial = wl_display_next_serial(swc.display);
    150 
    151 	if (width < 0)
    152 		width = toplevel->window.configure.width;
    153 	if (height < 0)
    154 		height = toplevel->window.configure.height;
    155 
    156 	xdg_toplevel_send_configure(toplevel->resource, width, height, &toplevel->states);
    157 	xdg_surface_send_configure(toplevel->xdg_surface->resource, serial);
    158 
    159 	return serial;
    160 }
    161 
    162 static void
    163 configure(struct window *window, uint32_t width, uint32_t height)
    164 {
    165 	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
    166 
    167 	window->configure.acknowledged = false;
    168 	toplevel->xdg_surface->configure_serial = send_configure(toplevel, width, height);
    169 }
    170 
    171 static void
    172 focus(struct window *window)
    173 {
    174 	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
    175 
    176 	add_state(toplevel, XDG_TOPLEVEL_STATE_ACTIVATED);
    177 	send_configure(toplevel, -1, -1);
    178 }
    179 
    180 static void
    181 unfocus(struct window *window)
    182 {
    183 	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
    184 
    185 	remove_state(toplevel, XDG_TOPLEVEL_STATE_ACTIVATED);
    186 	send_configure(toplevel, -1, -1);
    187 }
    188 
    189 static void
    190 close(struct window *window)
    191 {
    192 	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
    193 
    194 	xdg_toplevel_send_close(toplevel->resource);
    195 }
    196 
    197 static void
    198 set_mode(struct window *window, unsigned mode)
    199 {
    200 	struct xdg_toplevel *toplevel = wl_container_of(window, toplevel, window);
    201 
    202 	switch (window->mode) {
    203 	case WINDOW_MODE_TILED:
    204 		remove_state(toplevel, XDG_TOPLEVEL_STATE_MAXIMIZED);
    205 		break;
    206 	case WINDOW_MODE_FULLSCREEN:
    207 		remove_state(toplevel, XDG_TOPLEVEL_STATE_FULLSCREEN);
    208 		break;
    209 	}
    210 
    211 	switch (mode) {
    212 	case WINDOW_MODE_TILED:
    213 		add_state(toplevel, XDG_TOPLEVEL_STATE_MAXIMIZED);
    214 		break;
    215 	case WINDOW_MODE_FULLSCREEN:
    216 		add_state(toplevel, XDG_TOPLEVEL_STATE_FULLSCREEN);
    217 		break;
    218 	}
    219 
    220 	send_configure(toplevel, -1, -1);
    221 }
    222 
    223 static const struct window_impl toplevel_window_impl = {
    224 	.configure = configure,
    225 	.focus = focus,
    226 	.unfocus = unfocus,
    227 	.close = close,
    228 	.set_mode = set_mode,
    229 };
    230 
    231 static void
    232 set_parent(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent_resource)
    233 {
    234 	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource), *parent = NULL;
    235 
    236 	if (parent_resource)
    237 		parent = wl_resource_get_user_data(parent_resource);
    238 	window_set_parent(&toplevel->window, parent ? &parent->window : NULL);
    239 }
    240 
    241 static void
    242 set_title(struct wl_client *client, struct wl_resource *resource, const char *title)
    243 {
    244 	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
    245 	window_set_title(&toplevel->window, title, -1);
    246 }
    247 
    248 static void
    249 set_app_id(struct wl_client *client, struct wl_resource *resource, const char *app_id)
    250 {
    251 	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
    252 	window_set_app_id(&toplevel->window, app_id);
    253 }
    254 
    255 static void
    256 show_window_menu(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, int32_t x, int32_t y)
    257 {
    258 }
    259 
    260 static void
    261 move(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial)
    262 {
    263 	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
    264 	struct button *button;
    265 
    266 	button = pointer_get_button(swc.seat->pointer, serial);
    267 	if (button)
    268 		window_begin_move(&toplevel->window, button);
    269 }
    270 
    271 static void
    272 resize(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, uint32_t edges)
    273 {
    274 	struct xdg_toplevel *toplevel = wl_resource_get_user_data(resource);
    275 	struct button *button;
    276 
    277 	button = pointer_get_button(swc.seat->pointer, serial);
    278 	if (button)
    279 		window_begin_resize(&toplevel->window, edges, button);
    280 }
    281 
    282 static void
    283 set_max_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height)
    284 {
    285 }
    286 
    287 static void
    288 set_min_size(struct wl_client *client, struct wl_resource *resource, int32_t width, int32_t height)
    289 {
    290 }
    291 
    292 static void
    293 set_maximized(struct wl_client *client, struct wl_resource *resource)
    294 {
    295 }
    296 
    297 static void
    298 unset_maximized(struct wl_client *client, struct wl_resource *resource)
    299 {
    300 }
    301 
    302 static void
    303 set_fullscreen(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output)
    304 {
    305 }
    306 
    307 static void
    308 unset_fullscreen(struct wl_client *client, struct wl_resource *resource)
    309 {
    310 }
    311 
    312 static void
    313 set_minimized(struct wl_client *client, struct wl_resource *resource)
    314 {
    315 }
    316 
    317 static const struct xdg_toplevel_interface toplevel_impl = {
    318 	.destroy = destroy_resource,
    319 	.set_parent = set_parent,
    320 	.set_title = set_title,
    321 	.set_app_id = set_app_id,
    322 	.show_window_menu = show_window_menu,
    323 	.move = move,
    324 	.resize = resize,
    325 	.set_max_size = set_max_size,
    326 	.set_min_size = set_min_size,
    327 	.set_maximized = set_maximized,
    328 	.unset_maximized = unset_maximized,
    329 	.set_fullscreen = set_fullscreen,
    330 	.unset_fullscreen = unset_fullscreen,
    331 	.set_minimized = set_minimized,
    332 };
    333 
    334 static struct xdg_toplevel *
    335 xdg_toplevel_new(struct wl_client *client, uint32_t version, uint32_t id, struct xdg_surface *xdg_surface)
    336 {
    337 	struct xdg_toplevel *toplevel;
    338 
    339 	toplevel = malloc(sizeof(*toplevel));
    340 	if (!toplevel)
    341 		goto error0;
    342 	toplevel->xdg_surface = xdg_surface;
    343 	toplevel->resource = wl_resource_create(client, &xdg_toplevel_interface, version, id);
    344 	if (!toplevel->resource)
    345 		goto error1;
    346 	window_initialize(&toplevel->window, &toplevel_window_impl, xdg_surface->surface);
    347 	wl_array_init(&toplevel->states);
    348 	wl_resource_set_implementation(toplevel->resource, &toplevel_impl, toplevel, &destroy_toplevel);
    349 	window_manage(&toplevel->window);
    350 
    351 	return toplevel;
    352 
    353 error1:
    354 	free(toplevel);
    355 error0:
    356 	return NULL;
    357 }
    358 
    359 /* xdg_surface */
    360 static void
    361 get_toplevel(struct wl_client *client, struct wl_resource *resource, uint32_t id)
    362 {
    363 	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
    364 	struct xdg_toplevel *toplevel;
    365 
    366 	if (xdg_surface->role) {
    367 		wl_resource_post_error(resource, XDG_WM_BASE_ERROR_ROLE, "surface already has a role");
    368 		return;
    369 	}
    370 	toplevel = xdg_toplevel_new(client, wl_resource_get_version(resource), id, xdg_surface);
    371 	if (!toplevel) {
    372 		wl_client_post_no_memory(client);
    373 		return;
    374 	}
    375 	xdg_surface->role = toplevel->resource;
    376 	wl_resource_add_destroy_listener(xdg_surface->role, &xdg_surface->role_destroy_listener);
    377 }
    378 
    379 static void
    380 get_popup(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *parent, struct wl_resource *positioner)
    381 {
    382 }
    383 
    384 static void
    385 ack_configure(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
    386 {
    387 	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
    388 	struct window *window;
    389 
    390 	if (!xdg_surface->role)
    391 		return;
    392 	window = wl_resource_get_user_data(xdg_surface->role);
    393 	if (window && serial == xdg_surface->configure_serial)
    394 		window->configure.acknowledged = true;
    395 }
    396 
    397 static void
    398 set_window_geometry(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
    399 {
    400 }
    401 
    402 static const struct xdg_surface_interface xdg_surface_impl = {
    403 	.destroy = destroy_resource,
    404 	.get_toplevel = get_toplevel,
    405 	.get_popup = get_popup,
    406 	.ack_configure = ack_configure,
    407 	.set_window_geometry = set_window_geometry,
    408 };
    409 
    410 static void
    411 handle_surface_destroy(struct wl_listener *listener, void *data)
    412 {
    413 	struct xdg_surface *xdg_surface = wl_container_of(listener, xdg_surface, surface_destroy_listener);
    414 
    415 	wl_resource_destroy(xdg_surface->resource);
    416 }
    417 
    418 static void
    419 handle_role_destroy(struct wl_listener *listener, void *data)
    420 {
    421 	struct xdg_surface *xdg_surface = wl_container_of(listener, xdg_surface, role_destroy_listener);
    422 
    423 	xdg_surface->role = NULL;
    424 }
    425 
    426 static void
    427 destroy_xdg_surface(struct wl_resource *resource)
    428 {
    429 	struct xdg_surface *xdg_surface = wl_resource_get_user_data(resource);
    430 
    431 	wl_list_remove(&xdg_surface->surface_destroy_listener.link);
    432 	if (xdg_surface->role)
    433 		wl_resource_destroy(xdg_surface->role);
    434 	free(xdg_surface);
    435 }
    436 
    437 static struct xdg_surface *
    438 xdg_surface_new(struct wl_client *client, uint32_t version, uint32_t id, struct surface *surface)
    439 {
    440 	struct xdg_surface *xdg_surface;
    441 
    442 	xdg_surface = malloc(sizeof(*xdg_surface));
    443 	if (!xdg_surface)
    444 		goto error0;
    445 	xdg_surface->resource = wl_resource_create(client, &xdg_surface_interface, version, id);
    446 	if (!xdg_surface->resource)
    447 		goto error1;
    448 	xdg_surface->surface = surface;
    449 	xdg_surface->surface_destroy_listener.notify = &handle_surface_destroy;
    450 	xdg_surface->role = NULL;
    451 	xdg_surface->role_destroy_listener.notify = &handle_role_destroy;
    452 	wl_resource_add_destroy_listener(surface->resource, &xdg_surface->surface_destroy_listener);
    453 	wl_resource_set_implementation(xdg_surface->resource, &xdg_surface_impl, xdg_surface, destroy_xdg_surface);
    454 
    455 	return xdg_surface;
    456 
    457 error1:
    458 	free(xdg_surface);
    459 error0:
    460 	return NULL;
    461 }
    462 
    463 /* xdg_shell */
    464 static void
    465 create_positioner(struct wl_client *client, struct wl_resource *resource, uint32_t id)
    466 {
    467 	struct xdg_positioner *positioner;
    468 	uint32_t version;
    469 
    470 	positioner = malloc(sizeof(*positioner));
    471 	if (!positioner)
    472 		goto error0;
    473 	version = wl_resource_get_version(resource);
    474 	positioner->resource = wl_resource_create(client, &xdg_positioner_interface, version, id);
    475 	if (!positioner->resource)
    476 		goto error1;
    477 	wl_resource_set_implementation(positioner->resource, &positioner_impl, positioner, &destroy_positioner);
    478 	return;
    479 
    480 error1:
    481 	free(positioner);
    482 error0:
    483 	wl_resource_post_no_memory(resource);
    484 }
    485 
    486 static void
    487 get_xdg_surface(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource)
    488 {
    489 	struct xdg_surface *xdg_surface;
    490 	struct surface *surface = wl_resource_get_user_data(surface_resource);
    491 
    492 	xdg_surface = xdg_surface_new(client, wl_resource_get_version(resource), id, surface);
    493 	if (!xdg_surface)
    494 		wl_client_post_no_memory(client);
    495 }
    496 
    497 static void
    498 pong(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
    499 {
    500 }
    501 
    502 static const struct xdg_wm_base_interface wm_base_impl = {
    503 	.destroy = destroy_resource,
    504 	.create_positioner = create_positioner,
    505 	.get_xdg_surface = get_xdg_surface,
    506 	.pong = pong,
    507 };
    508 
    509 static void
    510 bind_wm_base(struct wl_client *client, void *data, uint32_t version, uint32_t id)
    511 {
    512 	struct wl_resource *resource;
    513 
    514 	resource = wl_resource_create(client, &xdg_wm_base_interface, version, id);
    515 	if (!resource) {
    516 		wl_client_post_no_memory(client);
    517 		return;
    518 	}
    519 	wl_resource_set_implementation(resource, &wm_base_impl, NULL, NULL);
    520 }
    521 
    522 struct wl_global *
    523 xdg_shell_create(struct wl_display *display)
    524 {
    525 	return wl_global_create(display, &xdg_wm_base_interface, 1, NULL, &bind_wm_base);
    526 }