upgrade teamwork module to use teamwork v2: teamwork++

use display protocol and add wayland support
This commit is contained in:
Mike Blumenkrantz 2016-05-19 14:09:18 -04:00
parent 107872af91
commit 361bcd9bcd
8 changed files with 638 additions and 163 deletions

View File

@ -20,6 +20,18 @@ src/modules/teamwork/e_mod_tw.c \
src/modules/teamwork/sha1.c \
src/modules/teamwork/sha1.h
if HAVE_WAYLAND
src_modules_teamwork_module_la_SOURCES += \
src/modules/teamwork/wl.c \
src/modules/teamwork/wl_teamwork.c \
src/modules/teamwork/wl_teamwork.h
endif
if ! HAVE_WAYLAND_ONLY
src_modules_teamwork_module_la_SOURCES += \
src/modules/teamwork/x11.c
endif
PHONIES += teamwork install-teamwork
teamwork: $(teamworkpkg_LTLIBRARIES) $(teamwork_DATA)
install-teamwork: install-teamworkDATA install-teamworkpkgLTLIBRARIES

View File

@ -1,10 +1,6 @@
#ifndef E_MOD_MAIN_H
#define E_MOD_MAIN_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "e.h"
/**
@ -57,9 +53,35 @@ EINTERN Eina_Bool tw_hide(void *d EINA_UNUSED);
EINTERN void tw_popup_opacity_set(void);
EINTERN void tw_uri_show(const char *uri);
EINTERN void tw_link_detect(E_Client *ec, const char *uri);
EINTERN void tw_link_show(E_Client *ec, const char *uri, int x, int y);
EINTERN void tw_link_hide(E_Client *ec, const char *uri);
EINTERN void tw_link_open(E_Client *ec, const char *uri);
typedef void (*Teamwork_Signal_Cb)(E_Client *, const char *);
typedef void (*Teamwork_Signal_Progress_Cb)(E_Client *, const char *, uint32_t);
extern Teamwork_Signal_Cb tw_signal_link_complete[E_PIXMAP_TYPE_NONE];
extern Teamwork_Signal_Cb tw_signal_link_invalid[E_PIXMAP_TYPE_NONE];
extern Teamwork_Signal_Progress_Cb tw_signal_link_progress[E_PIXMAP_TYPE_NONE];
extern Teamwork_Signal_Cb tw_signal_link_downloading[E_PIXMAP_TYPE_NONE];
EINTERN E_Config_Dialog *e_int_config_teamwork_module(Evas_Object *parent, const char *params EINA_UNUSED);
E_API int e_modapi_shutdown(E_Module *m EINA_UNUSED);
#ifdef HAVE_WAYLAND
EINTERN Eina_Bool wl_tw_init(void);
EINTERN void wl_tw_shutdown(void);
#endif
#ifndef HAVE_WAYLAND_ONLY
EINTERN Eina_Bool x11_tw_init(void);
EINTERN void x11_tw_shutdown(void);
#endif
#define E_TW_VERSION 2
#undef DBG
#undef INF
#undef WRN

View File

@ -29,6 +29,7 @@ typedef struct Media
unsigned long long timestamp;
unsigned int tries;
Ecore_Thread *video_thread;
Eina_List *clients;
Eina_Stringshare *tmpfile;
Eina_Bool video;
Eina_Bool dummy : 1;
@ -52,12 +53,10 @@ static Media_Cache_List *tw_cache_list[2] = {NULL};
static Evas_Point last_coords = {0, 0};
static uint64_t tw_win = 0;
static E_Client *tw_win;
static Ecore_Timer *tw_hide_timer = NULL;
static Eldbus_Service_Interface *tw_dbus_iface = NULL;
static Eina_Stringshare *tw_tmpfile = NULL;
static int tw_tmpfd = -1;
static Ecore_Thread *tw_tmpthread = NULL;
@ -71,23 +70,6 @@ typedef enum
TEAMWORK_LINK_TYPE_REMOTE
} Teamwork_Link_Type;
typedef enum
{
TEAMWORK_SIGNAL_LINK_DOWNLOADING,
TEAMWORK_SIGNAL_LINK_PROGRESS,
TEAMWORK_SIGNAL_LINK_COMPLETE,
TEAMWORK_SIGNAL_LINK_INVALID,
} Teamwork_Signal;
static const Eldbus_Signal tw_signals[] =
{
[TEAMWORK_SIGNAL_LINK_DOWNLOADING] = {"LinkDownloading", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0},
[TEAMWORK_SIGNAL_LINK_PROGRESS] = {"LinkProgress", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"d", "Percent Completion"}), 0},
[TEAMWORK_SIGNAL_LINK_COMPLETE] = {"LinkComplete", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0},
[TEAMWORK_SIGNAL_LINK_INVALID] = {"LinkInvalid", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), 0},
{NULL, NULL, 0}
};
static void tw_show(Media *i);
static void tw_show_local_file(const char *uri);
static void tw_show_local_dir(const char *uri);
@ -99,35 +81,85 @@ static void tw_media_ping(const char *url, unsigned long long timestamp, Eina_Bo
static Eina_Binbuf *tw_media_get(const char *url, unsigned long long timestamp, Eina_Bool *video);
static Eina_Bool tw_idler_start(void);
EINTERN Teamwork_Signal_Cb tw_signal_link_complete[E_PIXMAP_TYPE_NONE];
EINTERN Teamwork_Signal_Cb tw_signal_link_invalid[E_PIXMAP_TYPE_NONE];
EINTERN Teamwork_Signal_Progress_Cb tw_signal_link_progress[E_PIXMAP_TYPE_NONE];
EINTERN Teamwork_Signal_Cb tw_signal_link_downloading[E_PIXMAP_TYPE_NONE];
static void
dbus_signal_link_complete(Media *i)
media_client_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
{
unsigned int u = ecore_time_unix_get();
if (i->show) tw_show(i);
Media *i = data;
E_Client *ec = e_comp_object_client_get(obj);
i->clients = eina_list_remove(i->clients, ec);
}
static void
signal_link_complete(Media *i)
{
E_Client *ec;
if (i->show && (i->clients || (!tw_win))) tw_show(i);
i->show = 0;
eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_COMPLETE, i->addr, u);
EINA_LIST_FREE(i->clients, ec)
{
E_Pixmap_Type type = e_pixmap_type_get(ec->pixmap);
if (e_client_has_xwindow(ec))
type = E_PIXMAP_TYPE_X;
if (tw_signal_link_complete[type])
tw_signal_link_complete[type](ec, i->addr);
evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_DEL, media_client_del, i);
}
}
static void
dbus_signal_link_invalid(Media *i)
signal_link_invalid(Media *i)
{
unsigned int u = ecore_time_unix_get();
eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_INVALID, i->addr, u);
E_Client *ec;
EINA_LIST_FREE(i->clients, ec)
{
E_Pixmap_Type type = e_pixmap_type_get(ec->pixmap);
if (e_client_has_xwindow(ec))
type = E_PIXMAP_TYPE_X;
if (tw_signal_link_invalid[type])
tw_signal_link_invalid[type](ec, i->addr);
evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_DEL, media_client_del, i);
}
}
static void
dbus_signal_link_progress(Media *i, double pr)
signal_link_progress(Media *i, double pr)
{
unsigned int u = ecore_time_unix_get();
Eina_List *l;
E_Client *ec;
eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_PROGRESS, i->addr, u, pr);
EINA_LIST_FOREACH(i->clients, l, ec)
{
E_Pixmap_Type type = e_pixmap_type_get(ec->pixmap);
if (e_client_has_xwindow(ec))
type = E_PIXMAP_TYPE_X;
if (tw_signal_link_progress[type])
tw_signal_link_progress[type](ec, i->addr, lround(pr));
}
}
static void
dbus_signal_link_downloading(Media *i)
signal_link_downloading(Media *i)
{
unsigned int u = ecore_time_unix_get();
eldbus_service_signal_emit(tw_dbus_iface, TEAMWORK_SIGNAL_LINK_DOWNLOADING, i->addr, u);
Eina_List *l;
E_Client *ec;
EINA_LIST_FOREACH(i->clients, l, ec)
{
E_Pixmap_Type type = e_pixmap_type_get(ec->pixmap);
if (e_client_has_xwindow(ec))
type = E_PIXMAP_TYPE_X;
if (tw_signal_link_downloading[type])
tw_signal_link_downloading[type](ec, i->addr);
}
}
static Eina_Bool
@ -143,7 +175,7 @@ download_media_complete(void *data EINA_UNUSED, int type EINA_UNUSED, Ecore_Con_
if (tw_media_add(i->addr, i->buf, i->timestamp, i->video) == 1)
tw_mod->media_size += eina_binbuf_length_get(i->buf);
E_FREE_FUNC(i->client, ecore_con_url_free);
dbus_signal_link_complete(i);
signal_link_complete(i);
download_media_cleanup();
DBG("MEDIA CACHE: %zu bytes", tw_mod->media_size);
return ECORE_CALLBACK_DONE;
@ -177,7 +209,7 @@ download_media_status(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_Con_Event
if (i->valid)
{
dbus_signal_link_progress(i, ev->down.now / ev->down.total);
signal_link_progress(i, ev->down.now / ev->down.total);
return ECORE_CALLBACK_DONE; //already checked
}
status = ecore_con_url_status_code_get(ev->url_con);
@ -213,11 +245,11 @@ download_media_status(void *data EINA_UNUSED, int t EINA_UNUSED, Ecore_Con_Event
break;
}
i->valid = !i->dummy;
if (i->valid) dbus_signal_link_progress(i, ev->down.now / ev->down.total);
if (i->valid) signal_link_progress(i, ev->down.now / ev->down.total);
return ECORE_CALLBACK_DONE;
dummy:
dbus_signal_link_invalid(i);
signal_link_invalid(i);
tw_dummy_add(i->addr);
i->dummy = EINA_TRUE;
invalid:
@ -283,10 +315,10 @@ download_media_add(const char *url)
i->client = ecore_con_url_new(url);
ecore_con_url_data_set(i->client, i);
ecore_con_url_get(i->client);
dbus_signal_link_downloading(i);
signal_link_downloading(i);
}
if (!add) return i;
eina_hash_direct_add(tw_mod->media, url, i);
eina_hash_add(tw_mod->media, url, i);
tw_mod->media_list = eina_inlist_sorted_insert(tw_mod->media_list, EINA_INLIST_GET(i), (Eina_Compare_Cb)download_media_sort_cb);
return i;
}
@ -294,11 +326,15 @@ download_media_add(const char *url)
static void
download_media_free(Media *i)
{
E_Client *ec;
if (!i) return;
tw_mod->media_list = eina_inlist_remove(tw_mod->media_list, EINA_INLIST_GET(i));
if (i->client) ecore_con_url_free(i->client);
if (i->buf) eina_binbuf_free(i->buf);
if (i->tmpfile) ecore_file_unlink(i->tmpfile);
EINA_LIST_FREE(i->clients, ec)
evas_object_event_callback_del_full(ec->frame, EVAS_CALLBACK_DEL, media_client_del, i);
eina_stringshare_del(i->tmpfile);
eina_stringshare_del(i->addr);
free(i);
@ -336,7 +372,7 @@ download_media_cleanup(void)
}
static Teamwork_Link_Type
dbus_link_uri_local_type_get(const char *uri)
link_uri_local_type_get(const char *uri)
{
size_t len = strlen(uri);
@ -345,38 +381,39 @@ dbus_link_uri_local_type_get(const char *uri)
}
static Teamwork_Link_Type
dbus_link_uri_type_get(const char *uri)
link_uri_type_get(const char *uri)
{
if (!uri[0]) return TEAMWORK_LINK_TYPE_NONE; //invalid
if (uri[0] == '/') return dbus_link_uri_local_type_get(uri + 1); //probably a file?
if (uri[0] == '/') return link_uri_local_type_get(uri + 1); //probably a file?
if ((!strncasecmp(uri, "http://", 7)) || (!strncasecmp(uri, "https://", 8))) return TEAMWORK_LINK_TYPE_REMOTE;
if (!strncmp(uri, "file://", 7)) return dbus_link_uri_local_type_get(uri + 7);
if (!strncmp(uri, "file://", 7)) return link_uri_local_type_get(uri + 7);
WRN("Unknown link type for '%s'", uri);
return TEAMWORK_LINK_TYPE_NONE;
}
static Eldbus_Message *
dbus_link_detect_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
EINTERN void
tw_link_detect(E_Client *ec, const char *uri)
{
const char *uri;
unsigned int t;
Media *i;
if (!tw_config->allowed_media_age) goto out;
if (!eldbus_message_arguments_get(msg, "su", &uri, &t)) goto out;
if (!tw_config->allowed_media_age) return;
if (dbus_link_uri_type_get(uri) == TEAMWORK_LINK_TYPE_REMOTE)
download_media_add(uri);
out:
return eldbus_message_method_return_new(msg);
if (link_uri_type_get(uri) != TEAMWORK_LINK_TYPE_REMOTE) return;
i = download_media_add(uri);
if ((!i->clients) || (!eina_list_data_find(i->clients, ec)))
{
i->clients = eina_list_append(i->clients, ec);
evas_object_event_callback_add(ec->frame, EVAS_CALLBACK_DEL, media_client_del, i);
}
}
static void
dbus_link_show_helper(const char *uri, Eina_Bool signal_open)
link_show_helper(const char *uri, Eina_Bool signal_open)
{
Teamwork_Link_Type type;
if (tw_mod->pop && (!e_util_strcmp(evas_object_data_get(tw_mod->pop, "uri"), uri))) return;
type = dbus_link_uri_type_get(uri);
type = link_uri_type_get(uri);
switch (type)
{
case TEAMWORK_LINK_TYPE_NONE: break;
@ -409,64 +446,23 @@ dbus_link_show_helper(const char *uri, Eina_Bool signal_open)
if (tw_mod->pop) tw_mod->force = signal_open;
}
static Eldbus_Message *
dbus_link_show_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
EINTERN void
tw_link_show(E_Client *ec, const char *uri, int x, int y)
{
const char *uri;
if (eldbus_message_arguments_get(msg, "s", &uri))
{
tw_win = 0;
last_coords.x = last_coords.y = -1;
dbus_link_show_helper(uri, 1);
}
return eldbus_message_method_return_new(msg);
}
static Eldbus_Message *
dbus_link_hide_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *uri;
if (eldbus_message_arguments_get(msg, "s", &uri))
{
if (tw_mod->pop && (!tw_mod->sticky) && (!e_util_strcmp(evas_object_data_get(tw_mod->pop, "uri"), uri)))
{
tw_hide(NULL);
tw_mod->force = 0;
}
}
return eldbus_message_method_return_new(msg);
}
static Eldbus_Message *
dbus_link_mouse_in_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
{
const char *uri;
unsigned int t;
uint64_t win;
if (eldbus_message_arguments_get(msg, "sutii", &uri, &t, &win, &last_coords.x, &last_coords.y))
{
tw_win = win;
dbus_link_show_helper(uri, 0);
tw_win = ec;
last_coords.x = x;
last_coords.y = y;
link_show_helper(uri, 0);
tw_mod->hidden = 0;
}
return eldbus_message_method_return_new(msg);
}
static Eldbus_Message *
dbus_link_mouse_out_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
EINTERN void
tw_link_hide(E_Client *ec, const char *uri)
{
const char *uri;
unsigned int t;
uint64_t win;
if (eldbus_message_arguments_get(msg, "sutii", &uri, &t, &win, &last_coords.x, &last_coords.y))
{
if (ec != tw_win) return;
if (tw_mod->pop && (!tw_mod->sticky) &&
((tw_tmpfile && (!e_util_strcmp(evas_object_data_get(tw_mod->pop, "uri"), tw_tmpfile))) ||
(!e_util_strcmp(evas_object_data_get(tw_mod->pop, "uri"), uri))))
((tw_tmpfile && eina_streq(evas_object_data_get(tw_mod->pop, "uri"), tw_tmpfile)) ||
eina_streq(evas_object_data_get(tw_mod->pop, "uri"), uri)))
{
if (tw_config->mouse_out_delay)
{
@ -480,45 +476,22 @@ dbus_link_mouse_out_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const
else if (tw_tmpthread || tw_tmpfile)
tw_hide(NULL);
tw_mod->hidden = !tw_mod->pop;
}
return eldbus_message_method_return_new(msg);
}
static Eldbus_Message *
dbus_link_open_cb(const Eldbus_Service_Interface *iface EINA_UNUSED, const Eldbus_Message *msg)
EINTERN void
tw_link_open(E_Client *ec, const char *uri)
{
const char *uri;
if (eldbus_message_arguments_get(msg, "s", &uri))
{
char *sb;
size_t size = 4096, len = sizeof(E_BINDIR "/enlightenment_open ") - 1;
if (!ec->focused) return;
sb = malloc(size);
memcpy(sb, E_BINDIR "/enlightenment_open ", len);
sb = e_util_string_append_quoted(sb, &size, &len, uri);
ecore_exe_run(sb, NULL);
free(sb);
}
return eldbus_message_method_return_new(msg);
}
static const Eldbus_Method tw_methods[] = {
{ "LinkDetect", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}), NULL, dbus_link_detect_cb, 0 },
{ "LinkMouseIn", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"t", "Window ID"}, {"i", "X Coordinate"}, {"i", "Y Coordinate"}), NULL, dbus_link_mouse_in_cb, 0 },
{ "LinkMouseOut", ELDBUS_ARGS({"s", "URI"}, {"u", "Timestamp"}, {"t", "Window ID"}, {"i", "X Coordinate"}, {"i", "Y Coordinate"}), NULL, dbus_link_mouse_out_cb, 0 },
{ "LinkShow", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_show_cb, 0 },
{ "LinkHide", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_hide_cb, 0 },
{ "LinkOpen", ELDBUS_ARGS({"s", "URI"}), NULL, dbus_link_open_cb, 0 },
{ NULL, NULL, NULL, NULL, 0 }
};
static const Eldbus_Service_Interface_Desc tw_desc =
{
"org.enlightenment.wm.Teamwork", tw_methods, tw_signals, NULL, NULL, NULL
};
static Eet_Data_Descriptor *
media_cache_edd_new(void)
{
@ -778,7 +751,6 @@ tw_show_helper(Evas_Object *o, int w, int h)
{
int px, py, pw, ph;
double ratio = tw_config->popup_size / 100.;
E_Client *ec = NULL;
E_Zone *zone = e_zone_current_get();
evas_object_hide(tw_mod->pop);
@ -810,13 +782,12 @@ tw_show_helper(Evas_Object *o, int w, int h)
py = zone->h - ph;
evas_object_move(tw_mod->pop, px, py);
}
else if (tw_win && (((ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, (Ecore_Window)tw_win))) ||
((ec = e_pixmap_find_client(E_PIXMAP_TYPE_WL, tw_win)))))
else if (tw_win)
{
int x, y;
x = ec->client.x + last_coords.x;
y = ec->client.y + last_coords.y;
x = tw_win->client.x + last_coords.x;
y = tw_win->client.y + last_coords.y;
/* prefer tooltip left of last_coords */
px = x - pw - 3;
/* if it's offscreen, try right of last_coords */
@ -1167,7 +1138,7 @@ tw_hide(void *d EINA_UNUSED)
tw_tmpfd = -1;
}
eina_stringshare_replace(&tw_tmpfile, NULL);
tw_win = 0;
tw_win = NULL;
evas_object_hide(tw_mod->pop);
E_FREE_FUNC(tw_mod->pop, evas_object_del);
last_coords.x = last_coords.y = 0;
@ -1182,7 +1153,14 @@ e_tw_init(void)
char buf[PATH_MAX];
Eet_Data_Descriptor_Class eddc;
tw_dbus_iface = e_msgbus_interface_attach(&tw_desc);
#ifdef HAVE_WAYLAND
if (e_comp->comp_type == E_PIXMAP_TYPE_WL)
wl_tw_init();
#endif
#ifndef HAVE_WAYLAND_ONLY
if (e_comp_util_has_x())
x11_tw_init();
#endif
e_user_dir_concat_static(buf, "images/tw_cache_images.eet");
media[MEDIA_CACHE_TYPE_IMAGE] = eet_open(buf, EET_FILE_MODE_READ_WRITE);
@ -1235,6 +1213,15 @@ EINTERN void
e_tw_shutdown(void)
{
unsigned int x;
#ifdef HAVE_WAYLAND
if (e_comp->comp_type == E_PIXMAP_TYPE_WL)
wl_tw_shutdown();
#endif
#ifndef HAVE_WAYLAND_ONLY
if (e_comp_util_has_x())
x11_tw_shutdown();
#endif
E_FREE_LIST(handlers, ecore_event_handler_del);
for (x = 0; x <= MEDIA_CACHE_TYPE_VIDEO; x++)
{
@ -1254,7 +1241,6 @@ e_tw_shutdown(void)
E_FREE_FUNC(media[x], eet_close);
}
}
E_FREE_FUNC(tw_dbus_iface, eldbus_service_interface_unregister);
E_FREE_FUNC(dummies, eet_close);
E_FREE_FUNC(cleaner_edd, eet_data_descriptor_free);
E_FREE_FUNC(cache_edd, eet_data_descriptor_free);
@ -1276,5 +1262,5 @@ e_tw_shutdown(void)
EINTERN void
tw_uri_show(const char *uri)
{
dbus_link_show_helper(uri, 1);
link_show_helper(uri, 1);
}

136
src/modules/teamwork/wl.c Normal file
View File

@ -0,0 +1,136 @@
#define E_COMP_WL
#include "e_mod_main.h"
#include "wl_teamwork.h"
static struct wl_resource *tw_resource;
static struct wl_global *tw_global;
static void
tw_preload_uri(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED,
struct wl_resource *surface, const char *uri)
{
E_Client *ec;
ec = wl_resource_get_user_data(surface);
if (ec)
tw_link_detect(ec, uri);
}
static void
tw_activate_uri(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED,
struct wl_resource *surface, const char *uri, wl_fixed_t x, wl_fixed_t y)
{
E_Client *ec;
ec = wl_resource_get_user_data(surface);
if (ec)
tw_link_show(ec, uri, wl_fixed_to_int(x), wl_fixed_to_int(y));
}
static void
tw_deactivate_uri(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED,
struct wl_resource *surface, const char *uri)
{
E_Client *ec;
ec = wl_resource_get_user_data(surface);
if (ec)
tw_link_hide(ec, uri);
}
static void
tw_open_uri(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED,
struct wl_resource *surface, const char *uri)
{
E_Client *ec;
ec = wl_resource_get_user_data(surface);
if (ec)
tw_link_open(ec, uri);
}
static const struct zwp_teamwork_interface tw_interface =
{
tw_preload_uri,
tw_activate_uri,
tw_deactivate_uri,
tw_open_uri,
};
static void
wl_tw_cb_unbind(struct wl_resource *resource EINA_UNUSED)
{
tw_resource = NULL;
}
static void
wl_tw_cb_bind(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id)
{
struct wl_resource *res;
if (!(res = wl_resource_create(client, &zwp_teamwork_interface, E_TW_VERSION, id)))
{
ERR("Could not create zwp_teamwork_interface interface");
wl_client_post_no_memory(client);
return;
}
tw_resource = res;
wl_resource_set_implementation(res, &tw_interface, NULL, wl_tw_cb_unbind);
}
static void
wl_tw_link_complete(E_Client *ec, const char *uri)
{
if (e_object_is_del(E_OBJECT(ec))) return;
zwp_teamwork_send_completed_uri(tw_resource, ec->comp_data->surface, uri, 1);
}
static void
wl_tw_link_invalid(E_Client *ec, const char *uri)
{
if (e_object_is_del(E_OBJECT(ec))) return;
zwp_teamwork_send_completed_uri(tw_resource, ec->comp_data->surface, uri, 0);
}
static void
wl_tw_link_progress(E_Client *ec, const char *uri, uint32_t pct)
{
if (e_object_is_del(E_OBJECT(ec))) return;
zwp_teamwork_send_fetch_info(tw_resource, ec->comp_data->surface, uri, pct);
}
static void
wl_tw_link_downloading(E_Client *ec, const char *uri)
{
if (e_object_is_del(E_OBJECT(ec))) return;
zwp_teamwork_send_fetching_uri(tw_resource, ec->comp_data->surface, uri);
}
EINTERN Eina_Bool
wl_tw_init(void)
{
tw_global = wl_global_create(e_comp_wl->wl.disp, &zwp_teamwork_interface, E_TW_VERSION,
NULL, wl_tw_cb_bind);
if (!tw_global)
{
ERR("Could not add zwp_teamwork to wayland globals");
return EINA_FALSE;
}
tw_signal_link_complete[E_PIXMAP_TYPE_WL] = wl_tw_link_complete;
tw_signal_link_invalid[E_PIXMAP_TYPE_WL] = wl_tw_link_invalid;
tw_signal_link_progress[E_PIXMAP_TYPE_WL] = wl_tw_link_progress;
tw_signal_link_downloading[E_PIXMAP_TYPE_WL] = wl_tw_link_downloading;
return EINA_TRUE;
}
EINTERN void
wl_tw_shutdown(void)
{
E_FREE_FUNC(tw_resource, wl_resource_destroy);
E_FREE_FUNC(tw_global, wl_global_destroy);
tw_signal_link_complete[E_PIXMAP_TYPE_WL] = NULL;
tw_signal_link_invalid[E_PIXMAP_TYPE_WL] = NULL;
tw_signal_link_progress[E_PIXMAP_TYPE_WL] = NULL;
tw_signal_link_downloading[E_PIXMAP_TYPE_WL] = NULL;
}

View File

@ -0,0 +1,46 @@
#include <stdlib.h>
#include <stdint.h>
#include "wayland-util.h"
extern const struct wl_interface wl_surface_interface;
static const struct wl_interface *types[] = {
&wl_surface_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
NULL,
&wl_surface_interface,
NULL,
&wl_surface_interface,
NULL,
&wl_surface_interface,
NULL,
&wl_surface_interface,
NULL,
NULL,
&wl_surface_interface,
NULL,
NULL,
};
static const struct wl_message zwp_teamwork_requests[] = {
{ "preload_uri", "os", types + 0 },
{ "activate_uri", "osff", types + 2 },
{ "deactivate_uri", "os", types + 6 },
{ "open_uri", "os", types + 8 },
};
static const struct wl_message zwp_teamwork_events[] = {
{ "fetching_uri", "os", types + 10 },
{ "completed_uri", "osi", types + 12 },
{ "fetch_info", "osu", types + 15 },
};
WL_EXPORT const struct wl_interface zwp_teamwork_interface = {
"zwp_teamwork", 2,
4, zwp_teamwork_requests,
3, zwp_teamwork_events,
};

View File

@ -0,0 +1,93 @@
#ifndef TEAMWORK_SERVER_PROTOCOL_H
#define TEAMWORK_SERVER_PROTOCOL_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
#include "wayland-server.h"
struct wl_client;
struct wl_resource;
struct wl_surface;
struct zwp_teamwork;
extern const struct wl_interface zwp_teamwork_interface;
struct zwp_teamwork_interface {
/**
* preload_uri - (none)
* @surface: (none)
* @uri: (none)
*/
void (*preload_uri)(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface,
const char *uri);
/**
* activate_uri - (none)
* @surface: (none)
* @uri: (none)
* @x: surface local coords
* @y: surface local coords
*/
void (*activate_uri)(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface,
const char *uri,
wl_fixed_t x,
wl_fixed_t y);
/**
* deactivate_uri - (none)
* @surface: (none)
* @uri: (none)
*/
void (*deactivate_uri)(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface,
const char *uri);
/**
* open_uri - (none)
* @surface: (none)
* @uri: (none)
*/
void (*open_uri)(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *surface,
const char *uri);
};
#define ZWP_TEAMWORK_FETCHING_URI 0
#define ZWP_TEAMWORK_COMPLETED_URI 1
#define ZWP_TEAMWORK_FETCH_INFO 2
#define ZWP_TEAMWORK_FETCHING_URI_SINCE_VERSION 1
#define ZWP_TEAMWORK_COMPLETED_URI_SINCE_VERSION 1
#define ZWP_TEAMWORK_FETCH_INFO_SINCE_VERSION 1
static inline void
zwp_teamwork_send_fetching_uri(struct wl_resource *resource_, struct wl_resource *surface, const char *uri)
{
wl_resource_post_event(resource_, ZWP_TEAMWORK_FETCHING_URI, surface, uri);
}
static inline void
zwp_teamwork_send_completed_uri(struct wl_resource *resource_, struct wl_resource *surface, const char *uri, int32_t valid)
{
wl_resource_post_event(resource_, ZWP_TEAMWORK_COMPLETED_URI, surface, uri, valid);
}
static inline void
zwp_teamwork_send_fetch_info(struct wl_resource *resource_, struct wl_resource *surface, const char *uri, uint32_t progress)
{
wl_resource_post_event(resource_, ZWP_TEAMWORK_FETCH_INFO, surface, uri, progress);
}
#ifdef __cplusplus
}
#endif
#endif

141
src/modules/teamwork/x11.c Normal file
View File

@ -0,0 +1,141 @@
#define E_COMP_X
#include "e_mod_main.h"
enum
{
TEAMWORK_PRELOAD,
TEAMWORK_ACTIVATE,
TEAMWORK_DEACTIVATE,
TEAMWORK_OPEN,
TEAMWORK_NOPE,
};
enum
{
TEAMWORK_COMPLETED,
TEAMWORK_PROGRESS,
TEAMWORK_STARTED,
};
static Ecore_Event_Handler *handler;
static Ecore_X_Atom atoms[4];
static Ecore_X_Atom server_atoms[3];
static Ecore_X_Atom prop;
static Eina_Bool
x11_message_handler(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_X_Event_Client_Message *ev)
{
E_Client *ec;
int i;
char *uri;
ec = e_pixmap_find_client(E_PIXMAP_TYPE_X, ev->win);
if (!ec) return ECORE_CALLBACK_RENEW;
for (i = 0; i < TEAMWORK_NOPE; i++)
if (ev->message_type == atoms[i]) break;
if (i == TEAMWORK_NOPE) return ECORE_CALLBACK_RENEW;
uri = ecore_x_window_prop_string_get(ev->win, prop);
if (!uri) return ECORE_CALLBACK_RENEW;
if (ev->message_type == atoms[TEAMWORK_PRELOAD])
/*
format = 32
data.l[0] = version
*/
tw_link_detect(ec, uri);
else if (ev->message_type == atoms[TEAMWORK_ACTIVATE])
/*
format = 32
data.l[0] = version
data.l[1] = window_x
data.l[2] = window_y
*/
tw_link_show(ec, uri, ev->data.l[1], ev->data.l[2]);
else if (ev->message_type == atoms[TEAMWORK_DEACTIVATE])
/*
format = 32
data.l[0] = version
*/
tw_link_hide(ec, uri);
else if (ev->message_type == atoms[TEAMWORK_OPEN])
/*
format = 32
data.l[0] = version
*/
tw_link_open(ec, uri);
free(uri);
return ECORE_CALLBACK_RENEW;
}
static void
x11_tw_link_complete(E_Client *ec, const char *uri EINA_UNUSED)
{
if (e_object_is_del(E_OBJECT(ec))) return;
ecore_x_client_message32_send(e_client_util_win_get(ec), server_atoms[TEAMWORK_COMPLETED],
ECORE_X_EVENT_MASK_WINDOW_MANAGE | ECORE_X_EVENT_MASK_WINDOW_CHILD_CONFIGURE, E_TW_VERSION, 1, 0, 0, 0);
}
static void
x11_tw_link_invalid(E_Client *ec, const char *uri EINA_UNUSED)
{
if (e_object_is_del(E_OBJECT(ec))) return;
ecore_x_client_message32_send(e_client_util_win_get(ec), server_atoms[TEAMWORK_COMPLETED],
ECORE_X_EVENT_MASK_WINDOW_MANAGE | ECORE_X_EVENT_MASK_WINDOW_CHILD_CONFIGURE, E_TW_VERSION, 0, 0, 0, 0);
}
static void
x11_tw_link_progress(E_Client *ec, const char *uri EINA_UNUSED, uint32_t pct)
{
if (e_object_is_del(E_OBJECT(ec))) return;
ecore_x_client_message32_send(e_client_util_win_get(ec), server_atoms[TEAMWORK_PROGRESS],
ECORE_X_EVENT_MASK_WINDOW_MANAGE | ECORE_X_EVENT_MASK_WINDOW_CHILD_CONFIGURE, E_TW_VERSION, pct, 0, 0, 0);
}
static void
x11_tw_link_downloading(E_Client *ec, const char *uri EINA_UNUSED)
{
if (e_object_is_del(E_OBJECT(ec))) return;
ecore_x_client_message32_send(e_client_util_win_get(ec), server_atoms[TEAMWORK_STARTED],
ECORE_X_EVENT_MASK_WINDOW_MANAGE | ECORE_X_EVENT_MASK_WINDOW_CHILD_CONFIGURE, E_TW_VERSION, 0, 0, 0, 0);
}
EINTERN Eina_Bool
x11_tw_init(void)
{
const char *atom_names[] =
{
"_TEAMWORK_PRELOAD",
"_TEAMWORK_ACTIVATE",
"_TEAMWORK_DEACTIVATE",
"_TEAMWORK_OPEN",
"_TEAMWORK_COMPLETED",
"_TEAMWORK_PROGRESS",
"_TEAMWORK_STARTED",
"_TEAMWORK_PROP",
};
Ecore_X_Atom at[EINA_C_ARRAY_LENGTH(atom_names)];
int i;
ecore_x_atoms_get(atom_names, EINA_C_ARRAY_LENGTH(atom_names), at);
for (i = 0; i < 4; i++)
atoms[i] = at[i];
for (i = 4; i < 7; i++)
server_atoms[i] = at[i];
prop = at[7];
handler = ecore_event_handler_add(ECORE_X_EVENT_CLIENT_MESSAGE, (Ecore_Event_Handler_Cb)x11_message_handler, NULL);
tw_signal_link_complete[E_PIXMAP_TYPE_X] = x11_tw_link_complete;
tw_signal_link_invalid[E_PIXMAP_TYPE_X] = x11_tw_link_invalid;
tw_signal_link_progress[E_PIXMAP_TYPE_X] = x11_tw_link_progress;
tw_signal_link_downloading[E_PIXMAP_TYPE_X] = x11_tw_link_downloading;
return EINA_TRUE;
}
EINTERN void
x11_tw_shutdown(void)
{
E_FREE_FUNC(handler, ecore_event_handler_del);
tw_signal_link_complete[E_PIXMAP_TYPE_X] = NULL;
tw_signal_link_invalid[E_PIXMAP_TYPE_X] = NULL;
tw_signal_link_progress[E_PIXMAP_TYPE_X] = NULL;
tw_signal_link_downloading[E_PIXMAP_TYPE_X] = NULL;
}

39
src/protocol/teamwork.xml Normal file
View File

@ -0,0 +1,39 @@
<protocol name="teamwork">
<interface name="zwp_teamwork" version="2">
<request name="preload_uri">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uri" type="string"/>
</request>
<request name="activate_uri">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uri" type="string"/>
<arg name="x" type="fixed" summary="surface local coords"/>
<arg name="y" type="fixed" summary="surface local coords"/>
</request>
<request name="deactivate_uri">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uri" type="string"/>
</request>
<request name="open_uri">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uri" type="string"/>
</request>
<event name="fetching_uri">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uri" type="string"/>
</event>
<event name="completed_uri">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uri" type="string"/>
<arg name="valid" type="int" summary="1 if uri can be displayed, else 0"/>
</event>
<event name="fetch_info">
<arg name="surface" type="object" interface="wl_surface"/>
<arg name="uri" type="string"/>
<arg name="progress" type="uint" summary="percentage of download"/>
</event>
</interface>
</protocol>