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 <[email protected]>
---

v4: fixed the warning

 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 f6d9c79..16a0178 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,
@@ -6629,6 +6648,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 aa87ec0..5c0ea74 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 4d3611f..07c2ef3 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);
@@ -1332,6 +1346,28 @@ 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 b42110b..54cbf6d 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;
-- 
2.2.2

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to