discomfitor pushed a commit to branch master. http://git.enlightenment.org/core/enlightenment.git/commit/?id=da74e690f0139aa85272314f1d688a717c52668c
commit da74e690f0139aa85272314f1d688a717c52668c Author: Mike Blumenkrantz <zm...@osg.samsung.com> Date: Tue Apr 5 15:05:10 2016 -0400 redo xdg shell to enforce double buffering of client-side configure serials xdg shell configure states (maximize, fullscreen) return a client ack when the client has applied the state. the ack, followed by the next surface commit, indicates that the surface is ready to be transitioned into the configured state --- src/bin/e_comp_wl.c | 26 +++++ src/bin/e_comp_wl.h | 8 ++ src/modules/wl_desktop_shell/e_mod_main.c | 169 +++++++++++++++++++++++------- 3 files changed, 168 insertions(+), 35 deletions(-) diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c index 5370d2f..0617a3a 100644 --- a/src/bin/e_comp_wl.c +++ b/src/bin/e_comp_wl.c @@ -1058,6 +1058,7 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state) Eina_Rectangle *dmg; Eina_Bool placed = EINA_TRUE; int x = 0, y = 0, w, h; + Eina_Rectangle saved; first = !e_pixmap_usable_get(ec->pixmap); #ifndef HAVE_WAYLAND_ONLY @@ -1073,6 +1074,11 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state) e_client_unignore(ec); } + /* store to override in case of buffered fullscreen */ + memcpy(&saved, &ec->client, sizeof(Eina_Rectangle)); + saved.x -= ec->zone->x; + saved.y -= ec->zone->y; + if (state->new_attach) _e_comp_wl_surface_state_attach(ec, state); @@ -1195,6 +1201,26 @@ _e_comp_wl_surface_state_commit(E_Client *ec, E_Comp_Wl_Surface_State *state) state->sy = 0; state->new_attach = EINA_FALSE; + + if (ec->comp_data->shell.surface) + { + if (ec->comp_data->shell.set.fullscreen) + { + e_client_fullscreen(ec, E_FULLSCREEN_RESIZE); + memcpy(&ec->saved, &saved, sizeof(Eina_Rectangle)); + } + if (ec->comp_data->shell.set.unfullscreen) + e_client_unfullscreen(ec); + if (ec->comp_data->shell.set.maximize) + e_client_maximize(ec, + (e_config->maximize_policy & E_MAXIMIZE_TYPE) | E_MAXIMIZE_BOTH); + if (ec->comp_data->shell.set.unmaximize) + e_client_unmaximize(ec, E_MAXIMIZE_BOTH); + if (ec->comp_data->shell.set.minimize) + e_client_iconify(ec); + memset(&ec->comp_data->shell.set, 0, sizeof(ec->comp_data->shell.set)); + } + /* insert state frame callbacks into comp_data->frames * NB: This clears state->frames list */ ec->comp_data->frames = eina_list_merge(ec->comp_data->frames, diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h index 84fbd48..98044e9 100644 --- a/src/bin/e_comp_wl.h +++ b/src/bin/e_comp_wl.h @@ -286,6 +286,14 @@ struct _E_Comp_Wl_Client_Data void (*unmap)(struct wl_resource *resource); Eina_Rectangle window; E_Shell_Data *data; + struct + { + Eina_Bool fullscreen : 1; + Eina_Bool unfullscreen : 1; + Eina_Bool maximize : 1; + Eina_Bool unmaximize : 1; + Eina_Bool minimize : 1; + } set; } shell; struct { diff --git a/src/modules/wl_desktop_shell/e_mod_main.c b/src/modules/wl_desktop_shell/e_mod_main.c index d30ccca..57ca1bc 100644 --- a/src/modules/wl_desktop_shell/e_mod_main.c +++ b/src/modules/wl_desktop_shell/e_mod_main.c @@ -5,11 +5,26 @@ #define XDG_SERVER_VERSION 5 +typedef enum +{ + STATE_MAXIMIZED = (1 << 0), + STATE_UNMAXIMIZED = (1 << 1), + STATE_FULLSCREEN = (1 << 2), + STATE_UNFULLSCREEN = (1 << 3), +} State; + +typedef struct Pending_State +{ + State state; + uint32_t serial; +} Pending_State; + struct E_Shell_Data { uint32_t edges; int32_t width; int32_t height; + Eina_List *pending; Eina_Bool fullscreen : 1; Eina_Bool maximized : 1; Eina_Bool activated : 1; @@ -115,6 +130,9 @@ _e_shell_surface_destroy(struct wl_resource *resource) if (ec->comp_data) { + E_Shell_Data *shd = ec->comp_data->shell.data; + + E_FREE_LIST(shd->pending, free); E_FREE(ec->comp_data->shell.data); if (ec->comp_data->mapped) { @@ -603,17 +621,14 @@ _e_xdg_surface_state_add(struct wl_resource *resource, struct wl_array *states, } static void -_e_xdg_shell_surface_configure_send(struct wl_resource *resource, uint32_t edges, int32_t width, int32_t height) +_xdg_shell_surface_send_configure(struct wl_resource *resource, Eina_Bool fullscreen, Eina_Bool maximized, uint32_t edges, Eina_Bool focused, int32_t width, int32_t height) { - E_Client *ec; - E_Shell_Data *shd; struct wl_array states; uint32_t serial; + E_Client *ec; + E_Shell_Data *shd; + State pending = 0; - /* DBG("XDG_SHELL: Surface Configure Send: %d \t%d %d\tEdges: %d", */ - /* wl_resource_get_id(resource), width, height, edges); */ - - /* get the client for this resource */ if (!(ec = wl_resource_get_user_data(resource))) { wl_resource_post_error(resource, @@ -621,37 +636,74 @@ _e_xdg_shell_surface_configure_send(struct wl_resource *resource, uint32_t edges "No Client For Shell Surface"); return; } + if (ec->netwm.type == E_WINDOW_TYPE_POPUP_MENU) return; shd = ec->comp_data->shell.data; if ((shd->edges == edges) && (shd->width == width) && (shd->height == height) && - (shd->fullscreen == ec->fullscreen) && - ((!ec->fullscreen) || (shd->maximized == ec->maximized)) && - (shd->activated == ec->focused)) return; + (shd->fullscreen == fullscreen) && + ((!fullscreen) || (shd->maximized == maximized)) && + (shd->activated == focused)) return; shd->edges = edges; shd->width = width; shd->height = height; - shd->fullscreen = ec->fullscreen; - shd->maximized = ec->maximized; - shd->activated = ec->focused; - + if (shd->fullscreen != fullscreen) + { + if (fullscreen) + pending |= STATE_FULLSCREEN; + else + pending |= STATE_UNFULLSCREEN; + } + shd->fullscreen = fullscreen; + if (shd->maximized != maximized) + { + if (maximized) + pending |= STATE_MAXIMIZED; + else + pending |= STATE_UNMAXIMIZED; + } + shd->maximized = maximized; + shd->activated = focused; wl_array_init(&states); - if (ec->fullscreen) + if (fullscreen) _e_xdg_surface_state_add(resource, &states, XDG_SURFACE_STATE_FULLSCREEN); - else if (ec->maximized) + else if (maximized) _e_xdg_surface_state_add(resource, &states, XDG_SURFACE_STATE_MAXIMIZED); - if (edges != 0) + if (edges) _e_xdg_surface_state_add(resource, &states, XDG_SURFACE_STATE_RESIZING); - if (ec->focused) + if (focused) _e_xdg_surface_state_add(resource, &states, XDG_SURFACE_STATE_ACTIVATED); - if (ec->netwm.type != E_WINDOW_TYPE_POPUP_MENU) + serial = wl_display_next_serial(e_comp_wl->wl.disp); + xdg_surface_send_configure(resource, width, height, &states, serial); + { + Pending_State *ps; + + ps = E_NEW(Pending_State, 1); + ps->state = pending; + ps->serial = serial; + shd->pending = eina_list_append(shd->pending, ps); + } + + wl_array_release(&states); +} + +static void +_e_xdg_shell_surface_configure_send(struct wl_resource *resource, uint32_t edges, int32_t width, int32_t height) +{ + E_Client *ec; + + /* get the client for this resource */ + if (!(ec = wl_resource_get_user_data(resource))) { - serial = wl_display_next_serial(e_comp_wl->wl.disp); - xdg_surface_send_configure(resource, width, height, &states, serial); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Client For Shell Surface"); + return; } + if (ec->netwm.type == E_WINDOW_TYPE_POPUP_MENU) return; - wl_array_release(&states); + _xdg_shell_surface_send_configure(resource, ec->fullscreen, ec->maximized, edges, ec->focused, width, height); } static void @@ -832,9 +884,45 @@ _e_xdg_shell_surface_cb_resize(struct wl_client *client EINA_UNUSED, struct wl_r } static void -_e_xdg_shell_surface_cb_ack_configure(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, uint32_t serial EINA_UNUSED) +_e_xdg_shell_surface_cb_ack_configure(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial) { - /* No-Op */ + E_Client *ec; + Pending_State *ps; + E_Shell_Data *shd; + + ec = wl_resource_get_user_data(resource); + if (!ec) + { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, + "No Client For Shell Surface"); + return; + } + shd = ec->comp_data->shell.data; + EINA_LIST_FREE(shd->pending, ps) + { + if (ps->serial > serial) break; + if (ps->state & STATE_FULLSCREEN) + { + ec->comp_data->shell.set.fullscreen = 1; + ec->comp_data->shell.set.unfullscreen = 0; + } + if (ps->state & STATE_UNFULLSCREEN) + { + ec->comp_data->shell.set.unfullscreen = 1; + ec->comp_data->shell.set.fullscreen = 0; + } + if (ps->state & STATE_MAXIMIZED) + { + ec->comp_data->shell.set.maximize = 1; + ec->comp_data->shell.set.unmaximize = 0; + } + if (ps->state & STATE_UNMAXIMIZED) + { + ec->comp_data->shell.set.unmaximize = 1; + ec->comp_data->shell.set.maximize = 0; + } + free(ps); + } } static void @@ -857,6 +945,7 @@ static void _e_xdg_shell_surface_cb_maximized_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) { E_Client *ec; + int w, h; /* get the client for this resource */ if (!(ec = wl_resource_get_user_data(resource))) @@ -867,11 +956,21 @@ _e_xdg_shell_surface_cb_maximized_set(struct wl_client *client EINA_UNUSED, stru return; } - if (!ec->lock_user_maximize) + if (ec->lock_user_maximize) return; + if (e_config->window_maximize_animate) + w = ec->w, h = ec->h; + else { - e_client_maximize(ec, ((e_config->maximize_policy & E_MAXIMIZE_TYPE) | - E_MAXIMIZE_BOTH)); + switch (e_config->maximize_policy & E_MAXIMIZE_TYPE) + { + case E_MAXIMIZE_FULLSCREEN: + w = ec->zone->w, h = ec->zone->h; + break; + default: + e_zone_useful_geometry_get(ec->zone, NULL, NULL, &w, &h); + } } + _xdg_shell_surface_send_configure(resource, ec->fullscreen, 1, 0, ec->focused, w, h); } static void @@ -888,8 +987,8 @@ _e_xdg_shell_surface_cb_maximized_unset(struct wl_client *client EINA_UNUSED, st return; } - e_client_unmaximize(ec, E_MAXIMIZE_BOTH); - _e_xdg_shell_surface_configure_send(resource, 0, ec->w, ec->h); + if (ec->lock_user_maximize) return; + _xdg_shell_surface_send_configure(resource, ec->fullscreen, 0, 0, ec->focused, ec->saved.w, ec->saved.h); } static void @@ -906,8 +1005,8 @@ _e_xdg_shell_surface_cb_fullscreen_set(struct wl_client *client EINA_UNUSED, str return; } - if (!ec->lock_user_fullscreen) - e_client_fullscreen(ec, e_config->fullscreen_policy); + if (ec->lock_user_fullscreen) return; + _xdg_shell_surface_send_configure(resource, 1, ec->maximized, 0, ec->focused, ec->zone->w, ec->zone->h); } static void @@ -924,8 +1023,8 @@ _e_xdg_shell_surface_cb_fullscreen_unset(struct wl_client *client EINA_UNUSED, s return; } - if (!ec->lock_user_fullscreen) - e_client_unfullscreen(ec); + if (ec->lock_user_fullscreen) return; + _xdg_shell_surface_send_configure(resource, 0, ec->maximized, 0, ec->focused, ec->saved.w, ec->saved.h); } static void @@ -942,8 +1041,8 @@ _e_xdg_shell_surface_cb_minimized_set(struct wl_client *client EINA_UNUSED, stru return; } - if (!ec->lock_client_iconify) - e_client_iconify(ec); + if (!ec->lock_user_iconify) + ec->comp_data->shell.set.minimize = 1; } static const struct xdg_surface_interface _e_xdg_surface_interface = --