From e3da2b895a6a8d6269377ad85f4c5c974730161f Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Mon, 17 Jun 2013 09:48:48 +0000 Subject: [PATCH] Revert previous commit. Damn svn, didn't mean to delete the whole dir. SVN revision: 84558 --- AUTHORS | 1 + COPYING | 32 ++++ COPYING-PLAIN | 33 ++++ ChangeLog | 0 INSTALL | 11 ++ Makefile.am | 25 +++ NEWS | 0 README | 2 + TODO | 6 + autogen.sh | 16 ++ configure.ac | 69 +++++++ e-module-share.edc | 74 ++++++++ e_modules-share.spec.in | 48 +++++ images/module_icon.png | Bin 0 -> 2248 bytes images/module_icon.svg | 6 + m4/.svnignore | 0 module.desktop.in | 6 + src/Makefile.am | 22 +++ src/e_mod_main.c | 387 ++++++++++++++++++++++++++++++++++++++++ src/e_mod_main.h | 12 ++ src/e_share.h | 22 +++ src/sourcedrop.c | 128 +++++++++++++ 22 files changed, 900 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 COPYING-PLAIN create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100644 TODO create mode 100755 autogen.sh create mode 100644 configure.ac create mode 100644 e-module-share.edc create mode 100644 e_modules-share.spec.in create mode 100644 images/module_icon.png create mode 100755 images/module_icon.svg create mode 100644 m4/.svnignore create mode 100644 module.desktop.in create mode 100644 src/Makefile.am create mode 100644 src/e_mod_main.c create mode 100644 src/e_mod_main.h create mode 100644 src/e_share.h create mode 100644 src/sourcedrop.c diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..e684cdd --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Leif Middelschulte diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..9690c3f --- /dev/null +++ b/COPYING @@ -0,0 +1,32 @@ + +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 shall be included in +all copies of the Software and its Copyright notices. In addition publicly +documented acknowledgment must be given that this software has been used if no +source code of this software is made available publicly. Making the source +available publicly means including the source for this software with the +distribution, or a method to get this software via some reasonable mechanism +(electronic transfer via a network or media) as well as making an offer to +supply the source on request. This Copyright notice serves as an offer to +supply the source on on request as well. Instead of this, supplying +acknowledgments of use of this software in either Copyright notices, Manuals, +Publicity and Marketing documents or any documentation provided with any +product containing this software. This License does not apply to any software +that links to the libraries provided by this software (statically or +dynamically), but only to the software provided. + +Please see the COPYING-PLAIN for a plain-english explanation of this notice +and its intent. + +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 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. diff --git a/COPYING-PLAIN b/COPYING-PLAIN new file mode 100644 index 0000000..3d7fe1a --- /dev/null +++ b/COPYING-PLAIN @@ -0,0 +1,33 @@ +Plain English Copyright Notice + +This file is not intended to be the actual License. The reason this file +exists is that we here are programmers and engineers. We aren't lawyers. We +provide licenses that we THINK say the right things, but we have our own +intentions at heart. This is a plain-english explanation of what those +intentions are, and if you follow them you will be within the "spirit" of +the license. + +The intent is for us to enjoy writing software that is useful to us (the +AUTHORS) and allow others to use it freely and also benefit from the work we +put into making it. We don't want to restrict others using it. They should +not *HAVE* to make the source code of the applications they write that +simply link to these libraries (be that statically or dynamically), or for +them to be limited as to what license they choose to use (be it open, closed +or anything else). But we would like to know you are using these libraries. +We simply would like to know that it has been useful to someone. This is why +we ask for acknowledgement of some sort. + +You can do what you want with the source of this software - it doesn't +matter. We still have it here for ourselves and it is open and free to use +and download and play with. It can't be taken away. We don't really mind what +you do with the source to your software. We would simply like to know that +you are using it - especially if it makes it to a commerical product. If you +simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and +then make sure you include a paragraph or page in the manual for the product +with the copyright notice and state that you used this software, we will be +very happy. If you want to contribute back modifications and fixes you may have +made we will welcome those too with open arms (generally). If you want help +with changes needed, ports needed or features to be added, arrangements can +be easily made with some dialogue. + +Leif Middelschulte diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..8919fc2 --- /dev/null +++ b/INSTALL @@ -0,0 +1,11 @@ +COMPILING and INSTALLING: + +If you got a official release tar archive do: + ./autogen.sh + +Then to compile: + make + +To install: + make install + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..186fae4 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,25 @@ +MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess config.h.in \ + config.sub configure depcomp install-sh ltmain.sh \ + missing module.desktop config.rpath mkinstalldirs + +SUBDIRS = src + +EDJE_FLAGS = -v \ + -id $(top_srcdir)/images + +filesdir = $(datadir) +files_DATA = module.desktop e-module-share.edj + +EXTRA_DIST = module.desktop.in \ + e_modules-share.spec.in \ + e-module-share.edc \ + images/module_icon.png + +%.edj: %.edc + $(EDJE_CC) $(EDJE_FLAGS) $< $@ + +clean-local: + rm -rf e-module-share.edj module.desktop e_modules-share.spec *~ + +uninstall: + rm -rf $(DESTDIR)$(datadir) diff --git a/NEWS b/NEWS new file mode 100644 index 0000000..e69de29 diff --git a/README b/README new file mode 100644 index 0000000..6c6366c --- /dev/null +++ b/README @@ -0,0 +1,2 @@ +This module shall share data from the clipboard online. +The user shall be given a link to the share. diff --git a/TODO b/TODO new file mode 100644 index 0000000..f494dd8 --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +- Store and restore old links for every instance +- Enable HTTPS + +Future: +- Share files +- Extend to more services (1Click hosters and local p2p) diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..0846992 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +rm -rf autom4te.cache +rm -f aclocal.m4 ltmain.sh + +touch README + +echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS || exit 1 +echo "Running autoheader..." ; autoheader || exit 1 +echo "Running autoconf..." ; autoconf || exit 1 +echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1 +echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1 + +if [ -z "$NOCONFIGURE" ]; then + ./configure "$@" +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..5b27776 --- /dev/null +++ b/configure.ac @@ -0,0 +1,69 @@ +dnl Process this file with autoconf to produce a configure script. + +# get rid of that stupid cache mechanism +rm -f config.cache + +AC_INIT(share, 0.0.1, enlightenment-devel@lists.sourceforge.net) +AC_PREREQ(2.52) +AC_CONFIG_SRCDIR(configure.ac) +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +AC_ISC_POSIX + +AM_INIT_AUTOMAKE(1.6) +AC_CONFIG_HEADERS(config.h) + +AC_PROG_CC +AC_HEADER_STDC +AC_C_CONST + +define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl +define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl +AC_PROG_LIBTOOL + +PKG_CHECK_MODULES(E, [enlightenment]) +release=$(pkg-config --variable=release enlightenment) +MODULE_ARCH="$host_os-$host_cpu-$release" +AC_SUBST(MODULE_ARCH) +AC_DEFINE_UNQUOTED(MODULE_ARCH, "$MODULE_ARCH", "Module architecture") + +PKG_CHECK_MODULES(JSON, [json]) + +# +# Platform specific setup +# +############################# +case $host_os in + linux*) + PKG_CHECK_MODULES(BSD, [libbsd]) + ;; +esac + +# Find edje_cc +PKG_CHECK_MODULES(EDJE, [edje >= 0.5.0]) +AC_ARG_WITH(edje-cc, + AC_HELP_STRING([--with-edje-cc=PATH], [specify a specific path to edje_cc]), + [ + v=$withval; + EDJE_CC=$v + ],[ + EDJE_CC=$(pkg-config --variable=prefix edje)/bin/edje_cc + ] +) +AC_SUBST(EDJE_CC) +AC_MSG_CHECKING([Which edje_cc to use]) +AC_MSG_RESULT(${EDJE_CC}) + +datadir=$(pkg-config --variable=modules enlightenment)/${PACKAGE} +AC_ARG_ENABLE(homedir-install, + AS_HELP_STRING([--enable-homedir-install], [Install module in homedir]), + [ datadir="${HOME}/.e/e/modules/${PACKAGE}" ] +) + +AC_OUTPUT([ +Makefile +src/Makefile +e_modules-share.spec +module.desktop +], [ +]) diff --git a/e-module-share.edc b/e-module-share.edc new file mode 100644 index 0000000..28cd241 --- /dev/null +++ b/e-module-share.edc @@ -0,0 +1,74 @@ +collections { + + images.image: "module_icon.png" COMP; + + group { + name: "icon"; + max: 48 48; + parts { + part { + name: "image"; + type: IMAGE; + mouse_events: 0; + description { + state: "default" 0.00; + visible: 1; + aspect: 1.00 1.00; + aspect_preference: BOTH; + rel1 { + relative: 0.00 0.00; + offset: 0 0; + } + rel2 { + relative: 1.00 1.00; + offset: -1 -1; + } + image.normal: "module_icon.png"; + } + } + } + } + group { + name: "modules/share/main"; + max: 128 128; + parts { + part { name: "logo"; + type: IMAGE; + description { state: "default" 0.0; + aspect: 1.0 1.0; + aspect_preference: BOTH; + rel1.offset: 0 0; + rel2.offset: -1 -1; + image.normal: "module_icon.png"; + } + description { state: "active" 0.0; + inherit: "default" 0.0; + color: 255 255 255 128; + } + } + part { name: "inout"; + type: RECT; + mouse_events: 1; + description { state: "default" 0.0; + color: 255 255 255 0; + } + } + } + programs { + program { name: "go_active"; + signal: "active"; + source: ""; + action: STATE_SET "active" 0.0; + target: "logo"; + transition: LINEAR 0.5; + } + program { name: "go_passive"; + signal: "passive"; + source: ""; + action: STATE_SET "default" 0.0; + target: "logo"; + transition: LINEAR 0.5; + } + } + } +} diff --git a/e_modules-share.spec.in b/e_modules-share.spec.in new file mode 100644 index 0000000..95ab663 --- /dev/null +++ b/e_modules-share.spec.in @@ -0,0 +1,48 @@ +%define module_name share +%{!?_rel:%{expand:%%global _rel 0.enl%{?dist}}} + +Summary: %{module_name} module for the Enlightenment window manager +Name: e_modules-%{module_name} +Version: @VERSION@ +Release: %{_rel} +License: BSD +Group: User Interface/Desktops +URL: http://www.enlightenment.org/ +Source: ftp://ftp.enlightenment.org/pub/enlightenment/%{module_name}-%{version}.tar.gz +Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings } +Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)} +Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}} +BuildRequires: ecore-devel, evas-devel, edje-bin +BuildRequires: edje-devel, eet-devel, enlightenment-devel >= 0.16.999 +Requires: enlightenment >= 0.16.999 +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description +%{module_name} module for the Enlightenment window manager. + +%prep +%setup -q -n %{module_name}-%{version} + +%build +%{configure} +%{__make} %{?_smp_mflags} %{?mflags} + +%install +%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install +%{find_lang} %{module_name} || true > %{module_name}.lang + +%clean +test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files -f %{module_name}.lang +%defattr(-, root, root) +%doc AUTHORS ChangeLog COPYING* INSTALL NEWS README +%{_libdir}/enlightenment/modules/%{module_name}* + +%changelog diff --git a/images/module_icon.png b/images/module_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..42d4f00b0333803ec1e316f2d3e9dcd39d33b299 GIT binary patch literal 2248 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 Tk&%NVg35p+*3GWohIrvW6i5ZN literal 0 HcmV?d00001 diff --git a/images/module_icon.svg b/images/module_icon.svg new file mode 100755 index 0000000..9ae179f --- /dev/null +++ b/images/module_icon.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/m4/.svnignore b/m4/.svnignore new file mode 100644 index 0000000..e69de29 diff --git a/module.desktop.in b/module.desktop.in new file mode 100644 index 0000000..12bcee8 --- /dev/null +++ b/module.desktop.in @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=Link +Name=Share +Icon=e-module-share +X-Enlightenment-ModuleType=utils +Comment=Gadget that shares your clipboard content online and puts a link to it into your clipboard diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..dcfd792 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,22 @@ +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = -I. \ + -I$(top_srcdir) \ + -I$(includedir) \ + @E_CFLAGS@ \ + @JSON_CFLAGS@ \ + @BSD_CFLAGS@ + +pkgdir = $(datadir)/$(MODULE_ARCH) +pkg_LTLIBRARIES = module.la +module_la_SOURCES = e_mod_main.c \ + e_mod_main.h \ + e_share.h \ + sourcedrop.c + +module_la_LIBADD = @E_LIBS@ @JSON_LIBS@ @BSD_LIBS@ -lm +module_la_LDFLAGS = -module -avoid-version +module_la_DEPENDENCIES = $(top_builddir)/config.h + +clean-local: + rm -rf *~ diff --git a/src/e_mod_main.c b/src/e_mod_main.c new file mode 100644 index 0000000..479f2bd --- /dev/null +++ b/src/e_mod_main.c @@ -0,0 +1,387 @@ +#include "e_mod_main.h" +#include "e_share.h" +#include + +#define __UNUSED__ +#define _(S) S + +/* actual module specifics */ +typedef struct _Instance Instance; +struct _Instance +{ + E_Gadcon_Client *gcc; + E_Menu *menu; + Ecore_X_Window win; + Evas_Object *o_button; + Eina_List *handlers; + Eina_List *shares; +}; + +/* gadcon requirements */ +static E_Gadcon_Client *_gc_init(E_Gadcon * gc, const char *name, const char *id, const char *style); +static void _gc_shutdown(E_Gadcon_Client * gcc); +static void _gc_orient(E_Gadcon_Client * gcc, E_Gadcon_Orient orient); +static const char *_gc_label(const E_Gadcon_Client_Class *client_class); +static Evas_Object *_gc_icon(const E_Gadcon_Client_Class *client_class, Evas * evas); +static const char *_gc_id_new(const E_Gadcon_Client_Class *client_class); + +static void _share_button_cb_mouse_down(void *data, Evas *evas, Evas_Object *obj, Evas_Event_Mouse_Down *ev); +static Eina_Bool _share_x_selection_notify_handler(Instance *instance, int type, void *event); +static void _share_menu_post_cb(void *data, E_Menu *menu __UNUSED__); +static void _share_menu_share_request_click_cb(Instance *inst, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__); +static void _share_menu_share_item_click_cb(Share_Data *selected_share, E_Menu *m, E_Menu_Item *mi); +static void _share_open_link_in_browser(const Share_Data *sd); +static void _share_notify(const Share_Data *sd); +static void _share_notification_clicked_cb(void *data, unsigned int id); +static void _free_share_data(Share_Data *sd); + +static E_Module *share_module = NULL; + +/* and actually define the gadcon class that this module provides (just 1) */ +static const E_Gadcon_Client_Class _gadcon_class = { + GADCON_CLIENT_CLASS_VERSION, + "share", + { + _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL, + e_gadcon_site_is_not_toolbar + }, + E_GADCON_CLIENT_STYLE_PLAIN +}; + +static E_Gadcon_Client * +_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style) +{ + Evas_Object *o; + E_Gadcon_Client *gcc; + Instance *inst; + + inst = E_NEW(Instance, 1); + + /* + char buf[PATH_MAX]; + snprintf(buf, sizeof(buf), "%s/e-module-share.edj", e_module_dir_get(share_module)); + + o = edje_object_add(gc->evas); + if (!e_theme_edje_object_set(o, "base/theme/modules/share", "modules/share/main")) + edje_object_file_set(o, buf, "modules/share/main"); + edje_object_signal_emit(o, "passive", ""); + */ + + o = e_icon_add(gc->evas); + e_icon_fdo_icon_set(o, "emblem-shared"); + evas_object_show(o); + + gcc = e_gadcon_client_new(gc, name, id, style, o); + gcc->data = inst; + + inst->gcc = gcc; + inst->win = ecore_evas_window_get(gc->ecore_evas); + inst->o_button = o; + + e_gadcon_client_util_menu_attach(gcc); + + evas_object_event_callback_add(inst->o_button, EVAS_CALLBACK_MOUSE_DOWN, (Evas_Object_Event_Cb)_share_button_cb_mouse_down, inst); + E_LIST_HANDLER_APPEND(inst->handlers, ECORE_X_EVENT_SELECTION_NOTIFY, _share_x_selection_notify_handler, inst); + + return gcc; +} + +static void +_gc_shutdown(E_Gadcon_Client *gcc) +{ + Instance *inst; + + inst = gcc->data; + E_FREE_LIST(inst->handlers, ecore_event_handler_del); + inst->handlers = NULL; + + if (inst->menu) + { + e_menu_post_deactivate_callback_set(inst->menu, NULL, NULL); + e_object_del(E_OBJECT(inst->menu)); + inst->menu = NULL; + } + + E_FREE_LIST(inst->shares, _free_share_data); + inst->shares = NULL; + + evas_object_del(inst->o_button); + E_FREE(inst); +} + +static void +_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient) +{ + e_gadcon_client_aspect_set (gcc, 16, 16); + e_gadcon_client_min_size_set (gcc, 16, 16); +} + +static const char * +_gc_label (const E_Gadcon_Client_Class *client_class) +{ + return "Share"; +} + +static Evas_Object * +_gc_icon(const E_Gadcon_Client_Class *client_class, Evas * evas) +{ + Evas_Object *o; + /* + char buf[PATH_MAX]; + + o = edje_object_add(evas); + snprintf (buf, sizeof(buf), "%s/e-module-share.edj", e_module_dir_get(share_module)); + edje_object_file_set(o, buf, "icon"); + */ + + o = e_icon_add(evas); + e_icon_fdo_icon_set(o, "emblem-shared"); + + return o; +} + +static const char * +_gc_id_new (const E_Gadcon_Client_Class *client_class) +{ + return _gadcon_class.name; +} + +static void +_share_button_cb_mouse_down(void *data, Evas *evas, Evas_Object *obj, Evas_Event_Mouse_Down *ev) +{ + Instance *inst = (Instance*)data; + Evas_Coord x, y, w, h; + int cx, cy; + int dir; + E_Menu_Item *mi; + Eina_List *it; + Share_Data *share; + + if (!inst) return; + + if ((ev->button == 1) && (!inst->menu)) + { + /* Coordinates and sizing */ + evas_object_geometry_get(inst->o_button, &x, &y, &w, &h); + e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &cx, &cy, + NULL, NULL); + x += cx; + y += cy; + + inst->menu = e_menu_new(); + + mi = e_menu_item_new(inst->menu); + e_menu_item_label_set(mi, _("Share Clipboard Content")); + e_menu_item_callback_set(mi, (E_Menu_Cb)_share_menu_share_request_click_cb, inst); + + mi = e_menu_item_new(inst->menu); + e_menu_item_separator_set(mi, EINA_TRUE); + + EINA_LIST_FOREACH(inst->shares, it, share) + { + mi = e_menu_item_new(inst->menu); + e_menu_item_label_set(mi, share->name); + e_menu_item_callback_set(mi, (E_Menu_Cb)_share_menu_share_item_click_cb, share); + } + + e_menu_post_deactivate_callback_set(inst->menu, + _share_menu_post_cb, inst); + + /* Proper menu orientation */ + switch (inst->gcc->gadcon->orient) + { + case E_GADCON_ORIENT_TOP: + case E_GADCON_ORIENT_CORNER_TL: + case E_GADCON_ORIENT_CORNER_TR: + dir = E_MENU_POP_DIRECTION_DOWN; + break; + + case E_GADCON_ORIENT_BOTTOM: + case E_GADCON_ORIENT_CORNER_BL: + case E_GADCON_ORIENT_CORNER_BR: + dir = E_MENU_POP_DIRECTION_UP; + break; + + case E_GADCON_ORIENT_LEFT: + case E_GADCON_ORIENT_CORNER_LT: + case E_GADCON_ORIENT_CORNER_LB: + dir = E_MENU_POP_DIRECTION_RIGHT; + break; + + case E_GADCON_ORIENT_RIGHT: + case E_GADCON_ORIENT_CORNER_RT: + case E_GADCON_ORIENT_CORNER_RB: + dir = E_MENU_POP_DIRECTION_LEFT; + break; + + case E_GADCON_ORIENT_FLOAT: + case E_GADCON_ORIENT_HORIZ: + case E_GADCON_ORIENT_VERT: + default: + dir = E_MENU_POP_DIRECTION_AUTO; + break; + } + + e_gadcon_locked_set(inst->gcc->gadcon, EINA_TRUE); + + /* We display not relatively to the gadget, but similarly to + * the start menu - thus the need for direction etc. + */ + e_menu_activate_mouse(inst->menu, + e_util_zone_current_get + (e_manager_current_get()), + x, y, w, h, dir, ev->timestamp); + } +} + +static Eina_Bool +_share_x_selection_notify_handler(Instance *instance, int type, void *event) +{ + Ecore_X_Event_Selection_Notify *ev; + Share_Data *sd = NULL; + + if (!instance) + return EINA_TRUE; + + ev = event; + if ((ev->selection == ECORE_X_SELECTION_CLIPBOARD) && + (strcmp(ev->target, ECORE_X_SELECTION_TARGET_UTF8_STRING) == 0)) + { + Ecore_X_Selection_Data_Text *text_data; + + text_data = ev->data; + if ((text_data->data.content == ECORE_X_SELECTION_CONTENT_TEXT) && + (text_data->text)) + { + char buf[20]; + if (text_data->data.length == 0) return EINA_TRUE; + + sd = E_NEW(Share_Data, 1); + sd->inst = instance; + snprintf(buf, ((text_data->data.length >= sizeof(buf)) ? (sizeof(buf) - 1) : text_data->data.length), text_data->text); + asprintf(&sd->name, "%s", buf); + asprintf(&sd->content, "%s", text_data->text); + + sourcedrop_share(sd); + } + } + + return ECORE_CALLBACK_PASS_ON; +} + +/* Updates the X selection with the selected text of the entry */ +void +_clipboard_update(const char *text, const Instance *inst) +{ + EINA_SAFETY_ON_NULL_RETURN(inst); + EINA_SAFETY_ON_NULL_RETURN(text); + + ecore_x_selection_clipboard_set(inst->win, text, strlen(text) + 1); +} + +void e_share_upload_completed(Share_Data *sd) +{ + if (!sd) return; + ((Instance*)sd->inst)->shares = eina_list_append(((Instance*)sd->inst)->shares, sd); + _share_notify(sd); + _clipboard_update(sd->url, sd->inst); +} + +static void +_share_menu_share_request_click_cb(Instance *inst, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__) +{ + if (!inst) return; + ecore_x_selection_clipboard_request(inst->win, + ECORE_X_SELECTION_TARGET_UTF8_STRING); +} + +static void +_share_menu_share_item_click_cb(Share_Data *selected_share, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__) +{ + _share_open_link_in_browser(selected_share); +} + +static void +_share_notify(const Share_Data *sd) +{ + char buf[256]; + E_Notification_Notify *n = E_NEW(E_Notification_Notify, 1); + + if (!sd || !n) + return; + n->id = 0; + n->app_name = _("E Share"); + n->sumary = _("Your content has been shared."); + snprintf(buf, (sizeof(buf) - 1), _("Your clipboard's content is now available at %s."), sd->url); + n->body = buf; + n->icon.icon = "e"; + n->timeout = 2; + e_notification_client_send(n, NULL /*_share_notification_clicked_cb*/, sd); +} + +static void +_share_open_link_in_browser(const Share_Data *sd) +{ + char buf[256]; + + if (!sd) + return; + snprintf(buf, (sizeof(buf) - 1), "xdg-open %s", sd->url); + e_exec(e_gadcon_client_zone_get(((Instance*)sd->inst)->gcc), NULL, buf, NULL, NULL); +} + +static void +_share_notification_clicked_cb(void *data, unsigned int id) +{ + if (!data) + return; + _share_open_link_in_browser((Share_Data*)data); +} + +static void +_share_menu_post_cb(void *data, E_Menu *menu __UNUSED__) +{ + Instance *inst = data; + + if (!inst) return; + e_gadcon_locked_set(inst->gcc->gadcon, EINA_FALSE); + inst->menu = NULL; +} + +static void _free_share_data(Share_Data *sd) +{ + free(sd->name); + free(sd->content); + free(sd->url); + free(sd); +} + +/* module setup */ +EAPI E_Module_Api e_modapi = { + E_MODULE_API_VERSION, + "Share" +}; + +EAPI void * +e_modapi_init (E_Module * m) +{ + share_module = m; + sourcedrop_init(); + e_gadcon_provider_register(&_gadcon_class); + return share_module; +} + +EAPI int +e_modapi_shutdown (E_Module * m) +{ + sourcedrop_shutdown(); + share_module = NULL; + e_gadcon_provider_unregister(&_gadcon_class); + return 1; +} + +EAPI int +e_modapi_save(E_Module * m) +{ + return 1; +} diff --git a/src/e_mod_main.h b/src/e_mod_main.h new file mode 100644 index 0000000..eabfb8d --- /dev/null +++ b/src/e_mod_main.h @@ -0,0 +1,12 @@ +#ifndef E_MOD_MAIN_H +#define E_MOD_MAIN_H + +#include + +EAPI extern E_Module_Api e_modapi; + +EAPI void *e_modapi_init (E_Module *m); +EAPI int e_modapi_shutdown (E_Module *m); +EAPI int e_modapi_save (E_Module *m); + +#endif diff --git a/src/e_share.h b/src/e_share.h new file mode 100644 index 0000000..8f2e8ae --- /dev/null +++ b/src/e_share.h @@ -0,0 +1,22 @@ +#ifndef __E_SHARE_H__ +#define __E_SHARE_H__ + +#undef LOG +#define LOG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__) + +typedef struct _Share_Data { + void *inst; + char *name; + char *content; + char *url; +} Share_Data; + +/* API used by submodules */ +void e_share_upload_completed(Share_Data *share_data); + +/* Submodules' functions */ +void sourcedrop_init(void); +void sourcedrop_share(Share_Data *share_data); +void sourcedrop_shutdown(void); + +#endif diff --git a/src/sourcedrop.c b/src/sourcedrop.c new file mode 100644 index 0000000..8a790a9 --- /dev/null +++ b/src/sourcedrop.c @@ -0,0 +1,128 @@ +#include +#include +#ifdef __linux__ +#include // strlcpy, etc. found in libbsd +#else +#include +#endif + +#include "e_mod_main.h" +#include "e_share.h" + +#define BUFFER_SIZE_MAX 4096 +#define DROPNAME "Sourcedrop" +#define SOURCEDROP_URL "http://www.sourcedrop.net/paste" +#define RECOGNITION_STRING "Location: " + +static Ecore_Event_Handler *handler = NULL; + +static Eina_Bool __upload_completed_cb(void *data, int type, Ecore_Con_Event_Url_Complete *ev); +static json_object *jarray, *jparent; + +/* Converts an integer value to its hex character*/ +char to_hex(const char code) { + static char hex[] = "0123456789abcdef"; + return hex[code & 15]; +} + +/* Returns a url-encoded version of str */ +/* IMPORTANT: be sure to free() the returned string after use */ +char *url_encode(const char *str) { + const char *pstr = str; + char *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf; + while (*pstr) { + if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') + *pbuf++ = *pstr; + else if (*pstr == ' ') + *pbuf++ = '+'; + else + *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15); + pstr++; + } + *pbuf = '\0'; + return buf; +} + +const char *json_encode(const char *title, const char *content) +{ + const char *encoded_string = NULL; + + jarray = json_object_new_array(); + jparent = json_object_new_object(); + json_object_object_add(jparent, "title", json_object_new_string(title)); + json_object_object_add(jparent, "content", json_object_new_string(content)); + json_object_array_add(jarray, jparent); + + encoded_string = json_object_to_json_string(jarray); + + return encoded_string; +} + +static Eina_Bool +__upload_completed_cb(void *data, int type, Ecore_Con_Event_Url_Complete *ev) +{ + char buf[BUFFER_SIZE_MAX]; + const Eina_List *headers = NULL, *it; + const char *header = NULL; + Share_Data *sd = NULL; + + json_object_put(jarray); + jarray = NULL; + json_object_put(jparent); + jparent = NULL; + + if (ev->status != 200) + { + LOG("E_SHARE/" DROPNAME ": This is not supposed to happen. The server returned status code: %d\n", ev->status); + return ECORE_CALLBACK_RENEW; + } + + headers = ecore_con_url_response_headers_get(ev->url_con); + EINA_LIST_FOREACH(headers, it, header) + { + if (strncmp(header, RECOGNITION_STRING, (sizeof(RECOGNITION_STRING) - 1)) == 0) + { + sd = ecore_con_url_data_get(ev->url_con); + strlcpy(buf, (char*)(header + sizeof(RECOGNITION_STRING) - 1), sizeof(buf)); + asprintf(&sd->url, "%s", buf); + e_share_upload_completed(sd); + ecore_con_url_free(ev->url_con); + break; + } + } + + return ECORE_CALLBACK_CANCEL; +} + +void sourcedrop_share(Share_Data *sd) +{ + Ecore_Con_Url *request_url = NULL; + char post_data[BUFFER_SIZE_MAX]; + const char *json_encoded = NULL; + char *url_encoded = NULL; + + EINA_SAFETY_ON_NULL_RETURN(sd); + + json_encoded = json_encode(sd->name, sd->content); + request_url = ecore_con_url_new(SOURCEDROP_URL); + url_encoded = url_encode(json_encoded); + snprintf(post_data, (sizeof(post_data) - 1), "data=%s", url_encoded); + free(url_encoded); + ecore_con_url_data_set(request_url, (void*)sd); + ecore_con_url_post(request_url, (void*)post_data, sizeof(post_data), "application/x-www-form-urlencoded"); +} + +void sourcedrop_init(void) +{ + ecore_init(); + ecore_con_init(); + handler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, (Ecore_Event_Handler_Cb)__upload_completed_cb, NULL); +} + +void sourcedrop_shutdown(void) +{ + ecore_event_handler_del(handler); + handler = NULL; + ecore_con_shutdown(); + ecore_shutdown(); +}