diff --git a/include/labwc.h b/include/labwc.h index 78e1b847..31385040 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -372,6 +372,7 @@ void view_toggle_maximize(struct view *view); void view_toggle_decorations(struct view *view); void view_set_decorations(struct view *view, bool decorations); void view_toggle_fullscreen(struct view *view); +void view_adjust_for_layout_change(struct view *view); void view_for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, void *user_data); void view_for_each_popup_surface(struct view *view, diff --git a/src/output.c b/src/output.c index 3f97402c..5be22038 100644 --- a/src/output.c +++ b/src/output.c @@ -940,9 +940,6 @@ output_destroy_notify(struct wl_listener *listener, void *data) struct output *output = wl_container_of(listener, output, destroy); wl_list_remove(&output->link); wl_list_remove(&output->destroy.link); - - /* Windows may have moved; redraw all outputs */ - damage_all_outputs(output->server); } static void @@ -1029,22 +1026,6 @@ new_output_notify(struct wl_listener *listener, void *data) wlr_output_enable_adaptive_sync(wlr_output, true); } wlr_output_layout_add_auto(server->output_layout, wlr_output); - - /* - * Output positions may have changed, so make sure that each - * wlr_output_cursor is "moved" (in per-output coordinates) to - * align with the seat cursor. Set a default cursor image so - * that the cursor isn't invisible on the new output. - * - * TODO: remember the most recent cursor image (see cursor.c) - * and set that rather than XCURSOR_DEFAULT - */ - wlr_cursor_move(server->seat.cursor, NULL, 0, 0); - wlr_xcursor_manager_set_cursor_image(server->seat.xcursor_manager, - XCURSOR_DEFAULT, server->seat.cursor); - - /* Windows may have moved; redraw all outputs */ - damage_all_outputs(server); } void @@ -1072,6 +1053,31 @@ output_init(struct server *server) output_manager_init(server); } +static void +output_update_for_layout_change(struct server *server) +{ + /* Adjust window positions/sizes */ + struct view *view; + wl_list_for_each(view, &server->views, link) { + view_adjust_for_layout_change(view); + } + + /* + * "Move" each wlr_output_cursor (in per-output coordinates) to + * align with the seat cursor. Set a default cursor image so + * that the cursor isn't invisible on new outputs. + * + * TODO: remember the most recent cursor image (see cursor.c) + * and set that rather than XCURSOR_DEFAULT + */ + wlr_cursor_move(server->seat.cursor, NULL, 0, 0); + wlr_xcursor_manager_set_cursor_image(server->seat.xcursor_manager, + XCURSOR_DEFAULT, server->seat.cursor); + + /* Redraw everything */ + damage_all_outputs(server); +} + static void output_config_apply(struct server *server, struct wlr_output_configuration_v1 *config) @@ -1111,6 +1117,7 @@ output_config_apply(struct server *server, } server->pending_output_config = NULL; + output_update_for_layout_change(server); } static bool @@ -1205,6 +1212,7 @@ handle_output_layout_change(struct wl_listener *listener, void *data) arrange_layers(output); } } + output_update_for_layout_change(server); } } diff --git a/src/view.c b/src/view.c index e3378890..5faa4667 100644 --- a/src/view.c +++ b/src/view.c @@ -115,24 +115,87 @@ view_output(struct view *view) return output_from_wlr_output(view->server, wlr_output); } -void -view_center(struct view *view) +static bool +view_compute_centered_position(struct view *view, int w, int h, int *x, int *y) { struct wlr_output *wlr_output = view_wlr_output(view); if (!wlr_output) { - return; + return false; } struct wlr_output_layout *layout = view->server->output_layout; struct wlr_output_layout_output *ol_output = wlr_output_layout_get(layout, wlr_output); if (!ol_output) { - return; + return false; } - int center_x = ol_output->x + wlr_output->width / wlr_output->scale / 2; - int center_y = ol_output->y + wlr_output->height / wlr_output->scale / 2; - view_move(view, center_x - view->w / 2, center_y - view->h / 2); + *x = ol_output->x + wlr_output->width / wlr_output->scale / 2 - w / 2; + *y = ol_output->y + wlr_output->height / wlr_output->scale / 2 - h / 2; + return true; +} + +void +view_center(struct view *view) +{ + int x, y; + if (view_compute_centered_position(view, view->w, view->h, &x, &y)) { + view_move(view, x, y); + } +} + +static void +view_apply_fullscreen_geometry(struct view *view, struct wlr_output *wlr_output) +{ + struct output *output = + output_from_wlr_output(view->server, wlr_output); + struct wlr_box box = { 0 }; + wlr_output_effective_resolution(wlr_output, &box.width, &box.height); + double ox = 0, oy = 0; + wlr_output_layout_output_coords(output->server->output_layout, + output->wlr_output, &ox, &oy); + box.x -= ox; + box.y -= oy; + view_move_resize(view, box); +} + +static void +view_apply_maximized_geometry(struct view *view) +{ + struct output *output = view_output(view); + struct wlr_box box = output_usable_area_in_layout_coords(output); + if (box.height == output->wlr_output->height && output->wlr_output->scale != 1) { + box.height /= output->wlr_output->scale; + } + if (box.width == output->wlr_output->width && output->wlr_output->scale != 1) { + box.width /= output->wlr_output->scale; + } + + if (view->ssd.enabled) { + struct border border = ssd_thickness(view); + box.x += border.left; + box.y += border.top; + box.width -= border.right + border.left; + box.height -= border.top + border.bottom; + } + view_move_resize(view, box); +} + +static void +view_apply_unmaximized_geometry(struct view *view) +{ + struct wlr_output_layout *layout = view->server->output_layout; + if (wlr_output_layout_intersects(layout, NULL, &view->unmaximized_geometry)) { + /* restore to original geometry */ + view_move_resize(view, view->unmaximized_geometry); + } else { + /* reposition if original geometry is offscreen */ + struct wlr_box box = view->unmaximized_geometry; + if (view_compute_centered_position(view, box.width, box.height, + &box.x, &box.y)) { + view_move_resize(view, box); + } + } } void @@ -155,27 +218,11 @@ view_maximize(struct view *view, bool maximize) view->unmaximized_geometry.width = view->w; view->unmaximized_geometry.height = view->h; - struct output *output = view_output(view); - struct wlr_box box = output_usable_area_in_layout_coords(output); - if (box.height == output->wlr_output->height && output->wlr_output->scale != 1) { - box.height /= output->wlr_output->scale; - } - if (box.width == output->wlr_output->width && output->wlr_output->scale != 1) { - box.width /= output->wlr_output->scale; - } - - if (view->ssd.enabled) { - struct border border = ssd_thickness(view); - box.x += border.left; - box.y += border.top; - box.width -= border.right + border.left; - box.height -= border.top + border.bottom; - } - view_move_resize(view, box); + view_apply_maximized_geometry(view); view->maximized = true; } else { /* unmaximize */ - view_move_resize(view, view->unmaximized_geometry); + view_apply_unmaximized_geometry(view); view->maximized = false; } } @@ -242,33 +289,42 @@ view_set_fullscreen(struct view *view, bool fullscreen, wlr_output = view_wlr_output(view); } view->fullscreen = wlr_output; - struct output *output = - output_from_wlr_output(view->server, wlr_output); - struct wlr_box box = { 0 }; - wlr_output_effective_resolution(wlr_output, &box.width, - &box.height); - double ox = 0, oy = 0; - wlr_output_layout_output_coords(output->server->output_layout, - output->wlr_output, &ox, &oy); - box.x -= ox; - box.y -= oy; - view_move_resize(view, box); + view_apply_fullscreen_geometry(view, view->fullscreen); } else { /* restore to normal */ if (view->maximized) { - view->maximized = false; - view->x = view->unmaximized_geometry.x; - view->y = view->unmaximized_geometry.y; - view->w = view->unmaximized_geometry.width; - view->h = view->unmaximized_geometry.height; - view_maximize(view, true); + view_apply_maximized_geometry(view); } else { - view_move_resize(view, view->unmaximized_geometry); + view_apply_unmaximized_geometry(view); } view->fullscreen = false; } } +void +view_adjust_for_layout_change(struct view *view) +{ + struct wlr_output_layout *layout = view->server->output_layout; + if (view->fullscreen) { + if (wlr_output_layout_get(layout, view->fullscreen)) { + /* recompute fullscreen geometry */ + view_apply_fullscreen_geometry(view, view->fullscreen); + } else { + /* output is gone, exit fullscreen */ + view_set_fullscreen(view, false, NULL); + } + } else if (view->maximized) { + /* recompute maximized geometry */ + view_apply_maximized_geometry(view); + } else { + /* reposition view if it's offscreen */ + struct wlr_box box = { view->x, view->y, view->w, view->h }; + if (!wlr_output_layout_intersects(layout, NULL, &box)) { + view_center(view); + } + } +} + void view_for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, void *user_data)