diff --git a/include/labwc.h b/include/labwc.h index 596bb0d7..6a68514e 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -315,7 +315,6 @@ struct output { struct wlr_box usable_area; struct wl_list regions; /* struct region.link */ - struct wlr_box regions_usable_area; struct lab_data_buffer *osd_buffer; diff --git a/include/regions.h b/include/regions.h index 87806123..e77cd3f0 100644 --- a/include/regions.h +++ b/include/regions.h @@ -33,12 +33,43 @@ struct region_overlay { /* Can be used as a cheap check to detect if there are any regions configured */ bool regions_available(void); -void regions_update(struct output *output); +/** + * regions_reconfigure*() - re-initializes all regions from struct rc. + * + * - all views are evacuated from the given output (or all of them) + * - all output local regions are destroyed + * - new output local regions are created from struct rc + * - the region geometry is re-calculated + */ +void regions_reconfigure(struct server *server); +void regions_reconfigure_output(struct output *output); + +/* re-calculate the geometry based on usable area */ +void regions_update_geometry(struct output *output); + +/** + * Mark all views which are currently region-tiled to the given output as + * evacuated. This means that the view->tiled_region pointer is reset to + * NULL but view->tiled_region_evacuate is set to a copy of the region name. + * + * The next time desktop_arrange_all_views() causes a call to + * view_apply_region_geometry() it will try to find a new output and then + * search for a region with the same name. If found, view->tiled_region will + * be set to the new region and view->tiled_region_evacuate will be free'd. + * + * If no region with the old name is found (e.g. the user deleted or renamed + * the region in rc.xml and caused a Reconfigure) the view will be reset to + * non-tiled state and view->tiled_region_evacuate will be free'd. + */ void regions_evacuate_output(struct output *output); + +/* Free all regions in given wl_list pointer */ void regions_destroy(struct seat *seat, struct wl_list *regions); +/* Get output local region from cursor or name, may be NULL */ struct region *regions_from_cursor(struct server *server); struct region *regions_from_name(const char *region_name, struct output *output); + void regions_show_overlay(struct view *view, struct seat *seat, struct region *region); void regions_hide_overlay(struct seat *seat); diff --git a/include/view.h b/include/view.h index c04885cc..8cf3859f 100644 --- a/include/view.h +++ b/include/view.h @@ -51,7 +51,7 @@ struct view { 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 */ + /* Pointer to an output owned struct region, may be NULL */ struct region *tiled_region; /* Set to region->name when tiled_region is free'd by a destroying output */ char *tiled_region_evacuate; @@ -132,6 +132,7 @@ void view_toggle_maximize(struct view *view); void view_toggle_decorations(struct view *view); void view_toggle_always_on_top(struct view *view); bool view_is_always_on_top(struct view *view); +bool view_is_tiled(struct view *view); void view_move_to_workspace(struct view *view, struct workspace *workspace); void view_set_decorations(struct view *view, bool decorations); void view_toggle_fullscreen(struct view *view); diff --git a/src/interactive.c b/src/interactive.c index f1007441..83731d52 100644 --- a/src/interactive.c +++ b/src/interactive.c @@ -45,7 +45,7 @@ interactive_begin(struct view *view, enum input_mode mode, uint32_t edges) */ return; } - if (view->maximized || view->tiled || view->tiled_region) { + if (view->maximized || view_is_tiled(view)) { /* * Un-maximize and restore natural width/height. * Don't reset tiled state yet since we may want diff --git a/src/output.c b/src/output.c index fa258ba9..991a1653 100644 --- a/src/output.c +++ b/src/output.c @@ -212,6 +212,9 @@ new_output_notify(struct wl_listener *listener, void *data) output->scene_output = wlr_scene_get_scene_output(server->scene, wlr_output); assert(output->scene_output); + /* Create regions from config */ + regions_reconfigure_output(output); + server->pending_output_layout_change--; do_output_layout_change(server); } @@ -452,7 +455,7 @@ void output_update_usable_area(struct output *output) { if (update_usable_area(output)) { - regions_update(output); + regions_update_geometry(output); desktop_arrange_all_views(output->server); } } @@ -466,9 +469,9 @@ output_update_all_usable_areas(struct server *server, bool layout_changed) wl_list_for_each(output, &server->outputs, link) { if (update_usable_area(output)) { usable_area_changed = true; - regions_update(output); + regions_update_geometry(output); } else if (layout_changed) { - regions_update(output); + regions_update_geometry(output); } } if (usable_area_changed || layout_changed) { diff --git a/src/regions.c b/src/regions.c index 727a78c3..7ca2d9d2 100644 --- a/src/regions.c +++ b/src/regions.c @@ -149,30 +149,52 @@ regions_hide_overlay(struct seat *seat) } void -regions_update(struct output *output) +regions_reconfigure_output(struct output *output) +{ + assert(output); + + /* Evacuate views and destroy current regions */ + if (!wl_list_empty(&output->regions)) { + regions_evacuate_output(output); + regions_destroy(&output->server->seat, &output->regions); + } + + /* Initialize regions from config */ + struct region *region; + wl_list_for_each(region, &rc.regions, link) { + struct region *region_new = znew(*region_new); + /* Create a copy */ + region_new->name = xstrdup(region->name); + region_new->percentage = region->percentage; + wl_list_append(&output->regions, ®ion_new->link); + } + + /* Update region geometries */ + regions_update_geometry(output); +} + +void +regions_reconfigure(struct server *server) +{ + struct output *output; + + /* Evacuate views and initialize regions from config */ + wl_list_for_each(output, &server->outputs, link) { + regions_reconfigure_output(output); + } + + /* Tries to match the evacuated views to the new regions */ + desktop_arrange_all_views(server); +} + +void +regions_update_geometry(struct output *output) { assert(output); struct region *region; struct wlr_box usable = output_usable_area_in_layout_coords(output); - /* Initialize regions */ - if (wl_list_empty(&output->regions)) { - wl_list_for_each(region, &rc.regions, link) { - struct region *region_new = znew(*region_new); - /* Create a copy */ - region_new->name = xstrdup(region->name); - region_new->percentage = region->percentage; - wl_list_append(&output->regions, ®ion_new->link); - } - } - - if (wlr_box_equal(&output->regions_usable_area, &usable)) { - /* Nothing changed */ - return; - } - output->regions_usable_area = usable; - /* Update regions */ struct wlr_box *perc, *geo; wl_list_for_each(region, &output->regions, link) { @@ -201,6 +223,8 @@ regions_evacuate_output(struct output *output) view->tiled_region_evacuate = xstrdup(region->name); } + /* Prevent carrying around a dangling pointer */ + view->tiled_region = NULL; break; } } diff --git a/src/server.c b/src/server.c index e36c2880..d8a816df 100644 --- a/src/server.c +++ b/src/server.c @@ -20,6 +20,7 @@ #include "labwc.h" #include "layers.h" #include "menu/menu.h" +#include "regions.h" #include "theme.h" #include "view.h" #include "workspaces.h" @@ -49,6 +50,7 @@ reload_config_and_theme(void) menu_reconfigure(g_server); seat_reconfigure(g_server); + regions_reconfigure(g_server); } static int diff --git a/src/view.c b/src/view.c index 0208ec58..0e620b2a 100644 --- a/src/view.c +++ b/src/view.c @@ -295,7 +295,7 @@ void view_store_natural_geometry(struct view *view) { assert(view); - if (view->maximized || view->tiled || view->tiled_region) { + if (view->maximized || view_is_tiled(view)) { /* Do not overwrite the stored geometry with special cases */ return; } @@ -347,7 +347,7 @@ static void view_apply_region_geometry(struct view *view) { assert(view); - assert(view->tiled_region); + assert(view->tiled_region || view->tiled_region_evacuate); if (view->tiled_region_evacuate) { /* View was evacuated from a destroying output */ @@ -357,7 +357,7 @@ view_apply_region_geometry(struct view *view) return; } - /* Get new output local region */ + /* Get new output local region, may be NULL */ view->tiled_region = regions_from_name( view->tiled_region_evacuate, output); @@ -500,7 +500,7 @@ view_apply_special_geometry(struct view *view) view_apply_maximized_geometry(view); } else if (view->tiled) { view_apply_tiled_geometry(view, NULL); - } else if (view->tiled_region) { + } else if (view->tiled_region || view->tiled_region_evacuate) { view_apply_region_geometry(view); } else { return false; @@ -538,6 +538,15 @@ view_restore_to(struct view *view, struct wlr_box geometry) view_move_resize(view, geometry); } +bool +view_is_tiled(struct view *view) +{ + if (!view) { + return false; + } + return view->tiled || view->tiled_region || view->tiled_region_evacuate; +} + /* Reset tiled state of view without changing geometry */ void view_set_untiled(struct view *view) @@ -545,6 +554,7 @@ view_set_untiled(struct view *view) assert(view); view->tiled = VIEW_EDGE_INVALID; view->tiled_region = NULL; + zfree(view->tiled_region_evacuate); } void