diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..ee22837 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Tom Hacohen diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..189a6b6 --- /dev/null +++ b/COPYING @@ -0,0 +1,25 @@ +Copyright notice for Clouseau: + +Copyright (C) 2000-2011 Tom Hacohen and various contributors (see AUTHORS) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..5209bd8 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,10 @@ + +MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ + config.h.in config.sub configure install-sh \ + depcomp libtool missing + +EXTRA_DIST = README AUTHORS COPYING + +SUBDIRS = src + +ACLOCAL_AMFLAGS = -I m4 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..26a214f --- /dev/null +++ b/README @@ -0,0 +1,4 @@ +Just run your wanted ecore/elm based app with this lib in LD_PRELOAD, e.g: +LD_PRELOAD=/usr/lib/clouseau/libclouseau.so elementary_test + +Click "Load" and the rest is straightforward. diff --git a/TODO b/TODO new file mode 100644 index 0000000..f04e124 --- /dev/null +++ b/TODO @@ -0,0 +1,9 @@ +* Make it an elm module (or setting an env var without a module?) so I'll be able to remotely connect to elm apps. +* Split UI and actual program code (better to do the previous bullet first on the bullet above). +* Add "grab screenshot" button. +* Add a clipping range rectangle. +* Add special per object info, for example edje part names? + +* Things to show per-object + * clipping info. + * callback list? diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..cf63ef1 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +rm -rf autom4te.cache +rm -f aclocal.m4 ltmain.sh + +echo "Running aclocal..." ; aclocal -I m4 $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..84412eb --- /dev/null +++ b/configure.ac @@ -0,0 +1,43 @@ +AC_INIT(clouseau, 0.1.0, tom@stosb.com) +AC_PREREQ(2.52) +AC_CONFIG_SRCDIR(configure.ac) +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +AC_CANONICAL_TARGET + +AM_INIT_AUTOMAKE(1.6 dist-bzip2) +AM_CONFIG_HEADER(config.h) + +AC_PROG_LIBTOOL + +dnl Checking for __attribute__ support +AC_MSG_CHECKING([for __attribute__]) +AC_CACHE_VAL(_cv_have___attribute__, + [ + AC_TRY_COMPILE([#include ], + [int func(int x); int foo(int x __attribute__ ((unused))) { exit(1); }], + [_cv_have___attribute__="yes"], + [_cv_have___attribute__="no"]) + ] +) + +if test "x${_cv_have___attribute__}" = "xyes" ; then + AC_DEFINE(HAVE___ATTRIBUTE__, 1, [Define to 1 if your compiler has __attribute__]) +fi +AC_MSG_RESULT(${_cv_have___attribute__}) + +PKG_CHECK_MODULES(EFL, + [ + elementary >= 0.7.0 + evas >= 1.0.0 + ] +) + +AC_CHECK_LIB(dl,dlopen) +AC_CHECK_FUNCS(dlopen dlerror) + +AC_OUTPUT([ + Makefile + src/Makefile + src/lib/Makefile + ]) diff --git a/make.sh b/make.sh new file mode 100755 index 0000000..d1f4e60 --- /dev/null +++ b/make.sh @@ -0,0 +1,4 @@ +#!/bin/sh +gcc -Wall -Wextra -fPIC -rdynamic -g3 -O0 -c libclouseau.c `pkg-config --libs --cflags elementary ecore evas` +gcc -g3 -O0 -shared -Wl,-soname,libclouseau.so.1 -o libclouseau.so.1.0.1 libclouseau.o -lc -ldl `pkg-config --libs --cflags elementary` + diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..a587cac --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,4 @@ + +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = lib diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 0000000..93739e5 --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,21 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I$(top_srcdir)/src/include \ +-I$(top_builddir)/src/include \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +@EFL_CFLAGS@ + +EXTRA_DIST = + +pkgdir = $(libdir)/clouseau +pkg_LTLIBRARIES = libclouseau.la + +libclouseau_la_SOURCES = libclouseau.c + +libclouseau_la_LDFLAGS = -module -avoid-version -rdynamic +libclouseau_la_DEPENDENCIES = $(top_builddir)/config.h +libclouseau_la_LIBADD = @EFL_LIBS@ +libclouseau_la_CFLAGS = @EFL_CFLAGS@ diff --git a/src/lib/libclouseau.c b/src/lib/libclouseau.c new file mode 100644 index 0000000..e2ea5c0 --- /dev/null +++ b/src/lib/libclouseau.c @@ -0,0 +1,448 @@ +#define _GNU_SOURCE 1 +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#define ELM_INTERNAL_API_ARGESFSDFEFC +#include + +#include "config.h" + +#ifdef HAVE___ATTRIBUTE__ +# define __UNUSED__ __attribute__((unused)) +#else +# define __UNUSED__ +#endif + +static Elm_Genlist_Item_Class itc, itc_ee; +static Eina_Bool _lib_init = EINA_FALSE; +static Eina_List *tree = NULL; +static Evas_Object *prop_list; + +static void libclouseau_highlight(Evas_Object *addr); +static Eina_Bool libclouseau_highlight_fade(void *rv); + +typedef struct _Tree_Item Tree_Item; +struct _Tree_Item +{ + Tree_Item *parent; + Eina_List *children; + union { + Ecore_Evas *ee; + Evas_Object *obj; + } data; +}; + +static void +_item_tree_item_free(Tree_Item *parent) +{ + Tree_Item *treeit; + + EINA_LIST_FREE(parent->children, treeit) + { + _item_tree_item_free(treeit); + } + + free(parent); +} + +static void +_item_tree_free(void) +{ + Tree_Item *treeit; + + EINA_LIST_FREE(tree, treeit) + { + _item_tree_item_free(treeit); + } +} + +static char * +item_label_get(void *data, Evas_Object *obj __UNUSED__, + const char *part __UNUSED__) +{ + Tree_Item *treeit = data; + char buf[256]; + if (elm_widget_is(treeit->data.obj)) + { + snprintf(buf, sizeof(buf), "%p %s (%s)", treeit->data.obj, + elm_widget_type_get(treeit->data.obj), + evas_object_type_get(treeit->data.obj)); + } + else + { + snprintf(buf, sizeof(buf), "%p %s", treeit->data.obj, + evas_object_type_get(treeit->data.obj)); + } + return strdup(buf); +} + +static char * +item_ee_label_get(void *data, Evas_Object *obj __UNUSED__, + const char *part __UNUSED__) +{ + Tree_Item *treeit = data; + char buf[256]; + snprintf(buf, sizeof(buf), "%p %s", treeit->data.ee, + ecore_evas_title_get(treeit->data.ee)); + return strdup(buf); +} + +static void +_gl_selected(void *data __UNUSED__, Evas_Object *pobj __UNUSED__, + void *event_info) +{ + elm_list_clear(prop_list); + + /* If not an object, return. */ + if (!elm_genlist_item_parent_get(event_info)) + return; + + Tree_Item *treeit = elm_genlist_item_data_get(event_info); + Evas_Object *obj = treeit->data.obj; + libclouseau_highlight(obj); + /* Populate properties list */ + { + char buf[1024]; + Eina_Bool visibility; + Evas_Coord x, y, w, h; + double dx, dy; + + visibility = evas_object_visible_get(obj); + snprintf(buf, sizeof(buf), "Visibility: %d", (int) visibility); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + + snprintf(buf, sizeof(buf), "Layer: %hd", + evas_object_layer_get(obj)); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + + evas_object_geometry_get(obj, &x, &y, &w, &h); + snprintf(buf, sizeof(buf), "Position: %d %d", x, y); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + snprintf(buf, sizeof(buf), "Size: %d %d", w, h); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + +#if 0 + if (evas_object_clip_get(obj)) + { + evas_object_geometry_get( + evas_object_clip_get(obj), &x, &y, &w, &h); + snprintf(buf, sizeof(buf), "Clipper position: %d %d", x, y); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + snprintf(buf, sizeof(buf), "Clipper size: %d %d", w, h); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + } +#endif + + evas_object_size_hint_min_get(obj, &w, &h); + snprintf(buf, sizeof(buf), "Min size: %d %d", w, h); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + + evas_object_size_hint_max_get(obj, &w, &h); + snprintf(buf, sizeof(buf), "Max size: %d %d", w, h); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + + evas_object_size_hint_request_get(obj, &w, &h); + snprintf(buf, sizeof(buf), "Request size: %d %d", w, h); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + + evas_object_size_hint_align_get(obj, &dx, &dy); + snprintf(buf, sizeof(buf), "Align: %.6lg %.6lg", dx, dy); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + + evas_object_size_hint_weight_get(obj, &dx, &dy); + snprintf(buf, sizeof(buf), "Weight: %.6lg %.6lg", dx, dy); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + + /* Handle color */ + { + int r, g, b, a; + evas_object_color_get(obj, &r, &g, &b, &a); + snprintf(buf, sizeof(buf), "Color: %d %d %d %d", r, g, b, a); + elm_list_item_append(prop_list, buf, NULL, NULL, NULL, NULL); + } + elm_list_go(prop_list); + } +} + +static void +gl_exp(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Elm_Genlist_Item *it = event_info; + Evas_Object *gl = elm_genlist_item_genlist_get(it); + Tree_Item *parent = elm_genlist_item_data_get(it); + Tree_Item *treeit; + Eina_List *itr; + + EINA_LIST_FOREACH(parent->children, itr, treeit) + { + Elm_Genlist_Item_Flags iflag = (treeit->children) ? + ELM_GENLIST_ITEM_SUBITEMS : ELM_GENLIST_ITEM_NONE; + elm_genlist_item_append(gl, &itc, treeit, it, iflag, + _gl_selected, NULL); + } +} + +static void +gl_con(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Elm_Genlist_Item *it = event_info; + elm_genlist_item_subitems_clear(it); +} + +static void +gl_exp_req(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Elm_Genlist_Item *it = event_info; + elm_genlist_item_expanded_set(it, EINA_TRUE); +} + +static void +gl_con_req(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info) +{ + Elm_Genlist_Item *it = event_info; + elm_genlist_item_expanded_set(it, EINA_FALSE); +} + +static void +libclouseau_item_add(Evas_Object *o, Evas_Object *gl, Tree_Item *parent) +{ + Eina_List *children, *tmp; + Evas_Object *child; + Tree_Item *treeit; + + treeit = calloc(1, sizeof(*treeit)); + treeit->data.obj = o; + treeit->parent = parent; + parent->children = eina_list_append(parent->children, treeit); + + children = evas_object_smart_members_get(o); + EINA_LIST_FOREACH(children, tmp, child){ + libclouseau_item_add(child, gl, treeit); + } +} + +static void +_load_list(Evas_Object *gl) +{ + Eina_List *os, *ot; + Evas_Object *o; + Eina_List *ees,*l; + Ecore_Evas *ee, *this_ee; + + elm_genlist_clear(gl); + _item_tree_free(); + + ees = ecore_evas_ecore_evas_list_get(); + + this_ee = ecore_evas_ecore_evas_get( + evas_object_evas_get(elm_object_top_widget_get(gl))); + + EINA_LIST_FOREACH(ees, l, ee) + { + if (this_ee == ee) + continue; + Tree_Item *treeit; + + Evas *e; + int w, h; + e = ecore_evas_get(ee); + evas_output_size_get(e, &w, &h); + + treeit = calloc(1, sizeof(*treeit)); + treeit->data.ee = ee; + + tree = eina_list_append(tree, treeit); + + os = evas_objects_in_rectangle_get(e, SHRT_MIN, SHRT_MIN, + USHRT_MAX, USHRT_MAX, EINA_TRUE, EINA_TRUE); + EINA_LIST_FOREACH(os, ot, o){ + libclouseau_item_add(o, gl, treeit); + } + + /* Insert the base ee items */ + { + Elm_Genlist_Item_Flags glflag = (treeit->children) ? + ELM_GENLIST_ITEM_SUBITEMS : ELM_GENLIST_ITEM_NONE; + elm_genlist_item_append(gl, &itc_ee, treeit, NULL, + glflag, NULL, NULL); + } + } +} + +static void +_bt_clicked(void *data, Evas_Object *obj, void *event_info __UNUSED__) +{ + elm_object_text_set(obj, "Reload"); + _load_list(data); +} + +void +libclouseau_init(void) +{ + Evas_Object *win, *bg, *panes, *bx, *bt; + + win = elm_win_add(NULL, PACKAGE_NAME, ELM_WIN_BASIC); + elm_win_autodel_set(win, EINA_TRUE); + elm_win_title_set(win, PACKAGE_NAME); + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + bx = elm_box_add(win); + evas_object_size_hint_weight_set(bx, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(bx, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_win_resize_object_add(win, bx); + evas_object_show(bx); + + bt = elm_button_add(win); + evas_object_size_hint_align_set(bt, 0.0, 0.5); + elm_object_text_set(bt, "Load"); + elm_box_pack_end(bx, bt); + evas_object_show(bt); + + panes = elm_panes_add(win); + evas_object_size_hint_weight_set(panes, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(panes, EVAS_HINT_FILL, EVAS_HINT_FILL); + elm_box_pack_end(bx, panes); + evas_object_show(panes); + + /* The list main */ + { + Evas_Object *gl; + + gl = elm_genlist_add(panes); + evas_object_size_hint_align_set(gl, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set(gl, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_panes_content_left_set(panes, gl); + evas_object_show(gl); + + evas_object_smart_callback_add(bt, "clicked", _bt_clicked, gl); + + itc_ee.item_style = "default"; + itc_ee.func.label_get = item_ee_label_get; + itc_ee.func.icon_get = NULL; + itc_ee.func.state_get = NULL; + itc_ee.func.del = NULL; + + itc.item_style = "default"; + itc.func.label_get = item_label_get; + itc.func.icon_get = NULL; + itc.func.state_get = NULL; + itc.func.del = NULL; + + evas_object_smart_callback_add(gl, "expand,request", gl_exp_req, gl); + evas_object_smart_callback_add(gl, "contract,request", gl_con_req, gl); + evas_object_smart_callback_add(gl, "expanded", gl_exp, gl); + evas_object_smart_callback_add(gl, "contracted", gl_con, gl); + evas_object_smart_callback_add(gl, "selected", _gl_selected, NULL); + } + + /* Properties list */ + { + prop_list = elm_list_add(panes); + evas_object_size_hint_align_set(prop_list, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set(prop_list, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + + elm_panes_content_right_set(panes, prop_list); + evas_object_show(prop_list); + } + + evas_object_resize(win, 500, 500); + evas_object_show(win); +} + +/* Hook on the main loop + * We only do something here if we didn't already go into elm_init, + * which probably means we are not using elm. */ +void +ecore_main_loop_begin(void) +{ + Eina_Bool _is_init = _lib_init; + void (*_ecore_main_loop_begin)(void) = + dlsym(RTLD_NEXT, "ecore_main_loop_begin"); + + if (!_is_init) + { + /* Make sure we init elementary, wouldn't be needed once we + * take away the ui to another proc. */ + elm_init(0, NULL); + + libclouseau_init(); + } + + _lib_init = EINA_TRUE; + _ecore_main_loop_begin(); + + return; +} + + +/* HIGHLIGHT code. */ + +/* The color of the highlight */ +enum { + HIGHLIGHT_R = 255, + HIGHLIGHT_G = 128, + HIGHLIGHT_B = 128, + HIGHLIGHT_A = 255, + + /* How much padding around the highlight box. + * Currently we don't want any. */ + PADDING = 0, +}; + +static void +libclouseau_highlight(Evas_Object *obj) +{ + Evas *e; + Evas_Object *r; + int x, y, w, h; + + e = evas_object_evas_get(obj); + if (!e) return; + + evas_object_geometry_get(obj, &x, &y, &w, &h); + + r = evas_object_rectangle_add(e); + evas_object_move(r, x - PADDING, y - PADDING); + evas_object_resize(r, w + (2 * PADDING), h + (2 * PADDING)); + evas_object_color_set(r, HIGHLIGHT_R, HIGHLIGHT_G, HIGHLIGHT_B, + HIGHLIGHT_A); + evas_object_show(r); + ecore_timer_add(0.1, libclouseau_highlight_fade, r); +} + +static Eina_Bool +libclouseau_highlight_fade(void *_rect) +{ + Evas_Object *rect = _rect; + int r, g, b, a; + double na; + + evas_object_color_get(rect, &r, &g, &b, &a); + if (a < 20) + { + evas_object_del(rect); + return EINA_FALSE; + } + + na = a - 20; + r = na / a * r; + g = na / a * g; + b = na / a * b; + evas_object_color_set(rect, r, g, b, na); + + return EINA_TRUE; +}