diff --git a/src/bin/Makefile.mk b/src/bin/Makefile.mk index e214a7d44..667a644b7 100644 --- a/src/bin/Makefile.mk +++ b/src/bin/Makefile.mk @@ -443,11 +443,15 @@ src/bin/generated/session-recovery-server-protocol.h \ src/bin/generated/www-protocol.c \ src/bin/generated/www-server-protocol.h \ src/bin/generated/screenshooter-protocol.c \ -src/bin/generated/screenshooter-server-protocol.h +src/bin/generated/screenshooter-server-protocol.h \ +src/bin/generated/xdg-foreign-unstable-v1-protocol.c \ +src/bin/generated/xdg-foreign-unstable-v1-server-protocol.h src/bin/e_comp_wl_extensions.c: \ src/bin/generated/screenshooter-server-protocol.h \ - src/bin/generated/session-recovery-server-protocol.h + src/bin/generated/session-recovery-server-protocol.h \ + src/bin/generated/xdg-foreign-unstable-v1-protocol.c \ + src/bin/generated/xdg-foreign-unstable-v1-server-protocol.h src/bin/e_comp_wl.c: \ src/bin/generated/www-server-protocol.h diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h index 48ff97ad6..8d0ac5a90 100644 --- a/src/bin/e_comp_wl.h +++ b/src/bin/e_comp_wl.h @@ -110,6 +110,17 @@ typedef struct E_Comp_Wl_Extension_Data { struct wl_global *global; } www; + /* begin xdg-foreign */ + struct + { + struct wl_global *global; + Eina_Hash *surfaces; + } zxdg_exporter_v1; + struct + { + struct wl_global *global; + } zxdg_importer_v1; + /* end xdg-foreign */ } E_Comp_Wl_Extension_Data; struct _E_Comp_Wl_Data diff --git a/src/bin/e_comp_wl_extensions.c b/src/bin/e_comp_wl_extensions.c index ea9833df6..517579b27 100644 --- a/src/bin/e_comp_wl_extensions.c +++ b/src/bin/e_comp_wl_extensions.c @@ -6,6 +6,26 @@ #include "screenshooter-server-protocol.h" #include "session-recovery-server-protocol.h" #include "www-server-protocol.h" +#include "xdg-foreign-unstable-v1-server-protocol.h" + +/* mutter uses 32, seems reasonable */ +#define HANDLE_LEN 32 + +typedef struct Exported +{ + E_Client *ec; + struct wl_resource *res; + char handle[HANDLE_LEN + 1]; + Eina_List *imported; +} Exported; + +typedef struct Imported +{ + /* child */ + E_Client *ec; + struct wl_resource *res; + Exported *ex; +} Imported; static void _e_comp_wl_extensions_client_move_begin(void *d EINA_UNUSED, E_Client *ec) @@ -207,6 +227,195 @@ _e_comp_wl_www_cb_create(struct wl_client *client, struct wl_resource *resource, e_object_ref(E_OBJECT(ec)); } +/////////////////////////////////////////////////////// + +static void +_e_comp_wl_zxdg_exported_v1_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void _imported_v1_del(Imported *im); +static void _exported_del(void *data, Evas *e, Evas_Object *obj, void *event_info); + +static void +_exported_v1_del(Exported *ex) +{ + while (ex->imported) + { + Imported *im = eina_list_data_get(ex->imported); + + zxdg_imported_v1_send_destroyed(im->res); + _imported_v1_del(im); + } + evas_object_event_callback_del(ex->ec->frame, EVAS_CALLBACK_DEL, _exported_del); + wl_resource_set_user_data(ex->res, NULL); + eina_hash_del_by_key(e_comp_wl->extensions->zxdg_exporter_v1.surfaces, ex->handle); + free(ex); +} + +static void +_e_zxdg_exported_v1_del(struct wl_resource *resource) +{ + Exported *ex = wl_resource_get_user_data(resource); + + if (ex) _exported_v1_del(ex); +} + +static void +_exported_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + _exported_v1_del(data); +} + +static void +_e_comp_wl_zxdg_exporter_v1_exporter_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static const struct zxdg_exported_v1_interface _e_zxdg_exported_v1_interface = +{ + _e_comp_wl_zxdg_exported_v1_destroy, +}; + +static void +_e_comp_wl_zxdg_exporter_v1_export(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface) +{ + E_Client *ec = wl_resource_get_user_data(surface); + Exported *ex; + + if ((!ec) || (!ec->comp_data->is_xdg_surface) || ec->comp_data->cursor) + { + wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid role for exported surface"); + return; + } + + ex = E_NEW(Exported, 1); + ex->ec = ec; + ex->res = wl_resource_create(client, &zxdg_exported_v1_interface, wl_resource_get_version(resource), id); + wl_resource_set_implementation(ex->res, &_e_zxdg_exported_v1_interface, ex, _e_zxdg_exported_v1_del); + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_DEL, _exported_del, ex); + + do + { + int n; + + for (n = 0; n < HANDLE_LEN; n++) + { + /* only printable ascii */ + ex->handle[n] = (rand() % (127 - 32)) + 32; + } + } while (eina_hash_find(e_comp_wl->extensions->zxdg_exporter_v1.surfaces, ex->handle)); + eina_hash_add(e_comp_wl->extensions->zxdg_exporter_v1.surfaces, ex->handle, ex); + + zxdg_exported_v1_send_handle(ex->res, ex->handle); +} + + +static void +_e_comp_wl_zxdg_imported_v1_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void _imported_del(void *data, Evas *e, Evas_Object *obj, void *event_info); + +static void +_imported_v1_del(Imported *im) +{ + im->ex->imported = eina_list_remove(im->ex->imported, im); + if (im->ec) + { + evas_object_event_callback_del(im->ec->frame, EVAS_CALLBACK_DEL, _imported_del); + e_client_parent_set(im->ec, NULL); + } + if (im->res) wl_resource_set_user_data(im->res, NULL); + free(im); +} + +static void +_e_zxdg_imported_v1_del(struct wl_resource *resource) +{ + Imported *im = wl_resource_get_user_data(resource); + + if (im) _imported_v1_del(im); +} + +static void +_imported_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED) +{ + Imported *im = data; + + im->ec = NULL; +} + +static void +_e_comp_wl_zxdg_importer_v1_importer_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource) +{ + wl_resource_destroy(resource); +} + +static void +_e_comp_wl_zxdg_imported_v1_set_parent_of(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *surface_resource) +{ + Imported *im = wl_resource_get_user_data(resource); + E_Client *ec = NULL; + + if (surface_resource) ec = wl_resource_get_user_data(surface_resource); + + if (ec && ((ec->netwm.type != E_WINDOW_TYPE_NORMAL) || (!ec->comp_data->is_xdg_surface))) + { + wl_resource_post_error(im->res, WL_DISPLAY_ERROR_INVALID_OBJECT, + "xdg_imported.set_parent_of called with invalid surface"); + return; + } + + if (im->ec) + evas_object_event_callback_del(im->ec->frame, EVAS_CALLBACK_DEL, _imported_del); + + im->ec = ec; + + if (ec) + { + evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_DEL, _imported_del, im); + e_client_parent_set(ec, im->ex->ec); + ec->parent->modal = ec; + ec->parent->lock_close = 1; + } +} + +static const struct zxdg_imported_v1_interface _e_zxdg_imported_v1_interface = +{ + _e_comp_wl_zxdg_imported_v1_destroy, + _e_comp_wl_zxdg_imported_v1_set_parent_of, +}; + +static void +_e_comp_wl_zxdg_importer_v1_import(struct wl_client *client, struct wl_resource *resource, uint32_t id, const char *handle) +{ + Imported *im; + Exported *ex; + + im = E_NEW(Imported, 1); + im->res = wl_resource_create(client, &zxdg_imported_v1_interface, wl_resource_get_version(resource), id); + wl_resource_set_implementation(im->res, &_e_zxdg_imported_v1_interface, NULL, _e_zxdg_imported_v1_del); + + ex = eina_hash_find(e_comp_wl->extensions->zxdg_exporter_v1.surfaces, handle); + if ((!ex) || (!ex->ec->netwm.type)) + { + zxdg_imported_v1_send_destroyed(im->res); + free(im); + return; + } + + im->ex = ex; + wl_resource_set_user_data(im->res, im); + ex->imported = eina_list_append(ex->imported, im); +} + +///////////////////////////////////////////////////////// + static const struct zwp_e_session_recovery_interface _e_session_recovery_interface = { _e_comp_wl_session_recovery_get_uuid, @@ -224,6 +433,18 @@ static const struct www_interface _e_www_interface = _e_comp_wl_www_cb_create }; +static const struct zxdg_exporter_v1_interface _e_zxdg_exporter_v1_interface = +{ + _e_comp_wl_zxdg_exporter_v1_exporter_destroy, + _e_comp_wl_zxdg_exporter_v1_export, +}; + +static const struct zxdg_importer_v1_interface _e_zxdg_importer_v1_interface = +{ + _e_comp_wl_zxdg_importer_v1_importer_destroy, + _e_comp_wl_zxdg_importer_v1_import, +}; + #define GLOBAL_BIND_CB(NAME, IFACE, ...) \ static void \ @@ -244,6 +465,8 @@ _e_comp_wl_##NAME##_cb_bind(struct wl_client *client, void *data EINA_UNUSED, ui GLOBAL_BIND_CB(session_recovery, zwp_e_session_recovery_interface) GLOBAL_BIND_CB(screenshooter, zwp_screenshooter_interface) GLOBAL_BIND_CB(www, www_interface) +GLOBAL_BIND_CB(zxdg_exporter_v1, zxdg_exporter_v1_interface) +GLOBAL_BIND_CB(zxdg_importer_v1, zxdg_importer_v1_interface) #define GLOBAL_CREATE_OR_RETURN(NAME, IFACE, VERSION) \ @@ -285,6 +508,9 @@ e_comp_wl_extensions_init(void) GLOBAL_CREATE_OR_RETURN(session_recovery, zwp_e_session_recovery_interface, 1); GLOBAL_CREATE_OR_RETURN(screenshooter, zwp_screenshooter_interface, 1); GLOBAL_CREATE_OR_RETURN(www, www_interface, 1); + GLOBAL_CREATE_OR_RETURN(zxdg_exporter_v1, zxdg_exporter_v1_interface, 1); + e_comp_wl->extensions->zxdg_exporter_v1.surfaces = eina_hash_string_superfast_new(NULL); + GLOBAL_CREATE_OR_RETURN(zxdg_importer_v1, zxdg_importer_v1_interface, 1); ecore_event_handler_add(ECORE_WL2_EVENT_SYNC_DONE, _dmabuf_add, NULL); diff --git a/src/protocol/xdg-foreign-unstable-v1.xml b/src/protocol/xdg-foreign-unstable-v1.xml new file mode 100644 index 000000000..062b09041 --- /dev/null +++ b/src/protocol/xdg-foreign-unstable-v1.xml @@ -0,0 +1,182 @@ + + + + + Copyright © 2015-2016 Red Hat Inc. + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + This protocol specifies a way for making it possible to reference a surface + of a different client. With such a reference, a client can, by using the + interfaces provided by this protocol, manipulate the relationship between + its own surfaces and the surface of some other client. For example, stack + some of its own surface above the other clients surface. + + In order for a client A to get a reference of a surface of client B, client + B must first export its surface using xdg_exporter.export. Upon doing this, + client B will receive a handle (a unique string) that it may share with + client A in some way (for example D-Bus). After client A has received the + handle from client B, it may use xdg_importer.import to create a reference + to the surface client B just exported. See the corresponding requests for + details. + + A possible use case for this is out-of-process dialogs. For example when a + sandboxed client without file system access needs the user to select a file + on the file system, given sandbox environment support, it can export its + surface, passing the exported surface handle to an unsandboxed process that + can show a file browser dialog and stack it above the sandboxed client's + surface. + + Warning! The protocol described in this file is experimental and backward + incompatible changes may be made. Backward compatible changes may be added + together with the corresponding interface version bump. Backward + incompatible changes are done by bumping the version number in the protocol + and interface names and resetting the interface version. Once the protocol + is to be declared stable, the 'z' prefix and the version number in the + protocol and interface names are removed and the interface version number is + reset. + + + + + A global interface used for exporting surfaces that can later be imported + using xdg_importer. + + + + + Notify the compositor that the xdg_exporter object will no longer be + used. + + + + + + The export request exports the passed surface so that it can later be + imported via xdg_importer. When called, a new xdg_exported object will + be created and xdg_exported.handle will be sent immediately. See the + corresponding interface and event for details. + + A surface may be exported multiple times, and each exported handle may + be used to create a xdg_imported multiple times. Only xdg_surface + surfaces may be exported. + + + + + + + + + A global interface used for importing surfaces exported by xdg_exporter. + With this interface, a client can create a reference to a surface of + another client. + + + + + Notify the compositor that the xdg_importer object will no longer be + used. + + + + + + The import request imports a surface from any client given a handle + retrieved by exporting said surface using xdg_exporter.export. When + called, a new xdg_imported object will be created. This new object + represents the imported surface, and the importing client can + manipulate its relationship using it. See xdg_imported for details. + + + + + + + + + A xdg_exported object represents an exported reference to a surface. The + exported surface may be referenced as long as the xdg_exported object not + destroyed. Destroying the xdg_exported invalidates any relationship the + importer may have established using xdg_imported. + + + + + Revoke the previously exported surface. This invalidates any + relationship the importer may have set up using the xdg_imported created + given the handle sent via xdg_exported.handle. + + + + + + The handle event contains the unique handle of this exported surface + reference. It may be shared with any client, which then can use it to + import the surface by calling xdg_importer.import. A handle may be + used to import the surface multiple times. + + + + + + + + A xdg_imported object represents an imported reference to surface exported + by some client. A client can use this interface to manipulate + relationships between its own surfaces and the imported surface. + + + + + Notify the compositor that it will no longer use the xdg_imported + object. Any relationship that may have been set up will at this point + be invalidated. + + + + + + Set the imported surface as the parent of some surface of the client. + The passed surface must be a toplevel xdg_surface. Calling this function + sets up a surface to surface relation with the same stacking and positioning + semantics as xdg_surface.set_parent. + + + + + + + The imported surface handle has been destroyed and any relationship set + up has been invalidated. This may happen for various reasons, for + example if the exported surface or the exported surface handle has been + destroyed, if the handle used for importing was invalid. + + + + +