diff --git a/include/regions.h b/include/regions.h index 180d83aa..f583a310 100644 --- a/include/regions.h +++ b/include/regions.h @@ -28,6 +28,7 @@ bool regions_available(void); void regions_init(struct server *server, struct seat *seat); void regions_update(struct output *output); +void regions_evacuate_output(struct output *output); void regions_destroy(struct wl_list *regions); struct region *regions_from_cursor(struct server *server); diff --git a/include/view.h b/include/view.h index b9c09793..c04885cc 100644 --- a/include/view.h +++ b/include/view.h @@ -50,7 +50,12 @@ struct view { bool minimized; bool maximized; uint32_t tiled; /* private, enum view_edge in src/view.c */ + + /* Pointer to an output owned struct region, may be NULL or already free'd */ struct region *tiled_region; + /* Set to region->name when tiled_region is free'd by a destroying output */ + char *tiled_region_evacuate; + struct wlr_output *fullscreen; /* geometry of the wlr_surface contained within the view */ diff --git a/src/output.c b/src/output.c index b30ba643..c28186ac 100644 --- a/src/output.c +++ b/src/output.c @@ -41,6 +41,7 @@ static void output_destroy_notify(struct wl_listener *listener, void *data) { struct output *output = wl_container_of(listener, output, destroy); + regions_evacuate_output(output); regions_destroy(&output->regions); wl_list_remove(&output->link); wl_list_remove(&output->frame.link); @@ -307,6 +308,7 @@ output_config_apply(struct server *server, } if (need_to_remove) { + regions_evacuate_output(output); wlr_output_layout_remove(server->output_layout, o); output->scene_output = NULL; } diff --git a/src/regions.c b/src/regions.c index 28333466..35937a2e 100644 --- a/src/regions.c +++ b/src/regions.c @@ -156,6 +156,26 @@ regions_update(struct output *output) } } +void +regions_evacuate_output(struct output *output) +{ + assert(output); + struct view *view; + struct region *region; + + wl_list_for_each(view, &output->server->views, link) { + wl_list_for_each(region, &output->regions, link) { + if (view->tiled_region == region) { + if (!view->tiled_region_evacuate) { + view->tiled_region_evacuate = + xstrdup(region->name); + } + break; + } + } + } +} + void regions_destroy(struct wl_list *regions) { diff --git a/src/view.c b/src/view.c index 7e14756a..4e572b3a 100644 --- a/src/view.c +++ b/src/view.c @@ -2,6 +2,7 @@ #include #include #include +#include "common/mem.h" #include "common/scene-helpers.h" #include "labwc.h" #include "menu/menu.h" @@ -348,6 +349,29 @@ view_apply_region_geometry(struct view *view) assert(view); assert(view->tiled_region); + if (view->tiled_region_evacuate) { + /* View was evacuated from a destroying output */ + struct output *output = view_output(view); + if (!output) { + wlr_log(WLR_INFO, "apply region geometry failed: no more ouputs"); + return; + } + + /* Get new output local region */ + view->tiled_region = regions_from_name( + view->tiled_region_evacuate, output); + + /* Get rid of the evacuate instruction */ + zfree(view->tiled_region_evacuate); + + if (!view->tiled_region) { + /* Existing region name doesn't exist in rc.xml anymore */ + view_set_untiled(view); + view_apply_natural_geometry(view); + return; + } + } + /* Create a copy of the original region geometry */ struct wlr_box geo = view->tiled_region->geo; @@ -980,6 +1004,10 @@ view_destroy(struct view *view) seat_reset_pressed(&server->seat); } + if (view->tiled_region_evacuate) { + zfree(view->tiled_region_evacuate); + } + osd_on_view_destroy(view); undecorate(view);