diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index d8fc53e2..81faba81 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -100,19 +100,6 @@ struct wlr_surface *desktop_surface_at(struct roots_desktop *desktop, double lx, double ly, double *sx, double *sy, struct roots_view **view); -struct roots_view *view_create(struct roots_desktop *desktop); -void view_destroy(struct roots_view *view); -void view_activate(struct roots_view *view, bool activate); -void view_apply_damage(struct roots_view *view); -void view_damage_whole(struct roots_view *view); -void view_update_position(struct roots_view *view, int x, int y); -void view_update_size(struct roots_view *view, int width, int height); -void view_update_decorated(struct roots_view *view, bool decorated); -void view_initial_focus(struct roots_view *view); -void view_map(struct roots_view *view, struct wlr_surface *surface); -void view_unmap(struct roots_view *view); -void view_arrange_maximized(struct roots_view *view); - void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_xdg_shell_surface(struct wl_listener *listener, void *data); void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data); diff --git a/include/rootston/view.h b/include/rootston/view.h index 0174e4f3..f8a969c4 100644 --- a/include/rootston/view.h +++ b/include/rootston/view.h @@ -9,80 +9,18 @@ #include #include -struct roots_wl_shell_surface { - struct roots_view *view; +struct roots_view; - struct wl_listener destroy; - struct wl_listener new_popup; - struct wl_listener request_move; - struct wl_listener request_resize; - struct wl_listener request_maximize; - struct wl_listener request_fullscreen; - struct wl_listener set_state; - struct wl_listener set_title; - struct wl_listener set_class; - - struct wl_listener surface_commit; -}; - -struct roots_xdg_surface_v6 { - struct roots_view *view; - - struct wl_listener destroy; - struct wl_listener new_popup; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener request_move; - struct wl_listener request_resize; - struct wl_listener request_maximize; - struct wl_listener request_fullscreen; - struct wl_listener set_title; - struct wl_listener set_app_id; - - struct wl_listener surface_commit; - - uint32_t pending_move_resize_configure_serial; -}; - -struct roots_xdg_toplevel_decoration; - -struct roots_xdg_surface { - struct roots_view *view; - - struct wl_listener destroy; - struct wl_listener new_popup; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener request_move; - struct wl_listener request_resize; - struct wl_listener request_maximize; - struct wl_listener request_fullscreen; - struct wl_listener set_title; - struct wl_listener set_app_id; - - - struct wl_listener surface_commit; - - uint32_t pending_move_resize_configure_serial; - - struct roots_xdg_toplevel_decoration *xdg_toplevel_decoration; -}; - -struct roots_xwayland_surface { - struct roots_view *view; - - struct wl_listener destroy; - struct wl_listener request_configure; - struct wl_listener request_move; - struct wl_listener request_resize; - struct wl_listener request_maximize; - struct wl_listener request_fullscreen; - struct wl_listener map; - struct wl_listener unmap; - struct wl_listener set_title; - struct wl_listener set_class; - - struct wl_listener surface_commit; +struct roots_view_interface { + void (*activate)(struct roots_view *view, bool active); + void (*move)(struct roots_view *view, double x, double y); + void (*resize)(struct roots_view *view, uint32_t width, uint32_t height); + void (*move_resize)(struct roots_view *view, double x, double y, + uint32_t width, uint32_t height); + void (*maximize)(struct roots_view *view, bool maximized); + void (*set_fullscreen)(struct roots_view *view, bool fullscreen); + void (*close)(struct roots_view *view); + void (*destroy)(struct roots_view *view); }; enum roots_view_type { @@ -95,6 +33,8 @@ enum roots_view_type { }; struct roots_view { + enum roots_view_type type; + const struct roots_view_interface *impl; struct roots_desktop *desktop; struct wl_list link; // roots_desktop::views @@ -120,25 +60,6 @@ struct roots_view { uint32_t width, height; } pending_move_resize; - // TODO: Something for roots-enforced width/height - enum roots_view_type type; - union { - struct wlr_wl_shell_surface *wl_shell_surface; - struct wlr_xdg_surface_v6 *xdg_surface_v6; - struct wlr_xdg_surface *xdg_surface; -#if WLR_HAS_XWAYLAND - struct wlr_xwayland_surface *xwayland_surface; -#endif - }; - union { - struct roots_wl_shell_surface *roots_wl_shell_surface; - struct roots_xdg_surface_v6 *roots_xdg_surface_v6; - struct roots_xdg_surface *roots_xdg_surface; -#if WLR_HAS_XWAYLAND - struct roots_xwayland_surface *roots_xwayland_surface; -#endif - }; - struct wlr_surface *wlr_surface; struct wl_list children; // roots_view_child::link @@ -153,28 +74,107 @@ struct roots_view { struct wl_signal unmap; struct wl_signal destroy; } events; +}; - // TODO: this should follow the typical type/impl pattern we use elsewhere - void (*activate)(struct roots_view *view, bool active); - void (*move)(struct roots_view *view, double x, double y); - void (*resize)(struct roots_view *view, uint32_t width, uint32_t height); - void (*move_resize)(struct roots_view *view, double x, double y, - uint32_t width, uint32_t height); - void (*maximize)(struct roots_view *view, bool maximized); - void (*set_fullscreen)(struct roots_view *view, bool fullscreen); - void (*close)(struct roots_view *view); - void (*destroy)(struct roots_view *view); +struct roots_wl_shell_surface { + struct roots_view view; + + struct wlr_wl_shell_surface *wl_shell_surface; + + struct wl_listener destroy; + struct wl_listener new_popup; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_fullscreen; + struct wl_listener set_state; + struct wl_listener set_title; + struct wl_listener set_class; + + struct wl_listener surface_commit; +}; + +struct roots_xdg_surface_v6 { + struct roots_view view; + + struct wlr_xdg_surface_v6 *xdg_surface_v6; + + struct wl_listener destroy; + struct wl_listener new_popup; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_fullscreen; + struct wl_listener set_title; + struct wl_listener set_app_id; + + struct wl_listener surface_commit; + + uint32_t pending_move_resize_configure_serial; +}; + +struct roots_xdg_toplevel_decoration; + +struct roots_xdg_surface { + struct roots_view view; + + struct wlr_xdg_surface *xdg_surface; + + struct wl_listener destroy; + struct wl_listener new_popup; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_fullscreen; + struct wl_listener set_title; + struct wl_listener set_app_id; + + struct wl_listener surface_commit; + + uint32_t pending_move_resize_configure_serial; + + struct roots_xdg_toplevel_decoration *xdg_toplevel_decoration; +}; + +#if WLR_HAS_XWAYLAND +struct roots_xwayland_surface { + struct roots_view view; + + struct wlr_xwayland_surface *xwayland_surface; + + struct wl_listener destroy; + struct wl_listener request_configure; + struct wl_listener request_move; + struct wl_listener request_resize; + struct wl_listener request_maximize; + struct wl_listener request_fullscreen; + struct wl_listener map; + struct wl_listener unmap; + struct wl_listener set_title; + struct wl_listener set_class; + + struct wl_listener surface_commit; +}; +#endif + +struct roots_view_child; + +struct roots_view_child_interface { + void (*destroy)(struct roots_view_child *child); }; struct roots_view_child { struct roots_view *view; + const struct roots_view_child_interface *impl; struct wlr_surface *wlr_surface; struct wl_list link; struct wl_listener commit; struct wl_listener new_subsurface; - - void (*destroy)(struct roots_view_child *child); }; struct roots_subsurface { @@ -219,6 +219,19 @@ struct roots_xdg_toplevel_decoration { struct wl_listener surface_commit; }; +void view_init(struct roots_view *view, const struct roots_view_interface *impl, + enum roots_view_type type, struct roots_desktop *desktop); +void view_destroy(struct roots_view *view); +void view_activate(struct roots_view *view, bool activate); +void view_apply_damage(struct roots_view *view); +void view_damage_whole(struct roots_view *view); +void view_update_position(struct roots_view *view, int x, int y); +void view_update_size(struct roots_view *view, int width, int height); +void view_update_decorated(struct roots_view *view, bool decorated); +void view_initial_focus(struct roots_view *view); +void view_map(struct roots_view *view, struct wlr_surface *surface); +void view_unmap(struct roots_view *view); +void view_arrange_maximized(struct roots_view *view); void view_get_box(const struct roots_view *view, struct wlr_box *box); void view_activate(struct roots_view *view, bool active); void view_move(struct roots_view *view, double x, double y); @@ -234,13 +247,19 @@ void view_close(struct roots_view *view); bool view_center(struct roots_view *view); void view_setup(struct roots_view *view); void view_teardown(struct roots_view *view); - void view_set_title(struct roots_view *view, const char *title); void view_set_app_id(struct roots_view *view, const char *app_id); void view_create_foreign_toplevel_handle(struct roots_view *view); - void view_get_deco_box(const struct roots_view *view, struct wlr_box *box); +struct roots_wl_shell_surface *roots_wl_shell_surface_from_view( + struct roots_view *view); +struct roots_xdg_surface *roots_xdg_surface_from_view(struct roots_view *view); +struct roots_xdg_surface_v6 *roots_xdg_surface_v6_from_view( + struct roots_view *view); +struct roots_xwayland_surface *roots_xwayland_surface_from_view( + struct roots_view *view); + enum roots_deco_part { ROOTS_DECO_PART_NONE = 0, ROOTS_DECO_PART_TOP_BORDER = (1 << 0), @@ -252,9 +271,10 @@ enum roots_deco_part { enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, double sy); -void view_child_init(struct roots_view_child *child, struct roots_view *view, +void view_child_init(struct roots_view_child *child, + const struct roots_view_child_interface *impl, struct roots_view *view, struct wlr_surface *wlr_surface); -void view_child_finish(struct roots_view_child *child); +void view_child_destroy(struct roots_view_child *child); struct roots_subsurface *subsurface_create(struct roots_view *view, struct wlr_subsurface *wlr_subsurface); diff --git a/rootston/bindings.c b/rootston/bindings.c index 057c17e9..9dc2223e 100644 --- a/rootston/bindings.c +++ b/rootston/bindings.c @@ -4,6 +4,7 @@ #include #include #include "rootston/bindings.h" +#include "rootston/view.h" static bool outputs_enabled = true; @@ -83,8 +84,10 @@ void execute_binding_command(struct roots_seat *seat, } else if (strcmp(command, "toggle_decoration_mode") == 0) { struct roots_view *focus = roots_seat_get_focus(seat); if (focus != NULL && focus->type == ROOTS_XDG_SHELL_VIEW) { + struct roots_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(focus); struct roots_xdg_toplevel_decoration *decoration = - focus->roots_xdg_surface->xdg_toplevel_decoration; + xdg_surface->xdg_toplevel_decoration; if (decoration != NULL) { enum wlr_xdg_toplevel_decoration_v1_mode mode = decoration->wlr_decoration->current_mode; diff --git a/rootston/desktop.c b/rootston/desktop.c index 63ff1382..147cc084 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -36,663 +36,14 @@ #include "rootston/xcursor.h" #include "wlr-layer-shell-unstable-v1-protocol.h" -struct roots_view *view_create(struct roots_desktop *desktop) { - struct roots_view *view = calloc(1, sizeof(struct roots_view)); - if (!view) { - return NULL; - } - view->desktop = desktop; - view->alpha = 1.0f; - wl_signal_init(&view->events.unmap); - wl_signal_init(&view->events.destroy); - wl_list_init(&view->children); - return view; -} - -void view_get_box(const struct roots_view *view, struct wlr_box *box) { - box->x = view->box.x; - box->y = view->box.y; - box->width = view->box.width; - box->height = view->box.height; -} - -void view_get_deco_box(const struct roots_view *view, struct wlr_box *box) { - view_get_box(view, box); - if (!view->decorated) { - return; - } - - box->x -= view->border_width; - box->y -= (view->border_width + view->titlebar_height); - box->width += view->border_width * 2; - box->height += (view->border_width * 2 + view->titlebar_height); -} - -enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, - double sy) { - if (!view->decorated) { - return ROOTS_DECO_PART_NONE; - } - - int sw = view->wlr_surface->current.width; - int sh = view->wlr_surface->current.height; - int bw = view->border_width; - int titlebar_h = view->titlebar_height; - - if (sx > 0 && sx < sw && sy < 0 && sy > -view->titlebar_height) { - return ROOTS_DECO_PART_TITLEBAR; - } - - enum roots_deco_part parts = 0; - if (sy >= -(titlebar_h + bw) && - sy <= sh + bw) { - if (sx < 0 && sx > -bw) { - parts |= ROOTS_DECO_PART_LEFT_BORDER; - } else if (sx > sw && sx < sw + bw) { - parts |= ROOTS_DECO_PART_RIGHT_BORDER; - } - } - - if (sx >= -bw && sx <= sw + bw) { - if (sy > sh && sy <= sh + bw) { - parts |= ROOTS_DECO_PART_BOTTOM_BORDER; - } else if (sy >= -(titlebar_h + bw) && sy < 0) { - parts |= ROOTS_DECO_PART_TOP_BORDER; - } - } - - // TODO corners - - return parts; -} - -static void view_update_output(const struct roots_view *view, - const struct wlr_box *before) { - struct roots_desktop *desktop = view->desktop; - - if (view->wlr_surface == NULL) { - return; - } - - struct wlr_box box; - view_get_box(view, &box); - - struct roots_output *output; - wl_list_for_each(output, &desktop->outputs, link) { - bool intersected = before != NULL && wlr_output_layout_intersects( - desktop->layout, output->wlr_output, before); - bool intersects = wlr_output_layout_intersects(desktop->layout, - output->wlr_output, &box); - if (intersected && !intersects) { - wlr_surface_send_leave(view->wlr_surface, output->wlr_output); - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_output_leave( - view->toplevel_handle, output->wlr_output); - } - } - if (!intersected && intersects) { - wlr_surface_send_enter(view->wlr_surface, output->wlr_output); - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_output_enter( - view->toplevel_handle, output->wlr_output); - } - } - } -} - -void view_move(struct roots_view *view, double x, double y) { - if (view->box.x == x && view->box.y == y) { - return; - } - - struct wlr_box before; - view_get_box(view, &before); - if (view->move) { - view->move(view, x, y); - } else { - view_update_position(view, x, y); - } - view_update_output(view, &before); -} - -void view_activate(struct roots_view *view, bool activate) { - if (view->activate) { - view->activate(view, activate); - } - - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_set_activated(view->toplevel_handle, - activate); - } -} - -void view_resize(struct roots_view *view, uint32_t width, uint32_t height) { - struct wlr_box before; - view_get_box(view, &before); - if (view->resize) { - view->resize(view, width, height); - } - view_update_output(view, &before); -} - -void view_move_resize(struct roots_view *view, double x, double y, - uint32_t width, uint32_t height) { - bool update_x = x != view->box.x; - bool update_y = y != view->box.y; - if (!update_x && !update_y) { - view_resize(view, width, height); - return; - } - - if (view->move_resize) { - view->move_resize(view, x, y, width, height); - return; - } - - view->pending_move_resize.update_x = update_x; - view->pending_move_resize.update_y = update_y; - view->pending_move_resize.x = x; - view->pending_move_resize.y = y; - view->pending_move_resize.width = width; - view->pending_move_resize.height = height; - - view_resize(view, width, height); -} - -static struct wlr_output *view_get_output(struct roots_view *view) { - struct wlr_box view_box; - view_get_box(view, &view_box); - - double output_x, output_y; - wlr_output_layout_closest_point(view->desktop->layout, NULL, - view->box.x + (double)view_box.width/2, - view->box.y + (double)view_box.height/2, - &output_x, &output_y); - return wlr_output_layout_output_at(view->desktop->layout, output_x, - output_y); -} - -void view_arrange_maximized(struct roots_view *view) { - if (view->fullscreen_output != NULL) { - return; - } - - struct wlr_box view_box; - view_get_box(view, &view_box); - - struct wlr_output *output = view_get_output(view); - struct roots_output *roots_output = output->data; - struct wlr_box *output_box = - wlr_output_layout_get_box(view->desktop->layout, output); - struct wlr_box usable_area; - memcpy(&usable_area, &roots_output->usable_area, - sizeof(struct wlr_box)); - usable_area.x += output_box->x; - usable_area.y += output_box->y; - - view_move_resize(view, usable_area.x, usable_area.y, - usable_area.width, usable_area.height); - view_rotate(view, 0); -} - -void view_maximize(struct roots_view *view, bool maximized) { - if (view->maximized == maximized || view->fullscreen_output != NULL) { - return; - } - - if (view->maximize) { - view->maximize(view, maximized); - } - - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_set_maximized(view->toplevel_handle, - maximized); - } - - if (!view->maximized && maximized) { - view->maximized = true; - view->saved.x = view->box.x; - view->saved.y = view->box.y; - view->saved.rotation = view->rotation; - view->saved.width = view->box.width; - view->saved.height = view->box.height; - - view_arrange_maximized(view); - } - - if (view->maximized && !maximized) { - view->maximized = false; - - view_move_resize(view, view->saved.x, view->saved.y, view->saved.width, - view->saved.height); - view_rotate(view, view->saved.rotation); - } -} - -void view_set_fullscreen(struct roots_view *view, bool fullscreen, - struct wlr_output *output) { - bool was_fullscreen = view->fullscreen_output != NULL; - if (was_fullscreen == fullscreen) { - // TODO: support changing the output? - return; - } - - // TODO: check if client is focused? - - if (view->set_fullscreen) { - view->set_fullscreen(view, fullscreen); - } - - if (!was_fullscreen && fullscreen) { - if (output == NULL) { - output = view_get_output(view); - } - struct roots_output *roots_output = - desktop_output_from_wlr_output(view->desktop, output); - if (roots_output == NULL) { - return; - } - - struct wlr_box view_box; - view_get_box(view, &view_box); - - view->saved.x = view->box.x; - view->saved.y = view->box.y; - view->saved.rotation = view->rotation; - view->saved.width = view_box.width; - view->saved.height = view_box.height; - - struct wlr_box *output_box = - wlr_output_layout_get_box(view->desktop->layout, output); - view_move_resize(view, output_box->x, output_box->y, output_box->width, - output_box->height); - view_rotate(view, 0); - - roots_output->fullscreen_view = view; - view->fullscreen_output = roots_output; - output_damage_whole(roots_output); - } - - if (was_fullscreen && !fullscreen) { - view_move_resize(view, view->saved.x, view->saved.y, view->saved.width, - view->saved.height); - view_rotate(view, view->saved.rotation); - - output_damage_whole(view->fullscreen_output); - view->fullscreen_output->fullscreen_view = NULL; - view->fullscreen_output = NULL; - } -} - -void view_rotate(struct roots_view *view, float rotation) { - if (view->rotation == rotation) { - return; - } - - view_damage_whole(view); - view->rotation = rotation; - view_damage_whole(view); -} - -void view_cycle_alpha(struct roots_view *view) { - view->alpha -= 0.05; - /* Don't go completely transparent */ - if (view->alpha < 0.1) { - view->alpha = 1.0; - } - view_damage_whole(view); -} - -void view_close(struct roots_view *view) { - if (view->close) { - view->close(view); - } -} - -bool view_center(struct roots_view *view) { - struct wlr_box box; - view_get_box(view, &box); - - struct roots_desktop *desktop = view->desktop; - struct roots_input *input = desktop->server->input; - struct roots_seat *seat = input_last_active_seat(input); - if (!seat) { - return false; - } - - struct wlr_output *output = - wlr_output_layout_output_at(desktop->layout, - seat->cursor->cursor->x, - seat->cursor->cursor->y); - if (!output) { - // empty layout - return false; - } - - const struct wlr_output_layout_output *l_output = - wlr_output_layout_get(desktop->layout, output); - - int width, height; - wlr_output_effective_resolution(output, &width, &height); - - double view_x = (double)(width - box.width) / 2 + l_output->x; - double view_y = (double)(height - box.height) / 2 + l_output->y; - view_move(view, view_x, view_y); - - return true; -} - -void view_child_finish(struct roots_view_child *child) { - if (child == NULL) { - return; - } - view_damage_whole(child->view); - wl_list_remove(&child->link); - wl_list_remove(&child->commit.link); - wl_list_remove(&child->new_subsurface.link); -} - -static void view_child_handle_commit(struct wl_listener *listener, - void *data) { - struct roots_view_child *child = wl_container_of(listener, child, commit); - view_apply_damage(child->view); -} - -static void view_child_handle_new_subsurface(struct wl_listener *listener, - void *data) { - struct roots_view_child *child = - wl_container_of(listener, child, new_subsurface); - struct wlr_subsurface *wlr_subsurface = data; - subsurface_create(child->view, wlr_subsurface); -} - -void view_child_init(struct roots_view_child *child, struct roots_view *view, - struct wlr_surface *wlr_surface) { - assert(child->destroy); - child->view = view; - child->wlr_surface = wlr_surface; - child->commit.notify = view_child_handle_commit; - wl_signal_add(&wlr_surface->events.commit, &child->commit); - child->new_subsurface.notify = view_child_handle_new_subsurface; - wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface); - wl_list_insert(&view->children, &child->link); -} - -static void subsurface_destroy(struct roots_view_child *child) { - assert(child->destroy == subsurface_destroy); - struct roots_subsurface *subsurface = (struct roots_subsurface *)child; - if (subsurface == NULL) { - return; - } - wl_list_remove(&subsurface->destroy.link); - wl_list_remove(&subsurface->map.link); - wl_list_remove(&subsurface->unmap.link); - view_child_finish(&subsurface->view_child); - free(subsurface); -} - -static void subsurface_handle_destroy(struct wl_listener *listener, - void *data) { - struct roots_subsurface *subsurface = - wl_container_of(listener, subsurface, destroy); - subsurface_destroy(&subsurface->view_child); -} - -static void subsurface_handle_map(struct wl_listener *listener, - void *data) { - struct roots_subsurface *subsurface = - wl_container_of(listener, subsurface, map); - struct roots_view *view = subsurface->view_child.view; - view_damage_whole(view); - input_update_cursor_focus(view->desktop->server->input); -} - -static void subsurface_handle_unmap(struct wl_listener *listener, - void *data) { - struct roots_subsurface *subsurface = - wl_container_of(listener, subsurface, unmap); - struct roots_view *view = subsurface->view_child.view; - view_damage_whole(view); - input_update_cursor_focus(view->desktop->server->input); -} - -struct roots_subsurface *subsurface_create(struct roots_view *view, - struct wlr_subsurface *wlr_subsurface) { - struct roots_subsurface *subsurface = - calloc(1, sizeof(struct roots_subsurface)); - if (subsurface == NULL) { - return NULL; - } - subsurface->wlr_subsurface = wlr_subsurface; - subsurface->view_child.destroy = subsurface_destroy; - view_child_init(&subsurface->view_child, view, wlr_subsurface->surface); - subsurface->destroy.notify = subsurface_handle_destroy; - wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); - subsurface->map.notify = subsurface_handle_map; - wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); - subsurface->unmap.notify = subsurface_handle_unmap; - wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap); - return subsurface; -} - -void view_destroy(struct roots_view *view) { - if (view == NULL) { - return; - } - - wl_signal_emit(&view->events.destroy, view); - - if (view->wlr_surface != NULL) { - view_unmap(view); - } - - // Can happen if fullscreened while unmapped, and hasn't been mapped - if (view->fullscreen_output != NULL) { - view->fullscreen_output->fullscreen_view = NULL; - } - - if (view->destroy) { - view->destroy(view); - } - - free(view); -} - -static void view_handle_new_subsurface(struct wl_listener *listener, - void *data) { - struct roots_view *view = wl_container_of(listener, view, new_subsurface); - struct wlr_subsurface *wlr_subsurface = data; - subsurface_create(view, wlr_subsurface); -} - -void view_map(struct roots_view *view, struct wlr_surface *surface) { - assert(view->wlr_surface == NULL); - - view->wlr_surface = surface; - - struct wlr_subsurface *subsurface; - wl_list_for_each(subsurface, &view->wlr_surface->subsurfaces, - parent_link) { - subsurface_create(view, subsurface); - } - - view->new_subsurface.notify = view_handle_new_subsurface; - wl_signal_add(&view->wlr_surface->events.new_subsurface, - &view->new_subsurface); - - wl_list_insert(&view->desktop->views, &view->link); - view_damage_whole(view); - input_update_cursor_focus(view->desktop->server->input); -} - -void view_unmap(struct roots_view *view) { - assert(view->wlr_surface != NULL); - - wl_signal_emit(&view->events.unmap, view); - - view_damage_whole(view); - wl_list_remove(&view->link); - - wl_list_remove(&view->new_subsurface.link); - - struct roots_view_child *child, *tmp; - wl_list_for_each_safe(child, tmp, &view->children, link) { - child->destroy(child); - } - - if (view->fullscreen_output != NULL) { - output_damage_whole(view->fullscreen_output); - view->fullscreen_output->fullscreen_view = NULL; - view->fullscreen_output = NULL; - } - - view->wlr_surface = NULL; - view->box.width = view->box.height = 0; - - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_destroy(view->toplevel_handle); - view->toplevel_handle = NULL; - } -} - -void view_initial_focus(struct roots_view *view) { - struct roots_input *input = view->desktop->server->input; - // TODO what seat gets focus? the one with the last input event? - struct roots_seat *seat; - wl_list_for_each(seat, &input->seats, link) { - roots_seat_set_focus(seat, view); - } -} - -void view_setup(struct roots_view *view) { - view_initial_focus(view); - - if (view->fullscreen_output == NULL && !view->maximized) { - view_center(view); - } - - view_create_foreign_toplevel_handle(view); - view_update_output(view, NULL); -} - -void view_apply_damage(struct roots_view *view) { - struct roots_output *output; - wl_list_for_each(output, &view->desktop->outputs, link) { - output_damage_from_view(output, view); - } -} - -void view_damage_whole(struct roots_view *view) { - struct roots_output *output; - wl_list_for_each(output, &view->desktop->outputs, link) { - output_damage_whole_view(output, view); - } -} - -void view_update_position(struct roots_view *view, int x, int y) { - if (view->box.x == x && view->box.y == y) { - return; - } - - view_damage_whole(view); - view->box.x = x; - view->box.y = y; - view_damage_whole(view); -} - -void view_update_size(struct roots_view *view, int width, int height) { - if (view->box.width == width && view->box.height == height) { - return; - } - - view_damage_whole(view); - view->box.width = width; - view->box.height = height; - view_damage_whole(view); -} - -void view_update_decorated(struct roots_view *view, bool decorated) { - if (view->decorated == decorated) { - return; - } - - view_damage_whole(view); - view->decorated = decorated; - if (decorated) { - view->border_width = 4; - view->titlebar_height = 12; - } else { - view->border_width = 0; - view->titlebar_height = 0; - } - view_damage_whole(view); -} - -void view_set_title(struct roots_view *view, const char *title) { - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, title); - } -} - -void view_set_app_id(struct roots_view *view, const char *app_id) { - if (view->toplevel_handle) { - wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, app_id); - } -} - -static void handle_toplevel_handle_request_maximize(struct wl_listener *listener, - void *data) { - struct roots_view *view = wl_container_of(listener, view, - toplevel_handle_request_maximize); - struct wlr_foreign_toplevel_handle_v1_maximized_event *event = data; - view_maximize(view, event->maximized); -} - -static void handle_toplevel_handle_request_activate(struct wl_listener *listener, - void *data) { - struct roots_view *view = - wl_container_of(listener, view, toplevel_handle_request_activate); - struct wlr_foreign_toplevel_handle_v1_activated_event *event = data; - - struct roots_seat *seat; - wl_list_for_each(seat, &view->desktop->server->input->seats, link) { - if (event->seat == seat->seat) { - roots_seat_set_focus(seat, view); - } - } -} - -static void handle_toplevel_handle_request_close(struct wl_listener *listener, - void *data) { - struct roots_view *view = - wl_container_of(listener, view, toplevel_handle_request_close); - view_close(view); -} - -void view_create_foreign_toplevel_handle(struct roots_view *view) { - view->toplevel_handle = - wlr_foreign_toplevel_handle_v1_create( - view->desktop->foreign_toplevel_manager_v1); - - view->toplevel_handle_request_maximize.notify = - handle_toplevel_handle_request_maximize; - wl_signal_add(&view->toplevel_handle->events.request_maximize, - &view->toplevel_handle_request_maximize); - view->toplevel_handle_request_activate.notify = - handle_toplevel_handle_request_activate; - wl_signal_add(&view->toplevel_handle->events.request_activate, - &view->toplevel_handle_request_activate); - view->toplevel_handle_request_close.notify = - handle_toplevel_handle_request_close; - wl_signal_add(&view->toplevel_handle->events.request_close, - &view->toplevel_handle_request_close); -} - static bool view_at(struct roots_view *view, double lx, double ly, struct wlr_surface **surface, double *sx, double *sy) { - if (view->type == ROOTS_WL_SHELL_VIEW && - view->wl_shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP) { - return false; + if (view->type == ROOTS_WL_SHELL_VIEW) { + struct wlr_wl_shell_surface *wl_shell_surface = + roots_wl_shell_surface_from_view(view)->wl_shell_surface; + if (wl_shell_surface->state == WLR_WL_SHELL_SURFACE_STATE_POPUP) { + return false; + } } if (view->wlr_surface == NULL) { return false; @@ -720,17 +71,23 @@ static bool view_at(struct roots_view *view, double lx, double ly, double _sx, _sy; struct wlr_surface *_surface = NULL; switch (view->type) { - case ROOTS_XDG_SHELL_V6_VIEW: - _surface = wlr_xdg_surface_v6_surface_at(view->xdg_surface_v6, + case ROOTS_XDG_SHELL_V6_VIEW:; + struct roots_xdg_surface_v6 *xdg_surface_v6 = + roots_xdg_surface_v6_from_view(view); + _surface = wlr_xdg_surface_v6_surface_at(xdg_surface_v6->xdg_surface_v6, view_sx, view_sy, &_sx, &_sy); break; - case ROOTS_XDG_SHELL_VIEW: - _surface = wlr_xdg_surface_surface_at(view->xdg_surface, + case ROOTS_XDG_SHELL_VIEW:; + struct roots_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(view); + _surface = wlr_xdg_surface_surface_at(xdg_surface->xdg_surface, view_sx, view_sy, &_sx, &_sy); break; - case ROOTS_WL_SHELL_VIEW: - _surface = wlr_wl_shell_surface_surface_at(view->wl_shell_surface, - view_sx, view_sy, &_sx, &_sy); + case ROOTS_WL_SHELL_VIEW:; + struct roots_wl_shell_surface *wl_shell_surface = + roots_wl_shell_surface_from_view(view); + _surface = wlr_wl_shell_surface_surface_at( + wl_shell_surface->wl_shell_surface, view_sx, view_sy, &_sx, &_sy); break; #if WLR_HAS_XWAYLAND case ROOTS_XWAYLAND_VIEW: diff --git a/rootston/meson.build b/rootston/meson.build index db90a508..6a4fbe76 100644 --- a/rootston/meson.build +++ b/rootston/meson.build @@ -12,10 +12,11 @@ sources = [ 'seat.c', 'switch.c', 'text_input.c', + 'view.c', 'virtual_keyboard.c', 'wl_shell.c', - 'xdg_shell.c', 'xdg_shell_v6.c', + 'xdg_shell.c', ] if conf_data.get('WLR_HAS_XWAYLAND', 0) == 1 diff --git a/rootston/output.c b/rootston/output.c index 3aad1c06..74200ca9 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -43,8 +43,9 @@ struct layout_data { float rotation; }; -static void get_layout_position(struct layout_data *data, double *lx, double *ly, - const struct wlr_surface *surface, int sx, int sy) { +static void get_layout_position(struct layout_data *data, + double *lx, double *ly, const struct wlr_surface *surface, + int sx, int sy) { double _sx = sx, _sy = sy; rotate_child_position(&_sx, &_sy, surface->current.width, surface->current.height, data->width, data->height, data->rotation); @@ -78,17 +79,23 @@ static void view_for_each_surface(struct roots_view *view, layout_data->rotation = view->rotation; switch (view->type) { - case ROOTS_XDG_SHELL_V6_VIEW: - wlr_xdg_surface_v6_for_each_surface(view->xdg_surface_v6, iterator, + case ROOTS_XDG_SHELL_V6_VIEW:; + struct roots_xdg_surface_v6 *xdg_surface_v6 = + roots_xdg_surface_v6_from_view(view); + wlr_xdg_surface_v6_for_each_surface(xdg_surface_v6->xdg_surface_v6, + iterator, user_data); + break; + case ROOTS_XDG_SHELL_VIEW:; + struct roots_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(view); + wlr_xdg_surface_for_each_surface(xdg_surface->xdg_surface, iterator, user_data); break; - case ROOTS_XDG_SHELL_VIEW: - wlr_xdg_surface_for_each_surface(view->xdg_surface, iterator, - user_data); - break; - case ROOTS_WL_SHELL_VIEW: - wlr_wl_shell_surface_for_each_surface(view->wl_shell_surface, iterator, - user_data); + case ROOTS_WL_SHELL_VIEW:; + struct roots_wl_shell_surface *wl_shell_surface = + roots_wl_shell_surface_from_view(view); + wlr_wl_shell_surface_for_each_surface(wl_shell_surface->wl_shell_surface, + iterator, user_data); break; #if WLR_HAS_XWAYLAND case ROOTS_XWAYLAND_VIEW: @@ -165,7 +172,10 @@ static void output_for_each_surface(struct roots_output *output, #if WLR_HAS_XWAYLAND if (view->type == ROOTS_XWAYLAND_VIEW) { - xwayland_children_for_each_surface(view->xwayland_surface, + struct roots_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view); + xwayland_children_for_each_surface( + xwayland_surface->xwayland_surface, iterator, layout_data, user_data); } #endif @@ -497,7 +507,10 @@ static void render_output(struct roots_output *output) { // the fullscreen window's children so we have to traverse the tree. #if WLR_HAS_XWAYLAND if (view->type == ROOTS_XWAYLAND_VIEW) { - xwayland_children_for_each_surface(view->xwayland_surface, + struct roots_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view); + xwayland_children_for_each_surface( + xwayland_surface->xwayland_surface, render_surface, &data.layout, &data); } #endif @@ -568,9 +581,12 @@ static bool view_accept_damage(struct roots_output *output, if (output->fullscreen_view->type == ROOTS_XWAYLAND_VIEW && view->type == ROOTS_XWAYLAND_VIEW) { // Special case: accept damage from children - struct wlr_xwayland_surface *xsurface = view->xwayland_surface; + struct wlr_xwayland_surface *xsurface = + roots_xwayland_surface_from_view(view)->xwayland_surface; + struct wlr_xwayland_surface *fullscreen_xsurface = + roots_xwayland_surface_from_view(output->fullscreen_view)->xwayland_surface; while (xsurface != NULL) { - if (output->fullscreen_view->xwayland_surface == xsurface) { + if (fullscreen_xsurface == xsurface) { return true; } xsurface = xsurface->parent; diff --git a/rootston/seat.c b/rootston/seat.c index cd95472d..385cf401 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -1293,9 +1293,12 @@ void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view) { bool unfullscreen = true; #if WLR_HAS_XWAYLAND - if (view && view->type == ROOTS_XWAYLAND_VIEW && - view->xwayland_surface->override_redirect) { - unfullscreen = false; + if (view && view->type == ROOTS_XWAYLAND_VIEW) { + struct roots_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view); + if (xwayland_surface->xwayland_surface->override_redirect) { + unfullscreen = false; + } } #endif @@ -1322,10 +1325,13 @@ void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view) { } #if WLR_HAS_XWAYLAND - if (view && view->type == ROOTS_XWAYLAND_VIEW && - !wlr_xwayland_or_surface_wants_focus( - view->xwayland_surface)) { - return; + if (view && view->type == ROOTS_XWAYLAND_VIEW) { + struct roots_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view); + if (!wlr_xwayland_or_surface_wants_focus( + xwayland_surface->xwayland_surface)) { + return; + } } #endif struct roots_seat_view *seat_view = NULL; diff --git a/rootston/view.c b/rootston/view.c new file mode 100644 index 00000000..a4c1611d --- /dev/null +++ b/rootston/view.c @@ -0,0 +1,659 @@ +#include +#include +#include +#include +#include "rootston/desktop.h" +#include "rootston/input.h" +#include "rootston/seat.h" +#include "rootston/server.h" +#include "rootston/view.h" + +void view_init(struct roots_view *view, const struct roots_view_interface *impl, + enum roots_view_type type, struct roots_desktop *desktop) { + assert(impl->destroy); + view->impl = impl; + view->type = type; + view->desktop = desktop; + view->alpha = 1.0f; + wl_signal_init(&view->events.unmap); + wl_signal_init(&view->events.destroy); + wl_list_init(&view->children); +} + +void view_destroy(struct roots_view *view) { + if (view == NULL) { + return; + } + + wl_signal_emit(&view->events.destroy, view); + + if (view->wlr_surface != NULL) { + view_unmap(view); + } + + // Can happen if fullscreened while unmapped, and hasn't been mapped + if (view->fullscreen_output != NULL) { + view->fullscreen_output->fullscreen_view = NULL; + } + + view->impl->destroy(view); +} + +void view_get_box(const struct roots_view *view, struct wlr_box *box) { + box->x = view->box.x; + box->y = view->box.y; + box->width = view->box.width; + box->height = view->box.height; +} + +void view_get_deco_box(const struct roots_view *view, struct wlr_box *box) { + view_get_box(view, box); + if (!view->decorated) { + return; + } + + box->x -= view->border_width; + box->y -= (view->border_width + view->titlebar_height); + box->width += view->border_width * 2; + box->height += (view->border_width * 2 + view->titlebar_height); +} + +enum roots_deco_part view_get_deco_part(struct roots_view *view, double sx, + double sy) { + if (!view->decorated) { + return ROOTS_DECO_PART_NONE; + } + + int sw = view->wlr_surface->current.width; + int sh = view->wlr_surface->current.height; + int bw = view->border_width; + int titlebar_h = view->titlebar_height; + + if (sx > 0 && sx < sw && sy < 0 && sy > -view->titlebar_height) { + return ROOTS_DECO_PART_TITLEBAR; + } + + enum roots_deco_part parts = 0; + if (sy >= -(titlebar_h + bw) && + sy <= sh + bw) { + if (sx < 0 && sx > -bw) { + parts |= ROOTS_DECO_PART_LEFT_BORDER; + } else if (sx > sw && sx < sw + bw) { + parts |= ROOTS_DECO_PART_RIGHT_BORDER; + } + } + + if (sx >= -bw && sx <= sw + bw) { + if (sy > sh && sy <= sh + bw) { + parts |= ROOTS_DECO_PART_BOTTOM_BORDER; + } else if (sy >= -(titlebar_h + bw) && sy < 0) { + parts |= ROOTS_DECO_PART_TOP_BORDER; + } + } + + // TODO corners + + return parts; +} + +static void view_update_output(const struct roots_view *view, + const struct wlr_box *before) { + struct roots_desktop *desktop = view->desktop; + + if (view->wlr_surface == NULL) { + return; + } + + struct wlr_box box; + view_get_box(view, &box); + + struct roots_output *output; + wl_list_for_each(output, &desktop->outputs, link) { + bool intersected = before != NULL && wlr_output_layout_intersects( + desktop->layout, output->wlr_output, before); + bool intersects = wlr_output_layout_intersects(desktop->layout, + output->wlr_output, &box); + if (intersected && !intersects) { + wlr_surface_send_leave(view->wlr_surface, output->wlr_output); + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_output_leave( + view->toplevel_handle, output->wlr_output); + } + } + if (!intersected && intersects) { + wlr_surface_send_enter(view->wlr_surface, output->wlr_output); + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_output_enter( + view->toplevel_handle, output->wlr_output); + } + } + } +} + +void view_move(struct roots_view *view, double x, double y) { + if (view->box.x == x && view->box.y == y) { + return; + } + + struct wlr_box before; + view_get_box(view, &before); + if (view->impl->move) { + view->impl->move(view, x, y); + } else { + view_update_position(view, x, y); + } + view_update_output(view, &before); +} + +void view_activate(struct roots_view *view, bool activate) { + if (view->impl->activate) { + view->impl->activate(view, activate); + } + + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_set_activated(view->toplevel_handle, + activate); + } +} + +void view_resize(struct roots_view *view, uint32_t width, uint32_t height) { + struct wlr_box before; + view_get_box(view, &before); + if (view->impl->resize) { + view->impl->resize(view, width, height); + } + view_update_output(view, &before); +} + +void view_move_resize(struct roots_view *view, double x, double y, + uint32_t width, uint32_t height) { + bool update_x = x != view->box.x; + bool update_y = y != view->box.y; + if (!update_x && !update_y) { + view_resize(view, width, height); + return; + } + + if (view->impl->move_resize) { + view->impl->move_resize(view, x, y, width, height); + return; + } + + view->pending_move_resize.update_x = update_x; + view->pending_move_resize.update_y = update_y; + view->pending_move_resize.x = x; + view->pending_move_resize.y = y; + view->pending_move_resize.width = width; + view->pending_move_resize.height = height; + + view_resize(view, width, height); +} + +static struct wlr_output *view_get_output(struct roots_view *view) { + struct wlr_box view_box; + view_get_box(view, &view_box); + + double output_x, output_y; + wlr_output_layout_closest_point(view->desktop->layout, NULL, + view->box.x + (double)view_box.width/2, + view->box.y + (double)view_box.height/2, + &output_x, &output_y); + return wlr_output_layout_output_at(view->desktop->layout, output_x, + output_y); +} + +void view_arrange_maximized(struct roots_view *view) { + if (view->fullscreen_output != NULL) { + return; + } + + struct wlr_box view_box; + view_get_box(view, &view_box); + + struct wlr_output *output = view_get_output(view); + struct roots_output *roots_output = output->data; + struct wlr_box *output_box = + wlr_output_layout_get_box(view->desktop->layout, output); + struct wlr_box usable_area; + memcpy(&usable_area, &roots_output->usable_area, + sizeof(struct wlr_box)); + usable_area.x += output_box->x; + usable_area.y += output_box->y; + + view_move_resize(view, usable_area.x, usable_area.y, + usable_area.width, usable_area.height); + view_rotate(view, 0); +} + +void view_maximize(struct roots_view *view, bool maximized) { + if (view->maximized == maximized || view->fullscreen_output != NULL) { + return; + } + + if (view->impl->maximize) { + view->impl->maximize(view, maximized); + } + + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_set_maximized(view->toplevel_handle, + maximized); + } + + if (!view->maximized && maximized) { + view->maximized = true; + view->saved.x = view->box.x; + view->saved.y = view->box.y; + view->saved.rotation = view->rotation; + view->saved.width = view->box.width; + view->saved.height = view->box.height; + + view_arrange_maximized(view); + } + + if (view->maximized && !maximized) { + view->maximized = false; + + view_move_resize(view, view->saved.x, view->saved.y, view->saved.width, + view->saved.height); + view_rotate(view, view->saved.rotation); + } +} + +void view_set_fullscreen(struct roots_view *view, bool fullscreen, + struct wlr_output *output) { + bool was_fullscreen = view->fullscreen_output != NULL; + if (was_fullscreen == fullscreen) { + // TODO: support changing the output? + return; + } + + // TODO: check if client is focused? + + if (view->impl->set_fullscreen) { + view->impl->set_fullscreen(view, fullscreen); + } + + if (!was_fullscreen && fullscreen) { + if (output == NULL) { + output = view_get_output(view); + } + struct roots_output *roots_output = + desktop_output_from_wlr_output(view->desktop, output); + if (roots_output == NULL) { + return; + } + + struct wlr_box view_box; + view_get_box(view, &view_box); + + view->saved.x = view->box.x; + view->saved.y = view->box.y; + view->saved.rotation = view->rotation; + view->saved.width = view_box.width; + view->saved.height = view_box.height; + + struct wlr_box *output_box = + wlr_output_layout_get_box(view->desktop->layout, output); + view_move_resize(view, output_box->x, output_box->y, output_box->width, + output_box->height); + view_rotate(view, 0); + + roots_output->fullscreen_view = view; + view->fullscreen_output = roots_output; + output_damage_whole(roots_output); + } + + if (was_fullscreen && !fullscreen) { + view_move_resize(view, view->saved.x, view->saved.y, view->saved.width, + view->saved.height); + view_rotate(view, view->saved.rotation); + + output_damage_whole(view->fullscreen_output); + view->fullscreen_output->fullscreen_view = NULL; + view->fullscreen_output = NULL; + } +} + +void view_rotate(struct roots_view *view, float rotation) { + if (view->rotation == rotation) { + return; + } + + view_damage_whole(view); + view->rotation = rotation; + view_damage_whole(view); +} + +void view_cycle_alpha(struct roots_view *view) { + view->alpha -= 0.05; + /* Don't go completely transparent */ + if (view->alpha < 0.1) { + view->alpha = 1.0; + } + view_damage_whole(view); +} + +void view_close(struct roots_view *view) { + if (view->impl->close) { + view->impl->close(view); + } +} + +bool view_center(struct roots_view *view) { + struct wlr_box box; + view_get_box(view, &box); + + struct roots_desktop *desktop = view->desktop; + struct roots_input *input = desktop->server->input; + struct roots_seat *seat = input_last_active_seat(input); + if (!seat) { + return false; + } + + struct wlr_output *output = wlr_output_layout_output_at(desktop->layout, + seat->cursor->cursor->x, seat->cursor->cursor->y); + if (!output) { + // empty layout + return false; + } + + const struct wlr_output_layout_output *l_output = + wlr_output_layout_get(desktop->layout, output); + + int width, height; + wlr_output_effective_resolution(output, &width, &height); + + double view_x = (double)(width - box.width) / 2 + l_output->x; + double view_y = (double)(height - box.height) / 2 + l_output->y; + view_move(view, view_x, view_y); + + return true; +} + +void view_child_destroy(struct roots_view_child *child) { + if (child == NULL) { + return; + } + view_damage_whole(child->view); + wl_list_remove(&child->link); + wl_list_remove(&child->commit.link); + wl_list_remove(&child->new_subsurface.link); + child->impl->destroy(child); +} + +static void view_child_handle_commit(struct wl_listener *listener, + void *data) { + struct roots_view_child *child = wl_container_of(listener, child, commit); + view_apply_damage(child->view); +} + +static void view_child_handle_new_subsurface(struct wl_listener *listener, + void *data) { + struct roots_view_child *child = + wl_container_of(listener, child, new_subsurface); + struct wlr_subsurface *wlr_subsurface = data; + subsurface_create(child->view, wlr_subsurface); +} + +void view_child_init(struct roots_view_child *child, + const struct roots_view_child_interface *impl, struct roots_view *view, + struct wlr_surface *wlr_surface) { + assert(impl->destroy); + child->impl = impl; + child->view = view; + child->wlr_surface = wlr_surface; + child->commit.notify = view_child_handle_commit; + wl_signal_add(&wlr_surface->events.commit, &child->commit); + child->new_subsurface.notify = view_child_handle_new_subsurface; + wl_signal_add(&wlr_surface->events.new_subsurface, &child->new_subsurface); + wl_list_insert(&view->children, &child->link); +} + +static const struct roots_view_child_interface subsurface_impl; + +static void subsurface_destroy(struct roots_view_child *child) { + assert(child->impl == &subsurface_impl); + struct roots_subsurface *subsurface = (struct roots_subsurface *)child; + wl_list_remove(&subsurface->destroy.link); + wl_list_remove(&subsurface->map.link); + wl_list_remove(&subsurface->unmap.link); + free(subsurface); +} + +static const struct roots_view_child_interface subsurface_impl = { + .destroy = subsurface_destroy, +}; + +static void subsurface_handle_destroy(struct wl_listener *listener, + void *data) { + struct roots_subsurface *subsurface = + wl_container_of(listener, subsurface, destroy); + view_child_destroy(&subsurface->view_child); +} + +static void subsurface_handle_map(struct wl_listener *listener, + void *data) { + struct roots_subsurface *subsurface = + wl_container_of(listener, subsurface, map); + struct roots_view *view = subsurface->view_child.view; + view_damage_whole(view); + input_update_cursor_focus(view->desktop->server->input); +} + +static void subsurface_handle_unmap(struct wl_listener *listener, + void *data) { + struct roots_subsurface *subsurface = + wl_container_of(listener, subsurface, unmap); + struct roots_view *view = subsurface->view_child.view; + view_damage_whole(view); + input_update_cursor_focus(view->desktop->server->input); +} + +struct roots_subsurface *subsurface_create(struct roots_view *view, + struct wlr_subsurface *wlr_subsurface) { + struct roots_subsurface *subsurface = + calloc(1, sizeof(struct roots_subsurface)); + if (subsurface == NULL) { + return NULL; + } + subsurface->wlr_subsurface = wlr_subsurface; + view_child_init(&subsurface->view_child, &subsurface_impl, + view, wlr_subsurface->surface); + subsurface->destroy.notify = subsurface_handle_destroy; + wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy); + subsurface->map.notify = subsurface_handle_map; + wl_signal_add(&wlr_subsurface->events.map, &subsurface->map); + subsurface->unmap.notify = subsurface_handle_unmap; + wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap); + return subsurface; +} + +static void view_handle_new_subsurface(struct wl_listener *listener, + void *data) { + struct roots_view *view = wl_container_of(listener, view, new_subsurface); + struct wlr_subsurface *wlr_subsurface = data; + subsurface_create(view, wlr_subsurface); +} + +void view_map(struct roots_view *view, struct wlr_surface *surface) { + assert(view->wlr_surface == NULL); + + view->wlr_surface = surface; + + struct wlr_subsurface *subsurface; + wl_list_for_each(subsurface, &view->wlr_surface->subsurfaces, + parent_link) { + subsurface_create(view, subsurface); + } + + view->new_subsurface.notify = view_handle_new_subsurface; + wl_signal_add(&view->wlr_surface->events.new_subsurface, + &view->new_subsurface); + + wl_list_insert(&view->desktop->views, &view->link); + view_damage_whole(view); + input_update_cursor_focus(view->desktop->server->input); +} + +void view_unmap(struct roots_view *view) { + assert(view->wlr_surface != NULL); + + wl_signal_emit(&view->events.unmap, view); + + view_damage_whole(view); + wl_list_remove(&view->link); + + wl_list_remove(&view->new_subsurface.link); + + struct roots_view_child *child, *tmp; + wl_list_for_each_safe(child, tmp, &view->children, link) { + view_child_destroy(child); + } + + if (view->fullscreen_output != NULL) { + output_damage_whole(view->fullscreen_output); + view->fullscreen_output->fullscreen_view = NULL; + view->fullscreen_output = NULL; + } + + view->wlr_surface = NULL; + view->box.width = view->box.height = 0; + + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_destroy(view->toplevel_handle); + view->toplevel_handle = NULL; + } +} + +void view_initial_focus(struct roots_view *view) { + struct roots_input *input = view->desktop->server->input; + // TODO what seat gets focus? the one with the last input event? + struct roots_seat *seat; + wl_list_for_each(seat, &input->seats, link) { + roots_seat_set_focus(seat, view); + } +} + +void view_setup(struct roots_view *view) { + view_initial_focus(view); + + if (view->fullscreen_output == NULL && !view->maximized) { + view_center(view); + } + + view_create_foreign_toplevel_handle(view); + view_update_output(view, NULL); +} + +void view_apply_damage(struct roots_view *view) { + struct roots_output *output; + wl_list_for_each(output, &view->desktop->outputs, link) { + output_damage_from_view(output, view); + } +} + +void view_damage_whole(struct roots_view *view) { + struct roots_output *output; + wl_list_for_each(output, &view->desktop->outputs, link) { + output_damage_whole_view(output, view); + } +} + +void view_update_position(struct roots_view *view, int x, int y) { + if (view->box.x == x && view->box.y == y) { + return; + } + + view_damage_whole(view); + view->box.x = x; + view->box.y = y; + view_damage_whole(view); +} + +void view_update_size(struct roots_view *view, int width, int height) { + if (view->box.width == width && view->box.height == height) { + return; + } + + view_damage_whole(view); + view->box.width = width; + view->box.height = height; + view_damage_whole(view); +} + +void view_update_decorated(struct roots_view *view, bool decorated) { + if (view->decorated == decorated) { + return; + } + + view_damage_whole(view); + view->decorated = decorated; + if (decorated) { + view->border_width = 4; + view->titlebar_height = 12; + } else { + view->border_width = 0; + view->titlebar_height = 0; + } + view_damage_whole(view); +} + +void view_set_title(struct roots_view *view, const char *title) { + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, title); + } +} + +void view_set_app_id(struct roots_view *view, const char *app_id) { + if (view->toplevel_handle) { + wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, app_id); + } +} + +static void handle_toplevel_handle_request_maximize(struct wl_listener *listener, + void *data) { + struct roots_view *view = wl_container_of(listener, view, + toplevel_handle_request_maximize); + struct wlr_foreign_toplevel_handle_v1_maximized_event *event = data; + view_maximize(view, event->maximized); +} + +static void handle_toplevel_handle_request_activate(struct wl_listener *listener, + void *data) { + struct roots_view *view = + wl_container_of(listener, view, toplevel_handle_request_activate); + struct wlr_foreign_toplevel_handle_v1_activated_event *event = data; + + struct roots_seat *seat; + wl_list_for_each(seat, &view->desktop->server->input->seats, link) { + if (event->seat == seat->seat) { + roots_seat_set_focus(seat, view); + } + } +} + +static void handle_toplevel_handle_request_close(struct wl_listener *listener, + void *data) { + struct roots_view *view = + wl_container_of(listener, view, toplevel_handle_request_close); + view_close(view); +} + +void view_create_foreign_toplevel_handle(struct roots_view *view) { + view->toplevel_handle = + wlr_foreign_toplevel_handle_v1_create( + view->desktop->foreign_toplevel_manager_v1); + + view->toplevel_handle_request_maximize.notify = + handle_toplevel_handle_request_maximize; + wl_signal_add(&view->toplevel_handle->events.request_maximize, + &view->toplevel_handle_request_maximize); + view->toplevel_handle_request_activate.notify = + handle_toplevel_handle_request_activate; + wl_signal_add(&view->toplevel_handle->events.request_activate, + &view->toplevel_handle_request_activate); + view->toplevel_handle_request_close.notify = + handle_toplevel_handle_request_close; + wl_signal_add(&view->toplevel_handle->events.request_close, + &view->toplevel_handle_request_close); +} diff --git a/rootston/wl_shell.c b/rootston/wl_shell.c index 2bf4f4c2..b60f6ac7 100644 --- a/rootston/wl_shell.c +++ b/rootston/wl_shell.c @@ -10,29 +10,31 @@ #include "rootston/input.h" #include "rootston/server.h" +static const struct roots_view_child_interface popup_impl; + static void popup_destroy(struct roots_view_child *child) { - assert(child->destroy == popup_destroy); + assert(child->impl == &popup_impl); struct roots_wl_shell_popup *popup = (struct roots_wl_shell_popup *)child; - if (popup == NULL) { - return; - } wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->set_state.link); wl_list_remove(&popup->new_popup.link); - view_child_finish(&popup->view_child); free(popup); } +static const struct roots_view_child_interface popup_impl = { + .destroy = popup_destroy, +}; + static void popup_handle_destroy(struct wl_listener *listener, void *data) { struct roots_wl_shell_popup *popup = wl_container_of(listener, popup, destroy); - popup_destroy((struct roots_view_child *)popup); + view_child_destroy(&popup->view_child); } static void popup_handle_set_state(struct wl_listener *listener, void *data) { struct roots_wl_shell_popup *popup = wl_container_of(listener, popup, set_state); - popup_destroy((struct roots_view_child *)popup); + view_child_destroy(&popup->view_child); } static struct roots_wl_shell_popup *popup_create(struct roots_view *view, @@ -53,8 +55,8 @@ static struct roots_wl_shell_popup *popup_create(struct roots_view *view, return NULL; } popup->wlr_wl_shell_surface = wlr_wl_shell_surface; - popup->view_child.destroy = popup_destroy; - view_child_init(&popup->view_child, view, wlr_wl_shell_surface->surface); + view_child_init(&popup->view_child, &popup_impl, + view, wlr_wl_shell_surface->surface); popup->destroy.notify = popup_handle_destroy; wl_signal_add(&wlr_wl_shell_surface->events.destroy, &popup->destroy); popup->set_state.notify = popup_handle_set_state; @@ -66,21 +68,21 @@ static struct roots_wl_shell_popup *popup_create(struct roots_view *view, static void resize(struct roots_view *view, uint32_t width, uint32_t height) { - assert(view->type == ROOTS_WL_SHELL_VIEW); - struct wlr_wl_shell_surface *surf = view->wl_shell_surface; + struct wlr_wl_shell_surface *surf = + roots_wl_shell_surface_from_view(view)->wl_shell_surface; wlr_wl_shell_surface_configure(surf, WL_SHELL_SURFACE_RESIZE_NONE, width, height); } static void close(struct roots_view *view) { - assert(view->type == ROOTS_WL_SHELL_VIEW); - struct wlr_wl_shell_surface *surf = view->wl_shell_surface; + struct wlr_wl_shell_surface *surf = + roots_wl_shell_surface_from_view(view)->wl_shell_surface; wl_client_destroy(surf->client); } static void destroy(struct roots_view *view) { - assert(view->type == ROOTS_WL_SHELL_VIEW); - struct roots_wl_shell_surface *roots_surface = view->roots_wl_shell_surface; + struct roots_wl_shell_surface *roots_surface = + roots_wl_shell_surface_from_view(view); wl_list_remove(&roots_surface->destroy.link); wl_list_remove(&roots_surface->request_move.link); wl_list_remove(&roots_surface->request_resize.link); @@ -93,10 +95,16 @@ static void destroy(struct roots_view *view) { free(roots_surface); } +static const struct roots_view_interface view_impl = { + .resize = resize, + .close = close, + .destroy = destroy, +}; + static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, request_move); - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_wl_shell_surface_move_event *e = data; struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); @@ -109,7 +117,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, request_resize); - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_wl_shell_surface_resize_event *e = data; struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); @@ -123,7 +131,7 @@ static void handle_request_maximize(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, request_maximize); - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; //struct wlr_wl_shell_surface_maximize_event *e = data; view_maximize(view, true); } @@ -132,7 +140,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, request_fullscreen); - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; struct wlr_wl_shell_surface_set_fullscreen_event *e = data; view_set_fullscreen(view, true, e->output); } @@ -140,8 +148,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, static void handle_set_state(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, set_state); - struct roots_view *view = roots_surface->view; - struct wlr_wl_shell_surface *surface = view->wl_shell_surface; + struct roots_view *view = &roots_surface->view; + struct wlr_wl_shell_surface *surface = roots_surface->wl_shell_surface; if (view->maximized && surface->state != WLR_WL_SHELL_SURFACE_STATE_MAXIMIZED) { view_maximize(view, false); @@ -155,21 +163,21 @@ static void handle_set_state(struct wl_listener *listener, void *data) { static void handle_set_title(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, set_state); - view_set_title(roots_surface->view, - roots_surface->view->wl_shell_surface->title); + view_set_title(&roots_surface->view, + roots_surface->wl_shell_surface->title); } static void handle_set_class(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, set_state); - view_set_app_id(roots_surface->view, - roots_surface->view->wl_shell_surface->class); + view_set_app_id(&roots_surface->view, + roots_surface->wl_shell_surface->class); } static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, surface_commit); - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; struct wlr_surface *wlr_surface = view->wlr_surface; view_apply_damage(view); @@ -197,13 +205,13 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, new_popup); struct wlr_wl_shell_surface *wlr_wl_shell_surface = data; - popup_create(roots_surface->view, wlr_wl_shell_surface); + popup_create(&roots_surface->view, wlr_wl_shell_surface); } static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_wl_shell_surface *roots_surface = wl_container_of(listener, roots_surface, destroy); - view_destroy(roots_surface->view); + view_destroy(&roots_surface->view); } void handle_wl_shell_surface(struct wl_listener *listener, void *data) { @@ -225,6 +233,12 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { if (!roots_surface) { return; } + + view_init(&roots_surface->view, &view_impl, ROOTS_WL_SHELL_VIEW, desktop); + roots_surface->view.box.width = surface->surface->current.width; + roots_surface->view.box.height = surface->surface->current.height; + roots_surface->wl_shell_surface = surface; + roots_surface->destroy.notify = handle_destroy; wl_signal_add(&surface->events.destroy, &roots_surface->destroy); roots_surface->new_popup.notify = handle_new_popup; @@ -251,45 +265,40 @@ void handle_wl_shell_surface(struct wl_listener *listener, void *data) { roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit); - struct roots_view *view = view_create(desktop); - if (!view) { - free(roots_surface); - return; - } - view->type = ROOTS_WL_SHELL_VIEW; - view->box.width = surface->surface->current.width; - view->box.height = surface->surface->current.height; + view_map(&roots_surface->view, surface->surface); + view_setup(&roots_surface->view); - view->wl_shell_surface = surface; - view->roots_wl_shell_surface = roots_surface; - view->resize = resize; - view->close = close; - view->destroy = destroy; - roots_surface->view = view; - - view_map(view, surface->surface); - view_setup(view); - - wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, - view->wl_shell_surface->title ?: "none"); - wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, - view->wl_shell_surface->class ?: "none"); + wlr_foreign_toplevel_handle_v1_set_title(roots_surface->view.toplevel_handle, + surface->title ?: "none"); + wlr_foreign_toplevel_handle_v1_set_app_id(roots_surface->view.toplevel_handle, + surface->class ?: "none"); if (surface->state == WLR_WL_SHELL_SURFACE_STATE_TRANSIENT) { // We need to map it relative to the parent bool found = false; struct roots_view *parent; wl_list_for_each(parent, &desktop->views, link) { - if (parent->type == ROOTS_WL_SHELL_VIEW && - parent->wl_shell_surface == surface->parent) { + if (parent->type != ROOTS_WL_SHELL_VIEW) { + continue; + } + + struct roots_wl_shell_surface *parent_surf = + roots_wl_shell_surface_from_view(parent); + if (parent_surf->wl_shell_surface == surface->parent) { found = true; break; } } if (found) { - view_move(view, + view_move(&roots_surface->view, parent->box.x + surface->transient_state->x, parent->box.y + surface->transient_state->y); } } } + +struct roots_wl_shell_surface *roots_wl_shell_surface_from_view( + struct roots_view *view) { + assert(view->impl == &view_impl); + return (struct roots_wl_shell_surface *)view; +} diff --git a/rootston/xdg_shell.c b/rootston/xdg_shell.c index 918f90ab..5686b3d7 100644 --- a/rootston/xdg_shell.c +++ b/rootston/xdg_shell.c @@ -10,25 +10,28 @@ #include "rootston/desktop.h" #include "rootston/input.h" #include "rootston/server.h" +#include "rootston/view.h" + +static const struct roots_view_child_interface popup_impl; static void popup_destroy(struct roots_view_child *child) { - assert(child->destroy == popup_destroy); + assert(child->impl == &popup_impl); struct roots_xdg_popup *popup = (struct roots_xdg_popup *)child; - if (popup == NULL) { - return; - } wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->map.link); wl_list_remove(&popup->unmap.link); - view_child_finish(&popup->view_child); free(popup); } +static const struct roots_view_child_interface popup_impl = { + .destroy = popup_destroy, +}; + static void popup_handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_popup *popup = wl_container_of(listener, popup, destroy); - popup_destroy((struct roots_view_child *)popup); + view_child_destroy(&popup->view_child); } static void popup_handle_map(struct wl_listener *listener, void *data) { @@ -113,8 +116,8 @@ static struct roots_xdg_popup *popup_create(struct roots_view *view, return NULL; } popup->wlr_popup = wlr_popup; - popup->view_child.destroy = popup_destroy; - view_child_init(&popup->view_child, view, wlr_popup->base->surface); + view_child_init(&popup->view_child, &popup_impl, + view, wlr_popup->base->surface); popup->destroy.notify = popup_handle_destroy; wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); popup->map.notify = popup_handle_map; @@ -130,31 +133,31 @@ static struct roots_xdg_popup *popup_create(struct roots_view *view, } -static void get_size(const struct roots_view *view, struct wlr_box *box) { - assert(view->type == ROOTS_XDG_SHELL_VIEW); - struct wlr_xdg_surface *surface = view->xdg_surface; +static void get_size(struct roots_view *view, struct wlr_box *box) { + struct wlr_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(view)->xdg_surface; struct wlr_box geo_box; - wlr_xdg_surface_get_geometry(surface, &geo_box); + wlr_xdg_surface_get_geometry(xdg_surface, &geo_box); box->width = geo_box.width; box->height = geo_box.height; } static void activate(struct roots_view *view, bool active) { - assert(view->type == ROOTS_XDG_SHELL_VIEW); - struct wlr_xdg_surface *surface = view->xdg_surface; - if (surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { - wlr_xdg_toplevel_set_activated(surface, active); + struct wlr_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(view)->xdg_surface; + if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + wlr_xdg_toplevel_set_activated(xdg_surface, active); } } -static void apply_size_constraints(struct wlr_xdg_surface *surface, +static void apply_size_constraints(struct wlr_xdg_surface *xdg_surface, uint32_t width, uint32_t height, uint32_t *dest_width, uint32_t *dest_height) { *dest_width = width; *dest_height = height; - struct wlr_xdg_toplevel_state *state = &surface->toplevel->current; + struct wlr_xdg_toplevel_state *state = &xdg_surface->toplevel->current; if (width < state->min_width) { *dest_width = state->min_width; } else if (state->max_width > 0 && @@ -170,26 +173,26 @@ static void apply_size_constraints(struct wlr_xdg_surface *surface, } static void resize(struct roots_view *view, uint32_t width, uint32_t height) { - assert(view->type == ROOTS_XDG_SHELL_VIEW); - struct wlr_xdg_surface *surface = view->xdg_surface; - if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + struct wlr_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(view)->xdg_surface; + if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { return; } uint32_t constrained_width, constrained_height; - apply_size_constraints(surface, width, height, &constrained_width, + apply_size_constraints(xdg_surface, width, height, &constrained_width, &constrained_height); - wlr_xdg_toplevel_set_size(surface, constrained_width, + wlr_xdg_toplevel_set_size(xdg_surface, constrained_width, constrained_height); } static void move_resize(struct roots_view *view, double x, double y, uint32_t width, uint32_t height) { - assert(view->type == ROOTS_XDG_SHELL_VIEW); - struct roots_xdg_surface *roots_surface = view->roots_xdg_surface; - struct wlr_xdg_surface *surface = view->xdg_surface; - if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + struct roots_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(view); + struct wlr_xdg_surface *wlr_xdg_surface = xdg_surface->xdg_surface; + if (wlr_xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { return; } @@ -197,7 +200,7 @@ static void move_resize(struct roots_view *view, double x, double y, bool update_y = y != view->box.y; uint32_t constrained_width, constrained_height; - apply_size_constraints(surface, width, height, &constrained_width, + apply_size_constraints(wlr_xdg_surface, width, height, &constrained_width, &constrained_height); if (update_x) { @@ -214,48 +217,48 @@ static void move_resize(struct roots_view *view, double x, double y, view->pending_move_resize.width = constrained_width; view->pending_move_resize.height = constrained_height; - uint32_t serial = wlr_xdg_toplevel_set_size(surface, constrained_width, - constrained_height); + uint32_t serial = wlr_xdg_toplevel_set_size(wlr_xdg_surface, + constrained_width, constrained_height); if (serial > 0) { - roots_surface->pending_move_resize_configure_serial = serial; - } else if (roots_surface->pending_move_resize_configure_serial == 0) { + xdg_surface->pending_move_resize_configure_serial = serial; + } else if (xdg_surface->pending_move_resize_configure_serial == 0) { view_update_position(view, x, y); } } static void maximize(struct roots_view *view, bool maximized) { - assert(view->type == ROOTS_XDG_SHELL_VIEW); - struct wlr_xdg_surface *surface = view->xdg_surface; - if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + struct wlr_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(view)->xdg_surface; + if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { return; } - wlr_xdg_toplevel_set_maximized(surface, maximized); + wlr_xdg_toplevel_set_maximized(xdg_surface, maximized); } static void set_fullscreen(struct roots_view *view, bool fullscreen) { - assert(view->type == ROOTS_XDG_SHELL_VIEW); - struct wlr_xdg_surface *surface = view->xdg_surface; - if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { + struct wlr_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(view)->xdg_surface; + if (xdg_surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { return; } - wlr_xdg_toplevel_set_fullscreen(surface, fullscreen); + wlr_xdg_toplevel_set_fullscreen(xdg_surface, fullscreen); } static void close(struct roots_view *view) { - assert(view->type == ROOTS_XDG_SHELL_VIEW); - struct wlr_xdg_surface *surface = view->xdg_surface; + struct wlr_xdg_surface *xdg_surface = + roots_xdg_surface_from_view(view)->xdg_surface; struct wlr_xdg_popup *popup = NULL; - wl_list_for_each(popup, &surface->popups, link) { + wl_list_for_each(popup, &xdg_surface->popups, link) { wlr_xdg_popup_destroy(popup->base); } - wlr_xdg_toplevel_send_close(surface); + wlr_xdg_toplevel_send_close(xdg_surface); } static void destroy(struct roots_view *view) { - assert(view->type == ROOTS_XDG_SHELL_VIEW); - struct roots_xdg_surface *roots_xdg_surface = view->roots_xdg_surface; + struct roots_xdg_surface *roots_xdg_surface = + roots_xdg_surface_from_view(view); wl_list_remove(&roots_xdg_surface->surface_commit.link); wl_list_remove(&roots_xdg_surface->destroy.link); wl_list_remove(&roots_xdg_surface->new_popup.link); @@ -267,14 +270,24 @@ static void destroy(struct roots_view *view) { wl_list_remove(&roots_xdg_surface->request_fullscreen.link); wl_list_remove(&roots_xdg_surface->set_title.link); wl_list_remove(&roots_xdg_surface->set_app_id.link); - roots_xdg_surface->view->xdg_surface->data = NULL; + roots_xdg_surface->xdg_surface->data = NULL; free(roots_xdg_surface); } +static const struct roots_view_interface view_impl = { + .activate = activate, + .resize = resize, + .move_resize = move_resize, + .maximize = maximize, + .set_fullscreen = set_fullscreen, + .close = close, + .destroy = destroy, +}; + static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_move); - struct roots_view *view = roots_xdg_surface->view; + struct roots_view *view = &roots_xdg_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_xdg_toplevel_move_event *e = data; struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); @@ -288,7 +301,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_resize); - struct roots_view *view = roots_xdg_surface->view; + struct roots_view *view = &roots_xdg_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_xdg_toplevel_resize_event *e = data; // TODO verify event serial @@ -303,8 +316,8 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { static void handle_request_maximize(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_maximize); - struct roots_view *view = roots_xdg_surface->view; - struct wlr_xdg_surface *surface = view->xdg_surface; + struct roots_view *view = &roots_xdg_surface->view; + struct wlr_xdg_surface *surface = roots_xdg_surface->xdg_surface; if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { return; @@ -317,8 +330,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_fullscreen); - struct roots_view *view = roots_xdg_surface->view; - struct wlr_xdg_surface *surface = view->xdg_surface; + struct roots_view *view = &roots_xdg_surface->view; + struct wlr_xdg_surface *surface = roots_xdg_surface->xdg_surface; struct wlr_xdg_toplevel_set_fullscreen_event *e = data; if (surface->role != WLR_XDG_SURFACE_ROLE_TOPLEVEL) { @@ -332,23 +345,23 @@ static void handle_set_title(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, set_title); - view_set_title(roots_xdg_surface->view, - roots_xdg_surface->view->xdg_surface->toplevel->title); + view_set_title(&roots_xdg_surface->view, + roots_xdg_surface->xdg_surface->toplevel->title); } static void handle_set_app_id(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, set_app_id); - view_set_app_id(roots_xdg_surface->view, - roots_xdg_surface->view->xdg_surface->toplevel->app_id); + view_set_app_id(&roots_xdg_surface->view, + roots_xdg_surface->xdg_surface->toplevel->app_id); } static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_surface = wl_container_of(listener, roots_surface, surface_commit); - struct roots_view *view = roots_surface->view; - struct wlr_xdg_surface *surface = view->xdg_surface; + struct roots_view *view = &roots_surface->view; + struct wlr_xdg_surface *surface = roots_surface->xdg_surface; if (!surface->mapped) { return; @@ -385,38 +398,38 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, new_popup); struct wlr_xdg_popup *wlr_popup = data; - popup_create(roots_xdg_surface->view, wlr_popup); + popup_create(&roots_xdg_surface->view, wlr_popup); } static void handle_map(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, map); - struct roots_view *view = roots_xdg_surface->view; + struct roots_view *view = &roots_xdg_surface->view; struct wlr_box box; get_size(view, &box); view->box.width = box.width; view->box.height = box.height; - view_map(view, view->xdg_surface->surface); + view_map(view, roots_xdg_surface->xdg_surface->surface); view_setup(view); wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, - view->xdg_surface->toplevel->title ?: "none"); + roots_xdg_surface->xdg_surface->toplevel->title ?: "none"); wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, - view->xdg_surface->toplevel->app_id ?: "none"); + roots_xdg_surface->xdg_surface->toplevel->app_id ?: "none"); } static void handle_unmap(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, unmap); - view_unmap(roots_xdg_surface->view); + view_unmap(&roots_xdg_surface->view); } static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_surface *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, destroy); - view_destroy(roots_xdg_surface->view); + view_destroy(&roots_xdg_surface->view); } void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { @@ -440,6 +453,11 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { if (!roots_surface) { return; } + + view_init(&roots_surface->view, &view_impl, ROOTS_XDG_SHELL_VIEW, desktop); + roots_surface->xdg_surface = surface; + surface->data = roots_surface; + roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit); @@ -468,43 +486,16 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) { &roots_surface->set_app_id); roots_surface->new_popup.notify = handle_new_popup; wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); - surface->data = roots_surface; - - struct roots_view *view = view_create(desktop); - if (!view) { - free(roots_surface); - return; - } - view->type = ROOTS_XDG_SHELL_VIEW; - - view->xdg_surface = surface; - view->roots_xdg_surface = roots_surface; - view->activate = activate; - view->resize = resize; - view->move_resize = move_resize; - view->maximize = maximize; - view->set_fullscreen = set_fullscreen; - view->close = close; - view->destroy = destroy; - roots_surface->view = view; - - if (surface->toplevel->client_pending.maximized) { - view_maximize(view, true); - } - if (surface->toplevel->client_pending.fullscreen) { - view_set_fullscreen(view, true, NULL); - } } - static void decoration_handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_toplevel_decoration *decoration = wl_container_of(listener, decoration, destroy); decoration->surface->xdg_toplevel_decoration = NULL; - view_update_decorated(decoration->surface->view, false); + view_update_decorated(&decoration->surface->view, false); wl_list_remove(&decoration->destroy.link); wl_list_remove(&decoration->request_mode.link); wl_list_remove(&decoration->surface_commit.link); @@ -531,7 +522,7 @@ static void decoration_handle_surface_commit(struct wl_listener *listener, bool decorated = decoration->wlr_decoration->current_mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; - view_update_decorated(decoration->surface->view, decorated); + view_update_decorated(&decoration->surface->view, decorated); } void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data) { @@ -541,7 +532,7 @@ void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data) { struct roots_xdg_surface *xdg_surface = wlr_decoration->surface->data; assert(xdg_surface != NULL); - struct wlr_xdg_surface *wlr_xdg_surface = xdg_surface->view->xdg_surface; + struct wlr_xdg_surface *wlr_xdg_surface = xdg_surface->xdg_surface; struct roots_xdg_toplevel_decoration *decoration = calloc(1, sizeof(struct roots_xdg_toplevel_decoration)); @@ -563,3 +554,8 @@ void handle_xdg_toplevel_decoration(struct wl_listener *listener, void *data) { decoration_handle_request_mode(&decoration->request_mode, wlr_decoration); } + +struct roots_xdg_surface *roots_xdg_surface_from_view(struct roots_view *view) { + assert(view->impl == &view_impl); + return (struct roots_xdg_surface *)view; +} diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index 8d989aef..4d6a7242 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -10,24 +10,26 @@ #include "rootston/input.h" #include "rootston/server.h" +static const struct roots_view_child_interface popup_impl; + static void popup_destroy(struct roots_view_child *child) { - assert(child->destroy == popup_destroy); + assert(child->impl == &popup_impl); struct roots_xdg_popup_v6 *popup = (struct roots_xdg_popup_v6 *)child; - if (popup == NULL) { - return; - } wl_list_remove(&popup->destroy.link); wl_list_remove(&popup->new_popup.link); wl_list_remove(&popup->map.link); wl_list_remove(&popup->unmap.link); - view_child_finish(&popup->view_child); free(popup); } +static const struct roots_view_child_interface popup_impl = { + .destroy = popup_destroy, +}; + static void popup_handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_popup_v6 *popup = wl_container_of(listener, popup, destroy); - popup_destroy((struct roots_view_child *)popup); + view_child_destroy(&popup->view_child); } static void popup_handle_map(struct wl_listener *listener, void *data) { @@ -113,8 +115,8 @@ static struct roots_xdg_popup_v6 *popup_create(struct roots_view *view, return NULL; } popup->wlr_popup = wlr_popup; - popup->view_child.destroy = popup_destroy; - view_child_init(&popup->view_child, view, wlr_popup->base->surface); + view_child_init(&popup->view_child, &popup_impl, + view, wlr_popup->base->surface); popup->destroy.notify = popup_handle_destroy; wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy); popup->map.notify = popup_handle_map; @@ -130,9 +132,9 @@ static struct roots_xdg_popup_v6 *popup_create(struct roots_view *view, } -static void get_size(const struct roots_view *view, struct wlr_box *box) { - assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; +static void get_size(struct roots_view *view, struct wlr_box *box) { + struct wlr_xdg_surface_v6 *surface = + roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; struct wlr_box geo_box; wlr_xdg_surface_v6_get_geometry(surface, &geo_box); @@ -141,8 +143,8 @@ static void get_size(const struct roots_view *view, struct wlr_box *box) { } static void activate(struct roots_view *view, bool active) { - assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + struct wlr_xdg_surface_v6 *surface = + roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { wlr_xdg_toplevel_v6_set_activated(surface, active); } @@ -170,8 +172,8 @@ static void apply_size_constraints(struct wlr_xdg_surface_v6 *surface, } static void resize(struct roots_view *view, uint32_t width, uint32_t height) { - assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + struct wlr_xdg_surface_v6 *surface = + roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { return; } @@ -186,9 +188,9 @@ static void resize(struct roots_view *view, uint32_t width, uint32_t height) { static void move_resize(struct roots_view *view, double x, double y, uint32_t width, uint32_t height) { - assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); - struct roots_xdg_surface_v6 *roots_surface = view->roots_xdg_surface_v6; - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + struct roots_xdg_surface_v6 *roots_surface = + roots_xdg_surface_v6_from_view(view); + struct wlr_xdg_surface_v6 *surface = roots_surface->xdg_surface_v6; if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { return; } @@ -224,8 +226,8 @@ static void move_resize(struct roots_view *view, double x, double y, } static void maximize(struct roots_view *view, bool maximized) { - assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + struct wlr_xdg_surface_v6 *surface = + roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { return; } @@ -234,8 +236,8 @@ static void maximize(struct roots_view *view, bool maximized) { } static void set_fullscreen(struct roots_view *view, bool fullscreen) { - assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + struct wlr_xdg_surface_v6 *surface = + roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { return; } @@ -244,8 +246,8 @@ static void set_fullscreen(struct roots_view *view, bool fullscreen) { } static void close(struct roots_view *view) { - assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + struct wlr_xdg_surface_v6 *surface = + roots_xdg_surface_v6_from_view(view)->xdg_surface_v6; struct wlr_xdg_popup_v6 *popup = NULL; wl_list_for_each(popup, &surface->popups, link) { wlr_xdg_surface_v6_send_close(popup->base); @@ -254,8 +256,8 @@ static void close(struct roots_view *view) { } static void destroy(struct roots_view *view) { - assert(view->type == ROOTS_XDG_SHELL_V6_VIEW); - struct roots_xdg_surface_v6 *roots_xdg_surface = view->roots_xdg_surface_v6; + struct roots_xdg_surface_v6 *roots_xdg_surface = + roots_xdg_surface_v6_from_view(view); wl_list_remove(&roots_xdg_surface->surface_commit.link); wl_list_remove(&roots_xdg_surface->destroy.link); wl_list_remove(&roots_xdg_surface->new_popup.link); @@ -270,10 +272,20 @@ static void destroy(struct roots_view *view) { free(roots_xdg_surface); } +static const struct roots_view_interface view_impl = { + .activate = activate, + .resize = resize, + .move_resize = move_resize, + .maximize = maximize, + .set_fullscreen = set_fullscreen, + .close = close, + .destroy = destroy, +}; + static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_move); - struct roots_view *view = roots_xdg_surface->view; + struct roots_view *view = &roots_xdg_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_xdg_toplevel_v6_move_event *e = data; struct roots_seat *seat = input_seat_from_wlr_seat(input, e->seat->seat); @@ -287,7 +299,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_resize); - struct roots_view *view = roots_xdg_surface->view; + struct roots_view *view = &roots_xdg_surface->view; struct roots_input *input = view->desktop->server->input; struct wlr_xdg_toplevel_v6_resize_event *e = data; // TODO verify event serial @@ -302,8 +314,8 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { static void handle_request_maximize(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_maximize); - struct roots_view *view = roots_xdg_surface->view; - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + struct roots_view *view = &roots_xdg_surface->view; + struct wlr_xdg_surface_v6 *surface = roots_xdg_surface->xdg_surface_v6; if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { return; @@ -316,8 +328,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, request_fullscreen); - struct roots_view *view = roots_xdg_surface->view; - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + struct roots_view *view = &roots_xdg_surface->view; + struct wlr_xdg_surface_v6 *surface = roots_xdg_surface->xdg_surface_v6; struct wlr_xdg_toplevel_v6_set_fullscreen_event *e = data; if (surface->role != WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { @@ -331,23 +343,23 @@ static void handle_set_title(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, set_title); - view_set_title(roots_xdg_surface->view, - roots_xdg_surface->view->xdg_surface_v6->toplevel->title); + view_set_title(&roots_xdg_surface->view, + roots_xdg_surface->xdg_surface_v6->toplevel->title); } static void handle_set_app_id(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, set_app_id); - view_set_app_id(roots_xdg_surface->view, - roots_xdg_surface->view->xdg_surface_v6->toplevel->app_id); + view_set_app_id(&roots_xdg_surface->view, + roots_xdg_surface->xdg_surface_v6->toplevel->app_id); } static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_surface = wl_container_of(listener, roots_surface, surface_commit); - struct roots_view *view = roots_surface->view; - struct wlr_xdg_surface_v6 *surface = view->xdg_surface_v6; + struct roots_view *view = &roots_surface->view; + struct wlr_xdg_surface_v6 *surface = roots_surface->xdg_surface_v6; if (!surface->mapped) { return; @@ -384,38 +396,38 @@ static void handle_new_popup(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, new_popup); struct wlr_xdg_popup_v6 *wlr_popup = data; - popup_create(roots_xdg_surface->view, wlr_popup); + popup_create(&roots_xdg_surface->view, wlr_popup); } static void handle_map(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, map); - struct roots_view *view = roots_xdg_surface->view; + struct roots_view *view = &roots_xdg_surface->view; struct wlr_box box; get_size(view, &box); view->box.width = box.width; view->box.height = box.height; - view_map(view, view->xdg_surface_v6->surface); + view_map(view, roots_xdg_surface->xdg_surface_v6->surface); view_setup(view); wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, - view->xdg_surface_v6->toplevel->title ?: "none"); + roots_xdg_surface->xdg_surface_v6->toplevel->title ?: "none"); wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, - view->xdg_surface_v6->toplevel->app_id ?: "none"); + roots_xdg_surface->xdg_surface_v6->toplevel->app_id ?: "none"); } static void handle_unmap(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, unmap); - view_unmap(roots_xdg_surface->view); + view_unmap(&roots_xdg_surface->view); } static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xdg_surface_v6 *roots_xdg_surface = wl_container_of(listener, roots_xdg_surface, destroy); - view_destroy(roots_xdg_surface->view); + view_destroy(&roots_xdg_surface->view); } void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { @@ -439,6 +451,10 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { if (!roots_surface) { return; } + + view_init(&roots_surface->view, &view_impl, ROOTS_XDG_SHELL_V6_VIEW, desktop); + roots_surface->xdg_surface_v6 = surface; + roots_surface->surface_commit.notify = handle_surface_commit; wl_signal_add(&surface->surface->events.commit, &roots_surface->surface_commit); @@ -461,35 +477,17 @@ void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { wl_signal_add(&surface->toplevel->events.request_fullscreen, &roots_surface->request_fullscreen); roots_surface->set_title.notify = handle_set_title; - wl_signal_add(&surface->toplevel->events.set_title, &roots_surface->set_title); + wl_signal_add(&surface->toplevel->events.set_title, + &roots_surface->set_title); roots_surface->set_app_id.notify = handle_set_app_id; wl_signal_add(&surface->toplevel->events.set_app_id, &roots_surface->set_app_id); roots_surface->new_popup.notify = handle_new_popup; wl_signal_add(&surface->events.new_popup, &roots_surface->new_popup); - - struct roots_view *view = view_create(desktop); - if (!view) { - free(roots_surface); - return; - } - view->type = ROOTS_XDG_SHELL_V6_VIEW; - - view->xdg_surface_v6 = surface; - view->roots_xdg_surface_v6 = roots_surface; - view->activate = activate; - view->resize = resize; - view->move_resize = move_resize; - view->maximize = maximize; - view->set_fullscreen = set_fullscreen; - view->close = close; - view->destroy = destroy; - roots_surface->view = view; - - if (surface->toplevel->client_pending.maximized) { - view_maximize(view, true); - } - if (surface->toplevel->client_pending.fullscreen) { - view_set_fullscreen(view, true, NULL); - } +} + +struct roots_xdg_surface_v6 *roots_xdg_surface_v6_from_view( + struct roots_view *view) { + assert(view->impl == &view_impl); + return (struct roots_xdg_surface_v6 *)view; } diff --git a/rootston/xwayland.c b/rootston/xwayland.c index f3f962e8..77a7ba12 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -11,13 +11,14 @@ #include "rootston/server.h" static void activate(struct roots_view *view, bool active) { - assert(view->type == ROOTS_XWAYLAND_VIEW); - wlr_xwayland_surface_activate(view->xwayland_surface, active); + struct wlr_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view)->xwayland_surface; + wlr_xwayland_surface_activate(xwayland_surface, active); } static void move(struct roots_view *view, double x, double y) { - assert(view->type == ROOTS_XWAYLAND_VIEW); - struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; + struct wlr_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view)->xwayland_surface; view_update_position(view, x, y); wlr_xwayland_surface_configure(xwayland_surface, x, y, xwayland_surface->width, xwayland_surface->height); @@ -48,8 +49,8 @@ static void apply_size_constraints( } static void resize(struct roots_view *view, uint32_t width, uint32_t height) { - assert(view->type == ROOTS_XWAYLAND_VIEW); - struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; + struct wlr_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view)->xwayland_surface; uint32_t constrained_width, constrained_height; apply_size_constraints(xwayland_surface, width, height, &constrained_width, @@ -61,8 +62,8 @@ static void resize(struct roots_view *view, uint32_t width, uint32_t height) { static void move_resize(struct roots_view *view, double x, double y, uint32_t width, uint32_t height) { - assert(view->type == ROOTS_XWAYLAND_VIEW); - struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; + struct wlr_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view)->xwayland_surface; bool update_x = x != view->box.x; bool update_y = y != view->box.y; @@ -90,25 +91,26 @@ static void move_resize(struct roots_view *view, double x, double y, } static void close(struct roots_view *view) { - assert(view->type == ROOTS_XWAYLAND_VIEW); - wlr_xwayland_surface_close(view->xwayland_surface); + struct wlr_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view)->xwayland_surface; + wlr_xwayland_surface_close(xwayland_surface); } static void maximize(struct roots_view *view, bool maximized) { - assert(view->type == ROOTS_XWAYLAND_VIEW); - - wlr_xwayland_surface_set_maximized(view->xwayland_surface, maximized); + struct wlr_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view)->xwayland_surface; + wlr_xwayland_surface_set_maximized(xwayland_surface, maximized); } static void set_fullscreen(struct roots_view *view, bool fullscreen) { - assert(view->type == ROOTS_XWAYLAND_VIEW); - - wlr_xwayland_surface_set_fullscreen(view->xwayland_surface, fullscreen); + struct wlr_xwayland_surface *xwayland_surface = + roots_xwayland_surface_from_view(view)->xwayland_surface; + wlr_xwayland_surface_set_fullscreen(xwayland_surface, fullscreen); } static void destroy(struct roots_view *view) { - assert(view->type == ROOTS_XWAYLAND_VIEW); - struct roots_xwayland_surface *roots_surface = view->roots_xwayland_surface; + struct roots_xwayland_surface *roots_surface = + roots_xwayland_surface_from_view(view); wl_list_remove(&roots_surface->destroy.link); wl_list_remove(&roots_surface->request_configure.link); wl_list_remove(&roots_surface->request_move.link); @@ -121,20 +123,31 @@ static void destroy(struct roots_view *view) { free(roots_surface); } +static const struct roots_view_interface view_impl = { + .activate = activate, + .resize = resize, + .move = move, + .move_resize = move_resize, + .maximize = maximize, + .set_fullscreen = set_fullscreen, + .close = close, + .destroy = destroy, +}; + static void handle_destroy(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, destroy); - view_destroy(roots_surface->view); + view_destroy(&roots_surface->view); } static void handle_request_configure(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_configure); struct wlr_xwayland_surface *xwayland_surface = - roots_surface->view->xwayland_surface; + roots_surface->xwayland_surface; struct wlr_xwayland_surface_configure_event *event = data; - view_update_position(roots_surface->view, event->x, event->y); + view_update_position(&roots_surface->view, event->x, event->y); wlr_xwayland_surface_configure(xwayland_surface, event->x, event->y, event->width, event->height); @@ -156,7 +169,7 @@ static struct roots_seat *guess_seat_for_view(struct roots_view *view) { static void handle_request_move(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_move); - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; struct roots_seat *seat = guess_seat_for_view(view); if (!seat || seat->cursor->mode != ROOTS_CURSOR_PASSTHROUGH) { @@ -169,7 +182,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) { static void handle_request_resize(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_resize); - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; struct roots_seat *seat = guess_seat_for_view(view); struct wlr_xwayland_resize_event *e = data; @@ -182,8 +195,9 @@ static void handle_request_resize(struct wl_listener *listener, void *data) { static void handle_request_maximize(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_maximize); - struct roots_view *view = roots_surface->view; - struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; + struct roots_view *view = &roots_surface->view; + struct wlr_xwayland_surface *xwayland_surface = + roots_surface->xwayland_surface; bool maximized = xwayland_surface->maximized_vert && xwayland_surface->maximized_horz; @@ -194,8 +208,9 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, request_fullscreen); - struct roots_view *view = roots_surface->view; - struct wlr_xwayland_surface *xwayland_surface = view->xwayland_surface; + struct roots_view *view = &roots_surface->view; + struct wlr_xwayland_surface *xwayland_surface = + roots_surface->xwayland_surface; view_set_fullscreen(view, xwayland_surface->fullscreen, NULL); } @@ -204,22 +219,22 @@ static void handle_set_title(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, set_title); - view_set_title(roots_surface->view, - roots_surface->view->xwayland_surface->title); + view_set_title(&roots_surface->view, + roots_surface->xwayland_surface->title); } static void handle_set_class(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, set_class); - view_set_app_id(roots_surface->view, - roots_surface->view->xwayland_surface->class); + view_set_app_id(&roots_surface->view, + roots_surface->xwayland_surface->class); } static void handle_surface_commit(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, surface_commit); - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; struct wlr_surface *wlr_surface = view->wlr_surface; view_apply_damage(view); @@ -247,7 +262,7 @@ static void handle_map(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, map); struct wlr_xwayland_surface *surface = data; - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; view->box.x = surface->x; view->box.y = surface->y; @@ -270,9 +285,9 @@ static void handle_map(struct wl_listener *listener, void *data) { view_setup(view); wlr_foreign_toplevel_handle_v1_set_title(view->toplevel_handle, - view->xwayland_surface->title ?: "none"); + roots_surface->xwayland_surface->title ?: "none"); wlr_foreign_toplevel_handle_v1_set_app_id(view->toplevel_handle, - view->xwayland_surface->class ?: "none"); + roots_surface->xwayland_surface->class ?: "none"); } else { view_initial_focus(view); } @@ -281,7 +296,7 @@ static void handle_map(struct wl_listener *listener, void *data) { static void handle_unmap(struct wl_listener *listener, void *data) { struct roots_xwayland_surface *roots_surface = wl_container_of(listener, roots_surface, unmap); - struct roots_view *view = roots_surface->view; + struct roots_view *view = &roots_surface->view; wl_list_remove(&roots_surface->surface_commit.link); view_unmap(view); @@ -302,6 +317,11 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { return; } + view_init(&roots_surface->view, &view_impl, ROOTS_XWAYLAND_VIEW, desktop); + roots_surface->view.box.x = surface->x; + roots_surface->view.box.y = surface->y; + roots_surface->xwayland_surface = surface; + roots_surface->destroy.notify = handle_destroy; wl_signal_add(&surface->events.destroy, &roots_surface->destroy); roots_surface->request_configure.notify = handle_request_configure; @@ -327,25 +347,10 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { roots_surface->set_class.notify = handle_set_class; wl_signal_add(&surface->events.set_class, &roots_surface->set_class); - - struct roots_view *view = view_create(desktop); - if (view == NULL) { - free(roots_surface); - return; - } - view->type = ROOTS_XWAYLAND_VIEW; - view->box.x = surface->x; - view->box.y = surface->y; - - view->xwayland_surface = surface; - view->roots_xwayland_surface = roots_surface; - view->activate = activate; - view->resize = resize; - view->move = move; - view->move_resize = move_resize; - view->maximize = maximize; - view->set_fullscreen = set_fullscreen; - view->close = close; - view->destroy = destroy; - roots_surface->view = view; +} + +struct roots_xwayland_surface *roots_xwayland_surface_from_view( + struct roots_view *view) { + assert(view->impl == &view_impl); + return (struct roots_xwayland_surface *)view; }