diff --git a/include/labwc.h b/include/labwc.h index 26754a21..fe6f5549 100644 --- a/include/labwc.h +++ b/include/labwc.h @@ -162,6 +162,7 @@ struct view_impl { void (*map)(struct view *view); void (*move)(struct view *view, double x, double y); void (*unmap)(struct view *view); + void (*maximize)(struct view *view, bool maximize); }; struct border { @@ -188,6 +189,7 @@ struct view { bool mapped; bool been_mapped; bool minimized; + bool maximized; /* geometry of the wlr_surface contained within the view */ int x, y, w, h; @@ -217,6 +219,7 @@ struct view { struct wl_listener request_move; struct wl_listener request_resize; struct wl_listener request_configure; + struct wl_listener request_maximize; struct wl_listener new_popup; /* xdg-shell only */ }; @@ -259,6 +262,7 @@ void view_move_resize(struct view *view, struct wlr_box geo); void view_move(struct view *view, double x, double y); void view_minimize(struct view *view); void view_unminimize(struct view *view); +void view_maximize(struct view *view, bool maximize); void view_for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, void *user_data); void view_for_each_popup(struct view *view, @@ -274,8 +278,8 @@ void desktop_focus_view(struct seat *seat, struct view *view); struct view *desktop_cycle_view(struct server *server, struct view *current); void desktop_focus_topmost_mapped_view(struct server *server); struct view *desktop_view_at(struct server *server, double lx, double ly, - struct wlr_surface **surface, double *sx, - double *sy, int *view_area); + struct wlr_surface **surface, double *sx, + double *sy, int *view_area); void cursor_init(struct seat *seat); @@ -287,7 +291,7 @@ void seat_focus_surface(struct seat *seat, struct wlr_surface *surface); void seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer); void interactive_begin(struct view *view, enum input_mode mode, - uint32_t edges); + uint32_t edges); void output_init(struct server *server); void output_damage_surface(struct output *output, struct wlr_surface *surface, diff --git a/src/cursor.c b/src/cursor.c index 899a13b7..9d1e9b49 100644 --- a/src/cursor.c +++ b/src/cursor.c @@ -323,6 +323,9 @@ cursor_button(struct wl_listener *listener, void *data) case LAB_DECO_PART_TITLE: interactive_begin(view, LAB_INPUT_STATE_MOVE, 0); break; + case LAB_DECO_BUTTON_MAXIMIZE: + view_maximize(view, !view->maximized); + break; } } diff --git a/src/view.c b/src/view.c index c1e456bf..9621b204 100644 --- a/src/view.c +++ b/src/view.c @@ -1,5 +1,7 @@ #include "labwc.h" +#include +#include void view_move_resize(struct view *view, struct wlr_box geo) { @@ -32,6 +34,71 @@ view_unminimize(struct view *view) view->impl->map(view); } +void +view_maximize(struct view *view, bool maximize) +{ + if(maximize == true) + { + struct wlr_output_layout *layout = view->server->output_layout; + struct wlr_output* output = + wlr_output_layout_output_at(layout, view->x, view->y); + struct wlr_output_layout_output* ol_output = + wlr_output_layout_get(layout, output); + + assert(layout); + if(output == NULL) + { + die("output NULL w/ x and y of: %d, %d", view->x, view->y); + } + assert(output); + assert(ol_output); + + int x = ol_output->x; + int y = ol_output->y; + int width = output->width; + int height = output->height; + + if(view->server_side_deco) + { + struct border border = deco_thickness(view); + x += border.right; + x += border.left; + y += border.top; + y += border.bottom; + + width -= border.right; + width -= border.left; + height -= border.top; + height -= border.bottom; + } + + struct wlr_box box = { + .x = x * output->scale, + .y = y * output->scale, + .width = width * output->scale, + .height = height * output->scale + }; + + view_move_resize(view, box); + view_move(view, box.x * output->scale, box.y * output->scale); + + view->maximized = true; + } + else + { + struct wlr_box box = { + .x = 20, + .y = 50, + .width = 640, + .height = 480 + }; + + view_move_resize(view, box); + view->maximized = false; + } + view->impl->maximize(view, maximize); +} + void view_for_each_surface(struct view *view, wlr_surface_iterator_func_t iterator, void *user_data) diff --git a/src/xdg.c b/src/xdg.c index 91fb7b22..e7b6bcf9 100644 --- a/src/xdg.c +++ b/src/xdg.c @@ -230,6 +230,26 @@ handle_request_resize(struct wl_listener *listener, void *data) interactive_begin(view, LAB_INPUT_STATE_RESIZE, event->edges); } +static void +handle_request_maximize(struct wl_listener *listener, void *data) +{ + /* This event is raised when a client would like to begin an interactive + * resize, typically because the user clicked on their client-side + * decorations. Note that a more sophisticated compositor should check + * the provied serial against a list of button press serials sent to + * this + * client, to prevent the client from requesting this whenever they want. + */ + + struct view *view = wl_container_of(listener, view, request_maximize); + + struct wlr_xdg_surface *surface = data; + if(view != NULL) { + view_maximize(view, surface->toplevel->client_pending.maximized); + } + +} + static void xdg_toplevel_view_configure(struct view *view, struct wlr_box geo) { @@ -279,6 +299,12 @@ xdg_toplevel_view_for_each_surface(struct view *view, wlr_xdg_surface_for_each_surface(view->xdg_surface, iterator, data); } +static void +xdg_toplevel_view_maximize(struct view *view, bool maximized) +{ + wlr_xdg_toplevel_set_maximized(view->xdg_surface, maximized); +} + static struct border xdg_shell_border(struct view *view) { @@ -345,6 +371,7 @@ static const struct view_impl xdg_toplevel_view_impl = { .map = xdg_toplevel_view_map, .move = xdg_toplevel_view_move, .unmap = xdg_toplevel_view_unmap, + .maximize = xdg_toplevel_view_maximize }; void @@ -363,6 +390,7 @@ xdg_surface_new(struct wl_listener *listener, void *data) view->type = LAB_XDG_SHELL_VIEW; view->impl = &xdg_toplevel_view_impl; view->xdg_surface = xdg_surface; + view->maximized = false; view->map.notify = handle_map; wl_signal_add(&xdg_surface->events.map, &view->map); @@ -379,6 +407,13 @@ xdg_surface_new(struct wl_listener *listener, void *data) wl_signal_add(&toplevel->events.request_move, &view->request_move); view->request_resize.notify = handle_request_resize; wl_signal_add(&toplevel->events.request_resize, &view->request_resize); + view->request_maximize.notify = handle_request_maximize; + wl_signal_add(&toplevel->events.request_maximize, &view->request_maximize); + + // hacky workaround to bug where sometimes a window starts maximized and + // when we hit the maximize button, labwc crashes. instead we unmaximize + // it from the start to avoid this situation + view_maximize(view, false); wl_list_insert(&server->views, &view->link); } diff --git a/src/xwayland.c b/src/xwayland.c index 6697580d..2485361e 100644 --- a/src/xwayland.c +++ b/src/xwayland.c @@ -47,6 +47,7 @@ handle_destroy(struct wl_listener *listener, void *data) wl_list_remove(&view->unmap.link); wl_list_remove(&view->destroy.link); wl_list_remove(&view->request_configure.link); + wl_list_remove(&view->request_maximize.link); free(view); } @@ -60,6 +61,16 @@ handle_request_configure(struct wl_listener *listener, void *data) damage_all_outputs(view->server); } +static void handle_request_maximize(struct wl_listener *listener, void *data) +{ + struct view *view = wl_container_of(listener, view, request_maximize); + + if(view != NULL) { + view_maximize(view, !view->maximized); + } + +} + static void configure(struct view *view, struct wlr_box geo) { @@ -159,6 +170,12 @@ unmap(struct view *view) desktop_focus_topmost_mapped_view(view->server); } +static void +maximize(struct view *view, bool maximized) +{ + wlr_xwayland_surface_set_maximized(view->xwayland_surface, maximized); +} + static const struct view_impl xwl_view_impl = { .configure = configure, .close = _close, @@ -166,6 +183,7 @@ static const struct view_impl xwl_view_impl = { .map = map, .move = move, .unmap = unmap, + .maximize = maximize }; void @@ -200,6 +218,8 @@ xwayland_surface_new(struct wl_listener *listener, void *data) view->request_configure.notify = handle_request_configure; wl_signal_add(&xsurface->events.request_configure, &view->request_configure); + view->request_maximize.notify = handle_request_maximize; + wl_signal_add(&xsurface->events.request_maximize, &view->request_maximize); wl_list_insert(&view->server->views, &view->link); }