#include "e.h"
-
-#include <libds/types/ds_surface.h>
-#include <libds/types/ds_xdg_shell_v6.h>
+#include <xdg-shell-unstable-v6-server-protocol.h>
#ifdef LOG
#undef LOG
#define LOG(f, e, x...) ELOGF("XDG6 <LOG>", f, e, ##x)
#define ERR(f, e, x...) ELOGF("XDG6 <ERR>", f, e, ##x)
-typedef struct _E_Xdg_Shell_V6 E_Xdg_Shell_V6;
-typedef struct _E_Xdg_Toplevel_V6 E_Xdg_Toplevel_V6;
+#define e_xdg_surface_role_biggest_struct E_Xdg_Toplevel
+#define E_XDG_SURFACE_V6_TYPE (int)0xE0b06000
+
+const int WAIT_ACK_COUNT_MAX = 16;
-struct _E_Xdg_Shell_V6
+typedef enum _E_Xdg_Surface_Role E_Xdg_Surface_Role;
+typedef struct _E_Xdg_Size E_Xdg_Size;
+typedef struct _E_Xdg_Shell E_Xdg_Shell;
+typedef struct _E_Xdg_Surface E_Xdg_Surface;
+typedef struct _E_Xdg_Toplevel E_Xdg_Toplevel;
+typedef struct _E_Xdg_Popup E_Xdg_Popup;
+typedef struct _E_Xdg_Positioner E_Xdg_Positioner;
+typedef struct _E_Xdg_Toplevel_State E_Xdg_Toplevel_State;
+typedef struct _E_Xdg_Surface_Configure E_Xdg_Surface_Configure;
+
+enum _E_Xdg_Surface_Role
{
- struct ds_xdg_shell_v6 *ds_xdg_shell;
+ E_XDG_SURFACE_ROLE_NONE,
+ E_XDG_SURFACE_ROLE_TOPLEVEL,
+ E_XDG_SURFACE_ROLE_POPUP,
+};
- struct wl_listener destroy;
- struct wl_listener new_surface;
+struct _E_Xdg_Size
+{
+ int w, h;
};
-struct _E_Xdg_Toplevel_V6
+struct _E_Xdg_Shell
{
- struct ds_xdg_toplevel_v6 *ds_toplevel;
- E_Client *ec;
+ struct wl_client *wclient;
+ struct wl_resource *resource; /* xdg_shell resource */
+ Eina_List *surfaces; /* list of all E_Xdg_Surface belonging to shell */
+ Eina_List *positioners; /* list of E_Xdg_Positioner */
+ uint32_t ping_serial;
+};
- struct wl_listener set_parent;
- struct wl_listener set_title;
- struct wl_listener set_app_id;
- struct wl_listener request_move;
- struct wl_listener request_resize;
- struct wl_listener request_maximize;
- struct wl_listener request_fullscreen;
- struct wl_listener request_minimize;
- struct wl_listener destroy;
- struct wl_listener configure;
- struct wl_listener ping_timeout;
- struct wl_listener surface_commit;
+struct _E_Xdg_Toplevel_State
+{
+ Eina_Bool maximized;
+ Eina_Bool fullscreen;
+ Eina_Bool resizing;
+ Eina_Bool activated;
};
-static void _e_xdg_shell_v6_cb_destroy(struct wl_listener *listener, void *data);
-static void _e_xdg_shell_v6_cb_new_surface(struct wl_listener *listener, void *data);
-static void _e_xdg_toplevel_v6_add(struct ds_xdg_surface_v6 *ds_xdg_surface);
-static void _e_xdg_toplevel_v6_cb_destroy(struct wl_listener *listener, void *data);
-static E_Xdg_Toplevel_V6 *_e_xdg_toplevel_v6_from_shell_surface_resource(struct wl_resource *shsurface_resource);
+struct _E_Xdg_Surface
+{
+ E_Object e_obj_inherit;
+ struct wl_resource *resource; /* wl_resource for Zxdg_Surface_V6 */
+ E_Client *ec; /* E_Client corresponding Xdg_Surface */
+ E_Xdg_Shell *shell; /* Xdg_Shell created Xdg_Surface */
+ Eina_List *configure_list; /* list of data being appended whenever configure send and remove by ack_configure */
+
+ Ecore_Idle_Enterer *configure_idle; /* Idle_Enterer for sending configure */
+ E_Comp_Wl_Hook *commit_hook; /* Handler raised when wl_surface is committed. */
+
+ E_Xdg_Surface_Role role;
+ Eina_Rectangle configured_geometry; /* configured geometry by compositor */
+ Eina_Rectangle window_geometry; /* window geometry set by client */
+
+ Eina_Bool configured :1;
+ Eina_Bool has_window_geometry: 1;
+ Eina_Bool wait_next_commit;
+};
-EINTERN Eina_Bool
-e_xdg_shell_v6_init(void)
+struct _E_Xdg_Toplevel
{
- static E_Xdg_Shell_V6 shell = { .ds_xdg_shell = NULL };
+ E_Xdg_Surface base;
+ struct wl_resource *resource;
+
+ struct
+ {
+ E_Xdg_Toplevel_State state;
+ E_Xdg_Size size;
+ uint32_t edges;
+ } pending;
+ struct
+ {
+ E_Xdg_Toplevel_State state;
+ E_Xdg_Size size;
+ E_Xdg_Size min_size, max_size;
+ } next;
+ struct
+ {
+ E_Xdg_Toplevel_State state;
+ E_Xdg_Size min_size, max_size;
+ } current;
+};
- LOG("Initializing Xdg_Shell_V6", NULL);
+struct _E_Xdg_Popup
+{
+ E_Xdg_Surface base;
- if (shell.ds_xdg_shell)
- {
- LOG("Xdg_Shell_V6 already initialized", NULL);
- return EINA_TRUE;
- }
+ struct wl_resource *resource;
+ E_Xdg_Surface *parent;
+
+ Eina_Rectangle geometry;
+ Eina_Bool committed;
+};
+
+struct _E_Xdg_Surface_Configure
+{
+ uint32_t serial;
+ E_Xdg_Toplevel_State state;
+ E_Xdg_Size size;
+};
+
+struct _E_Xdg_Positioner
+{
+ E_Xdg_Shell *shell;
+ struct wl_resource *resource; /* xdg_positioner_v6 resources */
+ E_Xdg_Size size;
+ Eina_Rectangle anchor_rect;
+ enum zxdg_positioner_v6_anchor anchor;
+ enum zxdg_positioner_v6_gravity gravity;
+ enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment;
+ struct
+ {
+ int x, y;
+ } offset;
+};
+
+static struct wl_global *global_resource = NULL;
+
+static void _e_xdg_shell_surface_add(E_Xdg_Shell *shell, E_Xdg_Surface *exsurf);
+static void _e_xdg_shell_surface_remove(E_Xdg_Shell *shell, E_Xdg_Surface *exsurf);
+static void _e_xdg_shell_ping(E_Xdg_Shell *shell);
+static Eina_Bool _e_xdg_surface_cb_configure_send(void *data);
+static Eina_Rectangle _e_xdg_positioner_geometry_get(E_Xdg_Positioner *p);
+/**********************************************************
+ * Implementation for Utility
+ **********************************************************/
+static Eina_Bool
+_e_client_shsurface_assignable_check(E_Client *ec)
+{
+ E_Comp_Wl_Client_Data *cdata;
- shell.ds_xdg_shell = ds_xdg_shell_v6_create(e_comp_wl->wl.disp);
- if (!shell.ds_xdg_shell)
+ if (!e_shell_e_client_shell_assignable_check(ec))
{
- ERR("Could not create ds_xdg_shell_v6", NULL);
+ ERR("Could not assign shell", ec);
+ cdata = e_client_cdata_get(ec);
+ wl_resource_post_error(cdata->surface,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "Could not assign shell surface to wl_surface");
return EINA_FALSE;
}
- shell.destroy.notify = _e_xdg_shell_v6_cb_destroy;
- ds_xdg_shell_v6_add_destroy_listener(shell.ds_xdg_shell, &shell.destroy);
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+_e_client_xdg_shell_v6_assigned_check(E_Client *ec)
+{
+ E_Comp_Wl_Client_Data *cdata = e_client_cdata_get(ec);
+ return !!cdata->sh_v6.res_role;
+}
- shell.new_surface.notify = _e_xdg_shell_v6_cb_new_surface;
- ds_xdg_shell_v6_add_new_surface_listener(shell.ds_xdg_shell, &shell.new_surface);
+static void
+_e_client_xdg_shell_v6_assign(E_Client *ec,
+ struct wl_resource *resource,
+ E_Comp_Wl_Sh_Surf_Role role)
+{
+ E_Comp_Wl_Client_Data *cdata;
- return EINA_TRUE;
+ if (!ec) return;
+ if (e_object_is_del(E_OBJECT(ec))) return;
+ cdata = e_client_cdata_get(ec);
+ if (!cdata) return;
+
+ cdata->sh_v6.res_role = resource;
+ cdata->sh_v6.role = role;
}
-EINTERN E_Client *
-e_xdg_shell_v6_xdg_surface_ec_get(struct wl_resource *resource)
+static void
+_e_client_xdg_shell_v6_role_assingment_unset(E_Client *ec)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Comp_Wl_Client_Data *cdata;
- toplevel = _e_xdg_toplevel_v6_from_shell_surface_resource(resource);
- if (!toplevel)
- {
- ERR("No E_Xdg_Toplevel_V6 in wl_resource", NULL);
- return NULL;
- }
+ if (!ec) return;
+ if (e_object_is_del(E_OBJECT(ec))) return;
+ cdata = e_client_cdata_get(ec);
+ if (!cdata) return;
- return toplevel->ec;
+ _e_client_xdg_shell_v6_assign(ec, NULL, E_COMP_WL_SH_SURF_ROLE_NONE);
}
static void
-_e_xdg_shell_v6_cb_destroy(struct wl_listener *listener, void *data)
+_validate_size(struct wl_resource *resource, int32_t value)
{
- E_Xdg_Shell_V6 *shell;
+ if (value <= 0)
+ wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid size passed");
+}
+/* End of utility */
- LOG("Destroy Xdg_Shell_V6", NULL);
+/**********************************************************
+ * Implementation for Xdg_popup
+ **********************************************************/
+static void
+_e_xdg_popup_positioner_apply(E_Xdg_Popup *popup, E_Xdg_Positioner *pos)
+{
+ popup->geometry = _e_xdg_positioner_geometry_get(pos);
- shell = wl_container_of(listener, shell, destroy);
+ /* TODO apply geometry to popup */
- wl_list_remove(&shell->destroy.link);
- wl_list_remove(&shell->new_surface.link);
- shell->ds_xdg_shell = NULL;
}
static void
-_e_xdg_shell_v6_cb_new_surface(struct wl_listener *listener, void *data)
+_e_xdg_popup_parent_set(E_Xdg_Popup *popup, E_Xdg_Surface *parent)
{
- struct ds_xdg_surface_v6 *ds_xdg_surface = data;
+ E_Comp_Wl_Client_Data *parent_cdata;
- if (ds_xdg_surface->role == DS_XDG_SURFACE_V6_ROLE_TOPLEVEL)
- _e_xdg_toplevel_v6_add(ds_xdg_surface);
- else
- ERR("Unexpected role of xdg_surface_v6: role(%d)", NULL, ds_xdg_surface->role);
+ popup->parent = parent;
+ parent_cdata = e_client_cdata_get(parent->ec);
+
+ /* set this client as a transient for parent */
+ e_shell_e_client_parent_set(popup->base.ec, parent_cdata->surface);
}
-static E_Xdg_Toplevel_V6 *
-_e_xdg_toplevel_v6_from_shell_surface_resource(struct wl_resource *shsurface_resource)
+static void
+_e_xdg_popup_set(E_Xdg_Popup *popup, struct wl_resource *resource)
{
- E_Xdg_Toplevel_V6 *toplevel;
- struct ds_xdg_surface_v6 *ds_xdg_surface;
- struct wl_listener *listener;
+ popup->resource = resource;
+ _e_client_xdg_shell_v6_assign(popup->base.ec, resource, E_COMP_WL_SH_SURF_ROLE_POPUP);
+ e_shell_e_client_popup_set(popup->base.ec);
+}
- ds_xdg_surface = ds_xdg_surface_v6_from_resource(shsurface_resource);
- if (!ds_xdg_surface)
- return NULL;
+static void
+_e_xdg_popup_committed(E_Xdg_Popup *popup)
+{
+ if (!popup->committed)
+ {
+ if (!popup->base.configure_idle)
+ {
+ popup->base.configure_idle =
+ ecore_idle_enterer_add(_e_xdg_surface_cb_configure_send, popup);
+ }
+ }
- listener = wl_signal_get(&ds_xdg_surface->events.destroy,
- _e_xdg_toplevel_v6_cb_destroy);
- if (listener)
- return wl_container_of(listener, toplevel, destroy);
+ popup->committed = EINA_TRUE;
- return NULL;
+ /* TODO: Weston does update the position of popup here */
}
static void
-_e_xdg_toplevel_v6_fullscreen_send(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_popup_configure_send(E_Xdg_Popup *popup)
{
- struct ds_xdg_toplevel_v6 *ds_toplevel = toplevel->ds_toplevel;
- E_Client *ec = toplevel->ec;
+ if (!popup) return;
+ if (!popup->resource) return;
+
+ zxdg_popup_v6_send_configure(popup->resource,
+ popup->geometry.x,
+ popup->geometry.y,
+ popup->geometry.w,
+ popup->geometry.h);
+}
- if (ds_toplevel->scheduled.fullscreen == ec->fullscreen)
- return;
+static void
+_e_xdg_popup_cb_resource_destroy(struct wl_resource *resource)
+{
+ E_Xdg_Popup *popup;
- LOG("Send fullscreen(%d)", ec, ec->fullscreen);
+ popup = wl_resource_get_user_data(resource);
+ popup->resource = NULL;
+ _e_client_xdg_shell_v6_role_assingment_unset(popup->base.ec);
+ e_object_unref(E_OBJECT(popup));
+}
- ds_xdg_toplevel_v6_set_fullscreen(ds_toplevel, ec->fullscreen);
+static void
+_e_xdg_popup_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
}
static void
-_e_xdg_toplevel_v6_maximized_send(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_popup_cb_grab(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *res_seat,
+ uint32_t serial)
{
- struct ds_xdg_toplevel_v6 *ds_toplevel = toplevel->ds_toplevel;
- E_Client *ec = toplevel->ec;
+ /* TODO no op */
+}
- if (ds_toplevel->scheduled.maximized == !!ec->maximized)
- return;
+static const struct zxdg_popup_v6_interface _e_xdg_popup_interface =
+{
+ _e_xdg_popup_cb_destroy,
+ _e_xdg_popup_cb_grab
+};
- LOG("Send maximized(%d)", ec, ec->maximized);
+/* End of Xdg_Popup */
- ds_xdg_toplevel_v6_set_maximized(ds_toplevel, ec->maximized);
+/**********************************************************
+ * Implementation for Xdg_toplevel
+ ***********************************************************/
+static void
+_e_xdg_toplevel_set(E_Xdg_Toplevel *toplevel, struct wl_resource *resource)
+{
+ toplevel->resource = resource;
+ _e_client_xdg_shell_v6_assign(toplevel->base.ec, resource, E_COMP_WL_SH_SURF_ROLE_TOPLV);
+ e_shell_e_client_toplevel_set(toplevel->base.ec);
+ e_comp_wl_shell_surface_ready(toplevel->base.ec);
}
static void
-_e_xdg_toplevel_v6_resizing_send(E_Xdg_Toplevel_V6 *toplevel, Eina_Bool resizing)
+_e_xdg_toplevel_committed(E_Xdg_Toplevel *toplevel)
{
- struct ds_xdg_toplevel_v6 *ds_toplevel = toplevel->ds_toplevel;
+ E_Client *ec;
+ E_Comp_Wl_Client_Data *cdata;
+ int pw, ph;
- if (ds_toplevel->scheduled.resizing == resizing)
- return;
+ ec = toplevel->base.ec;
+ if (!ec)
+ {
+ ERR("E_Xdg_Toplevel must have E_Client", NULL);
+ return;
+ }
+
+ cdata = e_client_cdata_get(ec);
+ if (!cdata)
+ {
+ ERR("E_Client must have E_Comp_Wl_Client_Data", ec);
+ return;
+ }
+
+ if (!toplevel->resource)
+ {
+ ERR("E_Client must have xdg_toplevel instance", ec);
+ return;
+ }
+
+ if (!e_pixmap_usable_get(ec->pixmap))
+ {
+ ERR("E_Pixmap should be valid here", ec);
+ return;
+ }
+
+ e_pixmap_size_get(ec->pixmap, &pw, &ph);
- LOG("Send resizing(%d)", toplevel->ec, resizing);
+ if ((toplevel->next.state.maximized || toplevel->next.state.fullscreen) &&
+ (toplevel->next.size.w != cdata->shell.window.w ||
+ toplevel->next.size.h != cdata->shell.window.h ||
+ toplevel->next.size.w != pw ||
+ toplevel->next.size.h != ph))
+ {
+ ERR("Xdg_surface buffer does not match the configured state\nmaximized: "
+ "%d fullscreen: %d, size:expected(%d %d) shell.request(%d %d) pixmap(%d %d)",
+ ec,
+ toplevel->next.state.maximized,
+ toplevel->next.state.fullscreen,
+ toplevel->next.size.w, toplevel->next.size.h,
+ cdata->shell.window.w, cdata->shell.window.h,
+ pw, ph);
+ /* TODO Disable this part for now, but need to consider enabling it later.
+ * To enable this part, we first need to ensure that do not send configure
+ * with argument of size as 0, and make client ensure that set
+ * window geometry correctly so that match its commit buffer size, if
+ * its state is maximize or fullscreen.
+ */
+ /*
+ wl_resource_post_error(toplevel->base.shell->resource,
+ ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
+ "xdg_surface buffer does not match the configured state");
+ return;
+ */
+ }
+ toplevel->current.state = toplevel->next.state;
+ toplevel->current.min_size = toplevel->next.min_size;
+ toplevel->current.max_size = toplevel->next.max_size;
- ds_xdg_toplevel_v6_set_resizing(ds_toplevel, resizing);
+ /* Now we can adjust size of its composite object corresponding client */
+ if (!ec->lock_client_size)
+ {
+ ec->icccm.min_w = toplevel->current.min_size.w;
+ ec->icccm.min_h = toplevel->current.min_size.h;
+ ec->icccm.max_w = toplevel->current.max_size.w;
+ ec->icccm.max_h = toplevel->current.max_size.h;
+ }
}
static void
-_e_xdg_toplevel_v6_activated_send(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_configure_ack(E_Xdg_Toplevel *toplevel,
+ E_Xdg_Surface_Configure *configure)
{
- struct ds_xdg_toplevel_v6 *ds_toplevel = toplevel->ds_toplevel;
- E_Client *ec = toplevel->ec, *focused_ec;
- Eina_Bool activated;
+ LOG("Ack configure TOPLEVEL size (%d %d) "
+ "state (f %d m %d r %d a %d)",
+ toplevel->base.ec,
+ configure->size.w, configure->size.h,
+ configure->state.fullscreen, configure->state.maximized,
+ configure->state.resizing, configure->state.activated);
+
+ toplevel->next.state = configure->state;
+ toplevel->next.size = configure->size;
+ toplevel->base.wait_next_commit = EINA_TRUE;
+}
- focused_ec = e_client_focused_get();
- activated = (focused_ec == ec);
+static void
+_e_xdg_toplevel_configure_send(E_Xdg_Toplevel *toplevel,
+ E_Xdg_Surface_Configure *configure)
+{
+ uint32_t *s;
+ struct wl_array states;
+ Eina_Bool array_added = EINA_FALSE;
- if (ds_toplevel->scheduled.activated == activated)
- return;
+ if (!toplevel->resource) return;
+
+ configure->state = toplevel->pending.state;
+ configure->size = toplevel->pending.size;
+
+ wl_array_init(&states);
+ if (toplevel->pending.state.maximized)
+ {
+ s = wl_array_add(&states, sizeof(uint32_t));
+ if (!s) goto err;
+ array_added = EINA_TRUE;
+ *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED;
+ }
+ if (toplevel->pending.state.fullscreen)
+ {
+ s = wl_array_add(&states, sizeof(uint32_t));
+ if (!s) goto err;
+ array_added = EINA_TRUE;
+ *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN;
+ }
+ if (toplevel->pending.state.resizing)
+ {
+ s = wl_array_add(&states, sizeof(uint32_t));
+ if (!s) goto err;
+ array_added = EINA_TRUE;
+ *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING;
+ }
+ if (toplevel->pending.state.activated)
+ {
+ s = wl_array_add(&states, sizeof(uint32_t));
+ if (!s) goto err;
+ *s = ZXDG_TOPLEVEL_V6_STATE_ACTIVATED;
+ }
+
+ LOG("Send configure: Topevel size (%d %d) "
+ "state (f %d m %d r %d a %d)",
+ toplevel->base.ec,
+ toplevel->pending.size.w, toplevel->pending.size.h,
+ toplevel->pending.state.fullscreen, toplevel->pending.state.maximized,
+ toplevel->pending.state.resizing, toplevel->pending.state.activated);
+
+ zxdg_toplevel_v6_send_configure(toplevel->resource,
+ toplevel->pending.size.w,
+ toplevel->pending.size.h,
+ &states);
- LOG("Send activated(%d)", ec, activated);
+ wl_array_release(&states);
- ds_xdg_toplevel_v6_set_activated(ds_toplevel, activated);
+ // clear toplevel's pending size
+ toplevel->pending.size.w = 0;
+ toplevel->pending.size.h = 0;
+
+ return;
+
+err:
+ ERR("Failed on adding item to states !", toplevel->base.ec);
+ if (array_added) wl_array_release(&states);
+ return;
}
static void
-_e_xdg_toplevel_v6_size_send(E_Xdg_Toplevel_V6 *toplevel, int32_t width, int32_t height)
+_e_xdg_toplevel_configure_pending_set(E_Xdg_Toplevel *toplevel,
+ uint32_t edges,
+ int32_t width,
+ int32_t height)
{
- E_Client *ec = toplevel->ec;
- struct ds_xdg_toplevel_v6 *ds_toplevel = toplevel->ds_toplevel;
- int32_t configure_width = 0, configure_height = 0;
+ E_Client *ec, *focused;
int mw, mh;
+ ec = toplevel->base.ec;
+
+ toplevel->pending.state.fullscreen = ec->fullscreen;
+ toplevel->pending.state.maximized = !!ec->maximized;
+ toplevel->pending.state.resizing = !!edges;
+ toplevel->pending.edges = edges;
if ((width != -1) && (height != -1))
{
- configure_width = width;
- configure_height = height;
+ /* NOTE:
+ * Width and Height are -1 means that the configure event doesn't consider size value.
+ * So, we update pending size if the size are not -1.
+ */
+ toplevel->pending.size.w = width;
+ toplevel->pending.size.h = height;
}
if (ec->fullscreen)
LOG("FORCELY STAY current fullscreen size (%d %d) of E_Client, requested size "
"is (%d %d), the state (maximize %d, fullscreen %d)",
ec, mw, mh, width, height, ec->maximized, ec->fullscreen);
- configure_width = mw;
- configure_height = mh;
+ toplevel->pending.size.w = mw;
+ toplevel->pending.size.h = mh;
}
else if (ec->maximized)
{
+ /* NOTE
+ * DO NOT configure maximized or fullscreen surface to (0x0) size.
+ * If the width or height arguments are zero, it means the client should
+ * decide its own window dimension. See xdg-shell-v6.xml
+ */
e_client_maximized_geometry_get(ec, NULL, NULL, &mw, &mh);
LOG("FORCELY STAY current maximized size (%d %d) of E_Client, requested size "
"is (%d %d), the state (maximize %d, fullscreen %d)",
- ec, mw, mh, width, height, ec->maximized, ec->fullscreen);
- configure_width = mw;
- configure_height = mh;
+ ec, mw, mh, width, height,
+ toplevel->pending.state.maximized,
+ toplevel->pending.state.fullscreen);
+ toplevel->pending.size.w = mw;
+ toplevel->pending.size.h = mh;
}
- LOG("Send size(%dx%d)", ec, configure_width, configure_height);
+ focused = e_client_focused_get();
+ toplevel->pending.state.activated = (ec == focused);
- ds_xdg_toplevel_v6_set_size(ds_toplevel, configure_width, configure_height);
+ LOG("Set pending state: edges %d size (%d %d) "
+ "state (f %d m %d r %d a %d)",
+ ec,
+ toplevel->pending.edges,
+ toplevel->pending.size.w, toplevel->pending.size.h,
+ toplevel->pending.state.fullscreen, toplevel->pending.state.maximized,
+ toplevel->pending.state.resizing, toplevel->pending.state.activated);
}
-static void
-_e_xdg_toplevel_v6_configure_send(struct wl_resource *shsurface_resource,
- uint32_t edges, int32_t width, int32_t height)
+static Eina_Bool
+_e_xdg_toplevel_pending_state_compare(E_Xdg_Toplevel *toplevel)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Surface_Configure *configure;
+ int pw, ph;
+ int cw, ch;
- toplevel = _e_xdg_toplevel_v6_from_shell_surface_resource(shsurface_resource);
- if (!toplevel)
- return;
+ struct {
+ E_Xdg_Toplevel_State state;
+ E_Xdg_Size size;
+ } configured;
- _e_xdg_toplevel_v6_fullscreen_send(toplevel);
- _e_xdg_toplevel_v6_maximized_send(toplevel);
- _e_xdg_toplevel_v6_resizing_send(toplevel, !!edges);
- _e_xdg_toplevel_v6_size_send(toplevel, width, height);
- _e_xdg_toplevel_v6_activated_send(toplevel);
-}
+ /* must send configure at least once */
+ if (!toplevel->base.configured)
+ return EINA_FALSE;
-static void
-_e_xdg_toplevel_v6_configure(struct wl_resource *shsurface_resource,
- Evas_Coord x, Evas_Coord y,
- Evas_Coord w, Evas_Coord h)
-{
- E_Xdg_Toplevel_V6 *toplevel;
+ if (!toplevel->base.configure_list)
+ {
+ /* if configure_list is empty, last configure is actually the current
+ * state */
+ e_pixmap_size_get(toplevel->base.ec->pixmap, &pw, &ph);
+ e_client_geometry_get(toplevel->base.ec, NULL, NULL, &cw, &ch);
+
+ if ((pw != cw) || (ph != ch))
+ {
+ ERR("The size of buffer is different with expected "
+ "client size. So, here, let it compare with buffer size.",
+ toplevel->base.ec);
+ }
+
+ configured.state = toplevel->current.state;
+ configured.size.w = pw;
+ configured.size.h = ph;
+ }
+ else
+ {
+ configure = eina_list_last_data_get(toplevel->base.configure_list);
+ configured.state = configure->state;
+ configured.size = configure->size;
+ }
- toplevel = _e_xdg_toplevel_v6_from_shell_surface_resource(shsurface_resource);
- if (!toplevel)
- return;
+ if (toplevel->pending.state.activated != configured.state.activated)
+ return EINA_FALSE;
+ if (toplevel->pending.state.fullscreen != configured.state.fullscreen)
+ return EINA_FALSE;
+ if (toplevel->pending.state.maximized != configured.state.maximized)
+ return EINA_FALSE;
+ if (toplevel->pending.state.resizing != configured.state.resizing)
+ return EINA_FALSE;
+
+ if ((toplevel->pending.size.w == configured.size.w) &&
+ (toplevel->pending.size.h == configured.size.h))
+ {
+ if (!toplevel->base.ec->changes.size)
+ return EINA_TRUE;
+ }
+
+ if ((toplevel->pending.size.w == 0) &&
+ (toplevel->pending.size.h == 0))
+ return EINA_TRUE;
- e_client_util_move_resize_without_frame(toplevel->ec, x, y, w, h);
+ return EINA_FALSE;
}
static void
-_e_xdg_toplevel_v6_ping(struct wl_resource *shsurface_resource)
+_e_xdg_toplevel_cb_resource_destroy(struct wl_resource *resource)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Toplevel *toplevel;
- toplevel = _e_xdg_toplevel_v6_from_shell_surface_resource(shsurface_resource);
- if (!toplevel)
- return;
-
- LOG("Ping", toplevel->ec);
+ toplevel = wl_resource_get_user_data(resource);
+ toplevel->resource = NULL;
+ _e_client_xdg_shell_v6_role_assingment_unset(toplevel->base.ec);
+ e_object_unref(E_OBJECT(toplevel));
+}
- ds_xdg_surface_v6_ping(toplevel->ds_toplevel->base);
+static void
+_e_xdg_toplevel_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
}
static void
-_e_xdg_surface_v6_map(struct wl_resource *shsurface_resource)
+_e_xdg_toplevel_cb_parent_set(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *res_parent)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Toplevel *toplevel, *parent;
+ E_Client *pc;
+ E_Comp_Wl_Client_Data *pc_cdata;
+ struct wl_resource *parent_wsurface = NULL;
- toplevel = _e_xdg_toplevel_v6_from_shell_surface_resource(shsurface_resource);
+ toplevel = wl_resource_get_user_data(resource);
if (!toplevel)
return;
- LOG("Map", toplevel->ec);
+ if (res_parent)
+ {
+ parent = wl_resource_get_user_data(res_parent);
+ if (!parent)
+ {
+ ERR("No E_Xdg_Toplevel data in wl_resource", NULL);
+ wl_resource_post_error(res_parent,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Xdg_Toplevel data in wl_resource");
+
+ return;
+ }
+
+ pc = parent->base.ec;
+ if (!pc)
+ {
+ ERR("Toplevel must have E_Client", NULL);
+ wl_resource_post_error(res_parent,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Client data in wl_resource");
+ return;
+ }
+
+ pc_cdata = e_client_cdata_get(pc);
+ if (!pc_cdata) return;
+
+ parent_wsurface = pc_cdata->surface;
+ }
+
+ /* set this client as a transient for parent */
+ e_shell_e_client_parent_set(toplevel->base.ec, parent_wsurface);
- toplevel->ds_toplevel->base->mapped = true;
- e_shell_e_client_map(toplevel->ec);
+ EC_CHANGED(toplevel->base.ec);
}
static void
-_e_xdg_toplevel_v6_unmap(struct wl_resource *shsurface_resource)
+_e_xdg_toplevel_cb_title_set(struct wl_client *client,
+ struct wl_resource *resource,
+ const char *title)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Toplevel *toplevel;
- toplevel = _e_xdg_toplevel_v6_from_shell_surface_resource(shsurface_resource);
+ toplevel = wl_resource_get_user_data(resource);
if (!toplevel)
return;
- LOG("Unmap", toplevel->ec);
-
- toplevel->ds_toplevel->base->mapped = false;
- e_shell_e_client_unmap(toplevel->ec);
+ e_shell_e_client_name_title_set(toplevel->base.ec, title, title);
}
-static E_Shell_Surface_Api shell_xdg_toplevel_v6_api = {
- .configure_send = _e_xdg_toplevel_v6_configure_send,
- .configure = _e_xdg_toplevel_v6_configure,
- .ping = _e_xdg_toplevel_v6_ping,
- .map = _e_xdg_surface_v6_map,
- .unmap = _e_xdg_toplevel_v6_unmap,
-};
-
static void
-_e_xdg_toplevel_v6_role_init(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_cb_app_id_set(struct wl_client *client,
+ struct wl_resource *resource,
+ const char *app_id)
{
- E_Client *ec = toplevel->ec;
- struct ds_xdg_surface_v6 *ds_xdg_surface = toplevel->ds_toplevel->base;
- struct ds_xdg_toplevel_v6 *ds_toplevel = toplevel->ds_toplevel;
- E_Comp_Wl_Client_Data *cdata;
+ E_Xdg_Toplevel *toplevel;
+ E_Client *ec;
- e_shell_e_client_shsurface_assign(ec,
- ds_xdg_surface->resource,
- &shell_xdg_toplevel_v6_api);
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
+ return;
- cdata = e_client_cdata_get(ec);
- if (cdata)
+ ec = toplevel->base.ec;
+ if (!ec)
{
- cdata->sh_v6.res_role = ds_toplevel->resource;
- cdata->sh_v6.role = E_COMP_WL_SH_SURF_ROLE_TOPLV;
+ ERR("Toplevel must have E_Client", NULL);
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Client data in wl_resource");
+ return;
}
- e_shell_e_client_toplevel_set(ec);
- e_comp_wl_shell_surface_ready(toplevel->ec);
+ /* use the wl_client to get the pid * and set it in the netwm props */
+ wl_client_get_credentials(client, &ec->netwm.pid, NULL, NULL);
+
+ e_shell_e_client_app_id_set(ec, app_id);
}
static void
-_e_xdg_toplevel_v6_client_parent_update(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_cb_win_menu_show(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *res_seat,
+ uint32_t serial,
+ int32_t x,
+ int32_t y)
{
- E_Client *ec = toplevel->ec;
- struct ds_xdg_toplevel_v6 *parent = toplevel->ds_toplevel->parent;
- struct wl_resource *parent_surface_resource = NULL;
-
- if (parent)
- parent_surface_resource = parent->base->ds_surface->resource;
-
- LOG("Set parent: resource(%p)", ec, parent_surface_resource);
-
- e_shell_e_client_parent_set(ec, parent_surface_resource);
- EC_CHANGED(ec);
+ /* TODO no op */
}
static void
-_e_xdg_toplevel_v6_title_update(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_cb_move(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *res_seat,
+ uint32_t serial)
{
- E_Client *ec = toplevel->ec;
- char *title = toplevel->ds_toplevel->title;
+ E_Xdg_Toplevel *toplevel;
- LOG("Set title: %s", ec, title ? title : "(null)");
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
+ return;
- e_shell_e_client_name_title_set(ec, title, title);
+ if (!e_shell_e_client_interactive_move(toplevel->base.ec, res_seat))
+ {
+ ERR("Failed to move this Toplevel", NULL);
+ return;
+ }
}
static void
-_e_xdg_toplevel_v6_app_id_update(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_cb_resize(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *res_seat,
+ uint32_t serial,
+ uint32_t edges)
{
- E_Client *ec = toplevel->ec;
- char *app_id = toplevel->ds_toplevel->app_id;
- struct wl_client *client;
-
- client = wl_resource_get_client(toplevel->ds_toplevel->resource);
- wl_client_get_credentials(client, &ec->netwm.pid, NULL, NULL);
+ E_Xdg_Toplevel *toplevel;
- LOG("Set app_id: %s, PID(%d)", ec, app_id ? app_id : "(null)", ec->netwm.pid);
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
+ return;
- e_shell_e_client_app_id_set(ec, app_id);
+ if (!e_shell_e_client_interactive_resize(toplevel->base.ec, resource, res_seat, edges))
+ {
+ ERR("Failed to resize this Toplevel", NULL);
+ return;
+ }
}
static void
-_e_xdg_toplevel_v6_move_begin(E_Xdg_Toplevel_V6 *toplevel, struct wl_resource *seat_resource)
+_e_xdg_toplevel_cb_max_size_set(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t w,
+ int32_t h)
{
- E_Client *ec = toplevel->ec;
+ E_Xdg_Toplevel *toplevel;
- LOG("Begin interactive move", ec);
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
+ return;
- if (!e_shell_e_client_interactive_move(ec, seat_resource))
- ERR("Failed to move this Toplevel(%p)", ec, toplevel);
+ toplevel->next.max_size.w = w;
+ toplevel->next.max_size.h = h;
+ toplevel->base.wait_next_commit = EINA_TRUE;
}
static void
-_e_xdg_toplevel_v6_resize_begin(E_Xdg_Toplevel_V6 *toplevel, struct wl_resource *seat_resource, uint32_t edges)
+_e_xdg_toplevel_cb_min_size_set(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t w,
+ int32_t h)
{
- E_Client *ec = toplevel->ec;
- struct wl_resource *toplevel_resource = toplevel->ds_toplevel->resource;
+ E_Xdg_Toplevel *toplevel;
- LOG("Begin interactive resize", ec);
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
+ return;
- if (!e_shell_e_client_interactive_resize(ec, toplevel_resource, seat_resource, edges))
- ERR("Failed to move this Toplevel(%p)", ec, toplevel);
+ toplevel->next.min_size.w = w;
+ toplevel->next.min_size.h = h;
+ toplevel->base.wait_next_commit = EINA_TRUE;
}
static void
-_e_xdg_toplevel_v6_maximize_set(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_cb_maximized_set(struct wl_client *client, struct wl_resource *resource)
{
- E_Client *ec = toplevel->ec;
- E_Maximize max = (e_config->maximize_policy & E_MAXIMIZE_TYPE) | E_MAXIMIZE_BOTH;
-
- LOG("Set maximize. lock_user_maximize:%d, dir:%d",
- ec, ec->lock_user_maximize, ec->maximize_dir);
+ E_Xdg_Toplevel *toplevel;
+ E_Client *ec;
+ E_Maximize max;
- if (ec->lock_user_maximize)
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
return;
- if ((ec->maximize_dir != E_MAXIMIZE_DIRECTION_ALL) &&
- (ec->maximize_dir != E_MAXIMIZE_DIRECTION_NONE))
- return;
+ ec = toplevel->base.ec;
+ if (!ec)
+ {
+ ERR("Toplevel must have E_Client", NULL);
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Client data in wl_resource");
+ return;
+ }
- e_client_layout_apply(ec, EINA_FALSE);
- e_client_maximize(ec, max);
+ ELOGF("XDG6", "Toplevel Maximized Set. res:%p, lock_user_maximize:%d, dir:%d", ec, resource, ec->lock_user_maximize, ec->maximize_dir);
+ if (!ec->lock_user_maximize)
+ {
+ if ((ec->maximize_dir == E_MAXIMIZE_DIRECTION_ALL) || (ec->maximize_dir == E_MAXIMIZE_DIRECTION_NONE))
+ {
+ e_client_layout_apply(ec, EINA_FALSE);
+
+ max = (e_config->maximize_policy & E_MAXIMIZE_TYPE) | E_MAXIMIZE_BOTH;
+ e_client_maximize(ec, max);
+ }
+ }
}
static void
-_e_xdg_toplevel_v6_maximize_unset(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_cb_maximized_unset(struct wl_client *client, struct wl_resource *resource)
{
- E_Client *ec = toplevel->ec;
+ E_Xdg_Toplevel *toplevel;
+ E_Client *ec;
+
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
+ return;
- LOG("Unset maximize. lock_user_maximize:%d", ec, ec->lock_user_maximize);
+ ec = toplevel->base.ec;
+ if (!ec)
+ {
+ ERR("Toplevel must have E_Client", NULL);
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Client data in wl_resource");
+ return;
+ }
e_client_layout_apply(ec, EINA_FALSE);
+ ELOGF("XDG6", "Toplevel Maximized Unset. res:%p, lock_user_maximize:%d", ec, resource, ec->lock_user_maximize);
+
ec->maximize_dir = E_MAXIMIZE_DIRECTION_NONE;
/* it's doubtful */
e_client_unmaximize(ec, E_MAXIMIZE_BOTH);
}
static void
-_e_xdg_toplevel_v6_fullscreen_set(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_cb_fullscreen_set(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *res_output)
{
- E_Client *ec = toplevel->ec;
-
- LOG("Set fullscreen. lock_user_fullscreen:%d", ec, ec->lock_user_fullscreen);
+ E_Xdg_Toplevel *toplevel;
+ E_Client *ec;
- if (ec->lock_user_fullscreen)
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
return;
- e_client_fullscreen(ec, e_config->fullscreen_policy);
+ ec = toplevel->base.ec;
+ if (!ec)
+ {
+ ERR("Toplevel must have E_Client", NULL);
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Client data in wl_resource");
+ return;
+ }
+
+ ELOGF("XDG6", "Toplevel Fullscreen Set. res:%p, lock_user_fullscreen:%d", ec, resource, ec->lock_user_fullscreen);
+ if (!ec->lock_user_fullscreen)
+ e_client_fullscreen(ec, e_config->fullscreen_policy);
}
static void
-_e_xdg_toplevel_v6_fullscreen_unset(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_cb_fullscreen_unset(struct wl_client *client, struct wl_resource *resource)
{
- E_Client *ec = toplevel->ec;
-
- LOG("Unset fullscreen. lock_user_fullscreen:%d", ec, ec->lock_user_fullscreen);
+ E_Xdg_Toplevel *toplevel;
+ E_Client *ec;
- if (ec->lock_user_fullscreen)
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
return;
- e_client_unfullscreen(ec);
+ ec = toplevel->base.ec;
+ if (!ec)
+ {
+ ERR("Toplevel must have E_Client", NULL);
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Client data in wl_resource");
+ return;
+ }
+
+ ELOGF("XDG6", "Toplevel Fullscreen Unset. res:%p, lock_user_fullscreen:%d", ec, resource, ec->lock_user_fullscreen);
+ if (!ec->lock_user_fullscreen)
+ e_client_unfullscreen(ec);
}
static void
-_e_xdg_toplevel_v6_minimize_set(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_toplevel_cb_minimized_set(struct wl_client *client, struct wl_resource *resource)
{
- E_Client *ec = toplevel->ec;
-
- LOG("Set minimize. lock_client_iconify:%d", ec, ec->lock_client_iconify);
+ E_Xdg_Toplevel *toplevel;
+ E_Client *ec;
- if (ec->lock_client_iconify)
+ toplevel = wl_resource_get_user_data(resource);
+ if (!toplevel)
return;
- e_client_iconify(ec);
+ ec = toplevel->base.ec;
+ if (!ec)
+ {
+ ERR("Toplevel must have E_Client", NULL);
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Client data in wl_resource");
+ return;
+ }
+
+ ELOGF("XDG6", "Toplevel Minimized Set. res:%p, lock_client_iconify:%d", ec, resource, ec->lock_client_iconify);
+ if (!ec->lock_client_iconify)
+ e_client_iconify(ec);
}
-static void
-_e_xdg_toplevel_v6_window_geometry_update(E_Xdg_Toplevel_V6 *toplevel)
+static const struct zxdg_toplevel_v6_interface _e_xdg_toplevel_interface =
{
- struct ds_xdg_surface_v6 *ds_xdg_surface = toplevel->ds_toplevel->base;
- E_Comp_Wl_Client_Data *cdata;
-
- cdata = e_client_cdata_get(toplevel->ec);
- if (!cdata)
- return;
+ _e_xdg_toplevel_cb_destroy,
+ _e_xdg_toplevel_cb_parent_set,
+ _e_xdg_toplevel_cb_title_set,
+ _e_xdg_toplevel_cb_app_id_set,
+ _e_xdg_toplevel_cb_win_menu_show,
+ _e_xdg_toplevel_cb_move,
+ _e_xdg_toplevel_cb_resize,
+ _e_xdg_toplevel_cb_max_size_set,
+ _e_xdg_toplevel_cb_min_size_set,
+ _e_xdg_toplevel_cb_maximized_set,
+ _e_xdg_toplevel_cb_maximized_unset,
+ _e_xdg_toplevel_cb_fullscreen_set,
+ _e_xdg_toplevel_cb_fullscreen_unset,
+ _e_xdg_toplevel_cb_minimized_set
+};
- EINA_RECTANGLE_SET(&cdata->shell.window,
- ds_xdg_surface->current.geometry.x,
- ds_xdg_surface->current.geometry.y,
- ds_xdg_surface->current.geometry.width,
- ds_xdg_surface->current.geometry.height);
-}
+/* End of Xdg_toplevel */
-static void
-_e_xdg_toplevel_v6_min_max_size_update(E_Xdg_Toplevel_V6 *toplevel)
+/**********************************************************
+ * Implementation for Xdg_Positioner
+ **********************************************************/
+static Eina_Rectangle
+_e_xdg_positioner_geometry_get(E_Xdg_Positioner *p)
{
- E_Client *ec = toplevel->ec;
- struct ds_xdg_toplevel_v6 *ds_toplevel = toplevel->ds_toplevel;
+ Eina_Rectangle geometry = {
+ .x = p->offset.x,
+ .y = p->offset.y,
+ .w = p->size.w,
+ .h = p->size.h,
+ };
+
+ if (p->anchor & ZXDG_POSITIONER_V6_ANCHOR_TOP)
+ geometry.y += p->anchor_rect.y;
+ else if (p->anchor & ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)
+ geometry.y += p->anchor_rect.y + p->anchor_rect.h;
+ else
+ geometry.y += p->anchor_rect.y + p->anchor_rect.h / 2;
- if (!ec->lock_client_size)
- return;
+ if (p->anchor & ZXDG_POSITIONER_V6_ANCHOR_LEFT)
+ geometry.x += p->anchor_rect.x;
+ else if (p->anchor & ZXDG_POSITIONER_V6_ANCHOR_RIGHT)
+ geometry.x += p->anchor_rect.x + p->anchor_rect.w;
+ else
+ geometry.x += p->anchor_rect.x + p->anchor_rect.w / 2;
+
+ if (p->gravity & ZXDG_POSITIONER_V6_GRAVITY_TOP)
+ geometry.y -= geometry.h;
+ else if (!(p->gravity & ZXDG_POSITIONER_V6_GRAVITY_BOTTOM))
+ geometry.y = geometry.h / 2;
+
+ if (p->gravity & ZXDG_POSITIONER_V6_GRAVITY_LEFT)
+ geometry.x -= geometry.w;
+ else if (!(p->gravity & ZXDG_POSITIONER_V6_GRAVITY_RIGHT))
+ geometry.x = geometry.w / 2;
+
+ if (p->constraint_adjustment == ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_NONE)
+ return geometry;
- ec->icccm.min_w = ds_toplevel->current.min_width;
- ec->icccm.min_h = ds_toplevel->current.min_height;
- ec->icccm.max_w = ds_toplevel->current.max_width;
- ec->icccm.max_h = ds_toplevel->current.max_height;
+ /* TODO: According to weston, add compositor policy configuration and the
+ * code here
+ */
+
+ return geometry;
}
-static void
-_e_xdg_toplevel_v6_cb_set_parent(struct wl_listener *listener, void *data)
+static Eina_Bool
+_e_xdg_positioner_validation_check(E_Xdg_Positioner *p)
{
- E_Xdg_Toplevel_V6 *toplevel;
-
- toplevel = wl_container_of(listener, toplevel, set_parent);
- _e_xdg_toplevel_v6_client_parent_update(toplevel);
+ return ((p->size.w != 0) && (p->anchor_rect.w != 0));
}
static void
-_e_xdg_toplevel_v6_cb_set_title(struct wl_listener *listener, void *data)
+_e_xdg_positioner_cb_resource_destroy(struct wl_resource *resource)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Positioner *p;
+
+ p = wl_resource_get_user_data(resource);
+ EINA_SAFETY_ON_NULL_RETURN(p);
- toplevel = wl_container_of(listener, toplevel, set_title);
- _e_xdg_toplevel_v6_title_update(toplevel);
+ if (!p->shell)
+ goto finish;
+
+ p->shell->positioners = eina_list_remove(p->shell->positioners, p);
+
+finish:
+ free(p);
}
static void
-_e_xdg_toplevel_v6_cb_set_app_id(struct wl_listener *listener, void *data)
+_e_xdg_positioner_cb_destroy(struct wl_client *client, struct wl_resource *resource)
{
- E_Xdg_Toplevel_V6 *toplevel;
-
- toplevel = wl_container_of(listener, toplevel, set_app_id);
- _e_xdg_toplevel_v6_app_id_update(toplevel);
+ wl_resource_destroy(resource);
}
static void
-_e_xdg_toplevel_v6_cb_request_move(struct wl_listener *listener, void *data)
+_e_xdg_positioner_cb_size_set(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t w, int32_t h)
{
- E_Xdg_Toplevel_V6 *toplevel;
- struct ds_xdg_toplevel_v6_event_request_move *event = data;
+ E_Xdg_Positioner *p;
+
+ _validate_size(resource, w);
+ _validate_size(resource, h);
- toplevel = wl_container_of(listener, toplevel, request_move);
- _e_xdg_toplevel_v6_move_begin(toplevel, event->seat_resource);
+ p = wl_resource_get_user_data(resource);
+ p->size.w = w;
+ p->size.h = h;
}
static void
-_e_xdg_toplevel_v6_cb_request_resize(struct wl_listener *listener, void *data)
+_e_xdg_positioner_cb_anchor_rect_set(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x, int32_t y, int32_t w, int32_t h)
{
- E_Xdg_Toplevel_V6 *toplevel;
- struct ds_xdg_toplevel_v6_event_request_resize *event = data;
+ E_Xdg_Positioner *p;
- toplevel = wl_container_of(listener, toplevel, request_resize);
- _e_xdg_toplevel_v6_resize_begin(toplevel, event->seat_resource, event->edges);
+ _validate_size(resource, w);
+ _validate_size(resource, h);
+
+ p = wl_resource_get_user_data(resource);
+ EINA_RECTANGLE_SET(&p->anchor_rect, x, y, w, h);
}
static void
-_e_xdg_toplevel_v6_cb_request_maximize(struct wl_listener *listener, void *data)
+_e_xdg_positioner_cb_anchor_set(struct wl_client *client,
+ struct wl_resource *resource,
+ enum zxdg_positioner_v6_anchor anchor)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Positioner *p;
- toplevel = wl_container_of(listener, toplevel, request_maximize);
- if (toplevel->ds_toplevel->requested.maximized)
- _e_xdg_toplevel_v6_maximize_set(toplevel);
+ if ((anchor & (ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_BOTTOM)) ==
+ (ZXDG_POSITIONER_V6_ANCHOR_TOP | ZXDG_POSITIONER_V6_ANCHOR_BOTTOM))
+ {
+ wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
+ "Invalid anchor values passed");
+ }
+ else if ((anchor & (ZXDG_POSITIONER_V6_ANCHOR_LEFT | ZXDG_POSITIONER_V6_ANCHOR_RIGHT)) ==
+ (ZXDG_POSITIONER_V6_ANCHOR_LEFT | ZXDG_POSITIONER_V6_ANCHOR_RIGHT))
+ {
+ wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
+ "Invalid anchor values passed");
+ }
else
- _e_xdg_toplevel_v6_maximize_unset(toplevel);
+ {
+ p = wl_resource_get_user_data(resource);
+ p->anchor = anchor;
+ }
}
static void
-_e_xdg_toplevel_v6_cb_request_fullscreen(struct wl_listener *listener, void *data)
+_e_xdg_positioner_cb_gravity_set(struct wl_client *client,
+ struct wl_resource *resource,
+ enum zxdg_positioner_v6_gravity gravity)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Positioner *p;
- toplevel = wl_container_of(listener, toplevel, request_fullscreen);
- if (toplevel->ds_toplevel->requested.fullscreen)
- _e_xdg_toplevel_v6_fullscreen_set(toplevel);
+ if ((gravity & (ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_BOTTOM)) ==
+ (ZXDG_POSITIONER_V6_GRAVITY_TOP | ZXDG_POSITIONER_V6_GRAVITY_BOTTOM))
+ {
+ wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
+ "Invalid gravity values passed");
+ }
+ else if ((gravity & (ZXDG_POSITIONER_V6_GRAVITY_LEFT | ZXDG_POSITIONER_V6_GRAVITY_RIGHT)) ==
+ (ZXDG_POSITIONER_V6_GRAVITY_LEFT | ZXDG_POSITIONER_V6_GRAVITY_RIGHT))
+ {
+ wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT,
+ "Invalid gravity values passed");
+ }
else
- _e_xdg_toplevel_v6_fullscreen_unset(toplevel);
+ {
+ p = wl_resource_get_user_data(resource);
+ p->gravity = gravity;
+ }
}
static void
-_e_xdg_toplevel_v6_cb_request_minimize(struct wl_listener *listener, void *data)
+_e_xdg_positioner_cb_constraint_adjustment_set(struct wl_client *client,
+ struct wl_resource *resource,
+ enum zxdg_positioner_v6_constraint_adjustment constraint_adjustment)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Positioner *p;
- toplevel = wl_container_of(listener, toplevel, request_minimize);
- _e_xdg_toplevel_v6_minimize_set(toplevel);
+ p = wl_resource_get_user_data(resource);
+ p->constraint_adjustment = constraint_adjustment;
}
static void
-_e_xdg_toplevel_v6_cb_configure(struct wl_listener *listener, void *data)
+_e_xdg_positioner_cb_offset_set(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x, int32_t y)
{
- E_Xdg_Toplevel_V6 *toplevel;
- struct ds_xdg_surface_v6 *ds_xdg_surface;
- struct ds_xdg_surface_v6_configure *oldest_configure;
- const int WAIT_ACK_COUNT_MAX = 16;
-
- toplevel = wl_container_of(listener, toplevel, configure);
- ds_xdg_surface = toplevel->ds_toplevel->base;
- if (wl_list_length(&ds_xdg_surface->configure_list) <= WAIT_ACK_COUNT_MAX)
- return;
+ E_Xdg_Positioner *p;
- oldest_configure = wl_container_of(ds_xdg_surface->configure_list.next,
- oldest_configure,
- link);
+ p = wl_resource_get_user_data(resource);
+ p->offset.x = x;
+ p->offset.y = y;
+}
- LOG("Don't rececive Configure Ack. Remove oldest configure:%p, serial:%d",
- toplevel->ec, oldest_configure, oldest_configure->serial);
+static const struct zxdg_positioner_v6_interface _e_xdg_positioner_interface =
+{
+ _e_xdg_positioner_cb_destroy,
+ _e_xdg_positioner_cb_size_set,
+ _e_xdg_positioner_cb_anchor_rect_set,
+ _e_xdg_positioner_cb_anchor_set,
+ _e_xdg_positioner_cb_gravity_set,
+ _e_xdg_positioner_cb_constraint_adjustment_set,
+ _e_xdg_positioner_cb_offset_set,
+};
+
+/* End of Xdg_positioner */
- wl_list_remove(&oldest_configure->link);
- free(oldest_configure);
+/**********************************************************
+ * Implementation for Xdg_Surface
+ **********************************************************/
+static const char *
+_e_xdg_surface_util_role_string_get(E_Xdg_Surface *exsurf)
+{
+ switch (exsurf->role)
+ {
+ case E_XDG_SURFACE_ROLE_TOPLEVEL:
+ return "TOPLEVEL";
+ case E_XDG_SURFACE_ROLE_POPUP:
+ return "POPUP";
+ default:
+ case E_XDG_SURFACE_ROLE_NONE:
+ return "NONE";
+ }
+}
+
+static Eina_Bool
+_e_xdg_surface_cb_configure_send(void *data)
+{
+ E_Xdg_Surface *exsurf;
+ E_Xdg_Surface_Configure *configure;
+ Eina_Bool wait_ack = EINA_FALSE;
+
+ exsurf = data;
+
+ EINA_SAFETY_ON_NULL_GOTO(exsurf, end);
+ EINA_SAFETY_ON_NULL_GOTO(exsurf->ec, end);
+ EINA_SAFETY_ON_NULL_GOTO(e_client_cdata_get(exsurf->ec), end);
+ EINA_SAFETY_ON_NULL_GOTO(exsurf->resource, end);
+
+ if (e_object_is_del(E_OBJECT(exsurf->ec)))
+ goto end;
+
+ /* Make configure */
+ configure = E_NEW(E_Xdg_Surface_Configure, 1);
+ if (!configure)
+ {
+ ERR("Failed to allocate memory: E_Xdg_Surface_Configure", NULL);
+ goto end;
+ }
+
+ configure->serial = wl_display_next_serial(e_comp_wl->wl.disp);
+
+ switch (exsurf->role)
+ {
+ case E_XDG_SURFACE_ROLE_NONE:
+ ERR("Cannot reach here", NULL);
+ break;
+ case E_XDG_SURFACE_ROLE_POPUP:
+ _e_xdg_popup_configure_send((E_Xdg_Popup *)exsurf);
+ wait_ack = EINA_TRUE;
+ break;
+ case E_XDG_SURFACE_ROLE_TOPLEVEL:
+ _e_xdg_toplevel_configure_send((E_Xdg_Toplevel *)exsurf, configure);
+ wait_ack = EINA_TRUE;
+ break;
+ }
+
+ zxdg_surface_v6_send_configure(exsurf->resource, configure->serial);
+
+ LOG("Send configure: %s serial %d", exsurf->ec,
+ _e_xdg_surface_util_role_string_get(exsurf), configure->serial);
+
+ if (wait_ack)
+ {
+ if (eina_list_count(exsurf->configure_list) > WAIT_ACK_COUNT_MAX)
+ {
+ E_Xdg_Surface_Configure *oldest_configure = NULL;
+ oldest_configure = eina_list_nth(exsurf->configure_list, 0);
+ if (oldest_configure)
+ {
+ ELOGF("XDG6", "Don't receive Configure Ack. Remove oldest configure:%p, serial:%d",
+ exsurf->ec, oldest_configure, oldest_configure->serial);
+ exsurf->configure_list = eina_list_remove(exsurf->configure_list, oldest_configure);
+ E_FREE(oldest_configure);
+ }
+ }
+ exsurf->configure_list = eina_list_append(exsurf->configure_list, configure);
+ }
+ else
+ E_FREE(configure);
+
+end:
+ if (exsurf)
+ exsurf->configure_idle = NULL;
+
+ return ECORE_CALLBACK_DONE;
}
static void
-_e_xdg_toplevel_v6_cb_ping_timeout(struct wl_listener *listener, void *data)
+_e_xdg_surface_configure_send(struct wl_resource *resource,
+ uint32_t edges,
+ int32_t width,
+ int32_t height)
{
- // This is intentionally left blank.
+ E_Xdg_Surface *exsurf;
+ Eina_Bool pending_same = EINA_FALSE;
+
+ EINA_SAFETY_ON_NULL_RETURN(resource);
+
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
+ {
+ ERR("Invalid wl_resource", NULL);
+ return;
+ }
+
+ LOG("Scheduling task to send configure %s edges %d w %d h %d",
+ exsurf->ec,
+ _e_xdg_surface_util_role_string_get(exsurf), edges, width, height);
+
+ switch (exsurf->role)
+ {
+ case E_XDG_SURFACE_ROLE_NONE:
+ default:
+ ERR("Cannot reach here", exsurf->ec);
+ break;
+ case E_XDG_SURFACE_ROLE_TOPLEVEL:
+ _e_xdg_toplevel_configure_pending_set((E_Xdg_Toplevel *)exsurf,
+ edges, width, height);
+
+ pending_same = _e_xdg_toplevel_pending_state_compare((E_Xdg_Toplevel *)exsurf);
+ if (pending_same)
+ {
+ LOG("\tSKIP Configuring state is same with current state",
+ exsurf->ec);
+ }
+ break;
+ case E_XDG_SURFACE_ROLE_POPUP:
+ break;
+ }
+
+ if (exsurf->configure_idle)
+ {
+ if (!pending_same)
+ return;
+
+ LOG("\tRemove configure idler", exsurf->ec);
+
+ E_FREE_FUNC(exsurf->configure_idle, ecore_idle_enterer_del);
+ }
+ else
+ {
+ if (pending_same)
+ return;
+
+ exsurf->configure_idle =
+ ecore_idle_enterer_add(_e_xdg_surface_cb_configure_send, exsurf);
+
+ LOG("\tAdd configure idler %p",
+ exsurf->ec, exsurf->configure_idle);
+ }
}
static void
-_e_xdg_toplevel_v6_cb_surface_commit(struct wl_listener *listener, void *data)
+_e_xdg_surface_configure(struct wl_resource *resource,
+ Evas_Coord x, Evas_Coord y,
+ Evas_Coord w, Evas_Coord h)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Surface *exsurf;
+
+ EINA_SAFETY_ON_NULL_RETURN(resource);
+
+ /* get the client for this resource */
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
+ {
+ ERR("No E_Xdg_Surface data in wl_resource", NULL);
+ return;
+ }
+
+ if (!exsurf->configured)
+ {
+ // any attempts by a client to attach or manipulate a buffer prior to the first xdg_surface.configure call must
+ // be treated as errors.
+ ERR("Could not handle %s prior to the first xdg_surface.configure",
+ exsurf->ec,
+ _e_xdg_surface_util_role_string_get(exsurf));
+
+ E_Client *provider_ec = NULL;
+ provider_ec = e_comp_wl_remote_surface_bound_provider_ec_get(exsurf->ec);
+ if (!provider_ec)
+ return;
+
+ ERR("This is bound the remote surface provider. So, set configure_ack by force", exsurf->ec);
+ exsurf->configured = EINA_TRUE;
+ }
- toplevel = wl_container_of(listener, toplevel, surface_commit);
- _e_xdg_toplevel_v6_window_geometry_update(toplevel);
- _e_xdg_toplevel_v6_min_max_size_update(toplevel);
+ EINA_RECTANGLE_SET(&exsurf->configured_geometry, x, y, w, h);
+
+ e_client_util_move_resize_without_frame(exsurf->ec, x, y, w, h);
}
static void
-_e_xdg_toplevel_v6_listener_init(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_surface_ping(struct wl_resource *resource)
{
- struct ds_xdg_toplevel_v6 *ds_toplevel = toplevel->ds_toplevel;
- struct ds_xdg_surface_v6 *ds_xdg_surface = toplevel->ds_toplevel->base;
- struct ds_surface *ds_surface = ds_xdg_surface->ds_surface;
+ E_Xdg_Surface *exsurf;
+
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
+ {
+ ERR("No E_Xdg_Surface data in wl_resource", NULL);
+ return;
+ }
- toplevel->set_parent.notify = _e_xdg_toplevel_v6_cb_set_parent;
- ds_xdg_toplevel_v6_add_set_parent_listener(ds_toplevel, &toplevel->set_parent);
+ if (e_object_is_del(E_OBJECT(exsurf->ec)))
+ return;
+
+ _e_xdg_shell_ping(exsurf->shell);
+}
- toplevel->set_title.notify = _e_xdg_toplevel_v6_cb_set_title;
- ds_xdg_toplevel_v6_add_set_title_listener(ds_toplevel, &toplevel->set_title);
+static void
+_e_xdg_surface_map(struct wl_resource *resource)
+{
+ E_Xdg_Surface *exsurf;
- toplevel->set_app_id.notify = _e_xdg_toplevel_v6_cb_set_app_id;
- ds_xdg_toplevel_v6_add_set_app_id_listener(ds_toplevel, &toplevel->set_app_id);
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
+ {
+ ERR("No E_Xdg_Surface in wl_resource", NULL);
+ return;
+ }
- toplevel->request_move.notify = _e_xdg_toplevel_v6_cb_request_move;
- ds_xdg_toplevel_v6_add_request_move_listener(ds_toplevel, &toplevel->request_move);
+ e_shell_e_client_map(exsurf->ec);
+}
- toplevel->request_resize.notify = _e_xdg_toplevel_v6_cb_request_resize;
- ds_xdg_toplevel_v6_add_request_resize_listener(ds_toplevel, &toplevel->request_resize);
+static void
+_e_xdg_surface_unmap(struct wl_resource *resource)
+{
+ E_Xdg_Surface *exsurf;
- toplevel->request_maximize.notify = _e_xdg_toplevel_v6_cb_request_maximize;
- ds_xdg_toplevel_v6_add_request_maximize_listener(ds_toplevel, &toplevel->request_maximize);
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
+ {
+ ERR("No E_Xdg_Surface in wl_resource", NULL);
+ return;
+ }
- toplevel->request_fullscreen.notify = _e_xdg_toplevel_v6_cb_request_fullscreen;
- ds_xdg_toplevel_v6_add_request_fullscreen_listener(ds_toplevel, &toplevel->request_fullscreen);
+ e_shell_e_client_unmap(exsurf->ec);
+}
- toplevel->request_minimize.notify = _e_xdg_toplevel_v6_cb_request_minimize;
- ds_xdg_toplevel_v6_add_request_minimize_listener(ds_toplevel, &toplevel->request_minimize);
+static Eina_Bool
+_e_xdg_surface_role_assign(E_Xdg_Surface *exsurf,
+ struct wl_resource *resource,
+ E_Xdg_Surface_Role role)
+{
+ E_Shell_Surface_Api api = {
+ .configure_send = _e_xdg_surface_configure_send,
+ .configure = _e_xdg_surface_configure,
+ .ping = _e_xdg_surface_ping,
+ .map = _e_xdg_surface_map,
+ .unmap = _e_xdg_surface_unmap,
+ };
+
+ if (_e_client_xdg_shell_v6_assigned_check(exsurf->ec))
+ {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "Client already has shell resource");
+ return EINA_FALSE;
+ }
- toplevel->destroy.notify = _e_xdg_toplevel_v6_cb_destroy;
- ds_xdg_surface_v6_add_destroy_listener(ds_xdg_surface, &toplevel->destroy);
+ exsurf->role = role;
- toplevel->configure.notify = _e_xdg_toplevel_v6_cb_configure;
- ds_xdg_surface_v6_add_configure_listener(ds_xdg_surface, &toplevel->configure);
+ e_shell_e_client_shsurface_api_set(exsurf->ec, &api);
- toplevel->ping_timeout.notify = _e_xdg_toplevel_v6_cb_ping_timeout;
- ds_xdg_surface_v6_add_ping_timeout_listener(ds_xdg_surface, &toplevel->ping_timeout);
+ switch (role)
+ {
+ case E_XDG_SURFACE_ROLE_NONE:
+ default:
+ ERR("Cannot reach here", exsurf->ec);
+ return EINA_FALSE;
+
+ case E_XDG_SURFACE_ROLE_TOPLEVEL:
+ _e_xdg_toplevel_set((E_Xdg_Toplevel *)exsurf, resource);
+ break;
+
+ case E_XDG_SURFACE_ROLE_POPUP:
+ _e_xdg_popup_set((E_Xdg_Popup *)exsurf, resource);
+ break;
+ }
- toplevel->surface_commit.notify = _e_xdg_toplevel_v6_cb_surface_commit;
- ds_surface_add_commit_listener(ds_surface, &toplevel->surface_commit);
+ return EINA_TRUE;
}
static void
-_e_xdg_toplevel_v6_listener_finish(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_surface_cb_destroy(struct wl_client *client, struct wl_resource *resource)
{
- wl_list_remove(&toplevel->set_parent.link);
- wl_list_remove(&toplevel->set_title.link);
- wl_list_remove(&toplevel->set_app_id.link);
- wl_list_remove(&toplevel->request_move.link);
- wl_list_remove(&toplevel->request_resize.link);
- wl_list_remove(&toplevel->request_maximize.link);
- wl_list_remove(&toplevel->request_fullscreen.link);
- wl_list_remove(&toplevel->request_minimize.link);
- wl_list_remove(&toplevel->destroy.link);
- wl_list_remove(&toplevel->configure.link);
- wl_list_remove(&toplevel->ping_timeout.link);
- wl_list_remove(&toplevel->surface_commit.link);
+ wl_resource_destroy(resource);
}
static void
-_e_xdg_toplevel_v6_init(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_surface_cb_toplevel_get(struct wl_client *client, struct wl_resource *resource, uint32_t id)
{
- struct ds_xdg_toplevel_v6 *ds_toplevel = toplevel->ds_toplevel;
+ E_Xdg_Surface *exsurf;
+ struct wl_resource *toplevel_resource;
- _e_xdg_toplevel_v6_title_update(toplevel);
- _e_xdg_toplevel_v6_app_id_update(toplevel);
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
+ {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Xdg_Surface data in wl_resource");
+ return;
+ }
- if (ds_toplevel->requested.maximized)
- _e_xdg_toplevel_v6_maximize_set(toplevel);
+ toplevel_resource = wl_resource_create(client, &zxdg_toplevel_v6_interface, 1, id);
+ if (!toplevel_resource)
+ {
+ ERR("Could not create xdg toplevel resource", NULL);
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ wl_resource_set_implementation(toplevel_resource,
+ &_e_xdg_toplevel_interface,
+ exsurf,
+ _e_xdg_toplevel_cb_resource_destroy);
- if (ds_toplevel->requested.fullscreen)
- _e_xdg_toplevel_v6_fullscreen_set(toplevel);
+ if (!_e_xdg_surface_role_assign(exsurf, toplevel_resource, E_XDG_SURFACE_ROLE_TOPLEVEL))
+ {
+ ERR("Failed to assign TOPLEVEL role", exsurf->ec);
+ wl_resource_destroy(toplevel_resource);
+ return;
+ }
- _e_xdg_toplevel_v6_role_init(toplevel);
+ e_object_ref(E_OBJECT(exsurf));
}
static void
-_e_xdg_toplevel_v6_finish(E_Xdg_Toplevel_V6 *toplevel)
+_e_xdg_surface_cb_popup_get(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t id,
+ struct wl_resource *res_parent,
+ struct wl_resource *res_pos)
{
- E_Client *ec = toplevel->ec;
- E_Comp_Wl_Client_Data *cdata;
+ struct wl_resource *popup_resource;
+ E_Xdg_Surface *exsurf, *parent;
+ E_Xdg_Positioner *p;
- cdata = e_client_cdata_get(ec);
- if (cdata)
+ if (!res_parent)
+ {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "Popup requires a parent shell surface");
+ return;
+ }
+
+ parent = wl_resource_get_user_data(res_parent);
+ if (!parent)
+ {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "xdg_popup must have parent");
+ return;
+ }
+
+ p = wl_resource_get_user_data(res_pos);
+ if (!p)
+ {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "invalid positioner");
+ return;
+ }
+
+ if (!_e_xdg_positioner_validation_check(p))
+ {
+ wl_resource_post_error(resource,
+ ZXDG_SHELL_V6_ERROR_INVALID_POSITIONER,
+ "invalid positioner");
+ return;
+ }
+
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
{
- cdata->sh_v6.res_role = toplevel->ds_toplevel->resource;
- cdata->sh_v6.role = E_COMP_WL_SH_SURF_ROLE_NONE;
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Xdg_Popup data in wl_resource");
+ return;
}
- e_shell_e_client_destroy(ec);
+ popup_resource = wl_resource_create(client, &zxdg_popup_v6_interface, 1, id);
+ if (!popup_resource)
+ {
+ ERR("Could not create xdg popup resource", NULL);
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ wl_resource_set_implementation(popup_resource,
+ &_e_xdg_popup_interface,
+ exsurf,
+ _e_xdg_popup_cb_resource_destroy);
+
+
+ if (!_e_xdg_surface_role_assign(exsurf, popup_resource, E_XDG_SURFACE_ROLE_POPUP))
+ {
+ ERR("Failed to assign role to surface", exsurf->ec);
+ wl_resource_destroy(popup_resource);
+ return;
+ }
+
+ _e_xdg_popup_parent_set((E_Xdg_Popup *)exsurf, parent);
+ _e_xdg_popup_positioner_apply((E_Xdg_Popup *)exsurf, p);
+
+ e_object_ref(E_OBJECT(exsurf));
}
static void
-_e_xdg_toplevel_v6_add(struct ds_xdg_surface_v6 *ds_xdg_surface)
+_e_xdg_surface_cb_win_geometry_set(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t x,
+ int32_t y,
+ int32_t w,
+ int32_t h)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Surface *exsurf;
- toplevel = E_NEW(E_Xdg_Toplevel_V6, 1);
- if (!toplevel)
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
+ {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Xdg_Surface data in wl_resource");
+ return;
+ }
+
+ LOG("Set window geometry: geometry(%d %d %d %d)",
+ exsurf->ec, x, y, w, h);
+
+ exsurf->has_window_geometry = EINA_TRUE;
+ EINA_RECTANGLE_SET(&exsurf->window_geometry, x, y, w, h);
+
+ exsurf->wait_next_commit = EINA_TRUE;
+}
+
+static void
+_e_xdg_surface_cb_configure_ack(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
+{
+ E_Xdg_Surface *exsurf;
+ E_Xdg_Surface_Configure *configure;
+ Eina_List *l, *ll;
+ Eina_Bool found = EINA_FALSE;
+
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
{
- ERR("Could not create E_Xdg_Toplevel_V6", NULL);
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Xdg_Surface data in wl_surface");
return;
}
- toplevel->ds_toplevel = ds_xdg_surface->toplevel;
- toplevel->ec = e_client_from_surface_resource(ds_xdg_surface->ds_surface->resource);
+ LOG("Ack configure", exsurf->ec);
- _e_xdg_toplevel_v6_listener_init(toplevel);
- _e_xdg_toplevel_v6_init(toplevel);
+ if ((exsurf->role != E_XDG_SURFACE_ROLE_TOPLEVEL) &&
+ (exsurf->role != E_XDG_SURFACE_ROLE_POPUP))
+ {
+ wl_resource_post_error(resource,
+ ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
+ "xdg_surface must have a role");
+ return;
+ }
- // FIXME HACK
- // For wayland clients which don't follow the rule of
- // xdg_shell_v6.configure, this sets `configured` variable as true to work
- // with libds which does follow the rule of xdg_shell_v6 spec.
- ds_xdg_surface->configured = EINA_TRUE;
+ EINA_LIST_FOREACH_SAFE(exsurf->configure_list, l, ll, configure)
+ {
+ if (configure->serial < serial)
+ {
+ exsurf->configure_list =
+ eina_list_remove_list(exsurf->configure_list, l);
+ free(configure);
+ }
+ else if (configure->serial == serial)
+ {
+ exsurf->configure_list =
+ eina_list_remove_list(exsurf->configure_list, l);
+ found = EINA_TRUE;
+ break;
+ }
+ else
+ break;
+ }
- LOG("Created E_Xdg_Toplevel_V6(%p)", toplevel->ec, toplevel);
+ LOG("Ack configure %s first %d serial %d found %d",
+ exsurf->ec,
+ _e_xdg_surface_util_role_string_get(exsurf),
+ !exsurf->configured,
+ serial, found);
+
+ if (!found)
+ {
+ wl_resource_post_error(exsurf->shell->resource,
+ ZXDG_SHELL_V6_ERROR_INVALID_SURFACE_STATE,
+ "Wrong configure serial: %u", serial);
+ return;
+ }
+
+ exsurf->configured = EINA_TRUE;
+
+ switch (exsurf->role)
+ {
+ case E_XDG_SURFACE_ROLE_NONE:
+ ERR("Cannot reach here", exsurf->ec);
+ break;
+ case E_XDG_SURFACE_ROLE_TOPLEVEL:
+ _e_xdg_toplevel_configure_ack((E_Xdg_Toplevel *)exsurf, configure);
+ break;
+ case E_XDG_SURFACE_ROLE_POPUP:
+ break;
+ }
+
+ E_FREE_FUNC(configure, free);
}
+static const struct zxdg_surface_v6_interface _e_xdg_surface_interface =
+{
+ _e_xdg_surface_cb_destroy,
+ _e_xdg_surface_cb_toplevel_get,
+ _e_xdg_surface_cb_popup_get,
+ _e_xdg_surface_cb_win_geometry_set,
+ _e_xdg_surface_cb_configure_ack
+};
+
static void
-_e_xdg_toplevel_v6_cb_destroy(struct wl_listener *listener, void *data)
+_e_xdg_surface_cb_commit(void *data, E_Client *ec)
{
- E_Xdg_Toplevel_V6 *toplevel;
+ E_Xdg_Surface *exsurf;
+ E_Comp_Wl_Client_Data *exsurf_cdata;
+
+ exsurf = (E_Xdg_Surface *)data;
- toplevel = wl_container_of(listener, toplevel, destroy);
+ if (exsurf->ec != ec)
+ return;
+
+ if (!exsurf->wait_next_commit)
+ return;
+
+ LOG("Wl_Surface Commit, Update Xdg_Surface state %s",
+ exsurf->ec,
+ _e_xdg_surface_util_role_string_get(exsurf));
+
+ exsurf->wait_next_commit = EINA_FALSE;
+
+ if (exsurf->has_window_geometry)
+ {
+ exsurf->has_window_geometry = EINA_FALSE;
+ exsurf_cdata = e_client_cdata_get(exsurf->ec);
+ EINA_RECTANGLE_SET(&exsurf_cdata->shell.window,
+ exsurf->window_geometry.x,
+ exsurf->window_geometry.y,
+ exsurf->window_geometry.w,
+ exsurf->window_geometry.h);
+ }
- LOG("Destroy E_Xdg_Toplevel_V6(%p)", toplevel->ec, toplevel);
+ switch (exsurf->role)
+ {
+ case E_XDG_SURFACE_ROLE_NONE:
+ wl_resource_post_error(exsurf->resource,
+ ZXDG_SURFACE_V6_ERROR_NOT_CONSTRUCTED,
+ "xdg_surface must have a role");
+ break;
+ case E_XDG_SURFACE_ROLE_TOPLEVEL:
+ _e_xdg_toplevel_committed((E_Xdg_Toplevel *)exsurf);
+ break;
+ case E_XDG_SURFACE_ROLE_POPUP:
+ _e_xdg_popup_committed((E_Xdg_Popup *)exsurf);
+ break;
+ }
+}
+
+static void
+_e_xdg_surface_free(E_Xdg_Surface *exsurf)
+{
+ free(exsurf);
+}
+
+static void
+_e_xdg_surface_del(E_Xdg_Surface *exsurf)
+{
+ _e_xdg_shell_surface_remove(exsurf->shell, exsurf);
+
+ E_FREE_LIST(exsurf->configure_list, free);
+ if (exsurf->configure_idle)
+ ecore_idle_enterer_del(exsurf->configure_idle);
+ if (exsurf->commit_hook)
+ e_comp_wl_hook_del(exsurf->commit_hook);
+}
+
+static void
+_e_xdg_surface_cb_resource_destroy(struct wl_resource *resource)
+{
+ E_Xdg_Surface *exsurf;
+
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
+ {
+ ERR("No E_Xdg_Surface data in wl_resource", NULL);
+ return;
+
+ }
+
+ LOG("Destroy resource of Xdg_Surface %s",
+ exsurf->ec,
+ _e_xdg_surface_util_role_string_get(exsurf));
+
+ /* Although zxdg_toplevel_v6 or zxdg_popup_v6 are still existed, unset
+ * assignment at here anyway. once zxdg_surface_v6 is destroyed, the
+ * attribute 'toplevel and popup' is no longer meaningful. */
+ _e_client_xdg_shell_v6_role_assingment_unset(exsurf->ec);
+
+ e_shell_e_client_destroy(exsurf->ec);
+ /* set null after destroying shell of e_client, ec will be freed */
+ exsurf->ec = NULL;
+
+ e_object_del(E_OBJECT(exsurf));
+}
+
+static E_Xdg_Surface *
+_e_xdg_surface_create(E_Xdg_Shell *shell,
+ struct wl_resource *wsurface,
+ uint32_t id)
+{
+ E_Xdg_Surface *exsurf;
+ E_Client *ec;
+
+ ec = e_client_from_surface_resource(wsurface);
+ if (!ec)
+ {
+ ERR("No E_Client data in wl_resource", NULL);
+ wl_resource_post_error(wsurface,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No data in wl_resource");
+ return NULL;
+ }
+
+ LOG("Create Xdg_Surface", ec);
+
+ if (!_e_client_shsurface_assignable_check(ec))
+ {
+ ERR("Cannot get xdg_surface with this wl_surface", ec);
+ return NULL;
+ }
+
+ exsurf = E_OBJECT_ALLOC(e_xdg_surface_role_biggest_struct,
+ E_XDG_SURFACE_V6_TYPE,
+ _e_xdg_surface_free);
+ if (!exsurf)
+ {
+ wl_client_post_no_memory(shell->wclient);
+ return NULL;
+ }
+ e_object_del_func_set(E_OBJECT(exsurf), E_OBJECT_CLEANUP_FUNC(_e_xdg_surface_del));
+
+ exsurf->resource = wl_resource_create(shell->wclient,
+ &zxdg_surface_v6_interface,
+ 1,
+ id);
+ if (!exsurf->resource)
+ {
+ ERR("Could not create wl_resource for xdg surface", ec);
+ wl_client_post_no_memory(shell->wclient);
+ e_object_del(E_OBJECT(exsurf));
+ return NULL;
+ }
+
+ wl_resource_set_implementation(exsurf->resource,
+ &_e_xdg_surface_interface,
+ exsurf,
+ _e_xdg_surface_cb_resource_destroy);
+
+ e_shell_e_client_shsurface_assign(ec, exsurf->resource, NULL);
+
+ exsurf->shell = shell;
+ exsurf->ec = ec;
+ exsurf->configured = EINA_FALSE;
+ exsurf->commit_hook =
+ e_comp_wl_hook_add(E_COMP_WL_HOOK_CLIENT_SURFACE_COMMIT,
+ _e_xdg_surface_cb_commit,
+ exsurf);
+
+ _e_xdg_shell_surface_add(shell, exsurf);
+
+ // base_output_resolution.
+ e_client_base_output_resolution_update(ec);
+
+ return exsurf;
+}
+/* End of Xdg_surface */
+
+/**********************************************************
+ * Implementation for Xdg_Shell
+ **********************************************************/
+static void
+_e_xdg_shell_surface_add(E_Xdg_Shell *shell, E_Xdg_Surface *exsurf)
+{
+ if (!shell) return;
+ shell->surfaces = eina_list_append(shell->surfaces, exsurf);
+}
+
+static void
+_e_xdg_shell_surface_remove(E_Xdg_Shell *shell, E_Xdg_Surface *exsurf)
+{
+ if (!shell) return;
+ shell->surfaces = eina_list_remove(shell->surfaces, exsurf);
+}
+
+static void
+_e_xdg_shell_ping(E_Xdg_Shell *shell)
+{
+ EINA_SAFETY_ON_NULL_RETURN(shell);
+ EINA_SAFETY_ON_NULL_RETURN(shell->resource);
+
+ if (shell->ping_serial != 0)
+ return;
+
+ ELOGF("XDG6", "Ping. res:%p", NULL, shell->resource);
+ shell->ping_serial = wl_display_next_serial(e_comp_wl->wl.disp);
+ zxdg_shell_v6_send_ping(shell->resource, shell->ping_serial);
+}
+
+static void
+_e_xdg_shell_cb_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+ LOG("Destroy Xdg_Shell", NULL);
+
+ wl_resource_destroy(resource);
+}
+
+static void
+_e_xdg_shell_cb_positioner_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)
+{
+ E_Xdg_Shell *shell;
+ E_Xdg_Positioner *p;
+ struct wl_resource *new_res;
+
+ LOG("Create Positioner", NULL);
+
+ shell = wl_resource_get_user_data(resource);
+ if (!shell)
+ {
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No resource for xdg_shell_v6");
+ return;
+ }
+
+ new_res = wl_resource_create(client, &zxdg_positioner_v6_interface, 1, id);
+ if (!new_res)
+ {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ p = E_NEW(E_Xdg_Positioner, 1);
+ if (!p)
+ {
+ wl_resource_destroy(new_res);
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+ p->shell = shell;
+ p->resource = new_res;
+
+ shell->positioners = eina_list_append(shell->positioners, p);
+
+ wl_resource_set_implementation(new_res,
+ &_e_xdg_positioner_interface,
+ p,
+ _e_xdg_positioner_cb_resource_destroy);
+}
+
+static void
+_e_xdg_shell_cb_surface_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *wsurface)
+{
+ E_Xdg_Shell *shell;
+ E_Xdg_Surface *exsurf;
+
+ shell = wl_resource_get_user_data(resource);
+ if (!shell)
+ {
+ ERR("No E_Xdg_Shell data in wl_resource", NULL);
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No shell data in wl_resource");
+ return;
+ }
+
+ exsurf = _e_xdg_surface_create(shell, wsurface, id);
+ if (!exsurf)
+ {
+ ERR("Failed to create E_Xdg_Surface", NULL);
+ return;
+ }
+}
+
+static void
+_e_xdg_shell_cb_pong(struct wl_client *client, struct wl_resource *resource, uint32_t serial)
+{
+ E_Xdg_Shell *shell;
+ E_Xdg_Surface *exsurf;
+ Eina_List *l;
+
+ ELOGF("XDG6", "Pong. res:%p", NULL, resource);
+
+ shell = wl_resource_get_user_data(resource);
+ if (!shell)
+ {
+ ERR("No E_Xdg_Shell data in wl_resource", NULL);
+ wl_resource_post_error(resource,
+ WL_DISPLAY_ERROR_INVALID_OBJECT,
+ "No E_Xdg_Shell data in wl_resource");
+ return;
+ }
+
+ EINA_LIST_FOREACH(shell->surfaces, l, exsurf)
+ e_shell_e_client_pong(exsurf->ec);
+
+ shell->ping_serial = 0;
+}
+
+static const struct zxdg_shell_v6_interface _e_xdg_shell_interface =
+{
+ _e_xdg_shell_cb_destroy,
+ _e_xdg_shell_cb_positioner_create,
+ _e_xdg_shell_cb_surface_get,
+ _e_xdg_shell_cb_pong
+};
+
+static E_Xdg_Shell *
+_e_xdg_shell_create(struct wl_client *client, struct wl_resource *resource)
+{
+ E_Xdg_Shell *shell;
+
+ shell = E_NEW(E_Xdg_Shell, 1);
+ if (!shell)
+ return NULL;
+
+ shell->wclient = client;
+ shell->resource = resource;
+
+ return shell;
+}
+
+static void
+_e_xdg_shell_destroy(E_Xdg_Shell *shell)
+{
+ E_Xdg_Surface *exsurf;
+ E_Xdg_Positioner *p;
+
+ EINA_LIST_FREE(shell->surfaces, exsurf)
+ {
+ /* Do we need to do it even though shell is just about to be destroyed? */
+ e_shell_e_client_pong(exsurf->ec);
+ exsurf->shell = NULL;
+ }
+
+ EINA_LIST_FREE(shell->positioners, p)
+ p->shell = NULL;
+
+ free(shell);
+}
+
+static void
+_e_xdg_shell_cb_unbind(struct wl_resource *resource)
+{
+ E_Xdg_Shell *shell;
+
+ LOG("Unbind Xdg_Shell", NULL);
+
+ shell = wl_resource_get_user_data(resource);
+ if (!shell)
+ {
+ ERR("No E_Xdg_Shell in wl_resource", NULL);
+ return;
+ }
+
+ _e_xdg_shell_destroy(shell);
+}
+
+static void
+_e_xdg_shell_cb_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t version, uint32_t id)
+{
+ E_Xdg_Shell *shell;
+ struct wl_resource *resource;
+
+ LOG("Bind Xdg_Shell", NULL);
+
+ /* Create resource for zxdg_shell_v6 */
+ resource = wl_resource_create(client,
+ &zxdg_shell_v6_interface,
+ version,
+ id);
+ if (!resource)
+ goto err_res;
+
+
+ shell = _e_xdg_shell_create(client, resource);
+ if (!shell)
+ {
+ ERR("Failed to create E_Xdg_Shell", NULL);
+ goto err_shell;
+ }
+
+ wl_resource_set_implementation(resource, &_e_xdg_shell_interface,
+ shell, _e_xdg_shell_cb_unbind);
+
+ return;
+err_shell:
+ wl_resource_destroy(resource);
+err_res:
+ wl_client_post_no_memory(client);
+}
+
+EINTERN Eina_Bool
+e_xdg_shell_v6_init(void)
+{
+ LOG("Initializing Xdg_Shell_V6", NULL);
+
+ /* try to create global xdg_shell interface */
+ global_resource = wl_global_create(e_comp_wl->wl.disp,
+ &zxdg_shell_v6_interface,
+ 1,
+ e_comp->wl_comp_data,
+ _e_xdg_shell_cb_bind);
+ if (!global_resource)
+ {
+ ERR("Could not create zxdg_shell_v6 global: %m", NULL);
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+EINTERN void
+e_xdg_shell_v6_shutdown(void)
+{
+ E_FREE_FUNC(global_resource, wl_global_destroy);
+}
+
+EINTERN E_Client *
+e_xdg_shell_v6_xdg_surface_ec_get(struct wl_resource *resource)
+{
+ E_Xdg_Surface *exsurf = NULL;
+
+ exsurf = wl_resource_get_user_data(resource);
+ if (!exsurf)
+ {
+ ERR("No E_Xdg_Shell in wl_resource", NULL);
+ return NULL;
+ }
- _e_xdg_toplevel_v6_listener_finish(toplevel);
- _e_xdg_toplevel_v6_finish(toplevel);
- free(toplevel);
+ return exsurf->ec;
}
+/* End of Xdg_shell */