summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeif Middelschulte <leif.middelschulte@gmail.com>2013-01-31 02:14:50 +0000
committerLeif Middelschulte <leif.middelschulte@gmail.com>2013-01-31 02:14:50 +0000
commitff8fbe6e4afcc53735525087c305de3cbd35ea22 (patch)
tree837fb83744c7836d75d4c37f5f11742fc01412e6
Welcome 'Share', conviently share you clipboard content online.
The uploaded text is syntax highlighted. Share places a link to the site that holds your content in your clipboard in return. SVN revision: 83496
-rw-r--r--AUTHORS1
-rw-r--r--COPYING32
-rw-r--r--COPYING-PLAIN33
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL11
-rw-r--r--Makefile.am25
-rw-r--r--NEWS0
-rw-r--r--README2
-rw-r--r--TODO6
-rwxr-xr-xautogen.sh16
-rw-r--r--configure.ac59
-rw-r--r--e-module-share.edc74
-rw-r--r--e_modules-share.spec.in48
-rw-r--r--images/module_icon.pngbin0 -> 2248 bytes
-rwxr-xr-ximages/module_icon.svg6
-rw-r--r--m4/.svnignore0
-rw-r--r--module.desktop.in6
-rw-r--r--src/Makefile.am21
-rw-r--r--src/e_mod_main.c387
-rw-r--r--src/e_mod_main.h12
-rw-r--r--src/e_share.h22
-rw-r--r--src/sourcedrop.c124
22 files changed, 885 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e684cdd
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
Leif Middelschulte <leif.middelschulte@gmail.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..9690c3f
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,32 @@
1
2Permission is hereby granted, free of charge, to any person obtaining a copy
3of this software and associated documentation files (the "Software"), to
4deal in the Software without restriction, including without limitation the
5rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6sell copies of the Software, and to permit persons to whom the Software is
7furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in
10all copies of the Software and its Copyright notices. In addition publicly
11documented acknowledgment must be given that this software has been used if no
12source code of this software is made available publicly. Making the source
13available publicly means including the source for this software with the
14distribution, or a method to get this software via some reasonable mechanism
15(electronic transfer via a network or media) as well as making an offer to
16supply the source on request. This Copyright notice serves as an offer to
17supply the source on on request as well. Instead of this, supplying
18acknowledgments of use of this software in either Copyright notices, Manuals,
19Publicity and Marketing documents or any documentation provided with any
20product containing this software. This License does not apply to any software
21that links to the libraries provided by this software (statically or
22dynamically), but only to the software provided.
23
24Please see the COPYING-PLAIN for a plain-english explanation of this notice
25and its intent.
26
27THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
31IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32CONNECTION 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 @@
1Plain English Copyright Notice
2
3This file is not intended to be the actual License. The reason this file
4exists is that we here are programmers and engineers. We aren't lawyers. We
5provide licenses that we THINK say the right things, but we have our own
6intentions at heart. This is a plain-english explanation of what those
7intentions are, and if you follow them you will be within the "spirit" of
8the license.
9
10The intent is for us to enjoy writing software that is useful to us (the
11AUTHORS) and allow others to use it freely and also benefit from the work we
12put into making it. We don't want to restrict others using it. They should
13not *HAVE* to make the source code of the applications they write that
14simply link to these libraries (be that statically or dynamically), or for
15them to be limited as to what license they choose to use (be it open, closed
16or anything else). But we would like to know you are using these libraries.
17We simply would like to know that it has been useful to someone. This is why
18we ask for acknowledgement of some sort.
19
20You can do what you want with the source of this software - it doesn't
21matter. We still have it here for ourselves and it is open and free to use
22and download and play with. It can't be taken away. We don't really mind what
23you do with the source to your software. We would simply like to know that
24you are using it - especially if it makes it to a commerical product. If you
25simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and
26then make sure you include a paragraph or page in the manual for the product
27with the copyright notice and state that you used this software, we will be
28very happy. If you want to contribute back modifications and fixes you may have
29made we will welcome those too with open arms (generally). If you want help
30with changes needed, ports needed or features to be added, arrangements can
31be easily made with some dialogue.
32
33Leif Middelschulte <leif.middelschulte@gmail.com>
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..8919fc2
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,11 @@
1COMPILING and INSTALLING:
2
3If you got a official release tar archive do:
4 ./autogen.sh
5
6Then to compile:
7 make
8
9To install:
10 make install
11
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..186fae4
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,25 @@
1MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess config.h.in \
2 config.sub configure depcomp install-sh ltmain.sh \
3 missing module.desktop config.rpath mkinstalldirs
4
5SUBDIRS = src
6
7EDJE_FLAGS = -v \
8 -id $(top_srcdir)/images
9
10filesdir = $(datadir)
11files_DATA = module.desktop e-module-share.edj
12
13EXTRA_DIST = module.desktop.in \
14 e_modules-share.spec.in \
15 e-module-share.edc \
16 images/module_icon.png
17
18%.edj: %.edc
19 $(EDJE_CC) $(EDJE_FLAGS) $< $@
20
21clean-local:
22 rm -rf e-module-share.edj module.desktop e_modules-share.spec *~
23
24uninstall:
25 rm -rf $(DESTDIR)$(datadir)
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..6c6366c
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
1This module shall share data from the clipboard online.
2The 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 @@
1- Store and restore old links for every instance
2- Enable HTTPS
3
4Future:
5- Share files
6- 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 @@
1#!/bin/sh
2
3rm -rf autom4te.cache
4rm -f aclocal.m4 ltmain.sh
5
6touch README
7
8echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS || exit 1
9echo "Running autoheader..." ; autoheader || exit 1
10echo "Running autoconf..." ; autoconf || exit 1
11echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1
12echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1
13
14if [ -z "$NOCONFIGURE" ]; then
15 ./configure "$@"
16fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..4344630
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,59 @@
1dnl Process this file with autoconf to produce a configure script.
2
3# get rid of that stupid cache mechanism
4rm -f config.cache
5
6AC_INIT(share, 0.0.1, enlightenment-devel@lists.sourceforge.net)
7AC_PREREQ(2.52)
8AC_CONFIG_SRCDIR(configure.ac)
9AC_CANONICAL_BUILD
10AC_CANONICAL_HOST
11AC_ISC_POSIX
12
13AM_INIT_AUTOMAKE(1.6)
14AC_CONFIG_HEADERS(config.h)
15
16AC_PROG_CC
17AC_HEADER_STDC
18AC_C_CONST
19
20define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
21define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
22AC_PROG_LIBTOOL
23
24PKG_CHECK_MODULES(E, [enlightenment])
25release=$(pkg-config --variable=release enlightenment)
26MODULE_ARCH="$host_os-$host_cpu-$release"
27AC_SUBST(MODULE_ARCH)
28AC_DEFINE_UNQUOTED(MODULE_ARCH, "$MODULE_ARCH", "Module architecture")
29
30PKG_CHECK_MODULES(JSON, [json])
31
32# Find edje_cc
33PKG_CHECK_MODULES(EDJE, [edje >= 0.5.0])
34AC_ARG_WITH(edje-cc,
35 AC_HELP_STRING([--with-edje-cc=PATH], [specify a specific path to edje_cc]),
36 [
37 v=$withval;
38 EDJE_CC=$v
39 ],[
40 EDJE_CC=$(pkg-config --variable=prefix edje)/bin/edje_cc
41 ]
42)
43AC_SUBST(EDJE_CC)
44AC_MSG_CHECKING([Which edje_cc to use])
45AC_MSG_RESULT(${EDJE_CC})
46
47datadir=$(pkg-config --variable=modules enlightenment)/${PACKAGE}
48AC_ARG_ENABLE(homedir-install,
49 AS_HELP_STRING([--enable-homedir-install], [Install module in homedir]),
50 [ datadir="${HOME}/.e/e/modules/${PACKAGE}" ]
51)
52
53AC_OUTPUT([
54Makefile
55src/Makefile
56e_modules-share.spec
57module.desktop
58], [
59])
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 @@
1collections {
2
3 images.image: "module_icon.png" COMP;
4
5 group {
6 name: "icon";
7 max: 48 48;
8 parts {
9 part {
10 name: "image";
11 type: IMAGE;
12 mouse_events: 0;
13 description {
14 state: "default" 0.00;
15 visible: 1;
16 aspect: 1.00 1.00;
17 aspect_preference: BOTH;
18 rel1 {
19 relative: 0.00 0.00;
20 offset: 0 0;
21 }
22 rel2 {
23 relative: 1.00 1.00;
24 offset: -1 -1;
25 }
26 image.normal: "module_icon.png";
27 }
28 }
29 }
30 }
31 group {
32 name: "modules/share/main";
33 max: 128 128;
34 parts {
35 part { name: "logo";
36 type: IMAGE;
37 description { state: "default" 0.0;
38 aspect: 1.0 1.0;
39 aspect_preference: BOTH;
40 rel1.offset: 0 0;
41 rel2.offset: -1 -1;
42 image.normal: "module_icon.png";
43 }
44 description { state: "active" 0.0;
45 inherit: "default" 0.0;
46 color: 255 255 255 128;
47 }
48 }
49 part { name: "inout";
50 type: RECT;
51 mouse_events: 1;
52 description { state: "default" 0.0;
53 color: 255 255 255 0;
54 }
55 }
56 }
57 programs {
58 program { name: "go_active";
59 signal: "active";
60 source: "";
61 action: STATE_SET "active" 0.0;
62 target: "logo";
63 transition: LINEAR 0.5;
64 }
65 program { name: "go_passive";
66 signal: "passive";
67 source: "";
68 action: STATE_SET "default" 0.0;
69 target: "logo";
70 transition: LINEAR 0.5;
71 }
72 }
73 }
74}
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 @@
1%define module_name share
2%{!?_rel:%{expand:%%global _rel 0.enl%{?dist}}}
3
4Summary: %{module_name} module for the Enlightenment window manager
5Name: e_modules-%{module_name}
6Version: @VERSION@
7Release: %{_rel}
8License: BSD
9Group: User Interface/Desktops
10URL: http://www.enlightenment.org/
11Source: ftp://ftp.enlightenment.org/pub/enlightenment/%{module_name}-%{version}.tar.gz
12Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings <mej@eterm.org>}
13Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)}
14Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}}
15BuildRequires: ecore-devel, evas-devel, edje-bin
16BuildRequires: edje-devel, eet-devel, enlightenment-devel >= 0.16.999
17Requires: enlightenment >= 0.16.999
18BuildRoot: %{_tmppath}/%{name}-%{version}-root
19
20%description
21%{module_name} module for the Enlightenment window manager.
22
23%prep
24%setup -q -n %{module_name}-%{version}
25
26%build
27%{configure}
28%{__make} %{?_smp_mflags} %{?mflags}
29
30%install
31%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install
32%{find_lang} %{module_name} || true > %{module_name}.lang
33
34%clean
35test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT
36
37%post
38/sbin/ldconfig
39
40%postun
41/sbin/ldconfig
42
43%files -f %{module_name}.lang
44%defattr(-, root, root)
45%doc AUTHORS ChangeLog COPYING* INSTALL NEWS README
46%{_libdir}/enlightenment/modules/%{module_name}*
47
48%changelog
diff --git a/images/module_icon.png b/images/module_icon.png
new file mode 100644
index 0000000..42d4f00
--- /dev/null
+++ b/images/module_icon.png
Binary files differ
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 @@
1<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="95.421px" height="90.213px" viewBox="0 0 95.421 90.213" enable-background="new 0 0 95.421 90.213" xml:space="preserve">
2<path d="M6.301,90.211C2.818,90.209,0.002,87.394,0,83.913l0,0V18.394c0.002-3.481,2.818-6.297,6.301-6.299l0,0h33.782l-9.003,9H9 v60.117l57.469,0.002V69.125l9.002-9l-0.002,23.788c-0.003,3.479-2.818,6.296-6.3,6.3l0,0L6.301,90.211L6.301,90.211z"/>
3<path d="M66.171,11.301V0l29.25,29.25L66.046,58.625v-11.75c0,0-14.586-2.894-29.583,6.458 c-8.209,5.084-13.752,11.773-17.167,17.042c0,0,1.11-18.25,11.61-34.875C44.033,14.716,66.171,11.301,66.171,11.301z"/>
4<path fill="#000000" d="M225.3,90.211c-3.482-0.002-6.299-2.817-6.301-6.298l0,0V18.394c0.002-3.481,2.818-6.297,6.301-6.299l0,0 h33.783l-9.004,9H228v60.117l57.47,0.002V69.125l9.002-9l-0.002,23.788c-0.003,3.479-2.818,6.296-6.3,6.3l0,0L225.3,90.211 L225.3,90.211z"/>
5<path fill="#000000" d="M285.171,11.301V0l29.25,29.25l-29.375,29.375v-11.75c0,0-17.23-1.192-29.584,6.458 c-8.209,5.084-13.104,10.167-17.166,17.042c0,0,1.109-18.25,11.609-34.875C263.033,14.716,285.171,11.301,285.171,11.301z"/>
6</svg> \ No newline at end of file
diff --git a/m4/.svnignore b/m4/.svnignore
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/m4/.svnignore
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 @@
1[Desktop Entry]
2Type=Link
3Name=Share
4Icon=e-module-share
5X-Enlightenment-ModuleType=utils
6Comment=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..87ed16d
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,21 @@
1MAINTAINERCLEANFILES = Makefile.in
2
3INCLUDES = -I. \
4 -I$(top_srcdir) \
5 -I$(includedir) \
6 @E_CFLAGS@ \
7 @JSON_CFLAGS@
8
9pkgdir = $(datadir)/$(MODULE_ARCH)
10pkg_LTLIBRARIES = module.la
11module_la_SOURCES = e_mod_main.c \
12 e_mod_main.h \
13 e_share.h \
14 sourcedrop.c
15
16module_la_LIBADD = @E_LIBS@ @JSON_LIBS@ -lm -lbsd
17module_la_LDFLAGS = -module -avoid-version
18module_la_DEPENDENCIES = $(top_builddir)/config.h
19
20clean-local:
21 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 @@
1#include "e_mod_main.h"
2#include "e_share.h"
3#include <string.h>
4
5#define __UNUSED__
6#define _(S) S
7
8/* actual module specifics */
9typedef struct _Instance Instance;
10struct _Instance
11{
12 E_Gadcon_Client *gcc;
13 E_Menu *menu;
14 Ecore_X_Window win;
15 Evas_Object *o_button;
16 Eina_List *handlers;
17 Eina_List *shares;
18};
19
20/* gadcon requirements */
21static E_Gadcon_Client *_gc_init(E_Gadcon * gc, const char *name, const char *id, const char *style);
22static void _gc_shutdown(E_Gadcon_Client * gcc);
23static void _gc_orient(E_Gadcon_Client * gcc, E_Gadcon_Orient orient);
24static const char *_gc_label(const E_Gadcon_Client_Class *client_class);
25static Evas_Object *_gc_icon(const E_Gadcon_Client_Class *client_class, Evas * evas);
26static const char *_gc_id_new(const E_Gadcon_Client_Class *client_class);
27
28static void _share_button_cb_mouse_down(void *data, Evas *evas, Evas_Object *obj, Evas_Event_Mouse_Down *ev);
29static Eina_Bool _share_x_selection_notify_handler(Instance *instance, int type, void *event);
30static void _share_menu_post_cb(void *data, E_Menu *menu __UNUSED__);
31static void _share_menu_share_request_click_cb(Instance *inst, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__);
32static void _share_menu_share_item_click_cb(Share_Data *selected_share, E_Menu *m, E_Menu_Item *mi);
33static void _share_open_link_in_browser(const Share_Data *sd);
34static void _share_notify(const Share_Data *sd);
35static void _share_notification_clicked_cb(void *data, unsigned int id);
36static void _free_share_data(Share_Data *sd);
37
38static E_Module *share_module = NULL;
39
40/* and actually define the gadcon class that this module provides (just 1) */
41static const E_Gadcon_Client_Class _gadcon_class = {
42 GADCON_CLIENT_CLASS_VERSION,
43 "share",
44 {
45 _gc_init, _gc_shutdown, _gc_orient, _gc_label, _gc_icon, _gc_id_new, NULL,
46 e_gadcon_site_is_not_toolbar
47 },
48 E_GADCON_CLIENT_STYLE_PLAIN
49};
50
51static E_Gadcon_Client *
52_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
53{
54 Evas_Object *o;
55 E_Gadcon_Client *gcc;
56 Instance *inst;
57
58 inst = E_NEW(Instance, 1);
59
60 /*
61 char buf[PATH_MAX];
62 snprintf(buf, sizeof(buf), "%s/e-module-share.edj", e_module_dir_get(share_module));
63
64 o = edje_object_add(gc->evas);
65 if (!e_theme_edje_object_set(o, "base/theme/modules/share", "modules/share/main"))
66 edje_object_file_set(o, buf, "modules/share/main");
67 edje_object_signal_emit(o, "passive", "");
68 */
69
70 o = e_icon_add(gc->evas);
71 e_icon_fdo_icon_set(o, "emblem-shared");
72 evas_object_show(o);
73
74 gcc = e_gadcon_client_new(gc, name, id, style, o);
75 gcc->data = inst;
76
77 inst->gcc = gcc;
78 inst->win = ecore_evas_window_get(gc->ecore_evas);
79 inst->o_button = o;
80
81 e_gadcon_client_util_menu_attach(gcc);
82
83 evas_object_event_callback_add(inst->o_button, EVAS_CALLBACK_MOUSE_DOWN, (Evas_Object_Event_Cb)_share_button_cb_mouse_down, inst);
84 E_LIST_HANDLER_APPEND(inst->handlers, ECORE_X_EVENT_SELECTION_NOTIFY, _share_x_selection_notify_handler, inst);
85
86 return gcc;
87}
88
89static void
90_gc_shutdown(E_Gadcon_Client *gcc)
91{
92 Instance *inst;
93
94 inst = gcc->data;
95 E_FREE_LIST(inst->handlers, ecore_event_handler_del);
96 inst->handlers = NULL;
97
98 if (inst->menu)
99 {
100 e_menu_post_deactivate_callback_set(inst->menu, NULL, NULL);
101 e_object_del(E_OBJECT(inst->menu));
102 inst->menu = NULL;
103 }
104
105 E_FREE_LIST(inst->shares, _free_share_data);
106 inst->shares = NULL;
107
108 evas_object_del(inst->o_button);
109 E_FREE(inst);
110}
111
112static void
113_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient)
114{
115 e_gadcon_client_aspect_set (gcc, 16, 16);
116 e_gadcon_client_min_size_set (gcc, 16, 16);
117}
118
119static const char *
120_gc_label (const E_Gadcon_Client_Class *client_class)
121{
122 return "Share";
123}
124
125static Evas_Object *
126_gc_icon(const E_Gadcon_Client_Class *client_class, Evas * evas)
127{
128 Evas_Object *o;
129 /*
130 char buf[PATH_MAX];
131
132 o = edje_object_add(evas);
133 snprintf (buf, sizeof(buf), "%s/e-module-share.edj", e_module_dir_get(share_module));
134 edje_object_file_set(o, buf, "icon");
135 */
136
137 o = e_icon_add(evas);
138 e_icon_fdo_icon_set(o, "emblem-shared");
139
140 return o;
141}
142
143static const char *
144_gc_id_new (const E_Gadcon_Client_Class *client_class)
145{
146 return _gadcon_class.name;
147}
148
149static void
150_share_button_cb_mouse_down(void *data, Evas *evas, Evas_Object *obj, Evas_Event_Mouse_Down *ev)
151{
152 Instance *inst = (Instance*)data;
153 Evas_Coord x, y, w, h;
154 int cx, cy;
155 int dir;
156 E_Menu_Item *mi;
157 Eina_List *it;
158 Share_Data *share;
159
160 if (!inst) return;
161
162 if ((ev->button == 1) && (!inst->menu))
163 {
164 /* Coordinates and sizing */
165 evas_object_geometry_get(inst->o_button, &x, &y, &w, &h);
166 e_gadcon_canvas_zone_geometry_get(inst->gcc->gadcon, &cx, &cy,
167 NULL, NULL);
168 x += cx;
169 y += cy;
170
171 inst->menu = e_menu_new();
172
173 mi = e_menu_item_new(inst->menu);
174 e_menu_item_label_set(mi, _("Share Clipboard Content"));
175 e_menu_item_callback_set(mi, (E_Menu_Cb)_share_menu_share_request_click_cb, inst);
176
177 mi = e_menu_item_new(inst->menu);
178 e_menu_item_separator_set(mi, EINA_TRUE);
179
180 EINA_LIST_FOREACH(inst->shares, it, share)
181 {
182 mi = e_menu_item_new(inst->menu);
183 e_menu_item_label_set(mi, share->name);
184 e_menu_item_callback_set(mi, (E_Menu_Cb)_share_menu_share_item_click_cb, share);
185 }
186
187 e_menu_post_deactivate_callback_set(inst->menu,
188 _share_menu_post_cb, inst);
189
190 /* Proper menu orientation */
191 switch (inst->gcc->gadcon->orient)
192 {
193 case E_GADCON_ORIENT_TOP:
194 case E_GADCON_ORIENT_CORNER_TL:
195 case E_GADCON_ORIENT_CORNER_TR:
196 dir = E_MENU_POP_DIRECTION_DOWN;
197 break;
198
199 case E_GADCON_ORIENT_BOTTOM:
200 case E_GADCON_ORIENT_CORNER_BL:
201 case E_GADCON_ORIENT_CORNER_BR:
202 dir = E_MENU_POP_DIRECTION_UP;
203 break;
204
205 case E_GADCON_ORIENT_LEFT:
206 case E_GADCON_ORIENT_CORNER_LT:
207 case E_GADCON_ORIENT_CORNER_LB:
208 dir = E_MENU_POP_DIRECTION_RIGHT;
209 break;
210
211 case E_GADCON_ORIENT_RIGHT:
212 case E_GADCON_ORIENT_CORNER_RT:
213 case E_GADCON_ORIENT_CORNER_RB:
214 dir = E_MENU_POP_DIRECTION_LEFT;
215 break;
216
217 case E_GADCON_ORIENT_FLOAT:
218 case E_GADCON_ORIENT_HORIZ:
219 case E_GADCON_ORIENT_VERT:
220 default:
221 dir = E_MENU_POP_DIRECTION_AUTO;
222 break;
223 }
224
225 e_gadcon_locked_set(inst->gcc->gadcon, EINA_TRUE);
226
227 /* We display not relatively to the gadget, but similarly to
228 * the start menu - thus the need for direction etc.
229 */
230 e_menu_activate_mouse(inst->menu,
231 e_util_zone_current_get
232 (e_manager_current_get()),
233 x, y, w, h, dir, ev->timestamp);
234 }
235}
236
237static Eina_Bool
238_share_x_selection_notify_handler(Instance *instance, int type, void *event)
239{
240 Ecore_X_Event_Selection_Notify *ev;
241 Share_Data *sd = NULL;
242
243 if (!instance)
244 return EINA_TRUE;
245
246 ev = event;
247 if ((ev->selection == ECORE_X_SELECTION_CLIPBOARD) &&
248 (strcmp(ev->target, ECORE_X_SELECTION_TARGET_UTF8_STRING) == 0))
249 {
250 Ecore_X_Selection_Data_Text *text_data;
251
252 text_data = ev->data;
253 if ((text_data->data.content == ECORE_X_SELECTION_CONTENT_TEXT) &&
254 (text_data->text))
255 {
256 char buf[20];
257 if (text_data->data.length == 0) return EINA_TRUE;
258
259 sd = E_NEW(Share_Data, 1);
260 sd->inst = instance;
261 snprintf(buf, ((text_data->data.length >= sizeof(buf)) ? (sizeof(buf) - 1) : text_data->data.length), text_data->text);
262 asprintf(&sd->name, "%s", buf);
263 asprintf(&sd->content, "%s", text_data->text);
264
265 sourcedrop_share(sd);
266 }
267 }
268
269 return ECORE_CALLBACK_PASS_ON;
270}
271
272/* Updates the X selection with the selected text of the entry */
273void
274_clipboard_update(const char *text, const Instance *inst)
275{
276 EINA_SAFETY_ON_NULL_RETURN(inst);
277 EINA_SAFETY_ON_NULL_RETURN(text);
278
279 ecore_x_selection_clipboard_set(inst->win, text, strlen(text) + 1);
280}
281
282void e_share_upload_completed(Share_Data *sd)
283{
284 if (!sd) return;
285 ((Instance*)sd->inst)->shares = eina_list_append(((Instance*)sd->inst)->shares, sd);
286 _share_notify(sd);
287 _clipboard_update(sd->url, sd->inst);
288}
289
290static void
291_share_menu_share_request_click_cb(Instance *inst, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
292{
293 if (!inst) return;
294 ecore_x_selection_clipboard_request(inst->win,
295 ECORE_X_SELECTION_TARGET_UTF8_STRING);
296}
297
298static void
299_share_menu_share_item_click_cb(Share_Data *selected_share, E_Menu *m __UNUSED__, E_Menu_Item *mi __UNUSED__)
300{
301 _share_open_link_in_browser(selected_share);
302}
303
304static void
305_share_notify(const Share_Data *sd)
306{
307 char buf[256];
308 E_Notification_Notify *n = E_NEW(E_Notification_Notify, 1);
309
310 if (!sd || !n)
311 return;
312 n->id = 0;
313 n->app_name = _("E Share");
314 n->sumary = _("Your content has been shared.");
315 snprintf(buf, (sizeof(buf) - 1), _("Your clipboard's content is now available at <highlight>%s</highlight>."), sd->url);
316 n->body = buf;
317 n->icon.icon = "e";
318 n->timeout = 2;
319 e_notification_client_send(n, NULL /*_share_notification_clicked_cb*/, sd);
320}
321
322static void
323_share_open_link_in_browser(const Share_Data *sd)
324{
325 char buf[256];
326
327 if (!sd)
328 return;
329 snprintf(buf, (sizeof(buf) - 1), "xdg-open %s", sd->url);
330 e_exec(e_gadcon_client_zone_get(((Instance*)sd->inst)->gcc), NULL, buf, NULL, NULL);
331}
332
333static void
334_share_notification_clicked_cb(void *data, unsigned int id)
335{
336 if (!data)
337 return;
338 _share_open_link_in_browser((Share_Data*)data);
339}
340
341static void
342_share_menu_post_cb(void *data, E_Menu *menu __UNUSED__)
343{
344 Instance *inst = data;
345
346 if (!inst) return;
347 e_gadcon_locked_set(inst->gcc->gadcon, EINA_FALSE);
348 inst->menu = NULL;
349}
350
351static void _free_share_data(Share_Data *sd)
352{
353 free(sd->name);
354 free(sd->content);
355 free(sd->url);
356 free(sd);
357}
358
359/* module setup */
360EAPI E_Module_Api e_modapi = {
361 E_MODULE_API_VERSION,
362 "Share"
363};
364
365EAPI void *
366e_modapi_init (E_Module * m)
367{
368 share_module = m;
369 sourcedrop_init();
370 e_gadcon_provider_register(&_gadcon_class);
371 return share_module;
372}
373
374EAPI int
375e_modapi_shutdown (E_Module * m)
376{
377 sourcedrop_shutdown();
378 share_module = NULL;
379 e_gadcon_provider_unregister(&_gadcon_class);
380 return 1;
381}
382
383EAPI int
384e_modapi_save(E_Module * m)
385{
386 return 1;
387}
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 @@
1#ifndef E_MOD_MAIN_H
2#define E_MOD_MAIN_H
3
4#include <e.h>
5
6EAPI extern E_Module_Api e_modapi;
7
8EAPI void *e_modapi_init (E_Module *m);
9EAPI int e_modapi_shutdown (E_Module *m);
10EAPI int e_modapi_save (E_Module *m);
11
12#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 @@
1#ifndef __E_SHARE_H__
2#define __E_SHARE_H__
3
4#undef LOG
5#define LOG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
6
7typedef struct _Share_Data {
8 void *inst;
9 char *name;
10 char *content;
11 char *url;
12} Share_Data;
13
14/* API used by submodules */
15void e_share_upload_completed(Share_Data *share_data);
16
17/* Submodules' functions */
18void sourcedrop_init(void);
19void sourcedrop_share(Share_Data *share_data);
20void sourcedrop_shutdown(void);
21
22#endif
diff --git a/src/sourcedrop.c b/src/sourcedrop.c
new file mode 100644
index 0000000..274457c
--- /dev/null
+++ b/src/sourcedrop.c
@@ -0,0 +1,124 @@
1#include <ctype.h>
2#include <json/json.h>
3#include <bsd/string.h>
4
5#include "e_mod_main.h"
6#include "e_share.h"
7
8#define BUFFER_SIZE_MAX 4096
9#define DROPNAME "Sourcedrop"
10#define SOURCEDROP_URL "http://www.sourcedrop.net/paste"
11#define RECOGNITION_STRING "Location: "
12
13static Ecore_Event_Handler *handler = NULL;
14
15static Eina_Bool __upload_completed_cb(void *data, int type, Ecore_Con_Event_Url_Complete *ev);
16static json_object *jarray, *jparent;
17
18/* Converts an integer value to its hex character*/
19char to_hex(const char code) {
20 static char hex[] = "0123456789abcdef";
21 return hex[code & 15];
22}
23
24/* Returns a url-encoded version of str */
25/* IMPORTANT: be sure to free() the returned string after use */
26char *url_encode(const char *str) {
27 const char *pstr = str;
28 char *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf;
29 while (*pstr) {
30 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~')
31 *pbuf++ = *pstr;
32 else if (*pstr == ' ')
33 *pbuf++ = '+';
34 else
35 *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
36 pstr++;
37 }
38 *pbuf = '\0';
39 return buf;
40}
41
42const char *json_encode(const char *title, const char *content)
43{
44 const char *encoded_string = NULL;
45
46 jarray = json_object_new_array();
47 jparent = json_object_new_object();
48 json_object_object_add(jparent, "title", json_object_new_string(title));
49 json_object_object_add(jparent, "content", json_object_new_string(content));
50 json_object_array_add(jarray, jparent);
51
52 encoded_string = json_object_to_json_string(jarray);
53
54 return encoded_string;
55}
56
57static Eina_Bool
58__upload_completed_cb(void *data, int type, Ecore_Con_Event_Url_Complete *ev)
59{
60 char buf[BUFFER_SIZE_MAX];
61 const Eina_List *headers = NULL, *it;
62 const char *header = NULL;
63 Share_Data *sd = NULL;
64
65 json_object_put(jarray);
66 jarray = NULL;
67 json_object_put(jparent);
68 jparent = NULL;
69
70 if (ev->status != 200)
71 {
72 LOG("E_SHARE/" DROPNAME ": This is not supposed to happen. The server returned status code: %d\n", ev->status);
73 return ECORE_CALLBACK_RENEW;
74 }
75
76 headers = ecore_con_url_response_headers_get(ev->url_con);
77 EINA_LIST_FOREACH(headers, it, header)
78 {
79 if (strncmp(header, RECOGNITION_STRING, (sizeof(RECOGNITION_STRING) - 1)) == 0)
80 {
81 sd = ecore_con_url_data_get(ev->url_con);
82 strlcpy(buf, (char*)(header + sizeof(RECOGNITION_STRING) - 1), sizeof(buf));
83 asprintf(&sd->url, "%s", buf);
84 e_share_upload_completed(sd);
85 ecore_con_url_free(ev->url_con);
86 break;
87 }
88 }
89
90 return ECORE_CALLBACK_CANCEL;
91}
92
93void sourcedrop_share(Share_Data *sd)
94{
95 Ecore_Con_Url *request_url = NULL;
96 char post_data[BUFFER_SIZE_MAX];
97 const char *json_encoded = NULL;
98 char *url_encoded = NULL;
99
100 EINA_SAFETY_ON_NULL_RETURN(sd);
101
102 json_encoded = json_encode(sd->name, sd->content);
103 request_url = ecore_con_url_new(SOURCEDROP_URL);
104 url_encoded = url_encode(json_encoded);
105 snprintf(post_data, (sizeof(post_data) - 1), "data=%s", url_encoded);
106 free(url_encoded);
107 ecore_con_url_data_set(request_url, (void*)sd);
108 ecore_con_url_post(request_url, (void*)post_data, sizeof(post_data), "application/x-www-form-urlencoded");
109}
110
111void sourcedrop_init(void)
112{
113 ecore_init();
114 ecore_con_init();
115 handler = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, (Ecore_Event_Handler_Cb)__upload_completed_cb, NULL);
116}
117
118void sourcedrop_shutdown(void)
119{
120 ecore_event_handler_del(handler);
121 handler = NULL;
122 ecore_con_shutdown();
123 ecore_shutdown();
124}