From 10da1b1c090d6e7d1b8b51efa74886e78452a23a Mon Sep 17 00:00:00 2001 From: Seunghun Lee Date: Fri, 11 May 2018 08:18:01 +0900 Subject: [PATCH] e_xdg_shell_v6: Reimplement xdg_shell_v6 support Change-Id: I8e90b19ae3acffe2e889405e44361a59c0adb0d6 --- src/bin/Makefile.mk | 6 +- src/bin/e_comp_wl_shell.c | 1791 +++++++++------------------------ src/bin/e_comp_wl_shell.h | 26 + src/bin/e_includes.h | 1 + src/bin/e_xdg_shell_v6.c | 2007 +++++++++++++++++++++++++++++++++++++ src/bin/e_xdg_shell_v6.h | 9 + 6 files changed, 2529 insertions(+), 1311 deletions(-) create mode 100644 src/bin/e_xdg_shell_v6.c create mode 100644 src/bin/e_xdg_shell_v6.h diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index 11ae0d1b7d..c104c991a2 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -126,7 +126,8 @@ src/bin/e_security.h \ src/bin/e_keyrouter.h \ src/bin/e_keyrouter_private.h \ src/bin/e_gesture.h \ -src/bin/e_input.h +src/bin/e_input.h \ +src/bin/e_xdg_shell_v6.h enlightenment_src = \ src/bin/e_actions.c \ @@ -237,7 +238,8 @@ src/bin/e_input_private.h \ src/bin/e_input.c \ src/bin/e_input_inputs.c \ src/bin/e_input_device.c \ -src/bin/e_input_evdev.c +src/bin/e_input_evdev.c \ +src/bin/e_xdg_shell_v6.c src_bin_enlightenment_CPPFLAGS = $(E_CPPFLAGS) -DEFL_BETA_API_SUPPORT -DEFL_EO_API_SUPPORT -DE_LOGGING=1 @WAYLAND_CFLAGS@ $(TTRACE_CFLAGS) $(DLOG_CFLAGS) $(PIXMAN_CFLAGS) $(POLICY_CFLAGS) @TIZEN_REMOTE_SURFACE_CFLAGS@ if HAVE_LIBGOMP diff --git a/src/bin/e_comp_wl_shell.c b/src/bin/e_comp_wl_shell.c index 9ea9d459e5..60790aa0b9 100644 --- a/src/bin/e_comp_wl_shell.c +++ b/src/bin/e_comp_wl_shell.c @@ -6,30 +6,160 @@ #define XDG_SERVER_VERSION 5 typedef struct _E_Xdg_Shell E_Xdg_Shell; -typedef struct _E_Xdg_Pos E_Xdg_Pos; struct _E_Xdg_Shell { struct wl_client *wc; struct wl_resource *res; /* xdg_shell resource */ Eina_List *ping_ecs; /* list of all ec which are waiting for pong response */ - Eina_List *positioners; /* list of E_Xdg_Pos */ }; -struct _E_Xdg_Pos +static Eina_Hash *xdg_sh_hash = NULL; + +EINTERN Eina_Bool +e_shell_e_client_shell_assignable_check(E_Client *ec) { - E_Xdg_Shell *sh; - struct wl_resource *res; /* xdg_positioner_v6 resources */ -}; + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); -static Eina_Hash *xdg_sh_hash = NULL; + if (e_object_is_del(E_OBJECT(ec))) + { + ELOGF("SHELL", "ERR: Could not assign shell: being deleted by compositor", + ec->pixmap, ec); + return EINA_FALSE; + } + else if (!ec->comp_data) + { + ELOGF("SHELL", "ERR: Could not assign shell: No E_Comp_Client_Data", + ec->pixmap, ec); + return EINA_FALSE; + } + else if (ec->comp_data->shell.surface) + { + ELOGF("SHELL", "ERR: Could not assign shell: Already assigned", + ec->pixmap, ec); + return EINA_FALSE; + } -static void -_e_shell_surface_parent_set(E_Client *ec, struct wl_resource *parent_resource) + return EINA_TRUE; +} + +EINTERN void +e_shell_e_client_shsurface_assign(E_Client *ec, + struct wl_resource *shsurface, + E_Shell_Surface_Api *api) +{ + E_Comp_Client_Data *cdata; + + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(shsurface); + + cdata = ec->comp_data; + if (!cdata) + { + ELOGF("SHELL", "ERR: E_Client must have E_Comp_Client_Data", + ec->pixmap, ec); + return; + } + + cdata->shell.surface = shsurface; + if (api) + { + cdata->shell.configure_send = api->configure_send; + cdata->shell.configure = api->configure; + cdata->shell.ping = api->ping; + cdata->shell.map = api->map; + cdata->shell.unmap = api->unmap; + } + + ec->netwm.ping = 1; + e_object_ref(E_OBJECT(ec)); +} + +EINTERN void +e_shell_e_client_shsurface_api_set(E_Client *ec, E_Shell_Surface_Api *api) +{ + E_Comp_Client_Data *cdata; + + EINA_SAFETY_ON_NULL_RETURN(ec); + EINA_SAFETY_ON_NULL_RETURN(api); + + cdata = ec->comp_data; + if (!cdata) + { + ELOGF("SHELL", "ERR: E_Client must have E_Comp_Client_Data", + ec->pixmap, ec); + return; + } + + cdata->shell.configure_send = api->configure_send; + cdata->shell.configure = api->configure; + cdata->shell.ping = api->ping; + cdata->shell.map = api->map; + cdata->shell.unmap = api->unmap; +} + +EINTERN void +e_shell_e_client_toplevel_set(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + + ELOGF("SHELL", "Set toplevel", ec->pixmap, ec); + + /* set toplevel client properties */ + ec->icccm.accepts_focus = 1; + if (!ec->internal) + ec->borderless = 1; + ec->lock_border = EINA_TRUE; + if ((!ec->internal) || (!ec->borderless)) + ec->border.changed = ec->changes.border = !ec->borderless; + if (ec->netwm.type == E_WINDOW_TYPE_UNKNOWN) + ec->netwm.type = E_WINDOW_TYPE_NORMAL; + ec->comp_data->set_win_type = EINA_TRUE; +} + +EINTERN void +e_shell_e_client_popup_set(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + + ELOGF("SHELL", "Set popup", ec->pixmap, ec); + + EC_CHANGED(ec); + ec->new_client = ec->override = 1; + e_client_unignore(ec); + e_comp->new_clients++; + if (!ec->internal) + ec->borderless = !ec->internal_elm_win; + ec->lock_border = EINA_TRUE; + if (!ec->internal) + ec->border.changed = ec->changes.border = !ec->borderless; + ec->changes.icon = !!ec->icccm.class; + ec->netwm.type = E_WINDOW_TYPE_POPUP_MENU; + ec->comp_data->set_win_type = EINA_TRUE; + evas_object_layer_set(ec->frame, E_LAYER_CLIENT_POPUP); +} + +EINTERN void +e_shell_e_client_pong(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + + if (e_object_is_del(E_OBJECT(ec))) return; + + ELOGF("SHELL", "Pong", ec->pixmap, ec); + + ec->ping_ok = EINA_TRUE; + ec->hung = EINA_FALSE; +} + +EINTERN void +e_shell_e_client_parent_set(E_Client *ec, struct wl_resource *parent_resource) { E_Client *pc; Ecore_Window pwin = 0; + EINA_SAFETY_ON_NULL_RETURN(ec); + if (!parent_resource) { ec->icccm.fetch.transient_for = EINA_FALSE; @@ -78,11 +208,44 @@ _e_shell_surface_parent_set(E_Client *ec, struct wl_resource *parent_resource) ec->icccm.transient_for = pwin; } +EINTERN Eina_Bool +e_shell_e_client_name_title_set(E_Client *ec, const char *name, const char *title) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); + + if (name) + eina_stringshare_replace(&ec->icccm.name, name); + + if (title) + { + eina_stringshare_replace(&ec->icccm.title, title); + if (ec->frame) + e_comp_object_frame_title_set(ec->frame, title); + } + + return EINA_TRUE; +} + +EINTERN Eina_Bool +e_shell_e_client_app_id_set(E_Client *ec, const char *app_id) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); + + /* set class */ + eina_stringshare_replace(&ec->icccm.class, app_id); + ec->changes.icon = !!ec->icccm.class; + EC_CHANGED(ec); + + return EINA_TRUE; +} + static void -_e_shell_surface_mouse_down_helper(E_Client *ec, E_Binding_Event_Mouse_Button *ev, Eina_Bool move, int resize_edges) +_e_shell_e_client_mouse_down_helper(E_Client *ec, E_Binding_Event_Mouse_Button *ev, Eina_Bool move, int resize_edges) { E_Pointer_Mode resize_mode = E_POINTER_RESIZE_NONE; + EINA_SAFETY_ON_NULL_RETURN(ec); + if (move) { /* tell E to start moving the client */ @@ -123,51 +286,141 @@ _e_shell_surface_mouse_down_helper(E_Client *ec, E_Binding_Event_Mouse_Button *e e_focus_event_mouse_down(ec); } -static void -_e_shell_surface_destroy(struct wl_resource *resource) +EINTERN Eina_Bool +e_shell_e_client_interactive_move(E_Client *ec, + /* TODO Multi seat is not yet supported */ + struct wl_resource *seat EINA_UNUSED) { - E_Client *ec = NULL; + E_Binding_Event_Mouse_Button ev; - /* get the client for this resource */ - if ((ec = wl_resource_get_user_data(resource))) + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); + + if ((ec->maximized) || (ec->fullscreen)) + return EINA_FALSE; + + TRACE_DS_BEGIN(SHELL:SURFACE MOVE REQUEST CB); + + switch (e_comp_wl->ptr.button) { - if (e_policy_visibility_client_grab_cancel(ec)) - { - ELOGF("POL_VIS", "CLIENT VIS ON(temp).", ec->pixmap, ec); - ec->visibility.obscured = E_VISIBILITY_UNOBSCURED; - ec->visibility.changed = 1; - } + case BTN_LEFT: ev.button = 1; break; + case BTN_MIDDLE: ev.button = 2; break; + case BTN_RIGHT: ev.button = 3; break; + default: ev.button = e_comp_wl->ptr.button; break; + } + + e_comp_object_frame_xy_unadjust(ec->frame, + wl_fixed_to_int(e_comp_wl->ptr.x), + wl_fixed_to_int(e_comp_wl->ptr.y), + &ev.canvas.x, + &ev.canvas.y); + + _e_shell_e_client_mouse_down_helper(ec, &ev, EINA_TRUE, 0); + + TRACE_DS_END(); + + return EINA_TRUE; +} + +EINTERN Eina_Bool +e_shell_e_client_interactive_resize(E_Client *ec, + struct wl_resource *resource, + /* TODO Multi seat is not yet supported */ + struct wl_resource *seat EINA_UNUSED, + uint32_t edges) +{ + E_Binding_Event_Mouse_Button ev; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ec, EINA_FALSE); + + if ((edges == 0) || (edges > 15) || + ((edges & 3) == 3) || ((edges & 12) == 12)) + return EINA_FALSE; + + if ((ec->maximized) || (ec->fullscreen)) + return EINA_FALSE; + + TRACE_DS_BEGIN(SHELL:SURFACE RESIZE REQUEST CB); + + e_comp_wl->resize.resource = resource; + e_comp_wl->resize.edges = edges; + e_comp_wl->ptr.grab_x = e_comp_wl->ptr.x - wl_fixed_from_int(ec->client.x); + e_comp_wl->ptr.grab_y = e_comp_wl->ptr.y - wl_fixed_from_int(ec->client.y); + + switch (e_comp_wl->ptr.button) + { + case BTN_LEFT: ev.button = 1; break; + case BTN_MIDDLE: ev.button = 2; break; + case BTN_RIGHT: ev.button = 3; break; + default: ev.button = e_comp_wl->ptr.button; break; + } + + e_comp_object_frame_xy_unadjust(ec->frame, + wl_fixed_to_int(e_comp_wl->ptr.x), + wl_fixed_to_int(e_comp_wl->ptr.y), + &ev.canvas.x, + &ev.canvas.y); + + _e_shell_e_client_mouse_down_helper(ec, &ev, EINA_FALSE, edges); - if ((e_object_unref(E_OBJECT(ec))) && - (!e_object_is_del(E_OBJECT(ec)))) + TRACE_DS_END(); + + return EINA_TRUE; +} + +EINTERN void +e_shell_e_client_destroy(E_Client *ec) +{ + EINA_SAFETY_ON_NULL_RETURN(ec); + + if (e_policy_visibility_client_grab_cancel(ec)) + { + ELOGF("POL_VIS", "CLIENT VIS ON(temp).", ec->pixmap, ec); + ec->visibility.obscured = E_VISIBILITY_UNOBSCURED; + ec->visibility.changed = 1; + } + + if ((e_object_unref(E_OBJECT(ec))) && + (!e_object_is_del(E_OBJECT(ec)))) + { + if (ec->comp_data->mapped) { - if (ec->comp_data->mapped) - { - if ((ec->comp_data->shell.surface) && - (ec->comp_data->shell.unmap)) - { - ELOGF("SHELL", "Call shell.unmap by destory surface", ec->pixmap, ec); - ec->comp_data->shell.unmap(ec->comp_data->shell.surface); - } - } - if (ec->parent) + if ((ec->comp_data->shell.surface) && + (ec->comp_data->shell.unmap)) { - ec->parent->transients = - eina_list_remove(ec->parent->transients, ec); - if (ec->parent->modal == ec) ec->parent->modal = NULL; - ec->parent = NULL; + ELOGF("SHELL", "Call shell.unmap by destory surface", ec->pixmap, ec); + ec->comp_data->shell.unmap(ec->comp_data->shell.surface); } - /* wl_resource_destroy(ec->comp_data->shell.surface); */ } - if (ec->comp_data) - ec->comp_data->shell.surface = NULL; - - ELOGF("SHELL", "Destroy shell surface", ec->pixmap, ec); + if (ec->parent) + { + ec->parent->transients = + eina_list_remove(ec->parent->transients, ec); + if (ec->parent->modal == ec) ec->parent->modal = NULL; + ec->parent = NULL; + } + /* wl_resource_destroy(ec->comp_data->shell.surface); */ } + if (ec->comp_data) + ec->comp_data->shell.surface = NULL; + + ELOGF("SHELL", "Destroy shell surface", ec->pixmap, ec); + e_policy_client_unmap(ec); } +static void +_e_shell_surface_destroy(struct wl_resource *resource) +{ + E_Client *ec = NULL; + + /* get the client for this resource */ + if (!(ec = wl_resource_get_user_data(resource))) + return; + + e_shell_e_client_destroy(ec); +} + static void _e_shell_surface_cb_destroy(struct wl_resource *resource) { @@ -180,17 +433,13 @@ _e_shell_surface_cb_pong(struct wl_client *client EINA_UNUSED, struct wl_resourc E_Client *ec; if ((ec = wl_resource_get_user_data(resource))) - { - ec->ping_ok = EINA_TRUE; - ec->hung = EINA_FALSE; - } + e_shell_e_client_pong(ec); } static void -_e_shell_surface_cb_move(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource EINA_UNUSED, uint32_t serial EINA_UNUSED) +_e_shell_surface_cb_move(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial EINA_UNUSED) { E_Client *ec; - E_Binding_Event_Mouse_Button ev; /* get the client for this resource */ if (!(ec = wl_resource_get_user_data(resource))) @@ -201,29 +450,13 @@ _e_shell_surface_cb_move(struct wl_client *client EINA_UNUSED, struct wl_resourc return; } - if ((ec->maximized) || (ec->fullscreen)) return; - - switch (e_comp_wl->ptr.button) - { - case BTN_LEFT: ev.button = 1; break; - case BTN_MIDDLE: ev.button = 2; break; - case BTN_RIGHT: ev.button = 3; break; - default: ev.button = e_comp_wl->ptr.button; break; - } - - e_comp_object_frame_xy_unadjust(ec->frame, - wl_fixed_to_int(e_comp_wl->ptr.x), - wl_fixed_to_int(e_comp_wl->ptr.y), - &ev.canvas.x, &ev.canvas.y); - - _e_shell_surface_mouse_down_helper(ec, &ev, EINA_TRUE, 0); + e_shell_e_client_interactive_move(ec, seat_resource); } static void -_e_shell_surface_cb_resize(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource EINA_UNUSED, uint32_t serial EINA_UNUSED, uint32_t edges) +_e_shell_surface_cb_resize(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial EINA_UNUSED, uint32_t edges) { E_Client *ec; - E_Binding_Event_Mouse_Button ev; /* get the client for this resource */ if (!(ec = wl_resource_get_user_data(resource))) @@ -234,30 +467,7 @@ _e_shell_surface_cb_resize(struct wl_client *client EINA_UNUSED, struct wl_resou return; } - if ((edges == 0) || (edges > 15) || - ((edges & 3) == 3) || ((edges & 12) == 12)) return; - - if ((ec->maximized) || (ec->fullscreen)) return; - - e_comp_wl->resize.resource = resource; - e_comp_wl->resize.edges = edges; - e_comp_wl->ptr.grab_x = e_comp_wl->ptr.x - wl_fixed_from_int(ec->client.x); - e_comp_wl->ptr.grab_y = e_comp_wl->ptr.y - wl_fixed_from_int(ec->client.y); - - switch (e_comp_wl->ptr.button) - { - case BTN_LEFT: ev.button = 1; break; - case BTN_MIDDLE: ev.button = 2; break; - case BTN_RIGHT: ev.button = 3; break; - default: ev.button = e_comp_wl->ptr.button; break; - } - - e_comp_object_frame_xy_unadjust(ec->frame, - wl_fixed_to_int(e_comp_wl->ptr.x), - wl_fixed_to_int(e_comp_wl->ptr.y), - &ev.canvas.x, &ev.canvas.y); - - _e_shell_surface_mouse_down_helper(ec, &ev, EINA_FALSE, edges); + e_shell_e_client_interactive_resize(ec, resource, seat_resource, edges); } static void @@ -275,15 +485,8 @@ _e_shell_surface_cb_toplevel_set(struct wl_client *client EINA_UNUSED, struct wl } /* set toplevel client properties */ - ec->icccm.accepts_focus = 1; - if (!ec->internal) - ec->borderless = !ec->internal; + e_shell_e_client_toplevel_set(ec); - ec->lock_border = EINA_TRUE; - if (!ec->internal) - ec->border.changed = ec->changes.border = !ec->borderless; - ec->netwm.type = E_WINDOW_TYPE_NORMAL; - ec->comp_data->set_win_type = EINA_TRUE; if ((!ec->lock_user_maximize) && (ec->maximized)) e_client_unmaximize(ec, E_MAXIMIZE_BOTH); if ((!ec->lock_user_fullscreen) && (ec->fullscreen)) @@ -304,7 +507,7 @@ _e_shell_surface_cb_transient_set(struct wl_client *client EINA_UNUSED, struct w } /* set this client as a transient for parent */ - _e_shell_surface_parent_set(ec, parent_resource); + e_shell_e_client_parent_set(ec, parent_resource); EC_CHANGED(ec); } @@ -355,7 +558,7 @@ _e_shell_surface_cb_popup_set(struct wl_client *client EINA_UNUSED, struct wl_re ec->layer = E_LAYER_CLIENT_POPUP; /* set this client as a transient for parent */ - _e_shell_surface_parent_set(ec, parent_resource); + e_shell_e_client_parent_set(ec, parent_resource); EC_CHANGED(ec); } @@ -402,8 +605,7 @@ _e_shell_surface_cb_title_set(struct wl_client *client EINA_UNUSED, struct wl_re } /* set title */ - eina_stringshare_replace(&ec->icccm.title, title); - if (ec->frame) e_comp_object_frame_title_set(ec->frame, title); + e_shell_e_client_name_title_set(ec, NULL, title); } static void @@ -640,7 +842,14 @@ static void _e_shell_cb_shell_surface_get(struct wl_client *client, struct wl_resource *resource EINA_UNUSED, uint32_t id, struct wl_resource *surface_resource) { E_Client *ec; - E_Comp_Client_Data *cdata; + struct wl_resource *shsurf_resource; + E_Shell_Surface_Api api = { + .configure_send = _e_shell_surface_configure_send, + .configure = _e_shell_surface_configure, + .ping = _e_shell_surface_ping, + .map = _e_shell_surface_map, + .unmap = _e_shell_surface_unmap, + }; /* get the pixmap from this surface so we can find the client */ if (!(ec = wl_resource_get_user_data(surface_resource))) @@ -650,47 +859,30 @@ _e_shell_cb_shell_surface_get(struct wl_client *client, struct wl_resource *reso "No Pixmap Set On Surface"); return; } - ec->netwm.ping = 1; - /* get the client data */ - if (!(cdata = ec->comp_data)) - { - wl_resource_post_error(surface_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Data For Client"); - return; - } - /* check for existing shell surface */ - if (cdata->shell.surface) + if (!e_shell_e_client_shell_assignable_check(ec)) { wl_resource_post_error(surface_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "Client already has shell surface"); + "Could not assign shell surface to wl_surface"); return; } - /* try to create a shell surface */ - if (!(cdata->shell.surface = - wl_resource_create(client, &wl_shell_surface_interface, 1, id))) + shsurf_resource = wl_resource_create(client, &wl_shell_surface_interface, 1, id); + if (!shsurf_resource) { - wl_resource_post_no_memory(surface_resource); + wl_client_post_no_memory(client); return; } - ELOGF("SHELL", "Create shell surface", ec->pixmap, ec); - wl_resource_set_implementation(cdata->shell.surface, + wl_resource_set_implementation(shsurf_resource, &_e_shell_surface_interface, ec, _e_shell_surface_cb_destroy); - e_object_ref(E_OBJECT(ec)); - - cdata->shell.configure_send = _e_shell_surface_configure_send; - cdata->shell.configure = _e_shell_surface_configure; - cdata->shell.ping = _e_shell_surface_ping; - cdata->shell.map = _e_shell_surface_map; - cdata->shell.unmap = _e_shell_surface_unmap; + ELOGF("SHELL", "Create shell surface", ec->pixmap, ec); + e_shell_e_client_shsurface_assign(ec, shsurf_resource, &api); e_comp_wl_shell_surface_ready(ec); } @@ -792,7 +984,7 @@ _e_xdg_shell_surface_cb_parent_set(struct wl_client *client EINA_UNUSED, struct } /* set this client as a transient for parent */ - _e_shell_surface_parent_set(ec, parent_resource); + e_shell_e_client_parent_set(ec, parent_resource); EC_CHANGED(ec); } @@ -812,9 +1004,7 @@ _e_xdg_shell_surface_cb_title_set(struct wl_client *client EINA_UNUSED, struct w } /* set title */ - eina_stringshare_replace(&ec->icccm.title, title); - eina_stringshare_replace(&ec->icccm.name, title); - if (ec->frame) e_comp_object_frame_title_set(ec->frame, title); + e_shell_e_client_name_title_set(ec, title, title); } static void @@ -834,11 +1024,7 @@ _e_xdg_shell_surface_cb_app_id_set(struct wl_client *client EINA_UNUSED, struct /* 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); - /* set class */ - eina_stringshare_replace(&ec->icccm.class, id); - /* eina_stringshare_replace(&ec->netwm.name, id); */ - ec->changes.icon = !!ec->icccm.class; - EC_CHANGED(ec); + e_shell_e_client_app_id_set(ec, id); } static void @@ -861,10 +1047,9 @@ _e_xdg_shell_surface_cb_window_menu_show(struct wl_client *client EINA_UNUSED, s } static void -_e_xdg_shell_surface_cb_move(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource EINA_UNUSED, uint32_t serial EINA_UNUSED) +_e_xdg_shell_surface_cb_move(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial EINA_UNUSED) { E_Client *ec; - E_Binding_Event_Mouse_Button ev; /* get the client for this resource */ if (!(ec = wl_resource_get_user_data(resource))) @@ -875,34 +1060,13 @@ _e_xdg_shell_surface_cb_move(struct wl_client *client EINA_UNUSED, struct wl_res return; } - if ((ec->maximized) || (ec->fullscreen)) return; - - TRACE_DS_BEGIN(SHELL:SURFACE MOVE REQUEST CB); - - switch (e_comp_wl->ptr.button) - { - case BTN_LEFT: ev.button = 1; break; - case BTN_MIDDLE: ev.button = 2; break; - case BTN_RIGHT: ev.button = 3; break; - default: ev.button = e_comp_wl->ptr.button; break; - } - - e_comp_object_frame_xy_unadjust(ec->frame, - wl_fixed_to_int(e_comp_wl->ptr.x), - wl_fixed_to_int(e_comp_wl->ptr.y), - &ev.canvas.x, - &ev.canvas.y); - - _e_shell_surface_mouse_down_helper(ec, &ev, EINA_TRUE, 0); - - TRACE_DS_END(); -} + e_shell_e_client_interactive_move(ec, seat_resource); +} static void -_e_xdg_shell_surface_cb_resize(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource EINA_UNUSED, uint32_t serial EINA_UNUSED, uint32_t edges) +_e_xdg_shell_surface_cb_resize(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial EINA_UNUSED, uint32_t edges) { E_Client *ec; - E_Binding_Event_Mouse_Button ev; /* get the client for this resource */ if (!(ec = wl_resource_get_user_data(resource))) @@ -913,38 +1077,7 @@ _e_xdg_shell_surface_cb_resize(struct wl_client *client EINA_UNUSED, struct wl_r return; } - if ((edges == 0) || - (edges > 15) || - ((edges & 3) == 3) || - ((edges & 12) == 12)) - return; - - if ((ec->maximized) || (ec->fullscreen)) return; - - TRACE_DS_BEGIN(SHELL:SURFACE RESIZE REQUEST CB); - - e_comp_wl->resize.resource = resource; - e_comp_wl->resize.edges = edges; - e_comp_wl->ptr.grab_x = e_comp_wl->ptr.x - wl_fixed_from_int(ec->client.x); - e_comp_wl->ptr.grab_y = e_comp_wl->ptr.y - wl_fixed_from_int(ec->client.y); - - switch (e_comp_wl->ptr.button) - { - case BTN_LEFT: ev.button = 1; break; - case BTN_MIDDLE: ev.button = 2; break; - case BTN_RIGHT: ev.button = 3; break; - default: ev.button = e_comp_wl->ptr.button; break; - } - - e_comp_object_frame_xy_unadjust(ec->frame, - wl_fixed_to_int(e_comp_wl->ptr.x), - wl_fixed_to_int(e_comp_wl->ptr.y), - &ev.canvas.x, - &ev.canvas.y); - - _e_shell_surface_mouse_down_helper(ec, &ev, EINA_FALSE, edges); - - TRACE_DS_END(); + e_shell_e_client_interactive_resize(ec, resource, seat_resource, edges); } static void @@ -1200,87 +1333,75 @@ _e_xdg_shell_surface_map_cb_timer(void *data) return ECORE_CALLBACK_CANCEL; } -static void -_e_xdg_shell_surface_map(struct wl_resource *resource) +EINTERN void +e_shell_e_client_map(E_Client *ec) { - E_Client *ec; + int pw = 0; + int ph = 0; + int cw; + int ch; - if (!resource) return; + EINA_SAFETY_ON_NULL_RETURN(ec); - TRACE_DS_BEGIN(SHELL:MAP); + if ((ec->comp_data->mapped) || (!e_pixmap_usable_get(ec->pixmap))) + return; - /* get the client for this resource */ - if (!(ec = wl_resource_get_user_data(resource))) + cw = ec->w; + ch = ec->h; + + e_pixmap_size_get(ec->pixmap, &pw, &ph); + evas_object_geometry_get(ec->frame, NULL, NULL, &cw, &ch); + if (cw == 0 && ch == 0) { - wl_resource_post_error(resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - TRACE_DS_END(); - return; + cw = ec->w; + ch = ec->h; } - if ((!ec->comp_data->mapped) && (e_pixmap_usable_get(ec->pixmap))) + if (pw != cw || ph != ch) { - int pw = 0; - int ph = 0; - int cw = ec->w; - int ch = ec->h; - e_pixmap_size_get(ec->pixmap, &pw, &ph); - evas_object_geometry_get(ec->frame, NULL, NULL, &cw, &ch); - if (cw == 0 && ch == 0) + if ((ec->changes.need_maximize) || + ((ec->maximized & E_MAXIMIZE_BOTH) == E_MAXIMIZE_BOTH)) { - cw = ec->w; - ch = ec->h; - } + // skip. because the pixmap's size doesnot same to ec's size + ELOGF("SHELL", + "Deny Map |win:0x%08x|ec_size:%d,%d|get_size:%d,%d|pix_size:%d,%d", + ec->pixmap, ec, + (unsigned int)e_client_util_win_get(ec), + ec->w, ec->h, cw, ch, pw, ph); - if (pw != cw || ph != ch) - { - if ((ec->changes.need_maximize) || - ((ec->maximized & E_MAXIMIZE_BOTH) == E_MAXIMIZE_BOTH)) - { - // skip. because the pixmap's size doesnot same to ec's size - ELOGF("SHELL", - "Deny Map |win:0x%08x|ec_size:%d,%d|get_size:%d,%d|pix_size:%d,%d", - ec->pixmap, ec, - (unsigned int)e_client_util_win_get(ec), - ec->w, ec->h, cw, ch, pw, ph); - - if (!ec->map_timer) - ec->map_timer = ecore_timer_add(3.0, _e_xdg_shell_surface_map_cb_timer, ec); - - TRACE_DS_END(); - return; - } - } - E_FREE_FUNC(ec->map_timer, ecore_timer_del); + if (!ec->map_timer) + ec->map_timer = ecore_timer_add(3.0, _e_xdg_shell_surface_map_cb_timer, ec); - ELOGF("SHELL", - "Map window |win:0x%08x|ec_size:%d,%d|pid:%d|title:%s, name:%s", - ec->pixmap, ec, - (unsigned int)e_client_util_win_get(ec), - ec->w, ec->h, ec->netwm.pid, ec->icccm.title, ec->netwm.name); + TRACE_DS_END(); + return; + } + } + E_FREE_FUNC(ec->map_timer, ecore_timer_del); - ELOGF("SHELL", - "spash:%d, first_mapped:%d, iconic:%d(client:%d), raise:%d, lower:%d, ignore:%d, override:%d, input_only:%d", - ec->pixmap, ec, - ec->use_splash, ec->first_mapped, ec->iconic, ec->exp_iconify.by_client, - ec->post_raise, ec->post_lower, ec->ignored, ec->override, ec->input_only); + ELOGF("SHELL", + "Map window |win:0x%08x|ec_size:%d,%d|pid:%d|title:%s, name:%s", + ec->pixmap, ec, + (unsigned int)e_client_util_win_get(ec), + ec->w, ec->h, ec->netwm.pid, ec->icccm.title, ec->netwm.name); - _e_shell_client_map_common_pre(ec); - _e_shell_client_map_common_post(ec); - } + ELOGF("SHELL", + "spash:%d, first_mapped:%d, iconic:%d(client:%d), raise:%d, lower:%d, ignore:%d, override:%d, input_only:%d", + ec->pixmap, ec, + ec->use_splash, ec->first_mapped, ec->iconic, ec->exp_iconify.by_client, + ec->post_raise, ec->post_lower, ec->ignored, ec->override, ec->input_only); - TRACE_DS_END(); + _e_shell_client_map_common_pre(ec); + _e_shell_client_map_common_post(ec); } static void -_e_xdg_shell_surface_unmap(struct wl_resource *resource) +_e_xdg_shell_surface_map(struct wl_resource *resource) { E_Client *ec; if (!resource) return; - TRACE_DS_BEGIN(SHELL:UNMAP); + TRACE_DS_BEGIN(SHELL:MAP); /* get the client for this resource */ if (!(ec = wl_resource_get_user_data(resource))) @@ -1292,6 +1413,15 @@ _e_xdg_shell_surface_unmap(struct wl_resource *resource) return; } + e_shell_e_client_map(ec); + + TRACE_DS_END(); +} + +EINTERN void +e_shell_e_client_unmap(E_Client *ec) +{ + E_FREE_FUNC(ec->map_timer, ecore_timer_del); if (ec->comp_data->mapped) @@ -1309,48 +1439,65 @@ _e_xdg_shell_surface_unmap(struct wl_resource *resource) (unsigned int)e_client_util_win_get(ec), ec->w, ec->h); } - - TRACE_DS_END(); } static void -_e_xdg_shell_cb_surface_get(struct wl_client *client, struct wl_resource *resource EINA_UNUSED, uint32_t id, struct wl_resource *surface_resource) +_e_xdg_shell_surface_unmap(struct wl_resource *resource) { E_Client *ec; - E_Comp_Client_Data *cdata; - /* get the pixmap from this surface so we can find the client */ - if (!(ec = wl_resource_get_user_data(surface_resource))) + if (!resource) return; + + TRACE_DS_BEGIN(SHELL:UNMAP); + + /* get the client for this resource */ + if (!(ec = wl_resource_get_user_data(resource))) { - wl_resource_post_error(surface_resource, + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Pixmap Set On Surface"); + "No Client For Shell Surface"); + TRACE_DS_END(); return; } - ec->netwm.ping = 1; + e_shell_e_client_unmap(ec); + + TRACE_DS_END(); +} + +static void +_e_xdg_shell_cb_surface_get(struct wl_client *client, struct wl_resource *resource EINA_UNUSED, uint32_t id, struct wl_resource *surface_resource) +{ + E_Client *ec; + struct wl_resource *shsurf_resource; + E_Shell_Surface_Api api = { + .configure_send = _e_xdg_shell_surface_configure_send, + .configure = _e_xdg_shell_surface_configure, + .ping = _e_xdg_shell_surface_ping, + .map = _e_xdg_shell_surface_map, + .unmap = _e_xdg_shell_surface_unmap, + }; - /* get the client data */ - if (!(cdata = ec->comp_data)) + /* get the pixmap from this surface so we can find the client */ + if (!(ec = wl_resource_get_user_data(surface_resource))) { wl_resource_post_error(surface_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Data For Client"); + "No Pixmap Set On Surface"); return; } - /* check for existing shell surface */ - if (cdata->shell.surface) + if (!e_shell_e_client_shell_assignable_check(ec)) { wl_resource_post_error(surface_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "Client already has XDG shell surface"); + "Could not assign shell surface to wl_surface"); return; } /* try to create a shell surface */ - if (!(cdata->shell.surface = - wl_resource_create(client, &xdg_surface_interface, 1, id))) + shsurf_resource = wl_resource_create(client, &xdg_surface_interface, 1, id); + if (!shsurf_resource) { ERR("Could not create xdg shell surface"); wl_resource_post_no_memory(surface_resource); @@ -1358,29 +1505,13 @@ _e_xdg_shell_cb_surface_get(struct wl_client *client, struct wl_resource *resour } ELOGF("SHELL", "Create xdg shell surface", ec->pixmap, ec); - wl_resource_set_implementation(cdata->shell.surface, + wl_resource_set_implementation(shsurf_resource, &_e_xdg_surface_interface, ec, _e_shell_surface_cb_destroy); - e_object_ref(E_OBJECT(ec)); - - cdata->shell.configure_send = _e_xdg_shell_surface_configure_send; - cdata->shell.configure = _e_xdg_shell_surface_configure; - cdata->shell.ping = _e_xdg_shell_surface_ping; - cdata->shell.map = _e_xdg_shell_surface_map; - cdata->shell.unmap = _e_xdg_shell_surface_unmap; - - /* set toplevel client properties */ - ec->icccm.accepts_focus = 1; - if (!ec->internal) - ec->borderless = 1; - ec->lock_border = EINA_TRUE; - if ((!ec->internal) || (!ec->borderless)) - ec->border.changed = ec->changes.border = !ec->borderless; - if (ec->netwm.type == E_WINDOW_TYPE_UNKNOWN) - ec->netwm.type = E_WINDOW_TYPE_NORMAL; - ec->comp_data->set_win_type = EINA_TRUE; + e_shell_e_client_shsurface_assign(ec, shsurf_resource, &api); + e_shell_e_client_toplevel_set(ec); e_comp_wl_shell_surface_ready(ec); } @@ -1401,6 +1532,14 @@ _e_xdg_shell_cb_popup_get(struct wl_client *client, struct wl_resource *resource { E_Client *ec; E_Comp_Client_Data *cdata; + struct wl_resource *shsurf_resource; + E_Shell_Surface_Api api = { + .configure_send = _e_xdg_shell_surface_configure_send, + .configure = _e_xdg_shell_surface_configure, + .ping = _e_xdg_shell_surface_ping, + .map = _e_xdg_shell_surface_map, + .unmap = _e_xdg_shell_surface_unmap, + }; /* get the pixmap from this surface so we can find the client */ if (!(ec = wl_resource_get_user_data(surface_resource))) @@ -1411,21 +1550,11 @@ _e_xdg_shell_cb_popup_get(struct wl_client *client, struct wl_resource *resource return; } - /* get the client data */ - if (!(cdata = ec->comp_data)) - { - wl_resource_post_error(surface_resource, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Data For Client"); - return; - } - - /* check for existing shell surface */ - if (cdata->shell.surface) + if (!e_shell_e_client_shell_assignable_check(ec)) { wl_resource_post_error(surface_resource, WL_DISPLAY_ERROR_INVALID_OBJECT, - "Client already has shell popup surface"); + "Could not assign shell surface to wl_surface"); return; } @@ -1439,8 +1568,8 @@ _e_xdg_shell_cb_popup_get(struct wl_client *client, struct wl_resource *resource } /* try to create a shell surface */ - if (!(cdata->shell.surface = - wl_resource_create(client, &xdg_popup_interface, 1, id))) + shsurf_resource = wl_resource_create(client, &xdg_popup_interface, 1, id); + if (!shsurf_resource) { ERR("Could not create xdg shell surface"); wl_resource_post_no_memory(surface_resource); @@ -1448,36 +1577,18 @@ _e_xdg_shell_cb_popup_get(struct wl_client *client, struct wl_resource *resource } ELOGF("SHELL", "Create xdg shell popup surface", ec->pixmap, ec); - wl_resource_set_implementation(cdata->shell.surface, + wl_resource_set_implementation(shsurf_resource, &_e_xdg_popup_interface, ec, NULL); - e_object_ref(E_OBJECT(ec)); - - cdata->shell.configure_send = _e_xdg_shell_surface_configure_send; - cdata->shell.configure = _e_xdg_shell_surface_configure; - cdata->shell.ping = _e_xdg_shell_surface_ping; - cdata->shell.map = _e_xdg_shell_surface_map; - cdata->shell.unmap = _e_xdg_shell_surface_unmap; - - EC_CHANGED(ec); - ec->new_client = ec->override = 1; - e_client_unignore(ec); - e_comp->new_clients++; - if (!ec->internal) - ec->borderless = !ec->internal_elm_win; - ec->lock_border = EINA_TRUE; - if (!ec->internal) - ec->border.changed = ec->changes.border = !ec->borderless; - ec->changes.icon = !!ec->icccm.class; - ec->netwm.type = E_WINDOW_TYPE_POPUP_MENU; - ec->comp_data->set_win_type = EINA_TRUE; - evas_object_layer_set(ec->frame, E_LAYER_CLIENT_POPUP); + e_shell_e_client_shsurface_assign(ec, shsurf_resource, &api); + e_shell_e_client_popup_set(ec); /* set this client as a transient for parent */ - _e_shell_surface_parent_set(ec, parent_resource); + e_shell_e_client_parent_set(ec, parent_resource); + cdata = ec->comp_data; if (ec->parent) { cdata->popup.x = E_CLAMP(x, 0, ec->parent->client.w); @@ -1502,12 +1613,7 @@ _e_xdg_shell_cb_pong(struct wl_client *client, struct wl_resource *resource, uin EINA_SAFETY_ON_FALSE_RETURN(esh->res == resource); EINA_LIST_FREE(esh->ping_ecs, ec) - { - if (e_object_is_del(E_OBJECT(ec))) continue; - - ec->ping_ok = EINA_TRUE; - ec->hung = EINA_FALSE; - } + e_shell_e_client_pong(ec); } static void @@ -1539,10 +1645,8 @@ static void _e_xdg_shell_cb_unbind(struct wl_resource *resource) { E_Xdg_Shell *esh; - E_Xdg_Pos *epos; E_Client *ec; struct wl_client *client; - Eina_List *l, *ll; client = wl_resource_get_client(resource); EINA_SAFETY_ON_NULL_RETURN(client); @@ -1551,16 +1655,7 @@ _e_xdg_shell_cb_unbind(struct wl_resource *resource) EINA_SAFETY_ON_NULL_RETURN(esh); EINA_LIST_FREE(esh->ping_ecs, ec) - { - if (e_object_is_del(E_OBJECT(ec))) continue; - ec->ping_ok = EINA_TRUE; - ec->hung = EINA_FALSE; - } - - EINA_LIST_FOREACH_SAFE(esh->positioners, l, ll, epos) - { - E_FREE(epos); - } + e_shell_e_client_pong(ec); eina_hash_del_by_key(xdg_sh_hash, &client); @@ -1649,985 +1744,67 @@ err: wl_client_post_no_memory(client); } -//////////////////////////////////////////////////////////////////////////////// static void -_e_xdg_surf_v6_configure_send(struct wl_resource *res_xdg_surf_v6, - uint32_t edges, - int32_t width, - int32_t height) +_e_tz_surf_cb_tz_res_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface) { + struct wl_resource *res; E_Client *ec; - E_Comp_Client_Data *cdata; - struct wl_array states; - uint32_t serial; - struct wl_resource *resource; - - EINA_SAFETY_ON_NULL_RETURN(res_xdg_surf_v6); + uint32_t res_id; - ec = wl_resource_get_user_data(res_xdg_surf_v6); - if (!ec) + /* get the pixmap from this surface so we can find the client */ + if (!(ec = wl_resource_get_user_data(surface))) { - wl_resource_post_error(res_xdg_surf_v6, + wl_resource_post_error(surface, WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); + "No Pixmap Set On Surface"); return; } - cdata = ec->comp_data; - EINA_SAFETY_ON_NULL_RETURN(cdata); - EINA_SAFETY_ON_NULL_RETURN(cdata->sh_v6.res_role); - - resource = cdata->sh_v6.res_role; - - wl_array_init(&states); - - if (ec->fullscreen) - { - _e_xdg_surface_state_add(resource, &states, ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN); + /* find the window id for this pixmap */ + res_id = e_pixmap_res_id_get(ec->pixmap); - // send fullscreen size - if ((width == 0) && (height == 0)) - { - width = ec->client.w && ec->client.h? ec->client.w : ec->w; - height = ec->client.w && ec->client.h? ec->client.h : ec->h; - } - } - else if (ec->maximized) + /* try to create a tizen_gid */ + if (!(res = wl_resource_create(client, + &tizen_resource_interface, + wl_resource_get_version(resource), + id))) { - _e_xdg_surface_state_add(resource, &states, ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED); - - // send maximized size - if ((width == 0) && (height == 0)) - { - width = ec->client.w && ec->client.h? ec->client.w : ec->w; - height = ec->client.w && ec->client.h? ec->client.h : ec->h; - } + wl_resource_post_no_memory(resource); + return; } - if (edges != 0) - _e_xdg_surface_state_add(resource, &states, ZXDG_TOPLEVEL_V6_STATE_RESIZING); - - if (ec->focused) - _e_xdg_surface_state_add(resource, &states, ZXDG_TOPLEVEL_V6_STATE_ACTIVATED); - - zxdg_toplevel_v6_send_configure(cdata->sh_v6.res_role, width, height, &states); - serial = wl_display_next_serial(e_comp_wl->wl.disp); - zxdg_surface_v6_send_configure(res_xdg_surf_v6, serial); - - wl_array_release(&states); + wl_resource_set_implementation(res, + &_e_tz_res_interface, + ec, + NULL); - ELOGF("SH", "SEND configure v6 %dx%d", ec->pixmap, ec, width, height); + tizen_resource_send_resource_id(res, res_id); } static void -_e_xdg_sh_v6_ping(struct wl_resource *res_xdg_surf_v6) +_e_tz_surf_cb_destroy(struct wl_client *client, struct wl_resource *resource) { - E_Client *ec; - uint32_t serial; - struct wl_client *client; - E_Xdg_Shell *esh; + wl_resource_destroy(resource); +} - if (!res_xdg_surf_v6) return; +static const struct tizen_surface_interface _e_tz_surf_interface = +{ + _e_tz_surf_cb_tz_res_get, + _e_tz_surf_cb_destroy +}; - ec = wl_resource_get_user_data(res_xdg_surf_v6); - if (!ec) +static void +_e_tz_surf_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) +{ + struct wl_resource *res; + + if (!(res = wl_resource_create(client, + &tizen_surface_interface, + version, + id))) { - wl_resource_post_error(res_xdg_surf_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - client = wl_resource_get_client(res_xdg_surf_v6); - - esh = eina_hash_find(xdg_sh_hash, &client); - EINA_SAFETY_ON_NULL_RETURN(esh); - EINA_SAFETY_ON_NULL_RETURN(esh->res); - - if (!eina_list_data_find(esh->ping_ecs, ec)) - esh->ping_ecs = eina_list_append(esh->ping_ecs, ec); - - serial = wl_display_next_serial(e_comp_wl->wl.disp); - zxdg_shell_v6_send_ping(esh->res, serial); -} - -//////////////////////////////////////////////////////////////////////////////// -static void -_e_xdg_toplv_v6_cb_res_destroy(struct wl_resource *res_xdg_toplv_v6) -{ - _e_shell_surface_destroy(res_xdg_toplv_v6); -} - -static void -_e_xdg_toplv_v6_cb_destroy(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6) -{ - wl_resource_destroy(res_xdg_toplv_v6); -} - -static void -_e_xdg_toplv_v6_cb_parent_set(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6, - struct wl_resource *res_xdg_toplv_v6_parent) -{ - E_Client *ec, *pc; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - if (res_xdg_toplv_v6_parent) - { - pc = wl_resource_get_user_data(res_xdg_toplv_v6_parent); - if (!pc) - { - ERR("Could not get parent resource clinet"); - return; - } - if (!pc->comp_data) return; - res_xdg_toplv_v6_parent = pc->comp_data->surface; - } - - /* set this client as a transient for parent */ - _e_shell_surface_parent_set(ec, res_xdg_toplv_v6_parent); -} - -static void -_e_xdg_toplv_v6_cb_title_set(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6, - const char *title) -{ - E_Client *ec; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - eina_stringshare_replace(&ec->icccm.title, title); - eina_stringshare_replace(&ec->icccm.name, title); - if (ec->frame) e_comp_object_frame_title_set(ec->frame, title); -} - -static void -_e_xdg_toplv_v6_cb_app_id_set(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6, - const char *app_id) -{ - E_Client *ec; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - /* 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); - - /* set class */ - eina_stringshare_replace(&ec->icccm.class, app_id); - ec->changes.icon = !!ec->icccm.class; - EC_CHANGED(ec); -} - -static void -_e_xdg_toplv_v6_cb_win_menu_show(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6, - struct wl_resource *res_seat, - uint32_t serial, - int32_t x, - int32_t y) -{ - E_Client *ec; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - /* TODO no op */ -} - -static void -_e_xdg_toplv_v6_cb_move(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6, - struct wl_resource *res_seat, - uint32_t serial) -{ - E_Client *ec; - E_Binding_Event_Mouse_Button ev; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - if ((ec->maximized) || (ec->fullscreen)) return; - - TRACE_DS_BEGIN(SHELL:SURFACE MOVE REQUEST CB); - - switch (e_comp_wl->ptr.button) - { - case BTN_LEFT: ev.button = 1; break; - case BTN_MIDDLE: ev.button = 2; break; - case BTN_RIGHT: ev.button = 3; break; - default: ev.button = e_comp_wl->ptr.button; break; - } - - e_comp_object_frame_xy_unadjust(ec->frame, - wl_fixed_to_int(e_comp_wl->ptr.x), - wl_fixed_to_int(e_comp_wl->ptr.y), - &ev.canvas.x, - &ev.canvas.y); - - _e_shell_surface_mouse_down_helper(ec, &ev, EINA_TRUE, 0); - - TRACE_DS_END(); -} - -static void -_e_xdg_toplv_v6_cb_resize(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6, - struct wl_resource *res_seat, - uint32_t serial, - uint32_t edges) -{ - E_Client *ec; - E_Binding_Event_Mouse_Button ev; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - if ((edges == 0) || - (edges > 15) || - ((edges & 3) == 3) || - ((edges & 12) == 12)) - return; - - if ((ec->maximized) || (ec->fullscreen)) return; - - TRACE_DS_BEGIN(SHELL:SURFACE RESIZE REQUEST CB); - - e_comp_wl->resize.resource = res_xdg_toplv_v6; - e_comp_wl->resize.edges = edges; - e_comp_wl->ptr.grab_x = e_comp_wl->ptr.x - wl_fixed_from_int(ec->client.x); - e_comp_wl->ptr.grab_y = e_comp_wl->ptr.y - wl_fixed_from_int(ec->client.y); - - switch (e_comp_wl->ptr.button) - { - case BTN_LEFT: ev.button = 1; break; - case BTN_MIDDLE: ev.button = 2; break; - case BTN_RIGHT: ev.button = 3; break; - default: ev.button = e_comp_wl->ptr.button; break; - } - - e_comp_object_frame_xy_unadjust(ec->frame, - wl_fixed_to_int(e_comp_wl->ptr.x), - wl_fixed_to_int(e_comp_wl->ptr.y), - &ev.canvas.x, - &ev.canvas.y); - - _e_shell_surface_mouse_down_helper(ec, &ev, EINA_FALSE, edges); - - TRACE_DS_END(); -} - -static void -_e_xdg_toplv_v6_cb_max_size_set(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6, - int32_t w, - int32_t h) -{ - /* TODO no op */ -} - -static void -_e_xdg_toplv_v6_cb_min_size_set(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6, - int32_t w, - int32_t h) -{ - /* TODO no op */ -} - -static void -_e_xdg_toplv_v6_cb_maximized_set(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6) -{ - E_Client *ec; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - if (!ec->lock_user_maximize) - { - e_client_maximize(ec, - ((e_config->maximize_policy & E_MAXIMIZE_TYPE) | E_MAXIMIZE_BOTH)); - } -} - -static void -_e_xdg_toplv_v6_cb_maximized_unset(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6) -{ - E_Client *ec; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - e_client_unmaximize(ec, E_MAXIMIZE_BOTH); - - _e_xdg_shell_surface_configure_send(res_xdg_toplv_v6, - 0, - ec->w, - ec->h); // TODO -} - -static void -_e_xdg_toplv_v6_cb_fullscreen_set(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6, - struct wl_resource *res_output) -{ - E_Client *ec; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - if (!ec->lock_user_fullscreen) - e_client_fullscreen(ec, e_config->fullscreen_policy); -} - -static void -_e_xdg_toplv_v6_cb_fullscreen_unset(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6) -{ - E_Client *ec; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - if (!ec->lock_user_fullscreen) - e_client_unfullscreen(ec); -} - -static void -_e_xdg_toplv_v6_cb_minimized_set(struct wl_client *client, - struct wl_resource *res_xdg_toplv_v6) -{ - E_Client *ec; - - ec = wl_resource_get_user_data(res_xdg_toplv_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_toplv_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - - if (!ec->lock_client_iconify) - e_client_iconify(ec); -} - -static const struct zxdg_toplevel_v6_interface _e_xdg_toplv_v6_interface = -{ - _e_xdg_toplv_v6_cb_destroy, - _e_xdg_toplv_v6_cb_parent_set, - _e_xdg_toplv_v6_cb_title_set, - _e_xdg_toplv_v6_cb_app_id_set, - _e_xdg_toplv_v6_cb_win_menu_show, - _e_xdg_toplv_v6_cb_move, - _e_xdg_toplv_v6_cb_resize, - _e_xdg_toplv_v6_cb_max_size_set, - _e_xdg_toplv_v6_cb_min_size_set, - _e_xdg_toplv_v6_cb_maximized_set, - _e_xdg_toplv_v6_cb_maximized_unset, - _e_xdg_toplv_v6_cb_fullscreen_set, - _e_xdg_toplv_v6_cb_fullscreen_unset, - _e_xdg_toplv_v6_cb_minimized_set -}; - -//////////////////////////////////////////////////////////////////////////////// -static void -_e_xdg_popup_v6_cb_res_destroy(struct wl_resource *res_xdg_popup_v6) -{ - _e_shell_surface_destroy(res_xdg_popup_v6); -} - -static void -_e_xdg_popup_v6_cb_destroy(struct wl_client *client, - struct wl_resource *res_xdg_popup_v6) -{ - wl_resource_destroy(res_xdg_popup_v6); -} - -static void -_e_xdg_popup_v6_cb_grab(struct wl_client *client, - struct wl_resource *res_xdg_popup_v6, - struct wl_resource *res_seat, - uint32_t serial) -{ - /* TODO no op */ -} - -static const struct zxdg_popup_v6_interface _e_xdg_popup_v6_interface = -{ - _e_xdg_popup_v6_cb_destroy, - _e_xdg_popup_v6_cb_grab -}; - -//////////////////////////////////////////////////////////////////////////////// -static void -_e_xdg_pos_v6_cb_res_destroy(struct wl_resource *res_xdg_pos_v6) -{ - E_Xdg_Shell *esh = NULL; - E_Xdg_Pos *epos = NULL; - - epos = wl_resource_get_user_data(res_xdg_pos_v6); - EINA_SAFETY_ON_NULL_RETURN(epos); - - esh = epos->sh; - esh->positioners = eina_list_remove(esh->positioners, epos); - - E_FREE(epos); -} - -static void -_e_xdg_pos_v6_cb_destroy(struct wl_client *client, - struct wl_resource *res_xdg_pos_v6) -{ - wl_resource_destroy(res_xdg_pos_v6); -} - -static void -_e_xdg_pos_v6_cb_size_set(struct wl_client *client, - struct wl_resource *res_xdg_pos_v6, - int32_t w, - int32_t h) -{ - /* TODO: no op */ -} - -static void -_e_xdg_pos_v6_cb_anchor_rect_set(struct wl_client *client, - struct wl_resource *res_xdg_pos_v6, - int32_t x, - int32_t y, - int32_t w, - int32_t h) -{ - /* TODO: no op */ -} - -static void -_e_xdg_pos_v6_cb_anchor_set(struct wl_client *client, - struct wl_resource *res_xdg_pos_v6, - uint32_t anchor) -{ - /* TODO: no op */ -} - -static void -_e_xdg_pos_v6_cb_gravity_set(struct wl_client *client, - struct wl_resource *res_xdg_pos_v6, - uint32_t gravity) -{ - /* TODO: no op */ -} - -static void -_e_xdg_pos_v6_cb_constraint_adjustment_set(struct wl_client *client, - struct wl_resource *res_xdg_pos_v6, - uint32_t constraint_adjustment) -{ - /* TODO: no op */ -} - -static void -_e_xdg_pos_v6_cb_offset_set(struct wl_client *client, - struct wl_resource *res_xdg_pos_v6, - int32_t x, - int32_t y) -{ - /* TODO: no op */ -} - -static const struct zxdg_positioner_v6_interface _e_xdg_pos_v6_interface = -{ - _e_xdg_pos_v6_cb_destroy, - _e_xdg_pos_v6_cb_size_set, - _e_xdg_pos_v6_cb_anchor_rect_set, - _e_xdg_pos_v6_cb_anchor_set, - _e_xdg_pos_v6_cb_gravity_set, - _e_xdg_pos_v6_cb_constraint_adjustment_set, - _e_xdg_pos_v6_cb_offset_set -}; - -//////////////////////////////////////////////////////////////////////////////// -static void -_e_xdg_surf_v6_cb_destroy(struct wl_client *client, - struct wl_resource *res_xdg_surf_v6) -{ - wl_resource_destroy(res_xdg_surf_v6); -} - -static void -_e_xdg_surf_v6_cb_toplevel_get(struct wl_client *client, - struct wl_resource *res_xdg_surf_v6, - uint32_t id) -{ - E_Client *ec; - E_Comp_Client_Data *cdata; - - ec = wl_resource_get_user_data(res_xdg_surf_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_surf_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Pixmap Set On Surface"); - return; - } - - cdata = ec->comp_data; - if (!cdata) - { - wl_resource_post_error(res_xdg_surf_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Data For Client"); - return; - } - - if (cdata->sh_v6.res_role) - { - wl_resource_post_error(res_xdg_surf_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "Client already has shell toplevel resource"); - return; - } - - cdata->sh_v6.res_role = wl_resource_create(client, - &zxdg_toplevel_v6_interface, - 1, - id); - if (!cdata->sh_v6.res_role) - { - ERR("Could not create xdg toplevel resource"); - wl_resource_post_no_memory(res_xdg_surf_v6); - return; - } - - wl_resource_set_implementation(cdata->sh_v6.res_role, - &_e_xdg_toplv_v6_interface, - ec, - _e_xdg_toplv_v6_cb_res_destroy); // TODO - - e_object_ref(E_OBJECT(ec)); - - cdata->sh_v6.role = E_COMP_WL_SH_SURF_ROLE_TOPLV; - - cdata->shell.configure_send = _e_xdg_surf_v6_configure_send; - cdata->shell.configure = _e_xdg_shell_surface_configure; - cdata->shell.ping = _e_xdg_sh_v6_ping; - cdata->shell.map = _e_xdg_shell_surface_map; - cdata->shell.unmap = _e_xdg_shell_surface_unmap; - - /* set toplevel client properties */ - ec->icccm.accepts_focus = 1; - if (!ec->internal) - ec->borderless = 1; - ec->lock_border = EINA_TRUE; - if ((!ec->internal) || (!ec->borderless)) - ec->border.changed = ec->changes.border = !ec->borderless; - if (ec->netwm.type == E_WINDOW_TYPE_UNKNOWN) - ec->netwm.type = E_WINDOW_TYPE_NORMAL; - ec->comp_data->set_win_type = EINA_TRUE; - - e_comp_wl_shell_surface_ready(ec); -} - -static void -_e_xdg_surf_v6_cb_popup_get(struct wl_client *client, - struct wl_resource *res_xdg_surf_v6, - uint32_t id, - struct wl_resource *res_xdg_surf_v6_parent, - struct wl_resource *res_xdg_pos_v6) -{ - E_Client *ec; - E_Comp_Client_Data *cdata; - - ec = wl_resource_get_user_data(res_xdg_surf_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_surf_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Pixmap Set On Surface"); - return; - } - - cdata = ec->comp_data; - if (!cdata) - { - wl_resource_post_error(res_xdg_surf_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Data For Client"); - return; - } - - if (cdata->sh_v6.res_role) - { - wl_resource_post_error(res_xdg_surf_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "Client already has shell popup resource"); - return; - } - - if (!res_xdg_surf_v6_parent) - { - wl_resource_post_error(res_xdg_surf_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "Popup requires a parent shell surface"); - return; - } - - cdata->sh_v6.res_role = wl_resource_create(client, - &zxdg_popup_v6_interface, - 1, - id); - if (!cdata->sh_v6.res_role) - { - ERR("Could not create xdg popup resource"); - wl_resource_post_no_memory(res_xdg_surf_v6); - return; - } - - wl_resource_set_implementation(cdata->sh_v6.res_role, - &_e_xdg_popup_v6_interface, - ec, - _e_xdg_popup_v6_cb_res_destroy); // TODO - - e_object_ref(E_OBJECT(ec)); - - cdata->sh_v6.role = E_COMP_WL_SH_SURF_ROLE_POPUP; - - cdata->shell.configure_send = _e_xdg_surf_v6_configure_send; - cdata->shell.configure = _e_xdg_shell_surface_configure; - cdata->shell.ping = _e_xdg_sh_v6_ping; - cdata->shell.map = _e_xdg_shell_surface_map; - cdata->shell.unmap = _e_xdg_shell_surface_unmap; - - EC_CHANGED(ec); - ec->new_client = ec->override = 1; - e_client_unignore(ec); - e_comp->new_clients++; - if (!ec->internal) - ec->borderless = !ec->internal_elm_win; - ec->lock_border = EINA_TRUE; - if (!ec->internal) - ec->border.changed = ec->changes.border = !ec->borderless; - ec->changes.icon = !!ec->icccm.class; - ec->netwm.type = E_WINDOW_TYPE_POPUP_MENU; - ec->comp_data->set_win_type = EINA_TRUE; - evas_object_layer_set(ec->frame, E_LAYER_CLIENT_POPUP); - - /* set this client as a transient for parent */ - _e_shell_surface_parent_set(ec, res_xdg_surf_v6_parent); -} - -static void -_e_xdg_surf_v6_cb_win_geom_set(struct wl_client *client, - struct wl_resource *res_xdg_surf_v6, - int32_t x, - int32_t y, - int32_t w, - int32_t h) -{ - E_Client *ec; - - ec = wl_resource_get_user_data(res_xdg_surf_v6); - if (!ec) - { - wl_resource_post_error(res_xdg_surf_v6, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Client For Shell Surface"); - return; - } - EINA_RECTANGLE_SET(&ec->comp_data->shell.window, x, y, w, h); -} - -static void -_e_xdg_surf_v6_cb_configure_ack(struct wl_client *client, - struct wl_resource *res_xdg_surf_v6, - uint32_t serial) -{ - /* TODO no op */ -} - -static const struct zxdg_surface_v6_interface _e_xdg_surf_v6_interface = -{ - _e_xdg_surf_v6_cb_destroy, - _e_xdg_surf_v6_cb_toplevel_get, - _e_xdg_surf_v6_cb_popup_get, - _e_xdg_surf_v6_cb_win_geom_set, - _e_xdg_surf_v6_cb_configure_ack -}; - -//////////////////////////////////////////////////////////////////////////////// -static void -_e_xdg_sh_v6_cb_destroy(struct wl_client *client, - struct wl_resource *res_xdg_sh_v6) -{ - wl_resource_destroy(res_xdg_sh_v6); -} - -static void -_e_xdg_sh_v6_cb_pos_create(struct wl_client *client, - struct wl_resource *res_xdg_sh_v6, - uint32_t id) -{ - E_Xdg_Shell *esh = NULL; - E_Xdg_Pos *epos = NULL; - struct wl_resource *res_xdg_pos_v6 = NULL; - - esh = eina_hash_find(xdg_sh_hash, &client); - EINA_SAFETY_ON_NULL_GOTO(esh, err); - EINA_SAFETY_ON_NULL_GOTO(esh->res, err); - EINA_SAFETY_ON_FALSE_GOTO(esh->res == res_xdg_sh_v6, err); - - epos = E_NEW(E_Xdg_Pos, 1); - EINA_SAFETY_ON_NULL_GOTO(epos, err); - - res_xdg_pos_v6 = wl_resource_create(client, - &zxdg_positioner_v6_interface, - 1, - id); - EINA_SAFETY_ON_NULL_GOTO(res_xdg_pos_v6, err); - - wl_resource_set_implementation(res_xdg_pos_v6, - &_e_xdg_pos_v6_interface, - epos, - _e_xdg_pos_v6_cb_res_destroy); - - epos->sh = esh; - epos->res = res_xdg_pos_v6; - - esh->positioners = eina_list_append(esh->positioners, epos); - - return; - -err: - if (epos) E_FREE(epos); - wl_resource_post_no_memory(res_xdg_sh_v6); -} - -static void -_e_xdg_sh_v6_cb_surf_get(struct wl_client *client, - struct wl_resource *res_xdg_sh_v6 EINA_UNUSED, - uint32_t id, - struct wl_resource *res_surf) -{ - E_Client *ec = NULL; - E_Comp_Client_Data *cdata = NULL; - - ec = wl_resource_get_user_data(res_surf); - if (!ec) - { - wl_resource_post_error(res_surf, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Pixmap Set On Surface"); - return; - } - - cdata = ec->comp_data; - if (!cdata) - { - wl_resource_post_error(res_surf, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Data For Client"); - return; - } - - if (cdata->shell.surface) - { - wl_resource_post_error(res_surf, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "Client already has XDG shell surface"); - return; - } - - cdata->shell.surface = wl_resource_create(client, - &zxdg_surface_v6_interface, - 1, - id); - if (!cdata->shell.surface) - { - ERR("Could not create xdg shell surface"); - wl_resource_post_no_memory(res_surf); - return; - } - - wl_resource_set_implementation(cdata->shell.surface, - &_e_xdg_surf_v6_interface, - ec, - _e_shell_surface_cb_destroy); - - e_object_ref(E_OBJECT(ec)); - - ec->netwm.ping = 1; -} - -static const struct zxdg_shell_v6_interface _e_xdg_sh_v6_interface = -{ - _e_xdg_sh_v6_cb_destroy, - _e_xdg_sh_v6_cb_pos_create, - _e_xdg_sh_v6_cb_surf_get, - _e_xdg_shell_cb_pong /* use v5 pong handler */ -}; - -//////////////////////////////////////////////////////////////////////////////// -static void -_e_xdg_sh_v6_cb_bind(struct wl_client *client, - void *data, - uint32_t version, - uint32_t id) -{ - E_Xdg_Shell *esh; - struct wl_resource *res_xdg_sh_v6; - - res_xdg_sh_v6 = wl_resource_create(client, - &zxdg_shell_v6_interface, - version, - id); - EINA_SAFETY_ON_NULL_GOTO(res_xdg_sh_v6, err); - - esh = E_NEW(E_Xdg_Shell, 1); - EINA_SAFETY_ON_NULL_GOTO(esh, err); - - esh->wc = client; - esh->res = res_xdg_sh_v6; - eina_hash_add(xdg_sh_hash, &client, esh); - - wl_resource_set_implementation(res_xdg_sh_v6, - &_e_xdg_sh_v6_interface, - e_comp->wl_comp_data, - _e_xdg_shell_cb_unbind); - return; - -err: - wl_client_post_no_memory(client); -} - -static void -_e_tz_surf_cb_tz_res_get(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface) -{ - struct wl_resource *res; - E_Client *ec; - uint32_t res_id; - - /* get the pixmap from this surface so we can find the client */ - if (!(ec = wl_resource_get_user_data(surface))) - { - wl_resource_post_error(surface, - WL_DISPLAY_ERROR_INVALID_OBJECT, - "No Pixmap Set On Surface"); - return; - } - - /* find the window id for this pixmap */ - res_id = e_pixmap_res_id_get(ec->pixmap); - - /* try to create a tizen_gid */ - if (!(res = wl_resource_create(client, - &tizen_resource_interface, - wl_resource_get_version(resource), - id))) - { - wl_resource_post_no_memory(resource); - return; - } - - wl_resource_set_implementation(res, - &_e_tz_res_interface, - ec, - NULL); - - tizen_resource_send_resource_id(res, res_id); -} - -static void -_e_tz_surf_cb_destroy(struct wl_client *client, struct wl_resource *resource) -{ - wl_resource_destroy(resource); -} - -static const struct tizen_surface_interface _e_tz_surf_interface = -{ - _e_tz_surf_cb_tz_res_get, - _e_tz_surf_cb_destroy -}; - -static void -_e_tz_surf_cb_bind(struct wl_client *client, void *data, uint32_t version, uint32_t id) -{ - struct wl_resource *res; - - if (!(res = wl_resource_create(client, - &tizen_surface_interface, - version, - id))) - { - ERR("Could not create tizen_surface resource: %m"); - wl_client_post_no_memory(client); + ERR("Could not create tizen_surface resource: %m"); + wl_client_post_no_memory(client); return; } @@ -2660,13 +1837,9 @@ e_comp_wl_shell_init(void) return; } - if (!wl_global_create(e_comp_wl->wl.disp, - &zxdg_shell_v6_interface, - 1, - e_comp->wl_comp_data, - _e_xdg_sh_v6_cb_bind)) + if (!e_xdg_shell_v6_init()) { - ERR("Could not create xdg_shell global: %m"); + ERR("Could not init xdg_shell_v6"); return; } diff --git a/src/bin/e_comp_wl_shell.h b/src/bin/e_comp_wl_shell.h index 35467601a3..06fc7dd9a2 100644 --- a/src/bin/e_comp_wl_shell.h +++ b/src/bin/e_comp_wl_shell.h @@ -3,8 +3,34 @@ # ifndef E_COMP_WL_SHELL_H # define E_COMP_WL_SHELL_H +typedef struct +{ + void (*configure_send)(struct wl_resource *resource, uint32_t edges, int32_t width, int32_t height); + void (*configure)(struct wl_resource *resource, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h); + void (*ping)(struct wl_resource *resource); + void (*map)(struct wl_resource *resource); + void (*unmap)(struct wl_resource *resource); +} E_Shell_Surface_Api; + EINTERN void e_comp_wl_shell_init(void); EINTERN void e_comp_wl_shell_shutdown(void); +EINTERN Eina_Bool e_shell_e_client_shell_assignable_check(E_Client *ec); +EINTERN void e_shell_e_client_shsurface_assign(E_Client *ec, struct wl_resource *shsurface, E_Shell_Surface_Api *api); +EINTERN void e_shell_e_client_shsurface_api_set(E_Client *ec, E_Shell_Surface_Api *api); +EINTERN void e_shell_e_client_toplevel_set(E_Client *ec); +EINTERN void e_shell_e_client_popup_set(E_Client *ec); +EINTERN Eina_Bool e_shell_e_client_name_title_set(E_Client *ec, const char *name, const char *title); +EINTERN Eina_Bool e_shell_e_client_app_id_set(E_Client *ec, const char *app_id); +EINTERN void e_shell_e_client_parent_set(E_Client *ec, struct wl_resource *parent_resource); +EINTERN void e_shell_e_client_map(E_Client *ec); +EINTERN void e_shell_e_client_unmap(E_Client *ec); +EINTERN Eina_Bool e_shell_e_client_interactive_move(E_Client *ec, struct wl_resource *seat); +EINTERN Eina_Bool e_shell_e_client_interactive_resize(E_Client *ec, struct wl_resource *resource, struct wl_resource *seat, uint32_t edges); +EINTERN void e_shell_e_client_pong(E_Client *ec); +EINTERN void e_shell_e_client_destroy(E_Client *ec); + + + # endif #endif diff --git a/src/bin/e_includes.h b/src/bin/e_includes.h index b62f4b32ee..7d59e074e5 100644 --- a/src/bin/e_includes.h +++ b/src/bin/e_includes.h @@ -80,3 +80,4 @@ #include "e_keyrouter.h" #include "e_gesture.h" #include "e_input.h" +#include "e_xdg_shell_v6.h" diff --git a/src/bin/e_xdg_shell_v6.c b/src/bin/e_xdg_shell_v6.c new file mode 100644 index 0000000000..7af973839c --- /dev/null +++ b/src/bin/e_xdg_shell_v6.c @@ -0,0 +1,2007 @@ +#include "e.h" +#include + +#ifdef LOG +#undef LOG +#endif +#ifdef ERR +#undef ERR +#endif + +#define LOG(f, p, e, x...) ELOGF("XDG6 ", f, p, e, ##x) +#define ERR(f, p, e, x...) ELOGF("XDG6 ", f, p, e, ##x) + +#define e_xdg_surface_role_biggest_struct E_Xdg_Toplevel + +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 +{ + E_XDG_SURFACE_ROLE_NONE, + E_XDG_SURFACE_ROLE_TOPLEVEL, + E_XDG_SURFACE_ROLE_POPUP, +}; + +struct _E_Xdg_Size +{ + int w, h; +}; + +struct _E_Xdg_Shell +{ + 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 _E_Xdg_Toplevel_State +{ + Eina_Bool maximized; + Eina_Bool fullscreen; + Eina_Bool resizing; + Eina_Bool activated; +}; + +struct _E_Xdg_Surface +{ + 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 */ + Ecore_Event_Handler *commit_handler; /* Handler raised when wl_buffer 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; +}; + +struct _E_Xdg_Toplevel +{ + 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; +}; + +struct _E_Xdg_Popup +{ + E_Xdg_Surface base; + + 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) +{ + if (!e_shell_e_client_shell_assignable_check(ec)) + { + ERR("Could not assign shell", ec->pixmap, ec); + wl_resource_post_error(ec->comp_data->surface, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Could not assign shell surface to wl_surface"); + return EINA_FALSE; + } + + if (e_pixmap_usable_get(ec->pixmap)) + { + wl_resource_post_error(ec->comp_data->surface, + ZXDG_SURFACE_V6_ERROR_UNCONFIGURED_BUFFER, + "buffer attached/committed before configure"); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static Eina_Bool +_e_client_xdg_shell_v6_assigned_check(E_Client *ec) +{ + return !!ec->comp_data->sh_v6.res_role; +} + +static void +_e_client_xdg_shell_v6_assign(E_Client *ec, + struct wl_resource *resource, + E_Comp_Wl_Sh_Surf_Role role) +{ + ec->comp_data->sh_v6.res_role = resource; + ec->comp_data->sh_v6.role = role; +} + +static void +_validate_size(struct wl_resource *resource, int32_t value) +{ + if (value <= 0) + wl_resource_post_error(resource, ZXDG_POSITIONER_V6_ERROR_INVALID_INPUT, "Invalid size passed"); +} +/* End of utility */ + +/********************************************************** + * 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); + + /* TODO apply geometry to popup */ + +} + +static void +_e_xdg_popup_parent_set(E_Xdg_Popup *popup, E_Xdg_Surface *parent) +{ + popup->parent = parent; + /* set this client as a transient for parent */ + e_shell_e_client_parent_set(popup->base.ec, parent->ec->comp_data->surface); +} + +static void +_e_xdg_popup_set(E_Xdg_Popup *popup, struct wl_resource *resource) +{ + 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); +} + +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); + } + } + + popup->committed = EINA_TRUE; + + /* TODO: Weston does update the position of popup here */ +} + +static void +_e_xdg_popup_configure_send(E_Xdg_Popup *popup) +{ + zxdg_popup_v6_send_configure(popup->resource, + popup->geometry.x, + popup->geometry.y, + popup->geometry.w, + popup->geometry.h); +} + +static void +_e_xdg_popup_cb_resource_destroy(struct wl_resource *resource) +{ + /* Nothing to do here */ +} + +static void +_e_xdg_popup_cb_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +_e_xdg_popup_cb_grab(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *res_seat, + uint32_t serial) +{ + /* TODO no op */ +} + +static const struct zxdg_popup_v6_interface _e_xdg_popup_interface = +{ + _e_xdg_popup_cb_destroy, + _e_xdg_popup_cb_grab +}; + +/* End of Xdg_Popup */ + +/********************************************************** + * 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_committed(E_Xdg_Toplevel *toplevel) +{ + E_Client *ec; + int pw, ph; + + ec = toplevel->base.ec; + if (!ec) + { + ERR("E_Xdg_Toplevel must have E_Client", NULL, NULL); + return; + } + + if (!ec->comp_data) + { + ERR("E_Client must have E_Comp_Client_Data", ec->pixmap, ec); + return; + } + + if (!e_pixmap_usable_get(ec->pixmap)) + { + ERR("E_Pixmap should be valid here", ec->pixmap, ec); + return; + } + + e_pixmap_size_get(ec->pixmap, &pw, &ph); + + if ((toplevel->next.state.maximized || toplevel->next.state.fullscreen) && + (toplevel->next.size.w != ec->comp_data->shell.window.w || + toplevel->next.size.h != ec->comp_data->shell.window.h)) + { + ERR("Xdg_surface buffer does not match the configured state\nmaximized: " + "%d fullscreen: %d expected size (%d %d) window size (%d %d)", + ec->pixmap, ec, + toplevel->next.state.maximized, + toplevel->next.state.fullscreen, + toplevel->next.size.w, toplevel->next.size.h, + ec->comp_data->shell.window.w, ec->comp_data->shell.window.h); + /* 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; + + /* Now we can adjust size of its composite object corresponding client */ +} + +static void +_e_xdg_toplevel_configure_ack(E_Xdg_Toplevel *toplevel, + E_Xdg_Surface_Configure *configure) +{ + LOG("Ack configure TOPLEVEL size (%d %d) " + "state (f %d m %d r %d a %d)", + toplevel->base.ec->pixmap, 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; +} + +static void +_e_xdg_toplevel_configure_send(E_Xdg_Toplevel *toplevel, + E_Xdg_Surface_Configure *configure) +{ + uint32_t *s; + struct wl_array states; + + 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)); + *s = ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED; + } + if (toplevel->pending.state.fullscreen) + { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN; + } + if (toplevel->pending.state.resizing) + { + s = wl_array_add(&states, sizeof(uint32_t)); + *s = ZXDG_TOPLEVEL_V6_STATE_RESIZING; + } + if (toplevel->pending.state.activated) + { + s = wl_array_add(&states, sizeof(uint32_t)); + *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->pixmap, 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); + + wl_array_release(&states); +} + +static void +_e_xdg_toplevel_configure_pending_set(E_Xdg_Toplevel *toplevel, + uint32_t edges, + int32_t width, + int32_t height) +{ + E_Client *ec, *focused; + + 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; + toplevel->pending.size.w = width; + toplevel->pending.size.h = height; + + if ((toplevel->pending.state.maximized) || + (toplevel->pending.state.fullscreen)) + { + /* 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 + */ + LOG("FORCELY STAY current size (%d %d) of E_Client, requested size " + "is (%d %d), the state (maximize %d, fullscreen %d)", + ec->pixmap, ec, ec->w, ec->h, width, height, + toplevel->pending.state.maximized, + toplevel->pending.state.fullscreen); + toplevel->pending.size.w = ec->w; + toplevel->pending.size.h = ec->h; + } + + focused = e_client_focused_get(); + toplevel->pending.state.activated = (ec == focused); + + LOG("Set pending state: edges %d size (%d %d) " + "state (f %d m %d r %d a %d)", + ec->pixmap, 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 Eina_Bool +_e_xdg_toplevel_pending_state_compare(E_Xdg_Toplevel *toplevel) +{ + E_Xdg_Surface_Configure *configure; + int pw, ph; + int cw, ch; + + struct { + E_Xdg_Toplevel_State state; + E_Xdg_Size size; + } configured; + + /* must send configure at least once */ + if (!toplevel->base.configured) + return EINA_FALSE; + + 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->pixmap, 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; + } + + 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)) + return EINA_TRUE; + + if ((toplevel->pending.size.w == 0) && + (toplevel->pending.size.h == 0)) + return EINA_TRUE; + + return EINA_FALSE; +} + +static void +_e_xdg_toplevel_cb_resource_destroy(struct wl_resource *resource) +{ + /* Nothing to do here */ +} + +static void +_e_xdg_toplevel_cb_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +_e_xdg_toplevel_cb_parent_set(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *res_parent) +{ + E_Xdg_Toplevel *toplevel, *parent; + E_Client *pc; + struct wl_resource *parent_wsurface = NULL; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + if (res_parent) + { + parent = wl_resource_get_user_data(res_parent); + if (!parent) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, 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, NULL); + wl_resource_post_error(res_parent, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Client data in wl_resource"); + return; + } + + if (!pc->comp_data) return; + + parent_wsurface = pc->comp_data->surface; + } + + /* set this client as a transient for parent */ + e_shell_e_client_parent_set(toplevel->base.ec, parent_wsurface); +} + +static void +_e_xdg_toplevel_cb_title_set(struct wl_client *client, + struct wl_resource *resource, + const char *title) +{ + E_Xdg_Toplevel *toplevel; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + e_shell_e_client_name_title_set(toplevel->base.ec, title, title); +} + +static void +_e_xdg_toplevel_cb_app_id_set(struct wl_client *client, + struct wl_resource *resource, + const char *app_id) +{ + E_Xdg_Toplevel *toplevel; + E_Client *ec; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + ec = toplevel->base.ec; + if (!ec) + { + ERR("Toplevel must have E_Client", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Client data in wl_resource"); + return; + } + + /* 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_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) +{ + /* TODO no op */ +} + +static void +_e_xdg_toplevel_cb_move(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *res_seat, + uint32_t serial) +{ + E_Xdg_Toplevel *toplevel; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + if (!e_shell_e_client_interactive_move(toplevel->base.ec, res_seat)) + { + ERR("Failed to move this Toplevel", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Can't move this surface"); + return; + } +} + +static void +_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_Xdg_Toplevel *toplevel; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + if (!e_shell_e_client_interactive_resize(toplevel->base.ec, resource, res_seat, edges)) + { + ERR("Failed to resize this Toplevel", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "Can't resize this surface"); + return; + } +} + +static void +_e_xdg_toplevel_cb_max_size_set(struct wl_client *client, + struct wl_resource *resource, + int32_t w, + int32_t h) +{ + E_Xdg_Toplevel *toplevel; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No data in wl_resource"); + return; + } + + toplevel->next.max_size.w = w; + toplevel->next.max_size.h = h; +} + +static void +_e_xdg_toplevel_cb_min_size_set(struct wl_client *client, + struct wl_resource *resource, + int32_t w, + int32_t h) +{ + E_Xdg_Toplevel *toplevel; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No data in wl_resource"); + return; + } + + toplevel->next.min_size.w = w; + toplevel->next.min_size.h = h; +} + +static void +_e_xdg_toplevel_cb_maximized_set(struct wl_client *client, struct wl_resource *resource) +{ + E_Xdg_Toplevel *toplevel; + E_Client *ec; + E_Maximize max; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + ec = toplevel->base.ec; + if (!ec) + { + ERR("Toplevel must have E_Client", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Client data in wl_resource"); + return; + } + + if (!ec->lock_user_maximize) + { + max = (e_config->maximize_policy & E_MAXIMIZE_TYPE) | E_MAXIMIZE_BOTH; + e_client_maximize(ec, max); + } +} + +static void +_e_xdg_toplevel_cb_maximized_unset(struct wl_client *client, struct wl_resource *resource) +{ + E_Xdg_Toplevel *toplevel; + E_Client *ec; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + ec = toplevel->base.ec; + if (!ec) + { + ERR("Toplevel must have E_Client", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Client data in wl_resource"); + return; + } + + /* it's doubtful */ + e_client_unmaximize(ec, E_MAXIMIZE_BOTH); +} + +static void +_e_xdg_toplevel_cb_fullscreen_set(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *res_output) +{ + E_Xdg_Toplevel *toplevel; + E_Client *ec; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + ec = toplevel->base.ec; + if (!ec) + { + ERR("Toplevel must have E_Client", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Client data in wl_resource"); + return; + } + + if (!ec->lock_user_fullscreen) + e_client_fullscreen(ec, e_config->fullscreen_policy); +} + +static void +_e_xdg_toplevel_cb_fullscreen_unset(struct wl_client *client, struct wl_resource *resource) +{ + E_Xdg_Toplevel *toplevel; + E_Client *ec; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + ec = toplevel->base.ec; + if (!ec) + { + ERR("Toplevel must have E_Client", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Client data in wl_resource"); + return; + } + + if (!ec->lock_user_fullscreen) + e_client_unfullscreen(ec); +} + +static void +_e_xdg_toplevel_cb_minimized_set(struct wl_client *client, struct wl_resource *resource) +{ + E_Xdg_Toplevel *toplevel; + E_Client *ec; + + toplevel = wl_resource_get_user_data(resource); + if (!toplevel) + { + ERR("No E_Xdg_Toplevel data in wl_resource", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Toplevel data in wl_resource"); + return; + } + + ec = toplevel->base.ec; + if (!ec) + { + ERR("Toplevel must have E_Client", NULL, NULL); + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Client data in wl_resource"); + return; + } + + if (!ec->lock_client_iconify) + e_client_iconify(ec); +} + +static const struct zxdg_toplevel_v6_interface _e_xdg_toplevel_interface = +{ + _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 +}; + +/* End of Xdg_toplevel */ + +/********************************************************** + * Implementation for Xdg_Positioner + **********************************************************/ +static Eina_Rectangle +_e_xdg_positioner_geometry_get(E_Xdg_Positioner *p) +{ + 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 (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; + + /* TODO: According to weston, add compositor policy configuration and the + * code here + */ + + return geometry; +} + +static Eina_Bool +_e_xdg_positioner_validation_check(E_Xdg_Positioner *p) +{ + return ((p->size.w != 0) && (p->anchor_rect.w != 0)); +} + +static void +_e_xdg_positioner_cb_resource_destroy(struct wl_resource *resource) +{ + E_Xdg_Positioner *p; + + p = wl_resource_get_user_data(resource); + EINA_SAFETY_ON_NULL_RETURN(p); + + if (!p->shell) + goto finish; + + p->shell->positioners = eina_list_remove(p->shell->positioners, p); + +finish: + free(p); +} + +static void +_e_xdg_positioner_cb_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +_e_xdg_positioner_cb_size_set(struct wl_client *client, + struct wl_resource *resource, + int32_t w, int32_t h) +{ + E_Xdg_Positioner *p; + + _validate_size(resource, w); + _validate_size(resource, h); + + p = wl_resource_get_user_data(resource); + p->size.w = w; + p->size.h = h; +} + +static void +_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_Positioner *p; + + _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_positioner_cb_anchor_set(struct wl_client *client, + struct wl_resource *resource, + enum zxdg_positioner_v6_anchor anchor) +{ + E_Xdg_Positioner *p; + + 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 + { + p = wl_resource_get_user_data(resource); + p->anchor = anchor; + } +} + +static void +_e_xdg_positioner_cb_gravity_set(struct wl_client *client, + struct wl_resource *resource, + enum zxdg_positioner_v6_gravity gravity) +{ + E_Xdg_Positioner *p; + + 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 + { + p = wl_resource_get_user_data(resource); + p->gravity = gravity; + } +} + +static void +_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_Positioner *p; + + p = wl_resource_get_user_data(resource); + p->constraint_adjustment = constraint_adjustment; +} + +static void +_e_xdg_positioner_cb_offset_set(struct wl_client *client, + struct wl_resource *resource, + int32_t x, int32_t y) +{ + E_Xdg_Positioner *p; + + p = wl_resource_get_user_data(resource); + p->offset.x = x; + p->offset.y = y; +} + +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 */ + +/********************************************************** + * 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; + + exsurf = data; + + EINA_SAFETY_ON_NULL_GOTO(exsurf, end); + EINA_SAFETY_ON_NULL_GOTO(exsurf->ec, end); + EINA_SAFETY_ON_NULL_GOTO(exsurf->ec->comp_data, 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, NULL); + goto end; + } + + exsurf->configure_list = eina_list_append(exsurf->configure_list, configure); + 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, NULL); + break; + case E_XDG_SURFACE_ROLE_POPUP: + _e_xdg_popup_configure_send((E_Xdg_Popup *)exsurf); + break; + case E_XDG_SURFACE_ROLE_TOPLEVEL: + _e_xdg_toplevel_configure_send((E_Xdg_Toplevel *)exsurf, configure); + break; + } + + zxdg_surface_v6_send_configure(exsurf->resource, configure->serial); + + LOG("Send configure: %s serial %d", exsurf->ec->pixmap, exsurf->ec, + _e_xdg_surface_util_role_string_get(exsurf), configure->serial); + +end: + exsurf->configure_idle = NULL; + return ECORE_CALLBACK_DONE; +} + +static void +_e_xdg_surface_configure_send(struct wl_resource *resource, + uint32_t edges, + int32_t width, + int32_t height) +{ + 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, NULL); + return; + } + + LOG("Scheduling task to send configure %s edges %d w %d h %d", + exsurf->ex->pixmap, 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->pixmap, 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->pixmap, exsurf->ec); + } + break; + case E_XDG_SURFACE_ROLE_POPUP: + break; + } + + if (exsurf->configure_idle) + { + if (!pending_same) + return; + + LOG("\tRemove configure idler", exsurf->ec->pixmap, 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->pixmap, exsurf->ec, exsurf->configure_idle); + } +} + +static void +_e_xdg_surface_configure(struct wl_resource *resource, + Evas_Coord x, Evas_Coord y, + Evas_Coord w, Evas_Coord h) +{ + 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, NULL); + return; + } + + if ((exsurf->configured_geometry.x == x) && + (exsurf->configured_geometry.y == y) && + (exsurf->configured_geometry.w == w) && + (exsurf->configured_geometry.h == h)) + { + LOG("Configure (SKIP) Trying to resize it the same size " + "with previous %s (%d %d %d %d)", + exsurf->ec->pixmap, exsurf->ec, + _e_xdg_surface_util_role_string_get(exsurf), + x, y, w, h); + + return; + } + + EINA_RECTANGLE_SET(&exsurf->configured_geometry, x, y, w, h); + + LOG("Configure %s geometry (%d %d %d %d)", + exsurf->ec->pixmap, exsurf->ec, + _e_xdg_surface_util_role_string_get(exsurf), x, y, w, h); + + e_client_util_move_resize_without_frame(exsurf->ec, x, y, w, h); +} + +static void +_e_xdg_surface_ping(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, NULL); + return; + } + + if (e_object_is_del(E_OBJECT(exsurf->ec))) + return; + + _e_xdg_shell_ping(exsurf->shell); +} + +static void +_e_xdg_surface_map(struct wl_resource *resource) +{ + E_Xdg_Surface *exsurf; + + exsurf = wl_resource_get_user_data(resource); + if (!exsurf) + { + ERR("No E_Xdg_Surface in wl_resource", NULL, NULL); + return; + } + + e_shell_e_client_map(exsurf->ec); +} + +static void +_e_xdg_surface_unmap(struct wl_resource *resource) +{ + E_Xdg_Surface *exsurf; + + exsurf = wl_resource_get_user_data(resource); + if (!exsurf) + { + ERR("No E_Xdg_Surface in wl_resource", NULL, NULL); + return; + } + + e_shell_e_client_unmap(exsurf->ec); +} + +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; + } + + exsurf->role = role; + + e_shell_e_client_shsurface_api_set(exsurf->ec, &api); + + switch (role) + { + case E_XDG_SURFACE_ROLE_NONE: + default: + ERR("Cannot reach here", exsurf->ec->pixmap, 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; + } + + return EINA_TRUE; +} + +static void +_e_xdg_surface_cb_destroy(struct wl_client *client, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +_e_xdg_surface_cb_toplevel_get(struct wl_client *client, struct wl_resource *resource, uint32_t id) +{ + E_Xdg_Surface *exsurf; + struct wl_resource *toplevel_resource; + + 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; + } + + toplevel_resource = wl_resource_create(client, &zxdg_toplevel_v6_interface, 1, id); + if (!toplevel_resource) + { + ERR("Could not create xdg toplevel resource", NULL, 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 (!_e_xdg_surface_role_assign(exsurf, toplevel_resource, E_XDG_SURFACE_ROLE_TOPLEVEL)) + { + ERR("Failed to assign TOPLEVEL role", exsurf->ec->pixmap, exsurf->ec); + wl_resource_destroy(toplevel_resource); + return; + } +} + +static void +_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) +{ + struct wl_resource *popup_resource; + E_Xdg_Surface *exsurf, *parent; + E_Xdg_Positioner *p; + + 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) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Popup data in wl_resource"); + return; + } + + popup_resource = wl_resource_create(client, &zxdg_popup_v6_interface, 1, id); + if (!popup_resource) + { + ERR("Could not create xdg popup resource", NULL, NULL); + wl_resource_post_no_memory(resource); + } + + 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->pixmap, 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); +} + +static void +_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_Surface *exsurf; + + 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->pixmap, 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) + { + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No E_Xdg_Surface data in wl_surface"); + return; + } + + LOG("Ack configure", exsurf->ec->pixmap, exsurf->ec); + + 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; + } + + 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("Ack configure %s first %d serial %d found %d", + exsurf->ec->pixmap, 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->pixmap, 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 Eina_Bool +_e_xdg_surface_cb_commit(void *data, int type, void *event) +{ + E_Xdg_Surface *exsurf; + E_Event_Client *ev; + + exsurf = (E_Xdg_Surface *)data; + ev = (E_Event_Client *)event; + + if (exsurf->ec != ev->ec) + goto end; + + if (!exsurf->wait_next_commit) + goto end; + + LOG("Wl_Surface Commit, Update Xdg_Surface state %s", + exsurf->ec->pixmap, 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; + EINA_RECTANGLE_SET(&exsurf->ec->comp_data->shell.window, + exsurf->window_geometry.x, + exsurf->window_geometry.y, + exsurf->window_geometry.w, + exsurf->window_geometry.h); + } + + 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; + } + +end: + return ECORE_CALLBACK_PASS_ON; +} + +static void +_e_xdg_surface_destroy(E_Xdg_Surface *exsurf) +{ + _e_xdg_shell_surface_remove(exsurf->shell, exsurf); + + if (exsurf->configure_list) + eina_list_free(exsurf->configure_list); + if (exsurf->configure_idle) + ecore_idle_enterer_del(exsurf->configure_idle); + if (exsurf->commit_handler) + ecore_event_handler_del(exsurf->commit_handler); + + free(exsurf); +} + +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, NULL); + return; + + } + + LOG("Destroy resource of Xdg_Surface %s", + exsurf->ec->pixmap, exsurf->ec, + _e_xdg_surface_util_role_string_get(exsurf)); + + e_shell_e_client_destroy(exsurf->ec); + _e_xdg_surface_destroy(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 = wl_resource_get_user_data(wsurface); + if (!ec) + { + ERR("No E_Client data in wl_resource", NULL, NULL); + wl_resource_post_error(wsurface, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "No data in wl_resource"); + return NULL; + } + + LOG("Create Xdg_Surface", ec->pixmap, ec); + + if (!_e_client_shsurface_assignable_check(ec)) + { + ERR("Cannot get xdg_surface with this wl_surface", ec->pixmap, ec); + return NULL; + } + + exsurf = (E_Xdg_Surface *)calloc(1, sizeof(e_xdg_surface_role_biggest_struct)); + if (!exsurf) + { + wl_client_post_no_memory(shell->wclient); + return NULL; + } + + 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->pixmap, ec); + wl_client_post_no_memory(shell->wclient); + free(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_handler = + ecore_event_handler_add(E_EVENT_CLIENT_BUFFER_CHANGE, + _e_xdg_surface_cb_commit, + exsurf); + + _e_xdg_shell_surface_add(shell, exsurf); + + 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); + + if (shell->ping_serial != 0) + return; + + 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, 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, 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, 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, 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; + + LOG("Pong", NULL, NULL); + + shell = wl_resource_get_user_data(resource); + if (!shell) + { + ERR("No E_Xdg_Shell data in wl_resource", NULL, 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, NULL); + + shell = wl_resource_get_user_data(resource); + if (!shell) + { + ERR("No E_Xdg_Shell in wl_resource", NULL, 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, 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, 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, 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, NULL); + return EINA_FALSE; + } + + return EINA_TRUE; +} + +EINTERN void +e_xdg_shell_v6_shutdown(void) +{ + E_FREE_FUNC(global_resource, wl_global_destroy); +} +/* End of Xdg_shell */ diff --git a/src/bin/e_xdg_shell_v6.h b/src/bin/e_xdg_shell_v6.h new file mode 100644 index 0000000000..c77b23b7a3 --- /dev/null +++ b/src/bin/e_xdg_shell_v6.h @@ -0,0 +1,9 @@ +#ifdef E_TYPEDEFS +#else +# ifndef E_XDG_SHELL_V6_H +# define E_XDG_SHELL_V6_H + +EINTERN Eina_Bool e_xdg_shell_v6_init(void); + +# endif +#endif -- 2.34.1