From 6b4b24155fb3f6fbfc98f38ba3eb5f2f3115371f Mon Sep 17 00:00:00 2001 From: Giulio Camuffo Date: Thu, 29 Jan 2015 19:06:49 +0200 Subject: xwm: support maximizing xwayland windows This patch adds the maximize button to the window frame for the windows which set the MWM_DECOR_MAXIMIZE hint, and it wires it with the shell via a new method in weston_shell_interface. Additionally, it also listens for the wm hints coming from the client, but it doesn't support maximizing a window only vertically or horizontally. The window will be maximized only when both directions are maximized. Reviewed-by: Daniel Stone Reviewed-by: Bryce Harrington --- desktop-shell/shell.c | 72 +++++++++++++++++++++++------------- src/compositor.h | 1 + xwayland/window-manager.c | 93 ++++++++++++++++++++++++++++++++++++++++------- xwayland/xwayland.h | 2 + 4 files changed, 129 insertions(+), 39 deletions(-) diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 742a7100..26cadb63 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -3000,6 +3000,51 @@ shell_interface_set_fullscreen(struct shell_surface *shsurf, set_fullscreen(shsurf, method, framerate, output); } +static struct weston_output * +get_focused_output(struct weston_compositor *compositor) +{ + struct weston_seat *seat; + struct weston_output *output = NULL; + + wl_list_for_each(seat, &compositor->seat_list, link) { + /* Priority has touch focus, then pointer and + * then keyboard focus. We should probably have + * three for loops and check frist for touch, + * then for pointer, etc. but unless somebody has some + * objections, I think this is sufficient. */ + if (seat->touch && seat->touch->focus) + output = seat->touch->focus->output; + else if (seat->pointer && seat->pointer->focus) + output = seat->pointer->focus->output; + else if (seat->keyboard && seat->keyboard->focus) + output = seat->keyboard->focus->output; + + if (output) + break; + } + + return output; +} + +static void +shell_interface_set_maximized(struct shell_surface *shsurf) +{ + struct weston_output *output; + + surface_clear_next_states(shsurf); + shsurf->next_state.maximized = true; + shsurf->state_changed = true; + shsurf->type = SHELL_SURFACE_TOPLEVEL; + + if (!weston_surface_is_mapped(shsurf->surface)) + output = get_focused_output(shsurf->surface->compositor); + else + output = shsurf->surface->output; + + shell_surface_set_output(shsurf, output); + send_configure_for_surface(shsurf); +} + static int shell_interface_move(struct shell_surface *shsurf, struct weston_seat *ws) { @@ -3605,32 +3650,6 @@ get_primary_view(void *shell, struct shell_surface *shsurf) return shsurf->view; } -static struct weston_output * -get_focused_output(struct weston_compositor *compositor) -{ - struct weston_seat *seat; - struct weston_output *output = NULL; - - wl_list_for_each(seat, &compositor->seat_list, link) { - /* Priority has touch focus, then pointer and - * then keyboard focus. We should probably have - * three for loops and check frist for touch, - * then for pointer, etc. but unless somebody has some - * objections, I think this is sufficient. */ - if (seat->touch && seat->touch->focus) - output = seat->touch->focus->output; - else if (seat->pointer && seat->pointer->focus) - output = seat->pointer->focus->output; - else if (seat->keyboard && seat->keyboard->focus) - output = seat->keyboard->focus->output; - - if (output) - break; - } - - return output; -} - static void shell_get_shell_surface(struct wl_client *client, struct wl_resource *resource, @@ -6633,6 +6652,7 @@ module_init(struct weston_compositor *ec, ec->shell_interface.resize = surface_resize; ec->shell_interface.set_title = set_title; ec->shell_interface.set_window_geometry = set_window_geometry; + ec->shell_interface.set_maximized = shell_interface_set_maximized; weston_layer_init(&shell->fullscreen_layer, &ec->cursor_layer.link); weston_layer_init(&shell->panel_layer, &shell->fullscreen_layer.link); diff --git a/src/compositor.h b/src/compositor.h index aa87ec0b..5c0ea74b 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -121,6 +121,7 @@ struct weston_shell_interface { void (*set_window_geometry)(struct shell_surface *shsurf, int32_t x, int32_t y, int32_t width, int32_t height); + void (*set_maximized)(struct shell_surface *shsurf); }; struct weston_animation { diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c index 4d3611f2..07c2ef30 100644 --- a/xwayland/window-manager.c +++ b/xwayland/window-manager.c @@ -144,6 +144,8 @@ struct weston_wm_window { int fullscreen; int has_alpha; int delete_window; + int maximized_vert; + int maximized_horz; struct wm_size_hints size_hints; struct motif_wm_hints motif_hints; struct wl_list link; @@ -472,6 +474,10 @@ weston_wm_window_read_properties(struct weston_wm_window *window) for (i = 0; i < reply->value_len; i++) if (atom[i] == wm->atom.net_wm_state_fullscreen) window->fullscreen = 1; + if (atom[i] == wm->atom.net_wm_state_maximized_vert) + window->maximized_vert = 1; + if (atom[i] == wm->atom.net_wm_state_maximized_horz) + window->maximized_horz = 1; break; case TYPE_MOTIF_WM_HINTS: memcpy(&window->motif_hints, @@ -479,7 +485,7 @@ weston_wm_window_read_properties(struct weston_wm_window *window) sizeof window->motif_hints); if (window->motif_hints.flags & MWM_HINTS_DECORATIONS) window->decorate = - window->motif_hints.decorations > 0; + window->motif_hints.decorations; break; default: break; @@ -789,12 +795,16 @@ static void weston_wm_window_set_net_wm_state(struct weston_wm_window *window) { struct weston_wm *wm = window->wm; - uint32_t property[1]; + uint32_t property[3]; int i; i = 0; if (window->fullscreen) property[i++] = wm->atom.net_wm_state_fullscreen; + if (window->maximized_vert) + property[i++] = wm->atom.net_wm_state_maximized_vert; + if (window->maximized_horz) + property[i++] = wm->atom.net_wm_state_maximized_horz; xcb_change_property(wm->conn, XCB_PROP_MODE_REPLACE, @@ -811,10 +821,14 @@ weston_wm_window_create_frame(struct weston_wm_window *window) struct weston_wm *wm = window->wm; uint32_t values[3]; int x, y, width, height; + int buttons = FRAME_BUTTON_CLOSE; + + if (window->decorate & MWM_DECOR_MAXIMIZE) + buttons |= FRAME_BUTTON_MAXIMIZE; window->frame = frame_create(window->wm->theme, window->width, window->height, - FRAME_BUTTON_CLOSE, window->name); + buttons, window->name); frame_resize_inside(window->frame, window->width, window->height); weston_wm_window_get_frame_size(window, &width, &height); @@ -1331,6 +1345,28 @@ update_state(int action, int *state) static void weston_wm_window_configure(void *data); +static void +weston_wm_window_set_toplevel(struct weston_wm_window *window) +{ + struct weston_shell_interface *shell_interface = + &window->wm->server->compositor->shell_interface; + + shell_interface->set_toplevel(window->shsurf); + window->width = window->saved_width; + window->height = window->saved_height; + if (window->frame) + frame_resize_inside(window->frame, + window->width, + window->height); + weston_wm_window_configure(window); +} + +static inline bool +weston_wm_window_is_maximized(struct weston_wm_window *window) +{ + return window->maximized_horz && window->maximized_vert; +} + static void weston_wm_window_handle_state(struct weston_wm_window *window, xcb_client_message_event_t *client_message) @@ -1339,6 +1375,7 @@ weston_wm_window_handle_state(struct weston_wm_window *window, struct weston_shell_interface *shell_interface = &wm->server->compositor->shell_interface; uint32_t action, property; + int maximized = weston_wm_window_is_maximized(window); action = client_message->data.data32[0]; property = client_message->data.data32[1]; @@ -1356,15 +1393,26 @@ weston_wm_window_handle_state(struct weston_wm_window *window, 0, NULL); } else { if (window->shsurf) - shell_interface->set_toplevel(window->shsurf); - - window->width = window->saved_width; - window->height = window->saved_height; - if (window->frame) - frame_resize_inside(window->frame, - window->width, - window->height); - weston_wm_window_configure(window); + weston_wm_window_set_toplevel(window); + } + } else { + if (property == wm->atom.net_wm_state_maximized_vert && + update_state(action, &window->maximized_vert)) + weston_wm_window_set_net_wm_state(window); + if (property == wm->atom.net_wm_state_maximized_horz && + update_state(action, &window->maximized_horz)) + weston_wm_window_set_net_wm_state(window); + + if (maximized != weston_wm_window_is_maximized(window)) { + if (weston_wm_window_is_maximized(window)) { + window->saved_width = window->width; + window->saved_height = window->height; + + if (window->shsurf) + shell_interface->set_maximized(window->shsurf); + } else if (window->shsurf) { + weston_wm_window_set_toplevel(window); + } } } } @@ -1696,6 +1744,19 @@ weston_wm_handle_button(struct weston_wm *wm, xcb_generic_event_t *event) weston_wm_window_close(window, button->time); frame_status_clear(window->frame, FRAME_STATUS_CLOSE); } + + if (frame_status(window->frame) & FRAME_STATUS_MAXIMIZE) { + window->maximized_horz = !window->maximized_horz; + window->maximized_vert = !window->maximized_vert; + if (weston_wm_window_is_maximized(window)) { + window->saved_width = window->width; + window->saved_height = window->height; + shell_interface->set_maximized(window->shsurf); + } else { + weston_wm_window_set_toplevel(window); + } + frame_status_clear(window->frame, FRAME_STATUS_MAXIMIZE); + } } static void @@ -1884,6 +1945,8 @@ weston_wm_get_resources(struct weston_wm *wm) { "_NET_WM_PID", F(atom.net_wm_pid) }, { "_NET_WM_ICON", F(atom.net_wm_icon) }, { "_NET_WM_STATE", F(atom.net_wm_state) }, + { "_NET_WM_STATE_MAXIMIZED_VERT", F(atom.net_wm_state_maximized_vert) }, + { "_NET_WM_STATE_MAXIMIZED_HORZ", F(atom.net_wm_state_maximized_horz) }, { "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) }, { "_NET_WM_USER_TIME", F(atom.net_wm_user_time) }, { "_NET_WM_ICON_NAME", F(atom.net_wm_icon_name) }, @@ -2061,7 +2124,7 @@ weston_wm_create(struct weston_xserver *wxs, int fd) struct wl_event_loop *loop; xcb_screen_iterator_t s; uint32_t values[1]; - xcb_atom_t supported[3]; + xcb_atom_t supported[5]; wm = zalloc(sizeof *wm); if (wm == NULL) @@ -2112,6 +2175,8 @@ weston_wm_create(struct weston_xserver *wxs, int fd) supported[0] = wm->atom.net_wm_moveresize; supported[1] = wm->atom.net_wm_state; supported[2] = wm->atom.net_wm_state_fullscreen; + supported[3] = wm->atom.net_wm_state_maximized_vert; + supported[4] = wm->atom.net_wm_state_maximized_horz; xcb_change_property(wm->conn, XCB_PROP_MODE_REPLACE, wm->screen->root, @@ -2389,6 +2454,8 @@ xserver_map_shell_surface(struct weston_wm_window *window, parent->surface, window->x - parent->x, window->y - parent->y, flags); + } else if (weston_wm_window_is_maximized(window)) { + shell_interface->set_maximized(window->shsurf); } else { if (weston_wm_window_type_inactive(window)) { shell_interface->set_xwayland(window->shsurf, diff --git a/xwayland/xwayland.h b/xwayland/xwayland.h index b42110bd..54cbf6d6 100644 --- a/xwayland/xwayland.h +++ b/xwayland/xwayland.h @@ -102,6 +102,8 @@ struct weston_wm { xcb_atom_t net_wm_pid; xcb_atom_t net_wm_icon; xcb_atom_t net_wm_state; + xcb_atom_t net_wm_state_maximized_vert; + xcb_atom_t net_wm_state_maximized_horz; xcb_atom_t net_wm_state_fullscreen; xcb_atom_t net_wm_user_time; xcb_atom_t net_wm_icon_name; -- cgit v1.2.1