commit 73e055e1f99139a966a3beab69ecb42814b7d6a6 Author: Leandro Pereira Date: Thu Aug 12 20:08:35 2010 +0000 Adding Eve webbrowser, based on WebKit-EFL. This is a complete rewrite of the old Eve web browser, using the current WebKit-EFL port (available from the official WebKit SVN; instructions on how to build it are here[1]). The interface was designed for mobile devices and is based off the Efenniht theme for E17. [1] http://trac.webkit.org/wiki/EFLWebKit SVN revision: 51060 diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..bd92f67 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,3 @@ +Gustavo Sverzut Barbieri +Leandro Augusto Fogolin Pereira +Lucas De Marchi diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..fc8a5de --- /dev/null +++ b/COPYING @@ -0,0 +1,165 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..1461fb7 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,15 @@ +release 0.2.0.0: + better zoom handing: + + * auto fit (double-click some element) will keep whole object in + viewport. + + * click over links will not go immediately, so it's possible to + click and zoom over links as well + + * both auto-fit and interactive zoom modes will not choose or + allow levels of zoom that makes contents smaller than viewport. + + +release 0.1.0.0: + Initial release. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..497adc8 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,10 @@ +ACLOCAL_AMFLAGS = -I m4 + +SUBDIRS = src data po + +MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \ + config.h.in config.sub configure install-sh \ + ltconfig ltmain.sh missing mkinstalldirs \ + stamp-h.in acconfig.h depcomp + +EXTRA_DIST = README AUTHORS COPYING 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..5aabca5 --- /dev/null +++ b/README @@ -0,0 +1,6 @@ +eve + +WebKit-EFL demo application + +See INSTALL for help on how to install. +See COPYING for software usage, modification and redistribution license. diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..2d94945 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +DIRNAME=`basename $PWD` +if test "x$DIRNAME" = "xelementary-skel"; then + echo "Do not run autogen.sh from inside elementary-skel" + exit 1 +fi + +find . -name Makefile -delete +find . -name Makefile.in -delete + +autoreconf -f -i + +if [ -z "$NOCONFIGURE" ]; then + ./configure "$@" +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..d2b3a9f --- /dev/null +++ b/configure.ac @@ -0,0 +1,128 @@ +AC_INIT(eve, 0.2.0.0, barbieri@profusion.mobi) +AC_PREREQ([2.60]) +AC_CONFIG_SRCDIR([configure.ac]) +AC_CONFIG_MACRO_DIR([m4]) +AC_GNU_SOURCE +AC_CANONICAL_BUILD +AC_CANONICAL_HOST +AC_ISC_POSIX + +AM_INIT_AUTOMAKE(1.6 dist-bzip2) +AM_CONFIG_HEADER(config.h) + +define([AC_LIBTOOL_LANG_CXX_CONFIG], [:]) +define([AC_LIBTOOL_LANG_GCJ_CONFIG], [:]) +define([AC_LIBTOOL_LANG_F77_CONFIG], [:]) +AC_PROG_LIBTOOL + +VMAJ=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $1);}'` +VMIN=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $2);}'` +VMIC=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $3);}'` +SNAP=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $4);}'` +version_info=`expr $VMAJ + $VMIN`":$VMIC:$VMIN" +AC_SUBST(VMAJ) +AC_SUBST(version_info) + +AC_C_BIGENDIAN +AC_PROG_CC_C99 +AM_PROG_CC_C_O +AC_C_CONST +AC_FUNC_ALLOCA +AC_C___ATTRIBUTE__ + +ALL_LINGUAS=`cat po/LINGUAS | grep -v '^[ ]*#'` +AC_SUBST(ALL_LINGUAS) + +AM_GNU_GETTEXT_VERSION([0.12.1]) +AM_GNU_GETTEXT([external]) + +PKG_CHECK_MODULES([ELEMENTARY], [elementary]) +PKG_CHECK_MODULES([EWEBKIT], [ewebkit ecore-file]) + +AC_ARG_WITH([edje-cc], + [AC_HELP_STRING([--with-edje-cc=PATH], + [specify a specific path to edje_cc])], + [edje_cc=$withval; + AC_MSG_NOTICE([edje_cc explicitly set to $edje_cc]) + ],[edje_cc=$(pkg-config --variable=prefix edje)/bin/edje_cc]) +AC_SUBST(edje_cc) + +want_quicklaunch="auto" +AC_ARG_ENABLE([quicklaunch], + [AC_HELP_STRING([--disable-quicklaunch], + [disable build of quicklaunch (default=auto)])], + [if test "x${enableval}" = "xno"; then + want_quicklaunch="no" + elif test "x${enableval}" = "xyes"; then + want_quicklaunch="yes" + else + want_quicklaunch="auto" + fi + ], + [want_quicklaunch="auto"]) + +if test "x${want_quicklaunch}" = "xauto"; then + AC_MSG_CHECKING([checking for elementary_quicklaunch binary...]) + if test -x $(pkg-config --variable=prefix elementary)/bin/elementary_quicklaunch; then + AC_MSG_RESULT([found, enable quicklaunch.]) + want_quicklaunch="yes" + else + AC_MSG_RESULT([not found, disable quicklaunch.]) + want_quicklaunch="no" + fi +fi + +if test "x${want_quicklaunch}" = "xyes"; then + AC_ARG_WITH([quicklauncher-libdir], + [AC_HELP_STRING([--with-quicklauncher-libdir=PATH], + [specify a specific path to install quicklauncher binaries])], + [quicklauncher_libdir=$withval; + AC_MSG_NOTICE([quicklauncher_libdir explicitly set to $quicklauncher_libdir]) + ], + [quicklauncher_libdir=$(pkg-config --variable=libdir elementary)]) + AC_SUBST(quicklauncher_libdir) +fi + +AM_CONDITIONAL(BUILD_QUICKLAUNCH, test "x${want_quicklaunch}" = "xyes") + +AC_OUTPUT([ +Makefile +src/Makefile +src/bin/Makefile +data/Makefile +data/desktop/Makefile +data/themes/Makefile +po/Makefile.in +]) + + +cat << EOF + +eve configured with: + +Flags: + CFLAGS.....(C): $CFLAGS + CXXFLAGS.(C++): $CXXFLAGS + CPPFLAGS.(CPP): $CPPFLAGS + LDFLAGS...(LD): $LDFLAGS + +Installation: + PREFIX..............: $prefix + +Quick Launcher: ${want_quicklaunch} +EOF + +if test "x${want_quicklaunch}" = "xyes"; then +cat << EOF_QL + quicklauncher_libdir: $quicklauncher_libdir + +EOF_QL +fi + +cat << EOF2 + +Now type 'make' ('gmake' on some systems) to compile eve, if it +builds successfully then you can 'make install', acquiring required +permissions with 'su' or 'sudo'. + +EOF2 diff --git a/data/Makefile.am b/data/Makefile.am new file mode 100644 index 0000000..2408bfe --- /dev/null +++ b/data/Makefile.am @@ -0,0 +1,2 @@ +MAINTAINERCLEANFILES = Makefile.in +SUBDIRS = desktop themes diff --git a/data/desktop/Makefile.am b/data/desktop/Makefile.am new file mode 100644 index 0000000..c77aca3 --- /dev/null +++ b/data/desktop/Makefile.am @@ -0,0 +1,9 @@ +MAINTAINERCLEANFILES = Makefile.in + +desktopdir = $(datadir)/applications +desktop_DATA = eve.desktop + +icondir = $(datadir)/icons +icon_DATA = eve.png + +EXTRA_DIST = eve.desktop eve.png diff --git a/data/desktop/eve.desktop b/data/desktop/eve.desktop new file mode 100644 index 0000000..5378583 --- /dev/null +++ b/data/desktop/eve.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=eve +Comment=WebKit-EFL demo application +Exec=eve +Icon=eve +Terminal=false +Type=Application +Categories=Application;Utility; diff --git a/data/desktop/eve.png b/data/desktop/eve.png new file mode 100644 index 0000000..90b57af Binary files /dev/null and b/data/desktop/eve.png differ diff --git a/data/themes/.gitignore b/data/themes/.gitignore new file mode 100644 index 0000000..421ee87 --- /dev/null +++ b/data/themes/.gitignore @@ -0,0 +1 @@ +default.edj diff --git a/data/themes/Makefile.am b/data/themes/Makefile.am new file mode 100644 index 0000000..1c42325 --- /dev/null +++ b/data/themes/Makefile.am @@ -0,0 +1,56 @@ +MAINTAINERCLEANFILES = Makefile.in + +EDJE_CC = @edje_cc@ +EDJE_FLAGS = -v -id $(top_srcdir)/data/themes -fd $(top_srcdir)/data/themes + +filesdir = $(datadir)/$(PACKAGE) +files_DATA = ewebkit.edj default.edj + +images = \ + bookmark-list-back-button.png \ + bookmark-list-title.png \ + bt_back_normal.png \ + bt_back_selected.png \ + bt_bookmark_normal.png \ + bt_bookmark_selected.png \ + bt_fav_normal.png \ + bt_fav_selected.png \ + bt_forward_normal.png \ + bt_forward_selected.png \ + bt_home_normal.png \ + bt_home_selected.png \ + bt_reload_normal.png \ + bt_reload_selected.png \ + bt_tab_normal.png \ + bt_tab_selected.png \ + panel-top-triangle.png \ + scrollbar-bg.png \ + scrollbar-knob.png \ + shadow-bottom.png \ + tab-add.png \ + tab-bg.png \ + tab-bg-selected.png \ + tab-close.png \ + tab-header.png \ + toolbar-background-bottom.png \ + toolbar-background-top.png \ + url-entry.png \ + list-highlight.png \ + cur_box.png \ + cur_hi.png \ + cur_shine.png \ + cur_glow.png \ + cur_shad.png \ + progress-bar-background.png + +fonts = + +EXTRA_DIST = ewebkit.edj default.edc $(images) $(fonts) + +default.edj: Makefile $(images) $(fonts) default.edc + $(EDJE_CC) $(EDJE_FLAGS) \ + $(top_srcdir)/data/themes/default.edc \ + $(top_builddir)/data/themes/default.edj + +clean-local: + rm -f default.edj diff --git a/data/themes/bookmark-list-back-button.png b/data/themes/bookmark-list-back-button.png new file mode 100644 index 0000000..19b8075 Binary files /dev/null and b/data/themes/bookmark-list-back-button.png differ diff --git a/data/themes/bookmark-list-title.png b/data/themes/bookmark-list-title.png new file mode 100644 index 0000000..104c80a Binary files /dev/null and b/data/themes/bookmark-list-title.png differ diff --git a/data/themes/bt_back_normal.png b/data/themes/bt_back_normal.png new file mode 100644 index 0000000..5761310 Binary files /dev/null and b/data/themes/bt_back_normal.png differ diff --git a/data/themes/bt_back_selected.png b/data/themes/bt_back_selected.png new file mode 100644 index 0000000..cd0df37 Binary files /dev/null and b/data/themes/bt_back_selected.png differ diff --git a/data/themes/bt_bookmark_normal.png b/data/themes/bt_bookmark_normal.png new file mode 100644 index 0000000..816c71c Binary files /dev/null and b/data/themes/bt_bookmark_normal.png differ diff --git a/data/themes/bt_bookmark_selected.png b/data/themes/bt_bookmark_selected.png new file mode 100644 index 0000000..5b607b7 Binary files /dev/null and b/data/themes/bt_bookmark_selected.png differ diff --git a/data/themes/bt_fav_normal.png b/data/themes/bt_fav_normal.png new file mode 100644 index 0000000..3c35435 Binary files /dev/null and b/data/themes/bt_fav_normal.png differ diff --git a/data/themes/bt_fav_selected.png b/data/themes/bt_fav_selected.png new file mode 100644 index 0000000..97c9d06 Binary files /dev/null and b/data/themes/bt_fav_selected.png differ diff --git a/data/themes/bt_forward_normal.png b/data/themes/bt_forward_normal.png new file mode 100644 index 0000000..1abd052 Binary files /dev/null and b/data/themes/bt_forward_normal.png differ diff --git a/data/themes/bt_forward_selected.png b/data/themes/bt_forward_selected.png new file mode 100644 index 0000000..ca36530 Binary files /dev/null and b/data/themes/bt_forward_selected.png differ diff --git a/data/themes/bt_home_normal.png b/data/themes/bt_home_normal.png new file mode 100644 index 0000000..81184e3 Binary files /dev/null and b/data/themes/bt_home_normal.png differ diff --git a/data/themes/bt_home_selected.png b/data/themes/bt_home_selected.png new file mode 100644 index 0000000..8cc4fe7 Binary files /dev/null and b/data/themes/bt_home_selected.png differ diff --git a/data/themes/bt_reload_normal.png b/data/themes/bt_reload_normal.png new file mode 100644 index 0000000..49e06a9 Binary files /dev/null and b/data/themes/bt_reload_normal.png differ diff --git a/data/themes/bt_reload_selected.png b/data/themes/bt_reload_selected.png new file mode 100644 index 0000000..29ae15f Binary files /dev/null and b/data/themes/bt_reload_selected.png differ diff --git a/data/themes/bt_tab_normal.png b/data/themes/bt_tab_normal.png new file mode 100644 index 0000000..877a72e Binary files /dev/null and b/data/themes/bt_tab_normal.png differ diff --git a/data/themes/bt_tab_selected.png b/data/themes/bt_tab_selected.png new file mode 100644 index 0000000..76e79df Binary files /dev/null and b/data/themes/bt_tab_selected.png differ diff --git a/data/themes/cur_box.png b/data/themes/cur_box.png new file mode 100644 index 0000000..136b8c8 Binary files /dev/null and b/data/themes/cur_box.png differ diff --git a/data/themes/cur_glow.png b/data/themes/cur_glow.png new file mode 100644 index 0000000..fd922bd Binary files /dev/null and b/data/themes/cur_glow.png differ diff --git a/data/themes/cur_hi.png b/data/themes/cur_hi.png new file mode 100644 index 0000000..cbafef8 Binary files /dev/null and b/data/themes/cur_hi.png differ diff --git a/data/themes/cur_shad.png b/data/themes/cur_shad.png new file mode 100644 index 0000000..3e899de Binary files /dev/null and b/data/themes/cur_shad.png differ diff --git a/data/themes/cur_shine.png b/data/themes/cur_shine.png new file mode 100644 index 0000000..6df5a6d Binary files /dev/null and b/data/themes/cur_shine.png differ diff --git a/data/themes/default.edc b/data/themes/default.edc new file mode 100644 index 0000000..5c6309a --- /dev/null +++ b/data/themes/default.edc @@ -0,0 +1,1036 @@ +#define TOP_PANEL_HEIGHT 64 +#define BOTTOM_PANEL_HEIGHT 85 +#define TOOLBAR_ITEMS 5 +#define TOOLBAR_PADDING 0.03 +#define TOOLBAR_ITEM_SIZE 90 +#define URLBAR_PADDING 0.03 + +#define TOOLBAR_SPACE_AVAILABLE (1.0-TOOLBAR_PADDING*2) +#define TOOLBAR_POSITION(_item_number) ((TOOLBAR_SPACE_AVAILABLE/TOOLBAR_ITEMS)*_item_number) +#define TOOLBAR_BUTTON(_button_name,_button_title,_xpos) \ + part { name: "button-"_button_name"-normal"; \ + type: IMAGE; \ + description { state: "default" 0.0; \ + min: TOOLBAR_ITEM_SIZE TOOLBAR_ITEM_SIZE; \ + max: TOOLBAR_ITEM_SIZE TOOLBAR_ITEM_SIZE; \ + fixed: 1 1; \ + rel1 { \ + to_y: "panel-bottom"; \ + relative: (_xpos+TOOLBAR_PADDING) 1.0; \ + offset: -45 -46; \ + } \ + rel2 { \ + to_y: "panel-bottom"; \ + relative: (_xpos+TOOLBAR_PADDING) 1.0; \ + offset: (-TOOLBAR_ITEM_SIZE/2) (-TOOLBAR_ITEM_SIZE/2); \ + } \ + image.normal: "bt_"_button_name"_normal.png"; \ + } \ + } \ + part { name: "button-"_button_name"-selected"; \ + type: IMAGE; \ + mouse_events: 0; \ + description { state: "default" 0.0; \ + visible: 0; \ + min: TOOLBAR_ITEM_SIZE TOOLBAR_ITEM_SIZE; \ + max: TOOLBAR_ITEM_SIZE TOOLBAR_ITEM_SIZE; \ + fixed: 1 1; \ + rel1 { \ + to_y: "panel-bottom"; \ + relative: (_xpos+TOOLBAR_PADDING) 1.0; \ + offset: -45 -46; \ + } \ + rel2 { \ + to_y: "panel-bottom"; \ + relative: (_xpos+TOOLBAR_PADDING) 1.0; \ + offset: (-TOOLBAR_ITEM_SIZE/2) (-TOOLBAR_ITEM_SIZE/2); \ + } \ + image.normal: "bt_"_button_name"_selected.png"; \ + color: 255 255 255 0; \ + } \ + description { state: "visible" 0.0; \ + inherit: "default" 0.0; \ + visible: 1; \ + color: 255 255 255 255; \ + } \ + } \ + part { name: "button-"_button_name"-left-separator"; \ + type: RECT; \ + description { state: "default" 0.0; \ + fixed: 1 1; \ + min: 2 90; \ + max: 2 90; \ + rel1 { \ + to: "button-"_button_name"-normal"; \ + relative: 0.0 0.0; \ + offset: -1 12; \ + } \ + rel2 { \ + to: "button-"_button_name"-normal"; \ + relative: 0.0 1.0; \ + offset: -1 -1; \ + } \ + color: 0 0 0 128; \ + } \ + } \ + part { name: "button-"_button_name"-label"; \ + type: TEXT; \ + effect: GLOW; \ + mouse_events: 0; \ + description { state: "default" 0.0; \ + rel1 { \ + to: "button-"_button_name"-normal"; \ + relative: 0.0 0.0; \ + offset: 0 5; \ + } \ + rel2 { \ + to: "button-"_button_name"-normal"; \ + relative: 1.0 1.0; \ + offset: -1 -1; \ + } \ + text { \ + font: "Sans,Edje-Vera"; \ + size: 12; \ + text: _button_title; \ + align: 0.5 0.5; \ + } \ + color: 190 190 190 255; \ + color2: 20 20 20 255; \ + } \ + } \ + programs { \ + program { name: _button_name"-pressed"; \ + signal: "mouse,down,*"; \ + source: "button-"_button_name"-normal"; \ + action: STATE_SET "visible" 0.0; \ + target: "button-"_button_name"-selected"; \ + transition: ACCELERATE 0.3; \ + } \ + program { name: _button_name"-released"; \ + signal: "mouse,up,*"; \ + source: "button-"_button_name"-normal"; \ + action: STATE_SET "default" 0.0; \ + target: "button-"_button_name"-selected"; \ + transition: DECELERATE 0.6; \ + } \ + program { name: _button_name"-clicked"; \ + signal: "mouse,clicked,*"; \ + source: "button-"_button_name"-normal"; \ + action: SIGNAL_EMIT "action,"_button_name _button_name; \ + } \ + } + +#define URLBAR_BUTTON(_button_name,_pos) \ + part { name: "button-"_button_name"-normal"; \ + type: IMAGE; \ + description { state: "default" 0.0; \ + min: 40 40; \ + max: 40 40; \ + fixed: 1 1; \ + rel1 { \ + to_y: "panel-top"; \ + relative: _pos 0.0; \ + offset: 0 -5; \ + } \ + rel2 { \ + to_y: "panel-top"; \ + relative: _pos 1.0; \ + offset: -1 -1; \ + } \ + image.normal: "bt_"_button_name"_normal.png"; \ + } \ + } \ + part { name: "button-"_button_name"-selected"; \ + type: IMAGE; \ + mouse_events: 0; \ + description { state: "default" 0.0; \ + min: 40 40; \ + max: 40 40; \ + fixed: 1 1; \ + visible: 0; \ + rel1 { \ + to_y: "panel-top"; \ + relative: _pos 0.0; \ + offset: 0 -5; \ + } \ + rel2 { \ + to_y: "panel-top"; \ + relative: _pos 1.0; \ + offset: -1 -1; \ + } \ + image.normal: "bt_"_button_name"_selected.png"; \ + color: 255 255 255 0; \ + } \ + description { state: "visible" 0.0; \ + inherit: "default" 0.0; \ + visible: 1; \ + color: 255 255 255 255; \ + } \ + } \ + programs { \ + program { name: _button_name"-pressed"; \ + signal: "mouse,down,*"; \ + source: "button-"_button_name"-normal"; \ + action: STATE_SET "visible" 0.0; \ + target: "button-"_button_name"-selected"; \ + transition: ACCELERATE 0.3; \ + } \ + program { name: _button_name"-released"; \ + signal: "mouse,up,*"; \ + source: "button-"_button_name"-normal"; \ + action: STATE_SET "default" 0.0; \ + target: "button-"_button_name"-selected"; \ + transition: DECELERATE 0.6; \ + } \ + program { name: _button_name"-clicked"; \ + signal: "mouse,clicked,*"; \ + source: "button-"_button_name"-normal"; \ + action: SIGNAL_EMIT "action,"_button_name _button_name; \ + } \ + } + +collections { +#include "elm-scroller.edc" +#include "elm-list.edc" +#include "elm-gengrid.edc" +#include "elm-notify.edc" +#include "elm-pager.edc" +#include "elm-entry.edc" + group { name: "bg"; + parts { + part { name: "bg"; + type: RECT; + description { state: "default" 0.0; + color: 0 0 0 255; + min: 480 800; + } + } + } + } + group { name: "chrome"; + images { + image: "bt_back_normal.png" COMP; + image: "bt_back_selected.png" COMP; + image: "bt_bookmark_normal.png" COMP; + image: "bt_bookmark_selected.png" COMP; + image: "bt_forward_normal.png" COMP; + image: "bt_forward_selected.png" COMP; + image: "bt_reload_normal.png" COMP; + image: "bt_reload_selected.png" COMP; + image: "bt_tab_normal.png" COMP; + image: "bt_tab_selected.png" COMP; + image: "bt_home_normal.png" COMP; + image: "bt_home_selected.png" COMP; + image: "bt_fav_normal.png" COMP; + image: "bt_fav_selected.png" COMP; + image: "toolbar-background-bottom.png" COMP; + image: "toolbar-background-top.png" COMP; + image: "url-entry.png" COMP; + image: "bookmark-list-title.png" COMP; + image: "bookmark-list-back-button.png" COMP; + image: "tab-header.png" COMP; + image: "panel-top-triangle.png" COMP; + image: "progress-bar-background.png" COMP; + } + script { + public bookmark_list_visible; + public tab_grid_visible; + public favorited; + public panel_top_visible; + public progress_bar_visible; + + public fav_off() { + set_int(favorited, 0); + emit("action,fav_off", ""); + } + public fav_on() { + set_state(PART:"button-fav-selected", "visible", 0.0); + set_int(favorited, 1); + emit("action,fav_on", ""); + } + public fav_toggle() { + if (get_int(favorited) == 1) fav_off(); + else fav_on(); + } + public panel_top_hide() { + run_program(PROGRAM:"hide-view-mask"); + run_program(PROGRAM:"hide-top-panel"); + emit("view,mask,hidden", ""); + set_int(panel_top_visible, 0); + } + public panel_top_show() { + if (get_int(bookmark_list_visible) != 1 && get_int(tab_grid_visible) != 1) + run_program(PROGRAM:"show-white-view-mask"); + run_program(PROGRAM:"show-top-panel"); + emit("view,mask,visible", ""); + set_int(panel_top_visible, 1); + } + public panel_top_toggle() { + if (get_int(panel_top_visible) == 1) panel_top_hide(); + else panel_top_show(); + } + public tab_grid_hide() { + run_program(PROGRAM:"hide-tab-grid"); + set_state(PART:"button-tab-selected", "default", 0.0); + set_int(tab_grid_visible, 0); + if (get_int(bookmark_list_visible) != 1) run_program(PROGRAM:"show-white-view-mask"); + emit("tab,hide", ""); + } + public tab_grid_show() { + set_int(tab_grid_visible, 1); + if (get_int(bookmark_list_visible) == 1) bookmark_list_hide(); + run_program(PROGRAM:"show-tab-grid"); + set_state(PART:"button-tab-selected", "visible", 0.0); + run_program(PROGRAM:"show-black-view-mask"); + emit("tab,show", ""); + } + public tab_grid_toggle() { + if (get_int(tab_grid_visible) == 1) tab_grid_hide(); + else tab_grid_show(); + } + public bookmark_list_hide() { + run_program(PROGRAM:"hide-bookmark-list"); + set_state(PART:"button-bookmark-selected", "default", 0.0); + set_int(bookmark_list_visible, 0); + if (get_int(tab_grid_visible) != 1) run_program(PROGRAM:"show-white-view-mask"); + emit("bookmark,hide", ""); + } + public bookmark_list_show() { + set_int(bookmark_list_visible, 1); + if (get_int(tab_grid_visible) == 1) tab_grid_hide(); + run_program(PROGRAM:"show-bookmark-list"); + set_state(PART:"button-bookmark-selected", "visible", 0.0); + run_program(PROGRAM:"show-black-view-mask"); + emit("bookmark,show", ""); + } + public bookmark_list_toggle() { + if (get_int(bookmark_list_visible) == 1) bookmark_list_hide(); + else bookmark_list_show(); + } + public progress_bar_set_value(Float:value) { + if (value < 0.0) value = 0.0; + else if (value >= 1.0) value = 1.0; + + if (value >= 0.95) { + run_program(PROGRAM:"progress-bar-hide"); + set_int(progress_bar_visible, 0); + } else { + if (get_int(progress_bar_visible) == 0) { + set_int(progress_bar_visible, 1); + run_program(PROGRAM:"progress-bar-show"); + } + custom_state(PART:"progress-bar-mask", "visible", 0.0); + set_state_val(PART:"progress-bar-mask", STATE_REL2, value, 1.0); + set_state(PART:"progress-bar-mask", "custom", 0.0); + } + } + public message(Msg_Type:type, id, ...) { + if ((type == MSG_FLOAT) && (id == 1)) { + progress_bar_set_value(getfarg(2)); + } + } + } + parts { + part { name: "bg"; + type: RECT; + description { state: "default" 0.0; + color: 0 0 0 255; + min: 480 800; + } + } + part { name: "view"; + type: SWALLOW; + description { state: "default" 0.0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + to_y: "panel-bottom"; + relative: 1.0 0.0; + offset: -1 5; + } + } + } + part { name: "view-mask"; + type: RECT; + description { state: "default" 0.0; + rel1 { + to_y: "panel-top"; + relative: 0.0 1.0; + offset: 0 -10; + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + color: 0 0 0 0; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + } + description { state: "masking-white" 0.0; + inherit: "default" 0.0; + color: 255 255 255 0; + } + description { state: "masking-black" 0.0; + inherit: "default" 0.0; + color: 0 0 0 200; + } + } + part { name: "bookmark-list-header"; + type: IMAGE; + clip_to: "bookmark-list"; + description { state: "default" 0.0; + max: 99999 55; + rel1 { + to: "bookmark-list"; + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + to: "bookmark-list"; + relative: 1.0 0.0; + offset: -1 55; + } + image.normal: "bookmark-list-title.png"; + } + } + part { name: "bookmark-list-bg"; + type: RECT; + description { state: "default" 0.0; + rel1 { + to: "bookmark-list-header"; + relative: 0.0 1.0; + offset: 0 0; + } + rel2 { + to: "bookmark-list"; + relative: 1.0 1.0; + offset: -1 -1; + } + color: 0 0 0 255; + } + } + part { name: "bookmark-list-swallow"; + type: SWALLOW; + description { state: "default" 0.0; + fixed: 1 1; + rel1 { + to: "bookmark-list-header"; + relative: 0.0 1.0; + offset: 0 -1; + } + rel2 { + to: "bookmark-list"; + relative: 1.0 1.0; + offset: -1 -1; + } + } + description { state: "hide-left" 0.0; + inherit: "default" 0.0; + rel1 { + to: "bookmark-list-header"; + relative: -1.0 1.0; + offset: 0 0; + } + rel2 { + to: "bookmark-list"; + relative: 0.0 1.0; + offset: -1 -1; + } + } + description { state: "hide-right" 0.0; + inherit: "default" 0.0; + rel1 { + to: "bookmark-list-header"; + relative: 1.0 1.0; + offset: 0 0; + } + rel2 { + to: "bookmark-list"; + relative: 1.0 1.0; + offset: -1 -1; + } + } + } + part { name: "bookmark-list-title"; + type: TEXT; + clip_to: "bookmark-list"; + description { state: "default" 0.0; + rel1 { + to_y: "bookmark-list-header"; + to_x: "bookmark-list-swallow"; + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + to_y: "bookmark-list-header"; + to_x: "bookmark-list-swallow"; + relative: 1.0 1.0; + offset: -1 -1; + } + text { + font: "Sans,Edje-Vera"; + size: 12; + text: "Untitled"; + min: 0 1; + align: 0.5 0.7; + } + color: 190 190 190 255; + } + } + part { name: "bookmark-list-back-button-text"; + type: TEXT; + mouse_events: 0; + description { state: "default" 0.0; + rel1 { + to: "bookmark-list-back-button"; + relative: 0.0 0.0; + offset: 24 0; + } + rel2 { + to: "bookmark-list-back-button"; + relative: 1.0 1.0; + offset: -1 -1; + } + text { + font: "Sans,Edje-Vera"; + size: 9; /* 12 */ + text: "Back"; + min: 0 1; + align: 0.0 0.5; + } + color: 130 130 130 255; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + } + } + part { name: "bookmark-list-back-arrow"; + type: IMAGE; + mouse_events: 0; + description { state: "default" 0.0; + min: 13 16; + max: 13 16; + fixed: 1 1; + rel1 { + to: "bookmark-list-back-button"; + relative: 0.0 0.0; + offset: 13 0; + } + rel2 { + to: "bookmark-list-back-button"; + relative: 0.0 1.0; + offset: 0 -1; + } + image.normal: "bookmark-list-back-button.png"; + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + } + } + part { name: "bookmark-list-back-button"; + type: RECT; + clip_to: "bookmark-list"; + description { state: "default" 0.0; + rel1 { + to: "bookmark-list-header"; + relative: 0.0 0.0; + offset: 45 14; + } + rel2 { + to: "bookmark-list-header"; + relative: 0.0 1.0; + offset: 145 -2; + } + color: 0 0 0 0; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + rel1 { + to: "bookmark-list-header"; + relative: -1.0 0.0; + } + rel2 { + to: "bookmark-list-header"; + relative: -1.0 1.0; + } + } + description { state: "pressed" 0.0; + inherit: "default" 0.0; + color: 0 0 0 128; + } + } + part { name: "bookmark-list"; + type: RECT; + description { state: "default" 0.0; + fixed: 1 1; + visible: 0; + rel1 { + to_y: "panel-bottom"; + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + } + description { state: "visible" 0.0; + rel1 { + relative: 0.0 0.25; + offset: 0 0; + } + rel2 { + to_y: "panel-bottom"; + relative: 1.0 0.0; + offset: -1 5; + } + } + } + part { name: "tab-grid-swallow"; + type: SWALLOW; + description { state: "default" 0.0; + rel1 { + to: "tab-grid"; + relative: 0.0 0.0; + offset: 0 8; + } + rel2 { + to: "tab-grid"; + relative: 1.0 1.0; + offset: -1 -1; + } + } + } + part { name: "tab-grid-header"; + type: IMAGE; + clip_to: "tab-grid"; + description { state: "default" 0.0; + min: 1 14; + max: 99999 14; + fixed: 1 1; + rel1 { + to: "tab-grid"; + relative: 0.0 0.0; + offset: 0 10; + } + rel2 { + to: "tab-grid"; + relative: 1.0 0.0; + offset: -1 0; + } + image.normal: "tab-header.png"; + } + } + part { name: "tab-grid"; + type: RECT; + description { state: "default" 0.0; + fixed: 1 1; + visible: 0; + rel1 { + to_y: "panel-bottom"; + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + } + description { state: "visible" 0.0; + rel1 { + relative: 0.0 0.25; + offset: 0 0; + } + rel2 { + to_y: "panel-bottom"; + relative: 1.0 0.0; + offset: -1 5; + } + } + } + part { name: "panel-top-triangle"; + type: IMAGE; + description { state: "default" 0.0; + visible: 0; + min: 30 27; + max: 30 27; + fixed: 1 1; + image.normal: "panel-top-triangle.png"; + rel1 { + relative: 1.0 0.0; + offset: 60 60; + } + rel2 { + relative: 1.0 0.0; + offset: 60 60; + } + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + image.normal: "panel-top-triangle.png"; + rel1 { + relative: 1.0 0.0; + offset: -15 13; + } + rel2 { + relative: 1.0 0.0; + offset: -15 13; + } + } + description { state: "pressed" 0.0; + inherit: "visible" 0.0; + color: 255 255 255 128; + } + } + part { name: "panel-top"; + type: IMAGE; + description { state: "default" 0.0; + max: 99999 TOP_PANEL_HEIGHT; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 1.0 0.0; + offset: 0 TOP_PANEL_HEIGHT; + } + image.normal: "toolbar-background-top.png"; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + rel1 { + relative: 0.0 -1.0; + offset: 0 0; + } + rel2 { + relative: 1.0 0.0; + offset: -1 -TOP_PANEL_HEIGHT; + } + } + } + part { name: "panel-bottom"; + type: IMAGE; + description { state: "default" 0.0; + min: 480 (BOTTOM_PANEL_HEIGHT+5); + fixed: 1 1; + rel1 { + relative: 0.0 1.0; + offset: 0 -BOTTOM_PANEL_HEIGHT; + } + rel2 { + relative: 1.0 1.0; + offset: -1 -1; + } + image.normal: "toolbar-background-bottom.png"; + } + } + TOOLBAR_BUTTON("back", "Back", TOOLBAR_POSITION(1)) + TOOLBAR_BUTTON("forward", "Forward", TOOLBAR_POSITION(2)) + TOOLBAR_BUTTON("reload", "Reload", TOOLBAR_POSITION(3)) + TOOLBAR_BUTTON("tab", "Tabs", TOOLBAR_POSITION(4)) + TOOLBAR_BUTTON("bookmark", "Bookmarks", TOOLBAR_POSITION(5)) + URLBAR_BUTTON("home", 0.1) + URLBAR_BUTTON("fav", 0.9) + part { name: "button-bookmark-right-separator"; + type: RECT; + description { state: "default" 0.0; + fixed: 1 1; + min: 2 90; + max: 2 90; + rel1 { + to: "button-bookmark-normal"; + relative: 1.0 0.0; + offset: -2 12; + } + rel2 { + to: "button-bookmark-normal"; + relative: 1.0 1.0; + offset: -2 -1; + } + color: 0 0 0 128; + } + } + part { name: "url-entry-bg"; + type: IMAGE; + description { state: "default" 0.0; + fixed: 1 1; + min: 10 26; + max: 99999 26; + rel1 { + to_y: "panel-top"; + relative: 0.1 0.0; + offset: 45 57; + } + rel2 { + to_y: "panel-top"; + relative: 0.9 0.0; + offset: -45 -1; + } + image.normal: "url-entry.png"; + image.border: 4 4 4 4; + } + } + part { name: "progress-bar-mask"; + type: IMAGE; + description { state: "default" 0.0; + fixed: 1 1; + visible: 0; + rel1 { + to: "url-entry-bg"; + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + to: "url-entry-bg"; + relative: 1.0 1.0; + offset: -1 -1; + } + image.normal: "progress-bar-background.png"; + image.border: 2 2 2 2; + color: 255 255 255 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + } + } + part { name: "url-entry"; + type: SWALLOW; + description { state: "default" 0.0; + fixed: 1 1; + rel1 { + to: "url-entry-bg"; + relative: 0.0 0.0; + offset: 5 1; + } + rel2 { + to: "url-entry-bg"; + relative: 1.0 1.0; + offset: -6 -2; + } + } + } + programs { + program { name: "theme-load"; + signal: "load"; + script { + set_int(bookmark_list_visible, 0); + set_int(tab_grid_visible, 0); + set_int(favorited, 0); + set_int(panel_top_visible, 1); + set_int(progress_bar_visible, 0); + + set_state(PART:"view-mask", "masking-white", 0.0); + } + } + program { name: "list-back-clicked"; + signal: "mouse,clicked,*"; + source: "bookmark-list-back-button"; + action: SIGNAL_EMIT "list,back,clicked" ""; + } + program { name: "press-view-mask"; + signal: "mouse,down,*"; + source: "view-mask"; + script { + if (get_int(bookmark_list_visible) == 1) { + bookmark_list_hide(); + } else if (get_int(tab_grid_visible) == 1) { + tab_grid_hide(); + } else { + run_program(PROGRAM:"hide-view-mask"); + panel_top_hide(); + } + } + } + program { name: "press-panel-top-triangle"; + signal: "mouse,down,*"; + source: "panel-top-triangle"; + action: STATE_SET "pressed" 0.0; + target: "panel-top-triangle"; + transition: ACCELERATE 0.2; + } + program { name: "restore-top-panel"; + script { panel_top_show(); } + } + program { name: "release-panel-top-triangle"; + signal: "mouse,up,*"; + source: "panel-top-triangle"; + action: STATE_SET "visible" 0.0; + target: "panel-top-triangle"; + transition: ACCELERATE 0.2; + after: "restore-top-panel"; + } + program { name: "hide-view-mask"; + action: STATE_SET "hidden" 0.0; + target: "view-mask"; + transition: ACCELERATE 0.2; + } + program { name: "show-white-view-mask"; + action: STATE_SET "masking-white" 0.0; + target: "view-mask"; + transition: DECELERATE 0.2; + } + program { name: "show-black-view-mask"; + action: SIGNAL_EMIT "view,mask,show" ""; + action: STATE_SET "masking-black" 0.0; + target: "view-mask"; + transition: DECELERATE 0.2; + } + program { name: "show-top-triangle"; + action: STATE_SET "visible" 0.0; + target: "panel-top-triangle"; + transition: ACCELERATE 0.2; + } + program { name: "hide-top-triangle"; + action: STATE_SET "default" 0.0; + target: "panel-top-triangle"; + transition: DECELERATE 0.2; + } + program { name: "show-top-panel"; + action: STATE_SET "default" 0.0; + target: "panel-top"; + transition: DECELERATE 0.3; + after: "hide-top-triangle"; + } + program { name: "hide-top-panel"; + action: STATE_SET "hidden" 0.0; + target: "panel-top"; + transition: ACCELERATE 0.3; + after: "show-top-triangle"; + } + program { name: "show-bookmark-list"; + action: STATE_SET "visible" 0.0; + target: "bookmark-list"; + transition: ACCELERATE 0.2; + } + program { name: "hide-bookmark-list"; + action: STATE_SET "default" 0.0; + target: "bookmark-list"; + transition: DECELERATE 0.2; + } + program { name: "toggle-bookmark-list"; + signal: "mouse,clicked,*"; + source: "button-bookmark-normal"; + script { bookmark_list_toggle(); } + } + program { name: "show-tab-grid"; + action: STATE_SET "visible" 0.0; + target: "tab-grid"; + transition: ACCELERATE 0.2; + } + program { name: "hide-tab-grid"; + action: STATE_SET "default" 0.0; + target: "tab-grid"; + transition: DECELERATE 0.2; + } + program { name: "toggle-tab-grid"; + signal: "mouse,clicked,*"; + source: "button-tab-normal"; + script { tab_grid_toggle(); } + } + program { name: "toggle-fav"; + signal: "mouse,clicked,*"; + source: "button-fav-normal"; + script { fav_toggle(); } + } + program { name: "press-bookmark-list-button"; + signal: "mouse,down,*"; + source: "bookmark-list-back-button"; + action: STATE_SET "pressed" 0.0; + target: "bookmark-list-back-button"; + target: "bookmark-list-back-button-text"; + target: "bookmark-list-back-arrow"; + transition: ACCELERATE 0.2; + } + program { name: "release-bookmark-list-button"; + signal: "mouse,up,*"; + source: "bookmark-list-back-button"; + action: STATE_SET "default" 0.0; + target: "bookmark-list-back-button"; + target: "bookmark-list-back-button-text"; + target: "bookmark-list-back-arrow"; + transition: DECELERATE 0.2; + } + program { name: "list-animate-left"; + signal: "list,animate,left"; + action: STATE_SET "hide-left" 0.0; + target: "bookmark-list-swallow"; + transition: ACCELERATE 0.1; + after: "list-animate-left-2"; + } + program { name: "list-animate-left-2"; + action: STATE_SET "hide-right" 0.0; + target: "bookmark-list-swallow"; + after: "list-animate-final"; + } + program { name: "list-animate-right"; + signal: "list,animate,right"; + action: STATE_SET "hide-right" 0.0; + target: "bookmark-list-swallow"; + transition: ACCELERATE 0.1; + after: "list-animate-right-2"; + } + program { name: "list-animate-right-2"; + action: STATE_SET "hide-left" 0.0; + target: "bookmark-list-swallow"; + after: "list-animate-final"; + } + program { name: "list-animate-final"; + action: STATE_SET "default" 0.0; + target: "bookmark-list-swallow"; + transition: DECELERATE 0.2; + } + program { name: "bookmark-item-clicked"; + signal: "bookmark,item,clicked"; + script { bookmark_list_hide(); } + } + program { name: "tab-item-clicked"; + signal: "tab,item,clicked"; + script { tab_grid_hide(); } + } + program { name: "list-back-show"; + signal: "list,back,show"; + action: STATE_SET "default" 0.0; + target: "bookmark-list-back-button"; + transition: DECELERATE 0.3; + } + program { name: "list-back-hide"; + signal: "list,back,hide"; + action: STATE_SET "hidden" 0.0; + target: "bookmark-list-back-button"; + transition: ACCELERATE 0.5; + } + program { name: "favorite-hilight"; + signal: "favorite,hilight"; + action: STATE_SET "visible" 0.0; + target: "button-fav-selected"; + transition: ACCELERATE 0.5; + } + program { name: "favorite-default"; + signal: "favorite,default"; + action: STATE_SET "default" 0.0; + target: "button-fav-selected"; + transition: DECELERATE 0.5; + } + program { name: "progress-bar-hide"; + action: STATE_SET "default" 0.0; + target: "progress-bar-mask"; + transition: ACCELERATE 0.5; + } + program { name: "progress-bar-show"; + action: STATE_SET "visible" 0.0; + target: "progress-bar-mask"; + transition: DECELERATE 0.5; + } + } + } + } +} diff --git a/data/themes/elm-entry.edc b/data/themes/elm-entry.edc new file mode 100644 index 0000000..23b5ca7 --- /dev/null +++ b/data/themes/elm-entry.edc @@ -0,0 +1,227 @@ + group { name: "elm/entry/base-single/ewebkit/url"; + styles + { + style { name: "entry_single_textblock_style"; + base: "font=Sans font_size=10 align=left color=#787878 wrap=none"; + tag: "br" "\n"; + tag: "tab" "\t"; + tag: "em" "+ font=Sans:style=Oblique"; + tag: "b" "+ font=Sans:style=Bold"; + tag: "link" "+ color=#800 underline=on underline_color=#8008"; + tag: "hilight" "+ font=Sans:style=Bold"; + } + style { name: "entry_single_textblock_disabled_style"; + base: "font=Sans font_size=10 align=left color=#00000080 wrap=none"; + tag: "br" "\n"; + tag: "tab" "\t"; + tag: "em" "+ font=Sans:style=Oblique"; + tag: "b" "+ font=Sans:style=Bold"; + tag: "link" "+ color=#00000080 underline=on underline_color=#00000080"; + tag: "hilight" "+ font=Sans:style=Bold"; + } + } + parts { + part { name: "elm.text"; + type: TEXTBLOCK; + mouse_events: 1; + scale: 1; + entry_mode: EDITABLE; + select_mode: EXPLICIT; + multiline: 0; + source: "elm/entry/selection/ewebkit/url"; // selection under + source4: "elm/entry/cursor/ewebkit/url"; // cursorover + source5: "elm/entry/anchor/default"; // anchor under + description { state: "default" 0.0; + text { + style: "entry_single_textblock_style"; + min: 1 1; + max: 0 1; + } + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + text { + style: "entry_single_textblock_disabled_style"; + } + } + } + } + programs { + program { name: "focus"; + signal: "load"; + source: ""; + action: FOCUS_SET; + target: "elm.text"; + } + program { name: "disable"; + signal: "elm,state,disabled"; + source: "elm"; + action: STATE_SET "disabled" 0.0; + target: "elm.text"; + } + program { name: "enable"; + signal: "elm,state,enabled"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "elm.text"; + } + } + } + group { name: "elm/entry/selection/ewebkit/url"; + parts { + part { name: "bg"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + color: 128 128 128 128; + } + } + } + } + group { name: "elm/entry/cursor/ewebkit/url"; + images { + image: "cur_box.png" COMP; + image: "cur_hi.png" COMP; + image: "cur_shad.png" COMP; + image: "cur_shine.png" COMP; + image: "cur_glow.png" COMP; + } + parts { + part { name: "clip2"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + rel1.to: "clip"; + rel2.to: "clip"; + visible: 0; + } + description { state: "focused" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { name: "clip"; + type: RECT; + mouse_events: 0; + clip_to: "clip2"; + description { state: "default" 0.0; + rel1.offset: -10 0; + rel2.offset: 9 9; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + part { name: "bg"; + mouse_events: 0; + clip_to: "clip"; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.offset: -2 0; + rel2.to: "base"; + rel2.offset: 1 1; + image.border: 2 2 2 2; + image.normal: "cur_shad.png"; + } + } + part { name: "base"; + mouse_events: 0; + scale: 1; + clip_to: "clip"; + description { state: "default" 0.0; + min: 2 2; + align: 0.5 1.0; + rel1.relative: 0.0 1.0; + rel1.offset: 0 -1; + rel2.relative: 1.0 1.0; + rel2.offset: -1 -1; + image.normal: "cur_box.png"; + } + } + part { name: "hi"; + mouse_events: 0; + clip_to: "clip"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + rel2.relative: 1.0 0.5; + image.normal: "cur_hi.png"; + } + } + part { name: "shine"; + mouse_events: 0; + clip_to: "clip"; + clip_to: "clip2"; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + rel2.relative: 1.0 0.75; + image.border: 2 2 1 0; + image.normal: "cur_shine.png"; + fill.smooth: 0; + } + } + part { name: "glow"; + mouse_events: 0; + clip_to: "clip2"; + description { state: "default" 0.0; + rel1.to: "base"; + rel1.relative: 0.0 -2.0; + rel1.offset: -2 0; + rel2.to: "base"; + rel2.relative: 1.0 0.0; + rel2.offset: 1 1; + image.border: 2 2 0 4; + image.normal: "cur_glow.png"; + fill.smooth: 0; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + color: 255 255 255 0; + } + } + } + programs { + program { name: "show"; + signal: "show"; + source: ""; + action: STATE_SET "hidden" 0.0; + in: 1.0 0.0; + transition: DECELERATE 2.0; + target: "glow"; + after: "show2"; + } + program { name: "show2"; + action: STATE_SET "hidden" 0.0; + in: 0.2 0.0; + target: "clip"; + after: "show3"; + } + program { name: "show3"; + action: STATE_SET "default" 0.0; + in: 0.5 0.0; + target: "clip"; + after: "show4"; + } + program { name: "show4"; + action: STATE_SET "default" 0.0; + in: 0.5 0.0; + transition: DECELERATE 0.5; + target: "glow"; + after: "show"; + } + program { name: "focused"; + signal: "elm,action,focus"; + source: "elm"; + action: STATE_SET "focused" 0.0; + target: "clip2"; + } + program { name: "unfocused"; + signal: "elm,action,unfocus"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "clip2"; + } + } + } diff --git a/data/themes/elm-gengrid.edc b/data/themes/elm-gengrid.edc new file mode 100644 index 0000000..8b82e5c --- /dev/null +++ b/data/themes/elm-gengrid.edc @@ -0,0 +1,420 @@ +group { name: "elm/gengrid/item/default/ewebkit"; + alias: "elm/gengrid/item/default_style/ewebkit"; + data.item: "labels" "elm.text"; + data.item: "icons" "elm.swallow.icon elm.swallow.end"; + images { + image: "tab-bg.png" COMP; + image: "tab-bg-selected.png" COMP; + image: "tab-close.png" COMP; + } + parts { + part { + name: "event"; + repeat_events: 1; + description { + state: "default" 0.0; + } + } + part { name: "bg"; + clip_to: "disclip"; + mouse_events: 0; + description { state: "default" 0.0; + rel1 { + relative: 0.0 0.0; + offset: -5 -5; + } + rel2 { + relative: 1.0 1.0; + offset: 4 4; + } + image { + normal: "tab-bg.png"; + border: 28 28 20 20; + } + fill.smooth: 0; + } + } + part { name: "elm.swallow.pad"; + type: SWALLOW; + description { state: "default" 0.0; + visible: 0; + fixed: 1 0; + align: 0.0 0.5; + rel1 { + relative: 0.0 1.0; + offset: 0 -10; + } + rel2 { + to_y: "elm.text"; + relative: 0.0 0.0; + offset: -1 -1; + } + } + } + part { name: "elm.swallow.icon"; + clip_to: "disclip"; + type: SWALLOW; + description { state: "default" 0.0; + fixed: 1 0; + align: 0.5 0.5; + rel1 { + relative: 0.0 0.0; + offset: 22 13; + } + rel2 { + to_y: "elm.text"; + relative: 1.0 0.0; + offset: -24 -4; + } + } + } + part { name: "elm.swallow.end"; + clip_to: "disclip"; + type: SWALLOW; + description { state: "default" 0.0; + visible: 0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 0.0 0.0; + offset: 0 0; + } + } + } + part { name: "elm.text"; + clip_to: "disclip"; + type: TEXT; + mouse_events: 0; + scale: 1; + description { + state: "default" 0.0; + rel1 { + relative: 0.0 1.0; + offset: 18 0; + } + rel2 { + relative: 1.0 1.0; + offset: -21 -44; + } + color: 120 120 120 255; + text { + font: "Sans"; + size: 9; + min: 0 1; + align: 0.5 0.0; + } + } + } + part { name: "disclip"; + type: RECT; + description { state: "default" 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 255 255 255 64; + } + } + part { name: "bg-selected-border"; + clip_to: "disclip"; + mouse_events: 0; + description { state: "default" 0.0; + visible: 0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + color: 255 255 255 0; + image { + normal: "tab-bg-selected.png"; + border: 8 8 8 8; + } + fill.smooth: 0; + } + description { state: "selected" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + rel1 { + relative: 0.0 0.0; + offset: 15 5; + } + rel2 { + relative: 1.0 1.0; + offset: -16 -6; + } + image { + normal: "tab-bg-selected.png"; + border: 8 8 8 8; + } + } + } + part { name: "close-button"; + type: IMAGE; + description { state: "default" 0.0; + min: 15 15; + max: 15 15; + rel1 { + relative: 1.0 1.0; + offset: -40 1; + } + rel2 { + relative: 1.0 1.0; + offset: 29 -41; + } + image.normal: "tab-close.png"; + } + description { state: "selected" 0.0; + inherit: "default" 0.0; + color: 255 166 2 255; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + visible: 0; + } + } + part { name: "close-button-dedones"; + type: RECT; + clip_to: "disclip"; + description { state: "default" 0.0; + rel1 { + to: "close-button"; + relative: 0.0 0.0; + offset: -10 -10; + } + rel2 { + to: "close-button"; + relative: 1.0 1.0; + offset: 5 11; + } + color: 255 255 255 0; + } + } + } + programs { + // signal: elm,state,%s,active + // a "check" item named %s went active + // signal: elm,state,%s,passive + // a "check" item named %s went passive + // default is passive + program { + name: "tab_close_down"; + signal: "tab,close,hide"; + action: STATE_SET "hidden" 0.0; + target: "close-button"; + } + program { + name: "tab_down"; + signal: "mouse,down,*"; + source: "close-button-dedones"; + action: STATE_SET "selected" 0.0; + target: "close-button"; + transition: ACCELERATE 0.2; + } + program { + name: "tab_clicked"; + signal: "mouse,clicked,*"; + source: "close-button-dedones"; + action: SIGNAL_EMIT "tab,close" ""; + } + program { + name: "tab_up"; + signal: "mouse,up,*"; + source: "close-button-dedones"; + action: STATE_SET "default" 0.0; + target: "close-button"; + transition: DECELERATE 0.2; + } + program { + name: "go_active"; + signal: "elm,state,selected"; + source: "elm"; + action: STATE_SET "selected" 0.0; + target: "bg-selected-border"; + transition: ACCELERATE 0.1; + } + program { + name: "go_passive"; + signal: "elm,state,unselected"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "bg-selected-border"; + transition: DECELERATE 0.1; + } + } +} + +group { name: "elm/gengrid/item/new_page/ewebkit"; + data.item: "labels" "elm.text"; + data.item: "icons" "elm.swallow.icon elm.swallow.end"; + images { + image: "tab-bg.png" COMP; + image: "tab-bg-selected.png" COMP; + image: "tab-add.png" COMP; + } + parts { + part { + name: "event"; + repeat_events: 1; + description { + state: "default" 0.0; + } + } + part { name: "bg"; + clip_to: "disclip"; + mouse_events: 0; + description { state: "default" 0.0; + rel1 { + relative: 0.0 0.0; + offset: -5 -5; + } + rel2 { + relative: 1.0 1.0; + offset: 4 4; + } + image { + normal: "tab-bg.png"; + border: 28 28 20 20; + } + fill.smooth: 0; + } + } + part { name: "elm.swallow.pad"; + type: SWALLOW; + description { state: "default" 0.0; + fixed: 1 0; + align: 0.0 0.5; + rel1 { + relative: 0.0 1.0; + offset: 0 -10; + } + rel2 { + to_y: "elm.text"; + relative: 0.0 0.0; + offset: -1 -1; + } + } + } + part { name: "elm.swallow.icon"; + clip_to: "disclip"; + type: SWALLOW; + description { state: "default" 0.0; + fixed: 1 0; + align: 0.5 0.5; + rel1 { + relative: 0.0 0.0; + offset: 20 11; + } + rel2 { + to_y: "elm.text"; + relative: 1.0 0.0; + offset: -24 -4; + } + } + } + part { name: "elm.swallow.end"; + clip_to: "disclip"; + type: SWALLOW; + description { state: "default" 0.0; + rel1 { + relative: 0.0 0.0; + offset: 0 0; + } + rel2 { + relative: 0.0 0.0; + offset: 0 0; + } + } + } + part { name: "elm.text"; + clip_to: "disclip"; + type: RECT; + description { state: "default" 0.0; + visible: 0; + } + } + part { name: "disclip"; + type: RECT; + description { state: "default" 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + } + description { state: "disabled" 0.0; + inherit: "default" 0.0; + color: 255 255 255 64; + } + } + part { name: "add-img"; + type: IMAGE; + description { state: "default" 0.0; + min: 23 23; + max: 23 23; + rel1 { + relative: 1.0 1.0; + offset: -54 1; + } + rel2 { + relative: 1.0 1.0; + offset: -6 -43; + } + image.normal: "tab-add.png"; + } + } + part { name: "bg-selected-border"; + clip_to: "disclip"; + mouse_events: 0; + description { state: "default" 0.0; + visible: 0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + color: 255 255 255 0; + image { + normal: "tab-bg-selected.png"; + border: 8 8 8 8; + } + fill.smooth: 0; + } + description { state: "selected" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + rel1 { + relative: 0.0 0.0; + offset: 15 5; + } + rel2 { + relative: 1.0 1.0; + offset: -16 -6; + } + image { + normal: "tab-bg-selected.png"; + border: 8 8 8 8; + } + } + } + } + programs { + // signal: elm,state,%s,active + // a "check" item named %s went active + // signal: elm,state,%s,passive + // a "check" item named %s went passive + // default is passive + program { + name: "go_active"; + signal: "elm,state,selected"; + source: "elm"; + action: STATE_SET "selected" 0.0; + target: "bg-selected-border"; + transition: ACCELERATE 0.1; + } + program { + name: "go_passive"; + signal: "elm,state,unselected"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "bg-selected-border"; + transition: DECELERATE 0.1; + } + } +} diff --git a/data/themes/elm-list.edc b/data/themes/elm-list.edc new file mode 100644 index 0000000..094ae0a --- /dev/null +++ b/data/themes/elm-list.edc @@ -0,0 +1,222 @@ + group { name: "elm/list/item/ewebkit"; + alias: "elm/list/item_odd/ewebkit"; + data.item: "stacking" "above"; + images { + image: "list-highlight.png" COMP; + } + parts { + part { + name: "event"; + type: RECT; + repeat_events: 1; + description { + state: "default" 0.0; + color: 0 0 0 0; + } + } + part { name: "bg"; + mouse_events: 0; + description { state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: -10 -10; + } + rel2 { + relative: 1.0 1.0; + offset: 9 9; + } + image { + normal: "list-highlight.png"; + border: 6 6 6 6; + } + image.middle: SOLID; + } + description { state: "selected" 0.0; + inherit: "default" 0.0; + visible: 1; + color: 255 255 255 255; + rel1 { + relative: 0.0 0.0; + offset: 0 -1; + } + rel2 { + relative: 1.0 1.0; + offset: -1 1; + } + } + } + part { name: "elm.swallow.icon"; + type: SWALLOW; + description { state: "default" 0.0; + fixed: 1 0; + align: 0.0 0.5; + rel1 { + relative: 0.0 0.0; + offset: 4 4; + } + rel2 { + relative: 0.0 1.0; + offset: 4 -5; + } + } + } + part { name: "elm.swallow.end"; + type: SWALLOW; + description { state: "default" 0.0; + fixed: 1 0; + align: 1.0 0.5; + rel1 { + relative: 1.0 0.0; + offset: -5 4; + } + rel2 { + relative: 1.0 1.0; + offset: -5 -5; + } + } + } + part { name: "elm.text"; + type: TEXT; + effect: SOFT_SHADOW; + mouse_events: 0; + scale: 1; + description { + state: "default" 0.0; +// min: 16 16; + rel1 { + to_x: "elm.swallow.icon"; + relative: 1.0 0.0; + offset: 38 0; + } + rel2 { + to_x: "elm.swallow.end"; + relative: 0.0 1.0; + offset: -1 -1; + } + color: 190 190 190 255; + color3: 0 0 0 0; + text { + font: "Sans"; + size: 11; + min: 1 1; +// min: 0 1; + align: 0.0 0.35; + } + } + description { + state: "selected" 0.0; + inherit: "default" 0.0; + } + } + } + programs { + program { + name: "go_active"; + signal: "elm,state,selected"; + source: "elm"; + action: STATE_SET "selected" 0.0; + target: "bg"; + target: "elm.text"; + transition: ACCELERATE 0.2; + } + program { + name: "go_passive"; + signal: "elm,state,unselected"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "bg"; + target: "elm.text"; + transition: DECELERATE 0.1; + } + } + } + group { name: "elm/list/separator/ewebkit"; + data.item: "stacking" "above"; + parts { + part { + name: "event"; + type: RECT; + repeat_events: 1; + description { + state: "default" 0.0; + color: 0 0 0 0; + } + } + part { name: "bg"; + mouse_events: 0; + description { state: "default" 0.0; + visible: 0; + color: 255 255 255 0; + rel1 { + relative: 0.0 0.0; + offset: -5 -5; + } + rel2 { + relative: 0.5 1.0; + offset: 4 4; + } + } + description { state: "selected" 0.0; + inherit: "default" 0.0; + visible: 0; + color: 255 255 255 128; + rel1 { + relative: 0.0 0.0; + offset: -2 -2; + } + rel2 { + relative: 0.5 1.0; + offset: 1 1; + } + } + } + part { name: "elm.swallow.icon"; + type: SWALLOW; + description { state: "default" 0.0; + visible: 0; + fixed: 1 0; + align: 0.0 0.5; + rel1 { + relative: 0.0 0.0; + offset: 4 4; + } + rel2 { + relative: 0.0 1.0; + offset: 4 -5; + } + } + } + part { name: "elm.swallow.end"; + type: SWALLOW; + description { state: "default" 0.0; + visible: 0; + fixed: 1 0; + align: 1.0 0.5; + rel1 { + relative: 1.0 0.0; + offset: -5 4; + } + rel2 { + relative: 1.0 1.0; + offset: -5 -5; + } + } + } + part { name: "elm.text"; + type: TEXT; + effect: SOFT_SHADOW; + mouse_events: 0; + scale: 1; + description { + state: "default" 0.0; + visible: 0; + } + description { + state: "selected" 0.0; + inherit: "default" 0.0; + } + } + } + } diff --git a/data/themes/elm-notify.edc b/data/themes/elm-notify.edc new file mode 100644 index 0000000..53d94d8 --- /dev/null +++ b/data/themes/elm-notify.edc @@ -0,0 +1,146 @@ +group { name: "elm/notify/block_events/ewebkit"; + images.image: "shadow-bottom.png" COMP; + images.image: "tab-header.png" COMP; + parts { + part { name: "bg"; + type: RECT; + description { state: "default" 0.0; + rel1.relative: 0.0 1.0; + rel1.offset: 0 -310; + rel2.relative: 1.0 1.0; + rel2.offset: -1 -1; + color: 0 0 0 255; + } + } + part { name: "shadow"; + type: IMAGE; + description { state: "default" 0.0; + image.normal: "shadow-bottom.png"; + rel1 { + relative: 0.0 1.0; + offset: 0 -326; + } + rel2 { + relative: 1.0 1.0; + offset: -1 -311; + } + } + } + part { name: "border"; + type: IMAGE; + description { state: "default" 0.0; + image.normal: "tab-header.png"; + max: 99999 14; + rel1 { + to: "shadow"; + relative: 0.0 1.0; + offset: 0 -21; + } + rel2 { + to: "shadow"; + relative: 1.0 1.0; + offset: -1 15; + } + } + } + part { name: "block_events"; + type: RECT; + description { state: "default" 0.0; + color: 0 0 0 128; + visible: 1; + rel1.relative: 0.0 0.0; + rel1.offset: 0 0; + rel2.relative: 1.0 1.0; + rel2.offset: -1 -311; + } + } + } + programs { + program { + name: "block_clicked"; + signal: "mouse,clicked,1"; + source: "block_events"; + action: SIGNAL_EMIT "elm,action,clicked" "elm"; + } + } +} +group { name: "elm/notify/bottom/ewebkit"; + min: 400 300; + parts { + part { name: "base"; + type: RECT; + mouse_events: 0; + repeat_events: 1; + description { state: "default" 0.0; + visible: 0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + rel2.offset: -1 -1; + color: 0 0 0 0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + visible: 1; + } + } + part { name: "shad"; + mouse_events: 0; + description { state: "default" 0.0; + rel1.to: "elm.swallow.content"; + rel1.offset: -64 -64; + rel2.to: "elm.swallow.content"; + rel2.offset: 63 63; + } + } + part { name: "pop"; + mouse_events: 1; + description { state: "default" 0.0; + rel1.to: "elm.swallow.content"; + rel1.offset: -5 -5; + rel2.to: "elm.swallow.content"; + rel2.offset: 4 4; + } + } + part { name: "popover"; + mouse_events: 0; + description { state: "default" 0.0; + rel1.to: "pop"; + rel2.to: "pop"; + rel2.relative: 1.0 0.5; + } + } + part { name: "elm.swallow.content"; + type: SWALLOW; + description { state: "default" 0.0; + rel1.to: "base"; + rel2.to: "base"; + } + } + } + programs { + program { name: "show"; + signal: "elm,action,show"; + source: "elm"; + action: STATE_SET "visible" 0.0; + target: "base"; + } + program { name: "show_2"; + signal: "show"; + action: STATE_SET "default" 0.0; + target: "base"; + after: "show_3"; + } + program { name: "show_3"; + signal: "show"; + action: STATE_SET "visible" 0.0; + target: "base"; + transition: ACCELERATE 0.2; + } + program { name: "hide"; + signal: "elm,action,hide"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "base"; + } + } +} diff --git a/data/themes/elm-pager.edc b/data/themes/elm-pager.edc new file mode 100644 index 0000000..992a5eb --- /dev/null +++ b/data/themes/elm-pager.edc @@ -0,0 +1,122 @@ + group { name: "elm/pager/base/ewebkit"; + data.item: "onshow" "raise"; +// other options +// data.item: "onhide" "lower"; +// data.item: "onshow" "lower"; + parts { + part { name: "clip"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + rel1 { + to: "base"; + offset: -9999 -9999; + } + rel2 { + to: "base"; + offset: 9999 9999; + } + color: 255 255 255 255; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + color: 255 255 255 0; + visible: 0; + } + } + part { name: "base"; + mouse_events: 0; + clip_to: "clip"; + description { state: "default" 0.0; } + description { state: "hidden" 0.0; + inherit: "default" 0.0; + rel1.relative: -1.0 0.0; + rel2.relative: 0.0 1.0; + } + description { state: "visible" 0.0; + inherit: "default" 0.0; + rel1.relative: 0.0 0.0; + rel2.relative: 1.0 1.0; + } + } + part { name: "elm.swallow.content"; + type: SWALLOW; + clip_to: "clip"; + description { state: "default" 0.0; + rel1 { + to: "base"; + offset: 0 0; + } + rel2 { + to: "base"; + offset: -1 -1; + } + } + } + } + programs { + program { name: "push_start"; + signal: "elm,action,push"; + source: "elm"; + action: STATE_SET "hidden" 0.0; + target: "base"; + target: "clip"; + after: "show_start2"; + } + program { name: "show_start"; + signal: "elm,action,show"; + source: "elm"; + action: STATE_SET "hidden" 0.0; + target: "base"; + target: "clip"; + after: "show_start2"; + } + program { name: "show_start2"; + action: STATE_SET "visible" 0.0; + transition: DECELERATE 0.5; + target: "base"; + target: "clip"; + after: "show_end"; + } + program { name: "show_end"; + action: SIGNAL_EMIT "elm,action,show,finished" ""; + } + program { name: "pop_start"; + signal: "elm,action,pop"; + source: "elm"; + action: STATE_SET "visible" 0.0; + target: "base"; + target: "clip"; + after: "hide_start2"; + } + program { name: "hide_start"; + signal: "elm,action,hide"; + source: "elm"; + action: STATE_SET "visible" 0.0; + target: "base"; + target: "clip"; + after: "hide_start2"; + } + program { name: "hide_start2"; + action: STATE_SET "hidden" 0.0; + transition: DECELERATE 0.5; + target: "base"; + target: "clip"; + after: "hide_end"; + } + program { name: "hide_end"; + action: SIGNAL_EMIT "elm,action,hide,finished" ""; + } + program { name: "reset"; + signal: "elm,action,reset"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "base"; + target: "clip"; + } + } + } + diff --git a/data/themes/elm-scroller.edc b/data/themes/elm-scroller.edc new file mode 100644 index 0000000..652041d --- /dev/null +++ b/data/themes/elm-scroller.edc @@ -0,0 +1,398 @@ + group { name: "elm/scroller/base/ewebkit"; + + alias: "elm/list/base/ewebkit"; + alias: "elm/genlist/base/ewebkit"; + alias: "elm/carousel/base/ewebkit"; + alias: "elm/gengrid/base/ewebkit"; + + images { + image: "scrollbar-knob.png" COMP; + image: "scrollbar-bg.png" COMP; + } + script { + public sbvis_v, sbvis_h, sbalways_v, sbalways_h; + } + parts { + part { name: "bg"; + type: RECT; + description { state: "default" 0.0; + rel1.offset: 1 1; + rel2.offset: -2 -2; + color: 0 0 0 255; + } + } + part { name: "clipper"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + } + } + part { name: "elm.swallow.content"; + clip_to: "clipper"; + type: SWALLOW; + description { state: "default" 0.0; + rel1.offset: 1 1; + rel2.offset: -2 -2; + } + } + part { name: "conf_over"; + mouse_events: 0; + description { state: "default" 0.0; + rel1.offset: 0 0; + rel2.offset: -1 -1; + } + } + part { name: "sb_vbar_clip_master"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + } + description { state: "hidden" 0.0; + visible: 0; + color: 255 255 255 0; + } + } + part { name: "sb_vbar_clip"; + clip_to: "sb_vbar_clip_master"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + } + description { state: "hidden" 0.0; + visible: 0; + color: 255 255 255 0; + } + } + part { name: "sb_vbar"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + fixed: 1 1; + visible: 0; + min: 2 32; + align: 1.0 0.0; + rel1 { + relative: 1.0 0.0; + offset: -8 25; + } + rel2 { + relative: 1.0 0.0; + offset: -7 -7; + to_y: "sb_hbar"; + } + } + } + part { name: "sb_vbar_runner"; + clip_to: "sb_vbar_clip"; + mouse_events: 0; + description { state: "default" 0.0; + min: 3 3; + max: 3 99999; + rel1.to: "sb_vbar"; + rel2.to: "sb_vbar"; + fixed: 1 1; + } + } + part { name: "vknob-bg"; + type: IMAGE; + mouse_events: 0; + clip_to: sb_vbar_clip; + description { state: "default" 0.0; + image.normal: "scrollbar-bg.png"; + image.border: 1 1 3 2; + max: 3 99999; + rel1 { + relative: 1.0 0.0; + offset: -10 25; + } + rel2 { + relative: 1.0 1.0; + offset: -6 -25; + } + } + } + part { name: "elm.dragable.vbar"; + clip_to: "sb_vbar_clip"; + mouse_events: 0; + dragable { + x: 0 0 0; + y: 1 1 0; + confine: "sb_vbar"; + } + description { state: "default" 0.0; + fixed: 1 1; + min: 2 12; + rel1 { + relative: 1.0 0.5; + offset: -3 0; + to: "sb_vbar"; + } + rel2 { + relative: 1.0 0.5; + offset: -1 0; + to: "sb_vbar"; + } + image { + normal: "scrollbar-knob.png"; + } + } + } + part { name: "sb_hbar_clip_master"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + } + description { state: "hidden" 0.0; + visible: 0; + color: 255 255 255 0; + } + } + part { name: "sb_hbar_clip"; + clip_to: "sb_hbar_clip_master"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + } + description { state: "hidden" 0.0; + visible: 0; + color: 255 255 255 0; + } + } + part { name: "sb_hbar"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + fixed: 1 1; + visible: 0; + min: 17 17; + align: 0.0 1.0; + rel1 { + relative: 0.0 1.0; + offset: 0 -2; + } + rel2 { + relative: 0.0 1.0; + offset: -1 -2; + to_x: "sb_vbar"; + } + } + } + part { name: "sb_hbar_runner"; + clip_to: "sb_hbar_clip"; + mouse_events: 0; + description { state: "default" 0.0; + min: 3 3; + max: 99999 3; + rel1.to: "sb_hbar"; + rel2.to: "sb_hbar"; + } + } + part { name: "elm.dragable.hbar"; + clip_to: "sb_hbar_clip"; + mouse_events: 0; + dragable { + x: 1 1 0; + y: 0 0 0; + confine: "sb_hbar"; + } + description { state: "default" 0.0; + fixed: 1 1; + min: 17 17; + rel1 { + relative: 0.5 0.5; + offset: 0 0; + to: "sb_hbar"; + } + rel2 { + relative: 0.5 0.5; + offset: 0 0; + to: "sb_hbar"; + } + } + } + part { name: "sb_hbar_over1"; + clip_to: "sb_hbar_clip"; + mouse_events: 0; + description { state: "default" 0.0; + rel1.to: "elm.dragable.hbar"; + rel2.relative: 1.0 0.5; + rel2.to: "elm.dragable.hbar"; + } + } + part { name: "sb_hbar_over2"; + clip_to: "sb_hbar_clip"; + mouse_events: 0; + description { state: "default" 0.0; + rel1.to: "elm.dragable.hbar"; + rel2.to: "elm.dragable.hbar"; + } + } + } + programs { + program { name: "load"; + signal: "load"; + source: ""; + script { + set_state(PART:"sb_hbar_clip", "hidden", 0.0); + set_state(PART:"sb_vbar_clip", "hidden", 0.0); + set_int(sbvis_h, 0); + set_int(sbalways_v, 0); + set_int(sbalways_h, 0); + + emit("do-show-vbar", ""); + set_int(sbvis_v, 1); + } + } + + program { name: "vbar_show"; + signal: "elm,action,show,vbar"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "sb_vbar_clip_master"; + } + program { name: "vbar_hide"; + signal: "elm,action,hide,vbar"; + source: "elm"; + action: STATE_SET "hidden" 0.0; + target: "sb_vbar_clip_master"; + } + program { name: "vbar_show_always"; + signal: "elm,action,show_always,vbar"; + source: "elm"; + script { + new v; + v = get_int(sbvis_v); + v |= get_int(sbalways_v); + if (!v) { + set_int(sbalways_v, 1); + emit("do-show-vbar", ""); + set_int(sbvis_v, 1); + } + } + } + program { name: "vbar_show_notalways"; + signal: "elm,action,show_notalways,vbar"; + source: "elm"; + script { + new v; + v = get_int(sbalways_v); + if (v) { + set_int(sbalways_v, 0); + v = get_int(sbvis_v); + if (!v) { + emit("do-hide-vbar", ""); + set_int(sbvis_v, 0); + } + } + } + } + program { name: "sb_vbar_show"; + signal: "do-show-vbar"; + source: ""; + action: STATE_SET "default" 0.0; + transition: LINEAR 1.0; + target: "sb_vbar_clip"; + } + program { name: "sb_vbar_hide"; + signal: "do-hide-vbar"; + source: ""; + action: STATE_SET "hidden" 0.0; + transition: LINEAR 1.0; + target: "sb_vbar_clip"; + } + + program { name: "hbar_show"; + signal: "elm,action,show,hbar"; + source: "elm"; + action: STATE_SET "default" 0.0; + target: "sb_hbar_clip_master"; + } + program { name: "hbar_hide"; + signal: "elm,action,hide,hbar"; + source: "elm"; + action: STATE_SET "hidden" 0.0; + target: "sb_hbar_clip_master"; + } + program { name: "hbar_show_always"; + signal: "elm,action,show_always,hbar"; + source: "elm"; + script { + new v; + v = get_int(sbvis_h); + v |= get_int(sbalways_h); + if (!v) { + set_int(sbalways_h, 1); + emit("do-show-hbar", ""); + set_int(sbvis_h, 1); + } + } + } + program { name: "hbar_show_notalways"; + signal: "elm,action,show_notalways,hbar"; + source: "elm"; + script { + new v; + v = get_int(sbalways_h); + if (v) { + set_int(sbalways_h, 0); + v = get_int(sbvis_h); + if (!v) { + emit("do-hide-hbar", ""); + set_int(sbvis_h, 0); + } + } + } + } + program { name: "sb_hbar_show"; + signal: "do-show-hbar"; + source: ""; + action: STATE_SET "default" 0.0; + transition: LINEAR 1.0; + target: "sb_hbar_clip"; + } + program { name: "sb_hbar_hide"; + signal: "do-hide-hbar"; + source: ""; + action: STATE_SET "hidden" 0.0; + transition: LINEAR 1.0; + target: "sb_hbar_clip"; + } + } + } + group { name: "elm/scroller/base/ewebkit/url"; + parts { + part { name: "bg"; + type: RECT; + description { state: "default" 0.0; + rel1.offset: 1 1; + rel2.offset: -2 -2; + color: 255 255 255 0; + } + } + part { name: "clipper"; + type: RECT; + mouse_events: 0; + description { state: "default" 0.0; + rel1.to: "bg"; + rel2.to: "bg"; + } + } + part { name: "elm.swallow.content"; + clip_to: "clipper"; + type: SWALLOW; + description { state: "default" 0.0; + rel1.offset: 1 1; + rel2.offset: -2 -2; + color: 255 0 0 128; + } + } + part { name: "elm.dragable.vbar"; + description { state: "default" 0.0; visible: 0; } + } + part { name: "elm.dragable.hbar"; + description { state: "default" 0.0; visible: 0; } + } + } + } diff --git a/data/themes/ewebkit.edj b/data/themes/ewebkit.edj new file mode 100644 index 0000000..3d4a0cb Binary files /dev/null and b/data/themes/ewebkit.edj differ diff --git a/data/themes/list-highlight.png b/data/themes/list-highlight.png new file mode 100644 index 0000000..2c836bd Binary files /dev/null and b/data/themes/list-highlight.png differ diff --git a/data/themes/panel-top-triangle.png b/data/themes/panel-top-triangle.png new file mode 100644 index 0000000..676d1a9 Binary files /dev/null and b/data/themes/panel-top-triangle.png differ diff --git a/data/themes/progress-bar-background.png b/data/themes/progress-bar-background.png new file mode 100644 index 0000000..a844e20 Binary files /dev/null and b/data/themes/progress-bar-background.png differ diff --git a/data/themes/scrollbar-bg.png b/data/themes/scrollbar-bg.png new file mode 100644 index 0000000..3b1bb80 Binary files /dev/null and b/data/themes/scrollbar-bg.png differ diff --git a/data/themes/scrollbar-knob.png b/data/themes/scrollbar-knob.png new file mode 100644 index 0000000..b83c07b Binary files /dev/null and b/data/themes/scrollbar-knob.png differ diff --git a/data/themes/shadow-bottom.png b/data/themes/shadow-bottom.png new file mode 100644 index 0000000..145e2d4 Binary files /dev/null and b/data/themes/shadow-bottom.png differ diff --git a/data/themes/tab-add.png b/data/themes/tab-add.png new file mode 100644 index 0000000..dd2d501 Binary files /dev/null and b/data/themes/tab-add.png differ diff --git a/data/themes/tab-bg-selected.png b/data/themes/tab-bg-selected.png new file mode 100644 index 0000000..4cb01b4 Binary files /dev/null and b/data/themes/tab-bg-selected.png differ diff --git a/data/themes/tab-bg.png b/data/themes/tab-bg.png new file mode 100644 index 0000000..4b3dee4 Binary files /dev/null and b/data/themes/tab-bg.png differ diff --git a/data/themes/tab-close.png b/data/themes/tab-close.png new file mode 100644 index 0000000..865906c Binary files /dev/null and b/data/themes/tab-close.png differ diff --git a/data/themes/tab-header.png b/data/themes/tab-header.png new file mode 100644 index 0000000..6b6230e Binary files /dev/null and b/data/themes/tab-header.png differ diff --git a/data/themes/toolbar-background-bottom.png b/data/themes/toolbar-background-bottom.png new file mode 100644 index 0000000..56393b0 Binary files /dev/null and b/data/themes/toolbar-background-bottom.png differ diff --git a/data/themes/toolbar-background-top.png b/data/themes/toolbar-background-top.png new file mode 100644 index 0000000..4a1e0dc Binary files /dev/null and b/data/themes/toolbar-background-top.png differ diff --git a/data/themes/url-entry.png b/data/themes/url-entry.png new file mode 100644 index 0000000..1d7612f Binary files /dev/null and b/data/themes/url-entry.png differ diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..ad133fc --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,24 @@ +codeset.m4 +gettext.m4 +glibc21.m4 +iconv.m4 +intdiv0.m4 +inttypes-pri.m4 +inttypes.m4 +inttypes_h.m4 +isc-posix.m4 +lcmessage.m4 +lib-ld.m4 +lib-link.m4 +lib-prefix.m4 +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +lt~obsolete.m4 +nls.m4 +po.m4 +progtest.m4 +stdint_h.m4 +uintmax_t.m4 +ulonglong.m4 diff --git a/m4/ac_attribute.m4 b/m4/ac_attribute.m4 new file mode 100644 index 0000000..23479a9 --- /dev/null +++ b/m4/ac_attribute.m4 @@ -0,0 +1,47 @@ +dnl Copyright (C) 2004-2008 Kim Woelders +dnl Copyright (C) 2008 Vincent Torri +dnl That code is public domain and can be freely used or copied. +dnl Originally snatched from somewhere... + +dnl Macro for checking if the compiler supports __attribute__ + +dnl Usage: AC_C___ATTRIBUTE__ +dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__ +dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is +dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused)) +dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is +dnl defined to nothing. + +AC_DEFUN([AC_C___ATTRIBUTE__], +[ + +AC_MSG_CHECKING([for __attribute__]) + +AC_CACHE_VAL([ac_cv___attribute__], + [AC_TRY_COMPILE( + [ +#include + +int func(int x); +int foo(int x __attribute__ ((unused))) +{ + exit(1); +} + ], + [], + [ac_cv___attribute__="yes"], + [ac_cv___attribute__="no"] + )]) + +AC_MSG_RESULT($ac_cv___attribute__) + +if test "x${ac_cv___attribute__}" = "xyes" ; then + AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__]) + AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused]) + else + AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused]) +fi + +]) + +dnl End of ac_attribute.m4 diff --git a/po/.gitignore b/po/.gitignore new file mode 100644 index 0000000..e8dc6bc --- /dev/null +++ b/po/.gitignore @@ -0,0 +1,12 @@ +Makefile.in.in +Makevars.template +POTFILES +Rules-quot +boldquot.sed +en@boldquot.header +en@quot.header +insert-header.sin +quot.sed +remove-potcdate.sed +remove-potcdate.sin +stamp-po diff --git a/po/LINGUAS b/po/LINGUAS new file mode 100644 index 0000000..e69de29 diff --git a/po/Makevars b/po/Makevars new file mode 100644 index 0000000..18d1687 --- /dev/null +++ b/po/Makevars @@ -0,0 +1,7 @@ +DOMAIN = eve +subdir = po +top_builddir = .. +XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ +COPYRIGHT_HOLDER = Gustavo Sverzut Barbieri +MSGID_BUGS_ADDRESS = barbieri@profusion.mobi +EXTRA_LOCALE_CATEGORIES = diff --git a/po/POTFILES.in b/po/POTFILES.in new file mode 100644 index 0000000..91df206 --- /dev/null +++ b/po/POTFILES.in @@ -0,0 +1 @@ +src/bin/main.c diff --git a/src/.gitignore b/src/.gitignore new file mode 100644 index 0000000..16d8b4d --- /dev/null +++ b/src/.gitignore @@ -0,0 +1,6 @@ +.deps +.libs +*.o +*.a +*.lo +*.la diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..ccfbf1a --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,2 @@ +MAINTAINERCLEANFILES = Makefile.in +SUBDIRS = bin diff --git a/src/bin/.gitignore b/src/bin/.gitignore new file mode 100644 index 0000000..499bbe5 --- /dev/null +++ b/src/bin/.gitignore @@ -0,0 +1,2 @@ +eve +eve_ql diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am new file mode 100644 index 0000000..19e965d --- /dev/null +++ b/src/bin/Makefile.am @@ -0,0 +1,40 @@ +MAINTAINERCLEANFILES = Makefile.in + +INCLUDES = \ +-I$(top_srcdir) \ +-I$(top_srcdir)/src/bin \ +-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ +-DGETTEXT_PACKAGE=\"$(PACKAGE)\" \ +-DLOCALEDIR=\"$(localedir)\" \ +@ELEMENTARY_CFLAGS@ \ +@EWEBKIT_CFLAGS@ + +bin_PROGRAMS = eve +if BUILD_QUICKLAUNCH +bin_PROGRAMS += eve_ql +endif + +eve_LDADD = @ELEMENTARY_LIBS@ @EWEBKIT_LIBS@ +eve_SOURCES = main.c view.c chrome.c favorite.c history.c + +if BUILD_QUICKLAUNCH +############################################################################ +## Build quick launch binary, needs elementary_quicklaunch to be enabled. ## +## ## +## It is composed of a library with actual code and a binary that talks ## +## to server that will then fork() + dlopen() such library. ## +############################################################################ +eve_qldir = $(quicklauncher_libdir) +eve_ql_LTLIBRARIES = eve_ql.la +eve_ql_la_SOURCES = main.c view.c chrome.c +eve_ql_la_LIBADD = @ELEMENTARY_LIBS@ @EWEBKIT_LIBS@ +eve_ql_la_CFLAGS = +eve_ql_la_LDFLAGS = -module -avoid-version -no-undefined +eve_ql_SOURCES = main.c +eve_ql_LDADD = @ELEMENTARY_LIBS@ +eve_ql_CFLAGS = -DELM_LIB_QUICKLAUNCH=1 +eve_ql_LDFLAGS = +endif + +noinst_HEADERS = gettext.h private.h favorite.h history.h +EXTRA_DIST = gettext.h private.h favorite.h history.h diff --git a/src/bin/chrome.c b/src/bin/chrome.c new file mode 100644 index 0000000..c3f71ca --- /dev/null +++ b/src/bin/chrome.c @@ -0,0 +1,1369 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif /* _GNU_SOURCE */ +#include +#include + +#include + +#include "favorite.h" +#include "private.h" + +#define BOOKMARK_MENU_PREALLOC_SIZE 32 + +typedef struct _Bookmark_Menu_Item Bookmark_Menu_Item; +typedef struct _Bookmark_Menu_Filter_Context Bookmark_Menu_Filter_Context; +typedef Bookmark_Menu_Item *(*Bookmark_Menu_Callback)(Bookmark_Menu_Item *current_item); + +static Bookmark_Menu_Item *bookmark_menu_favorites(Bookmark_Menu_Item*); +static Bookmark_Menu_Item *bookmark_menu_history_today(Bookmark_Menu_Item*); +static Bookmark_Menu_Item *bookmark_menu_history_yesterday(Bookmark_Menu_Item*); +static Bookmark_Menu_Item *bookmark_menu_history_this_week(Bookmark_Menu_Item*); +static Bookmark_Menu_Item *bookmark_menu_history_most_visited(Bookmark_Menu_Item*); +static Bookmark_Menu_Item *bookmark_menu_history_least_visited(Bookmark_Menu_Item*); +static Bookmark_Menu_Item *bookmark_menu_history_by_domain(Bookmark_Menu_Item*); + +static Elm_Gengrid_Item_Class gic_default, gic_new_page; + +typedef enum { + ITEM_TYPE_LAST, + ITEM_TYPE_STATIC_FOLDER, + ITEM_TYPE_DYNAMIC_FOLDER, + ITEM_TYPE_PAGE, + ITEM_TYPE_CALLBACK, + ITEM_TYPE_SEPARATOR, +} Bookmark_Menu_Item_Type; + +struct _Bookmark_Menu_Item { + Bookmark_Menu_Item_Type type; + const char *text; + void *next; + Eina_Bool dynamic : 1; +}; + +struct _Bookmark_Menu_Filter_Context { + Bookmark_Menu_Item *current_bookmark_item; + double time; +}; + +static Bookmark_Menu_Item bookmark_menu_history[] = +{ + { ITEM_TYPE_DYNAMIC_FOLDER, "Today", bookmark_menu_history_today, EINA_FALSE }, + { ITEM_TYPE_DYNAMIC_FOLDER, "Yesterday", bookmark_menu_history_yesterday, EINA_FALSE }, + { ITEM_TYPE_DYNAMIC_FOLDER, "This week", bookmark_menu_history_this_week, EINA_FALSE }, + { ITEM_TYPE_SEPARATOR, NULL, NULL, EINA_FALSE }, + { ITEM_TYPE_DYNAMIC_FOLDER, "Most visited", bookmark_menu_history_most_visited, EINA_FALSE }, + { ITEM_TYPE_DYNAMIC_FOLDER, "Least visited", bookmark_menu_history_least_visited, EINA_FALSE }, + { ITEM_TYPE_SEPARATOR, NULL, NULL, EINA_FALSE }, + { ITEM_TYPE_DYNAMIC_FOLDER, "By domain", bookmark_menu_history_by_domain, EINA_FALSE }, + { ITEM_TYPE_LAST, NULL, NULL, EINA_FALSE } +}; + +static Bookmark_Menu_Item bookmark_menu_root[] = +{ + { ITEM_TYPE_STATIC_FOLDER, "History", bookmark_menu_history, EINA_FALSE }, + { ITEM_TYPE_DYNAMIC_FOLDER, "Favorites", bookmark_menu_favorites, EINA_FALSE }, + { ITEM_TYPE_SEPARATOR, NULL, NULL, EINA_FALSE }, + { ITEM_TYPE_PAGE, "ProFUSION", "http://profusion.mobi", EINA_FALSE }, + { ITEM_TYPE_PAGE, "WebKit", "http://webkit.org", EINA_FALSE }, + { ITEM_TYPE_PAGE, "Enlightenment", "http://enlightenment.org", EINA_FALSE }, +#ifdef STORM_TROOPER + { ITEM_TYPE_SEPARATOR, NULL, NULL, EINA_FALSE }, + { ITEM_TYPE_PAGE, "", "http://i.imgur.com/cJO3j.gif", EINA_FALSE }, +#endif + { ITEM_TYPE_LAST, NULL, NULL, EINA_FALSE } +}; + + +static Eina_List* +_eina_hash_sorted_keys_get(Eina_Hash *hash, Eina_Compare_Cb compare_func) +{ + Eina_List *keyvals = NULL, *keys = NULL, *keyvals_iter; + Eina_Iterator *iter = eina_hash_iterator_tuple_new(hash); + Eina_Hash_Tuple *keyval; + + EINA_ITERATOR_FOREACH(iter, keyval) + keyvals = eina_list_prepend(keyvals, keyval); + keyvals = eina_list_sort(keyvals, 0, compare_func); + EINA_LIST_FOREACH(keyvals, keyvals_iter, keyval) + keys = eina_list_append(keys, keyval->key); + + eina_list_free(keyvals); + eina_iterator_free(iter); + + return keys; +} +static Bookmark_Menu_Item* +_bookmark_menu_history(Eina_Iterator *items, Bookmark_Menu_Item *current_item, Eina_Bool (*filter)(Bookmark_Menu_Filter_Context *ctx, Hist_Item *item)) +{ + Bookmark_Menu_Item *bm_item; + Bookmark_Menu_Item *ret = NULL, *new_ret; + Bookmark_Menu_Filter_Context ctx; + int n_items = 0; + const char *url; + + ctx.time = ecore_time_get(); + ctx.current_bookmark_item = current_item; + + EINA_ITERATOR_FOREACH(items, url) + { + Hist_Item *item = hist_items_get(hist, url); + + if (!filter(&ctx, item)) continue; + + bm_item = calloc(1, sizeof(Bookmark_Menu_Item)); + bm_item->type = ITEM_TYPE_PAGE; + bm_item->text = eina_stringshare_add(hist_item_title_get(item)); + bm_item->next = (char *)hist_item_url_get(item); + bm_item->dynamic = 1; + + if (!ret) + ret = calloc(1, sizeof(*ret) * BOOKMARK_MENU_PREALLOC_SIZE); + else if (n_items % BOOKMARK_MENU_PREALLOC_SIZE == 0) + { + new_ret = realloc(ret, (BOOKMARK_MENU_PREALLOC_SIZE * n_items * sizeof(*ret))); + if (new_ret) ret = new_ret; + else goto realloc_error; + } + + memcpy(&ret[n_items], bm_item, sizeof(*ret)); + free(bm_item); + + n_items++; + } + +realloc_error: + + if (!n_items) return NULL; + + bm_item = calloc(1, sizeof(Bookmark_Menu_Item)); + bm_item->type = ITEM_TYPE_LAST; + new_ret = realloc(ret, (1 + n_items) * sizeof(*ret)); + if (!new_ret) + { + free(bm_item); + free(ret); + return NULL; + } + ret = new_ret; + memcpy(&ret[n_items], bm_item, sizeof(*ret)); + free(bm_item); + + return ret; +} + +static Eina_Bool +_domain_filter(Bookmark_Menu_Filter_Context *ctx, Hist_Item *item) +{ + char *domain = strstr(hist_item_url_get(item), "://"); + const char *filtered_domain = ctx->current_bookmark_item->text; + if (domain) + { + domain += 3; + return !strncmp(domain, filtered_domain, strlen(filtered_domain)); + } + return EINA_FALSE; +} + +static Bookmark_Menu_Item* +_bookmark_menu_history_by_domain(Bookmark_Menu_Item *current_item) +{ + Bookmark_Menu_Item *ret; + Eina_Iterator *items = eina_hash_iterator_key_new(hist_items_hash_get(hist)); + + ret = _bookmark_menu_history(items, current_item, _domain_filter); + eina_iterator_free(items); + + return ret; +} + +static Bookmark_Menu_Item* +bookmark_menu_history_by_domain(Bookmark_Menu_Item *current_item) +{ + Bookmark_Menu_Item *bm_item; + Bookmark_Menu_Item *ret = NULL, *new_ret; + Eina_Iterator *items = eina_hash_iterator_key_new(hist_items_hash_get(hist)); + Eina_Hash *domains = eina_hash_string_superfast_new(NULL); + const char *url; + int n_items = 0; + + EINA_ITERATOR_FOREACH(items, url) + { + char *urlcopy = strdup(url); + char *domain, *end; + + if ((domain = strcasestr(urlcopy, "http://"))) domain += 7; + else if ((domain = strcasestr(urlcopy, "https://"))) domain += 8; + else goto unknown_schema; + + if ((end = strchr(domain, '/'))) + { + *end = '\0'; + eina_hash_set(domains, strdup(domain), (void *)1); + } +unknown_schema: + free(urlcopy); + } + eina_iterator_free(items); + + items = eina_hash_iterator_key_new(domains); + EINA_ITERATOR_FOREACH(items, url) + { + bm_item = calloc(1, sizeof(Bookmark_Menu_Item)); + bm_item->type = ITEM_TYPE_DYNAMIC_FOLDER; + bm_item->text = eina_stringshare_add(url); + bm_item->next = _bookmark_menu_history_by_domain; + bm_item->dynamic = 1; + + if (!n_items) + ret = calloc(1, sizeof(*ret) * BOOKMARK_MENU_PREALLOC_SIZE); + else if (n_items % BOOKMARK_MENU_PREALLOC_SIZE == 0) + { + new_ret = realloc(ret, (BOOKMARK_MENU_PREALLOC_SIZE * n_items * sizeof(*ret))); + if (new_ret) ret = new_ret; + else goto realloc_error; + } + + memcpy(&ret[n_items], bm_item, sizeof(*ret)); + free(bm_item); + + n_items++; + } +realloc_error: + eina_iterator_free(items); + eina_hash_free(domains); + + if (!n_items) return NULL; + + bm_item = calloc(1, sizeof(Bookmark_Menu_Item)); + bm_item->type = ITEM_TYPE_LAST; + new_ret = realloc(ret, (1 + n_items) * sizeof(*ret)); + if (!new_ret) + { + free(bm_item); + free(ret); + return NULL; + } + ret = new_ret; + memcpy(&ret[n_items], bm_item, sizeof(*ret)); + free(bm_item); + + return ret; +} + +static Eina_Bool +_this_week_filter(Bookmark_Menu_Filter_Context *ctx, Hist_Item *item) +{ + double item_time = hist_item_last_visit_get(item); + double now = ctx->time; + return (now - item_time) <= 7 * 24 * 3600; +} + +static Eina_Bool +_today_filter(Bookmark_Menu_Filter_Context *ctx, Hist_Item *item) +{ + double item_time = hist_item_last_visit_get(item); + double now = ctx->time; + return (now - item_time) <= 24 * 3600; +} + + +static Eina_Bool +_yesterday_filter(Bookmark_Menu_Filter_Context *ctx, Hist_Item *item) +{ + double item_time = hist_item_last_visit_get(item); + double now = ctx->time; + return (now - item_time) > 24 * 3600 && (now - item_time) <= 48 * 3600; +} + +static Bookmark_Menu_Item* +bookmark_menu_history_today(Bookmark_Menu_Item *current_item) +{ + Eina_Iterator *iter = eina_hash_iterator_key_new(hist_items_hash_get(hist)); + Bookmark_Menu_Item *items = _bookmark_menu_history(iter, current_item, _today_filter); + eina_iterator_free(iter); + return items; +} + +static Bookmark_Menu_Item* +bookmark_menu_history_yesterday(Bookmark_Menu_Item *current_item) +{ + Eina_Iterator *iter = eina_hash_iterator_key_new(hist_items_hash_get(hist)); + Bookmark_Menu_Item *items = _bookmark_menu_history(iter, current_item, _yesterday_filter); + eina_iterator_free(iter); + return items; +} + +static Bookmark_Menu_Item* +bookmark_menu_history_this_week(Bookmark_Menu_Item *current_item) +{ + Eina_Iterator *iter = eina_hash_iterator_key_new(hist_items_hash_get(hist)); + Bookmark_Menu_Item *items = _bookmark_menu_history(iter, current_item, _this_week_filter); + eina_iterator_free(iter); + return items; +} + +static int +_cb_compare_hist_visit_count_decr(const void *data1, const void *data2) +{ + Hist_Item *f1 = ((Eina_Hash_Tuple *)data1)->data; + Hist_Item *f2 = ((Eina_Hash_Tuple *)data2)->data; + + return hist_item_visit_count_get(f2) - hist_item_visit_count_get(f1); +} + +static int +_cb_compare_hist_visit_count_incr(const void *data1, const void *data2) +{ + Hist_Item *f1 = ((Eina_Hash_Tuple *)data1)->data; + Hist_Item *f2 = ((Eina_Hash_Tuple *)data2)->data; + + return hist_item_visit_count_get(f1) - hist_item_visit_count_get(f2); +} + +static Bookmark_Menu_Item* +bookmark_menu_history_least_visited(Bookmark_Menu_Item *current_item) +{ + Eina_List *keys = _eina_hash_sorted_keys_get(hist_items_hash_get(hist), _cb_compare_hist_visit_count_incr); + Eina_Iterator *iter = eina_list_iterator_new(keys); + Bookmark_Menu_Item *items = _bookmark_menu_history(iter, current_item, _this_week_filter); + eina_list_free(keys); + eina_iterator_free(iter); + return items; +} + +static Bookmark_Menu_Item* +bookmark_menu_history_most_visited(Bookmark_Menu_Item *current_item) +{ + Eina_List *keys = _eina_hash_sorted_keys_get(hist_items_hash_get(hist), _cb_compare_hist_visit_count_decr); + Eina_Iterator *iter = eina_list_iterator_new(keys); + Bookmark_Menu_Item *items = _bookmark_menu_history(iter, current_item, _this_week_filter); + eina_list_free(keys); + eina_iterator_free(iter); + return items; +} + +static Bookmark_Menu_Item* +bookmark_menu_favorites(Bookmark_Menu_Item *current_item) +{ + Bookmark_Menu_Item *bm_item; + Bookmark_Menu_Item *ret = NULL, *new_ret; + Eina_Iterator *iter = eina_hash_iterator_key_new(fav_items_hash_get(fav)); + int n_items = 0; + const char *url; + + EINA_ITERATOR_FOREACH(iter, url) + { + Fav_Item *item = fav_items_get(fav, url); + + bm_item = calloc(1, sizeof(Bookmark_Menu_Item)); + bm_item->type = ITEM_TYPE_PAGE; + bm_item->text = eina_stringshare_add(fav_item_title_get(item)); + bm_item->next = (char *)fav_item_url_get(item); + bm_item->dynamic = 1; + + if (!n_items) + ret = calloc(1, sizeof(*ret) * BOOKMARK_MENU_PREALLOC_SIZE); + else if (n_items % BOOKMARK_MENU_PREALLOC_SIZE == 0) + { + new_ret = realloc(ret, (BOOKMARK_MENU_PREALLOC_SIZE * n_items * sizeof(*ret))); + if (new_ret) ret = new_ret; + else goto realloc_error; + } + + memcpy(&ret[n_items], bm_item, sizeof(*ret)); + free(bm_item); + + n_items++; + } +realloc_error: + eina_iterator_free(iter); + + if (!n_items) + { + free(ret); + return NULL; + } + + bm_item = calloc(1, sizeof(Bookmark_Menu_Item)); + bm_item->type = ITEM_TYPE_LAST; + new_ret = realloc(ret, (1 + n_items) * sizeof(*ret)); + if (!new_ret) + { + free(bm_item); + free(ret); + return NULL; + } + ret = new_ret; + memcpy(&ret[n_items], bm_item, sizeof(*ret)); + free(bm_item); + + return ret; +} + +static void +on_view_mask_visible(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Browser_Window *win = data; + Evas_Object *ed = elm_layout_edje_get(win->current_chrome); + Evas_Object *url_entry = edje_object_part_swallow_get(ed, "url-entry"); + + evas_object_focus_set(win->current_view, EINA_FALSE); + evas_object_focus_set(url_entry, EINA_TRUE); + elm_object_focus(url_entry); +} + +static void +on_view_mask_hidden(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Browser_Window *win = data; + + evas_object_focus_set(win->current_view, EINA_TRUE); +} + +static void +on_fav_on(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Evas_Object *view = data; + const char *url = ewk_view_uri_get(view); + + if (url) + { + const char *title = ewk_view_title_get(view); + fav_items_add(fav, url, fav_item_new(url, title, 1)); + } +} + +static void +on_fav_off(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Evas_Object *view = data; + const char *url = ewk_view_uri_get(view); + + if (url) fav_items_del(fav, url); +} + +static void +_is_favorite_check(Evas_Object *chrome, const char *url) +{ + Evas_Object *ed = elm_layout_edje_get(chrome); + Fav_Item *item; + + if (url && (item = fav_items_get(fav, url))) + { + fav_item_visit_count_set(item, fav_item_visit_count_get(item) + 1); + edje_object_signal_emit(ed, "favorite,hilight", ""); + } + else + edje_object_signal_emit(ed, "favorite,default", ""); +} + +static void +_history_update(const char *url, const char *title) +{ + Hist_Item *item; + + if (!url) return; + + if ((item = hist_items_get(hist, url))) + { + hist_item_visit_count_set(item, hist_item_visit_count_get(item) + 1); + hist_item_last_visit_set(item, ecore_time_get()); + hist_item_title_set(item, title); + } + else + hist_items_add(hist, url, hist_item_new(title, url, 1, ecore_time_get())); +} + +static void +_chrome_state_apply(Evas_Object * chrome, Evas_Object * view) +{ + const char *url = ewk_view_uri_get(view); + const char *title = ewk_view_title_get(view); + Evas_Object *ed = elm_layout_edje_get(chrome); + Evas_Object *text_url; + + if (!title) + title = url; + edje_object_part_text_set(ed, "text.title", title ? title : ""); + + text_url = edje_object_part_swallow_get(ed, "url-entry"); + elm_scrolled_entry_entry_set(text_url, url ? url : ""); + _is_favorite_check(chrome, url); + _history_update(url, title); + + // TODO: check if actions are possible: back/forward/pause/reload +} + +static void +on_view_load_progress(void *data, Evas_Object * view __UNUSED__, + void *event_info) +{ + Evas_Object *chrome = data; + Evas_Object *ed = elm_layout_edje_get(chrome); + + double *progress = event_info; + Edje_Message_Float msg = { *progress }; + edje_object_message_send(ed, EDJE_MESSAGE_FLOAT, 1, &msg); +} + +static void +on_view_title_changed(void *data, Evas_Object * view, + void *event_info __UNUSED__) +{ + Evas_Object *chrome = data; + + _chrome_state_apply(chrome, view); +} + +static void +on_view_uri_changed(void *data, Evas_Object * view, void *event_info __UNUSED__) +{ + Evas_Object *chrome = data; + + _chrome_state_apply(chrome, view); +} + +static void +on_view_zoom_interactive(void *data, Evas_Object * view __UNUSED__, + void *event_info) +{ + Evas_Object *chrome = data; + Evas_Object *ed = elm_layout_edje_get(chrome); + + const View_Zoom_Interactive *ev = event_info; + + char buf[256]; + + snprintf(buf, sizeof(buf), "zoom=%0.1f", ev->zoom); + edje_object_part_text_set(ed, "text.zoom", buf); +} + +static void +on_view_zoom_interactive_start(void *data, Evas_Object * view __UNUSED__, + void *event_info __UNUSED__) +{ + Evas_Object *chrome = data; + Evas_Object *ed = elm_layout_edje_get(chrome); + + edje_object_signal_emit(ed, "zoom,show", ""); +} + +static void +on_view_zoom_interactive_end(void *data, Evas_Object * view __UNUSED__, + void *event_info __UNUSED__) +{ + Evas_Object *chrome = data; + Evas_Object *ed = elm_layout_edje_get(chrome); + + edje_object_signal_emit(ed, "zoom,hide", ""); +} + +static void +on_view_statusbar_text_set(void *data, Evas_Object * view __UNUSED__, + void *event_info) +{ + Evas_Object *chrome = data; + Evas_Object *ed = elm_layout_edje_get(chrome); + const char *text = event_info; + + edje_object_part_text_set(ed, "text.statusbar", text); + edje_object_signal_emit(ed, "statusbar,show", ""); +} + +static void +on_view_link_hover_in(void *data, Evas_Object * view __UNUSED__, + void *event_info) +{ + Evas_Object *chrome = data; + Evas_Object *ed = elm_layout_edje_get(chrome); + const char **link = event_info; + + edje_object_part_text_set(ed, "text.statusbar", link[0]); + edje_object_signal_emit(ed, "statusbar,show", ""); +} + +static void +on_view_link_hover_out(void *data, Evas_Object * view __UNUSED__, + void *event_info __UNUSED__) +{ + Evas_Object *chrome = data; + Evas_Object *ed = elm_layout_edje_get(chrome); + + edje_object_signal_emit(ed, "statusbar,hide", ""); +} + +static Eina_Bool +_view_popup_delete(void *notify) +{ + evas_object_del(notify); + return EINA_FALSE; +} + +static void +on_view_popup_delete(void *data, Evas_Object * view, void *event_info) +{ + ecore_idler_add(_view_popup_delete, data); +} + +static void +_popup_item_selected(void *data, Evas_Object * obj, void *event_info) +{ + Evas_Object *view = data; + Elm_List_Item *it = elm_list_selected_item_get(obj); + const Eina_List *itr, *list = elm_list_items_get(obj); + void *d; + int i = 0; + + EINA_LIST_FOREACH(list, itr, d) + { + if (d == it) + break; + i++; + } + + ewk_view_popup_selected_set(view, i); + ewk_view_popup_destroy(view); +} + +static void +on_view_popup_new(void *data, Evas_Object * view, void *event_info) +{ + Ewk_Menu *menu = event_info; + Ewk_Menu_Item *item; + Eina_List *l; + Evas_Object *li; + Evas_Object *chrome = evas_object_data_get(view, "chrome"); + Evas_Object *notify = elm_notify_add(chrome); + + elm_object_style_set(notify, "ewebkit"); + evas_object_size_hint_weight_set(notify, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_notify_repeat_events_set(notify, EINA_FALSE); + elm_notify_orient_set(notify, ELM_NOTIFY_ORIENT_BOTTOM); + + li = elm_list_add(view); + elm_object_style_set(li, "ewebkit"); + elm_list_always_select_mode_set(li, 1); + evas_object_size_hint_weight_set(li, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_fill_set(li, EVAS_HINT_FILL, EVAS_HINT_FILL); + + EINA_LIST_FOREACH(menu->items, l, item) + elm_list_item_append(li, item->text, NULL, NULL, _popup_item_selected, + view); + + elm_list_go(li); + evas_object_show(li); + elm_notify_content_set(notify, li); + + evas_object_smart_callback_add(view, "popup,willdelete", + on_view_popup_delete, notify); + + evas_object_show(notify); +} + +static void +on_tab_close(void *data, Evas_Object * o, + const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Browser_Window *win = evas_object_data_get(o, "win"); + Evas_Object *chrome = evas_object_data_get(data, "chrome"); + Elm_Gengrid_Item *item = evas_object_data_get(o, "item"); + Evas_Object *ed; + + elm_gengrid_item_del(item); + tab_close_chrome(win, chrome); + + ed = elm_layout_edje_get(win->current_chrome); + edje_object_signal_emit(ed, "tab,item,clicked", ""); +} + +static void +on_tab_gengrid_item_realized(void *data, Evas_Object * o, void *event_info) +{ + Browser_Window *win = data; + Evas_Object *item = (Evas_Object *) elm_gengrid_item_object_get(event_info); + + evas_object_data_set(item, "item", event_info); + evas_object_data_set(item, "win", win); + edje_object_signal_callback_add(item, "tab,close", "", on_tab_close, + elm_gengrid_item_data_get(event_info)); +} + +static void +on_action_back(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Evas_Object *view = data; + + ewk_view_back(view); +} + +static void +on_action_forward(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, + const char *source __UNUSED__) +{ + Evas_Object *view = data; + + ewk_view_forward(view); +} + +static void on_bookmark_item_click(void *data, Evas_Object * obj, void *event_info __UNUSED__); +static void on_bookmark_item_back_click(void *data, Evas_Object *edje, const char *emission __UNUSED__, const char *source __UNUSED__); + +static void +bookmark_menu_set(Evas_Object *chrome, + Evas_Object *list, + Bookmark_Menu_Item *root, + const char *old_text) +{ + Browser_Window *win = evas_object_data_get(chrome, "win"); + Evas_Object *ed = elm_layout_edje_get(chrome); + int i; + + if (!eina_list_data_find(win->list_history, root)) + { + if (root == bookmark_menu_root || !root) + win->list_history = eina_list_prepend(win->list_history, NULL); + else + win->list_history = eina_list_prepend(win->list_history, root); + } + + elm_list_clear(list); + + if (!root || root == bookmark_menu_root) + { + root = bookmark_menu_root; + edje_object_part_text_set(ed, "bookmark-list-title", "Bookmarks"); + edje_object_signal_emit(ed, "list,back,hide", ""); + } + else + { + edje_object_part_text_set(ed, "bookmark-list-back-button-text", eina_stringshare_add(old_text ? old_text : "Bookmarks")); + edje_object_signal_callback_del(ed, "list,back,clicked", "", on_bookmark_item_back_click); + edje_object_signal_callback_add(ed, "list,back,clicked", "", on_bookmark_item_back_click, list); + + edje_object_signal_emit(ed, "list,back,show", ""); + } + + for (i = 0; root[i].type != ITEM_TYPE_LAST; i++) { + if (root[i].type == ITEM_TYPE_SEPARATOR) + { + Elm_List_Item *item = elm_list_item_append(list, NULL, NULL, NULL, NULL, NULL); + elm_list_item_separator_set(item, EINA_TRUE); + } + else + elm_list_item_append(list, root[i].text, NULL, NULL, on_bookmark_item_click, &root[i]); + } + + elm_list_go(list); +} + +static void +on_bookmark_item_back_click(void *data, Evas_Object *edje, + const char *emission __UNUSED__, + const char *source __UNUSED__) +{ + Bookmark_Menu_Item *bmi; + Browser_Window *win = evas_object_data_get(edje, "win"); + Evas_Object *list = data; + + edje_object_signal_emit(edje, "list,animate,right", ""); + edje_object_part_text_set(edje, "bookmark-list-title", edje_object_part_text_get(edje, "bookmark-list-back-button-text")); + eina_stringshare_del(edje_object_part_text_get(edje, "bookmark-list-back-button-text")); + + if ((bmi = win->list_history->data) && bmi->dynamic) + { + eina_stringshare_del(bmi->text); + free(bmi); + } + win->list_history = eina_list_remove_list(win->list_history, win->list_history); + win->list_history_titles = eina_list_remove_list(win->list_history_titles, win->list_history_titles); + + if (!win->list_history_titles) + bookmark_menu_set(win->current_chrome, list, win->list_history->data, "Bookmarks"); + else + bookmark_menu_set(win->current_chrome, list, win->list_history->data, win->list_history_titles->data); +} + +static void +on_bookmark_item_click(void *data, Evas_Object * obj, + void *event_info __UNUSED__) +{ + Evas_Object *chrome = evas_object_data_get(obj, "chrome"); + Evas_Object *ed = elm_layout_edje_get(chrome); + Bookmark_Menu_Item *bmi = data; + Browser_Window *win = evas_object_data_get(chrome, "win"); + const char *old_text = edje_object_part_text_get(ed, "bookmark-list-title"); + + if (!bmi) return; + + switch (bmi->type) { + case ITEM_TYPE_STATIC_FOLDER: + win->list_history_titles = eina_list_prepend(win->list_history_titles, old_text); + edje_object_signal_emit(ed, "list,animate,left", ""); + edje_object_part_text_set(ed, "bookmark-list-title", bmi->text); + bookmark_menu_set(chrome, obj, bmi->next, old_text); + break; + case ITEM_TYPE_DYNAMIC_FOLDER: + { + Bookmark_Menu_Callback callback = bmi->next; + if (!callback) return; + Bookmark_Menu_Item *new_root = callback(bmi); + if (new_root) + { + win->list_history_titles = eina_list_prepend(win->list_history_titles, old_text); + edje_object_part_text_set(ed, "bookmark-list-title", bmi->text); + edje_object_signal_emit(ed, "list,animate,left", ""); + bookmark_menu_set(chrome, obj, new_root, old_text); + } + } + break; + case ITEM_TYPE_LAST: + case ITEM_TYPE_SEPARATOR: + break; + case ITEM_TYPE_CALLBACK: + { + Bookmark_Menu_Callback callback = bmi->next; + Evas_Object *ed = elm_layout_edje_get(chrome); + if (callback) callback(bmi); + edje_object_signal_emit(ed, "bookmark,item,clicked", ""); + } + break; + default: + { + Browser_Window *win = evas_object_data_get(chrome, "win"); + Evas_Object *ed = elm_layout_edje_get(chrome); + if (win) ewk_view_uri_set(win->current_view, bmi->next); + edje_object_signal_emit(ed, "bookmark,item,clicked", ""); + } + break; + } +} + +Evas_Object * +view_screenshot_add(Evas *evas, const Evas_Object *view) +{ + Evas_Object *img; + Ewk_View_Smart_Data *sd; + Ewk_View_Private_Data *priv; + Eina_Rectangle rect = { 0, 0, 480, 800 }; + cairo_surface_t *surface; + cairo_format_t format; + cairo_t *cairo; + int stride; + void *pixels, *dest; + + sd = (Ewk_View_Smart_Data *) evas_object_smart_data_get(view); + priv = (Ewk_View_Private_Data *) sd->_priv; + + /* assuming colorspace is EVAS_COLORSPACE_ARGB8888 */ + stride = rect.w * 4; + format = CAIRO_FORMAT_RGB24; + + img = evas_object_image_filled_add(evas); + evas_object_resize(img, rect.w, rect.h); + evas_object_image_size_set(img, rect.w, rect.h); + evas_object_image_colorspace_set(img, EVAS_COLORSPACE_ARGB8888); + evas_object_image_alpha_set(img, EINA_FALSE); + pixels = evas_object_image_data_get(img, EINA_TRUE); + + surface = + cairo_image_surface_create_for_data(pixels, format, rect.w, rect.h, + stride); + if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS) + goto error_cairo_surface_create; + + cairo = cairo_create(surface); + if (cairo_status(cairo) != CAIRO_STATUS_SUCCESS) + goto error_cairo_create; + + if (!ewk_view_paint_contents(priv, cairo, &rect)) + { + evas_object_del(img); + img = NULL; + } + else + { + dest = evas_object_image_data_get(img, EINA_TRUE); + memmove(dest, pixels, rect.h * stride); + evas_object_image_data_set(img, dest); + } + + error_cairo_create: + cairo_destroy(cairo); + error_cairo_surface_create: + cairo_surface_destroy(surface); + + return img; +} + +static void +tab_grid_item_click(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *chrome = data; + Browser_Window *win = evas_object_data_get(chrome, "win"); + Evas_Object *ed = elm_layout_edje_get(chrome); + + edje_object_signal_emit(ed, "tab,item,clicked", ""); + tab_focus_chrome(win, chrome); +} + +static void +tab_grid_new_tab_click(void *data, Evas_Object *obj, void *event_info) +{ + Evas_Object *chrome = data; + Browser_Window *win = evas_object_data_get(chrome, "win"); + Evas_Object *ed = elm_layout_edje_get(chrome); + + edje_object_signal_emit(ed, "tab,item,clicked", ""); + tab_add(win, DEFAULT_URL); +} + +static void +on_action_tab_show(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, + const char *source __UNUSED__) +{ + Evas_Object *chrome = data; + Evas_Object *grid = evas_object_data_get(chrome, "tab-grid"); + Browser_Window *win = evas_object_data_get(chrome, "win"); + Eina_List *itr; + Evas_Object *itr_chrome; + + elm_gengrid_clear(grid); + + elm_gengrid_item_append(grid, &gic_new_page, NULL, tab_grid_new_tab_click, chrome); + + EINA_LIST_FOREACH(win->chromes, itr, itr_chrome) + { + Evas_Object *itr_view = evas_object_data_get(itr_chrome, "view"); + elm_gengrid_item_append(grid, &gic_default, itr_view, tab_grid_item_click, itr_chrome); + } +} + +static void +on_action_tab_hide(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, + const char *source __UNUSED__) +{ +} + +static void +on_action_bookmark_hide(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, + const char *source __UNUSED__) +{ + Evas_Object *chrome = data; + Evas_Object *edje = elm_layout_edje_get(chrome); + Bookmark_Menu_Item *bmi; + Browser_Window *win = evas_object_data_get(chrome, "win"); + + EINA_LIST_FREE(win->list_history, bmi) + if (bmi && bmi->dynamic) + { + eina_stringshare_del(bmi->text); + free(bmi); + } + eina_stringshare_del(edje_object_part_text_get(edje, "bookmark-list-back-button-text")); + eina_list_free(win->list_history_titles); + win->list_history = NULL; + win->list_history_titles = NULL; +} + +static void +on_action_bookmark_show(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, + const char *source __UNUSED__) +{ + Evas_Object *chrome = data; + Evas_Object *hl = evas_object_data_get(chrome, "bookmark-list"); + + bookmark_menu_set(chrome, hl, NULL, NULL); +} + +static void +on_action_pause(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Evas_Object *view = data; + + ewk_view_stop(view); +} + +static void +on_action_reload(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Evas_Object *view = data; + + ewk_view_reload(view); +} + +static void +on_action_home(void *data, Evas_Object * o __UNUSED__, + const char *emission __UNUSED__, const char *source __UNUSED__) +{ + Evas_Object *view = data; + + ewk_view_uri_set(view, DEFAULT_URL); +} + +static void +on_action_load_page(void *data, Evas_Object * view, void *event_info __UNUSED__) +{ + Evas_Object *ewk_view = data; + + const char *entry_data = elm_scrolled_entry_entry_get(view); + + char uri[2048]; + + snprintf(uri, 2048, "%s%s", + (strstr(entry_data, "://") ? "" : "http://"), entry_data); + + ewk_view_uri_set(ewk_view, uri); + evas_object_focus_set(ewk_view, EINA_TRUE); +} + +static void +on_view_load_error(void *data __UNUSED__, Evas_Object * view __UNUSED__, + void *event_info) +{ + const Ewk_Frame_Load_Error *error = event_info; + Evas_Object *frame = error->frame; + char *msg; + int len; + const char template[] = "" + "\n" + " \n" + " Error loading page.\n" + " \n" + " \n" + "

Error loading page

\n" + "

Error description: %s

\n" + "

Failing address: %s

\n" + "

Go back

" + " \n" "\n"; + + if (error->is_cancellation) + return; + if (!frame) + { + ERR("error loading '%s': %s", error->failing_url, error->description); + return; + } + + len = asprintf(&msg, template, error->description, error->failing_url); + if (len < 0) + { + ERR("error loading '%s': %s", error->failing_url, error->description); + return; + } + + ewk_frame_contents_alternate_set + (frame, msg, len, "text/html", NULL, NULL, error->failing_url); + free(msg); +} + +static void +on_view_download_request(void *data, Evas_Object * view __UNUSED__, + void *event_info) +{ + Ewk_Download *download = event_info; + + INF("Download: %s", download->url); +} + +static void +on_inputmethods_changed(void *data, Evas_Object* view, void *event_info) +{ + Eina_Bool active = (Eina_Bool)(long)event_info; + Evas_Object *win = data; + unsigned int imh; + INF("IM changed: active=%d", active); + + if (!active) + { + elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_OFF); + return; + } + + imh = ewk_view_imh_get(view); + INF("Imh:%d", imh); + if (imh & EWK_IMH_TELEPHONE) + elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_PHONE_NUMBER); + else if (imh & EWK_IMH_NUMBER) + elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_NUMERIC); + else if (imh & EWK_IMH_URL) + elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_URL); + else if (imh & EWK_IMH_PASSWORD) + elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_PASSWORD); +#if 0 + else if (imh & EWK_IMH_EMAIL) + elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_ +#endif + else + elm_win_keyboard_mode_set(win, ELM_WIN_KEYBOARD_ON); +} + +#if 0 +static void +win_title_set(Browser_Window * win) +{ + const char *view_title = ewk_view_title_get(win->view); + int p = ewk_view_load_progress_get(win->view) * 100; + char win_title[1024]; + + if (!view_title) + view_title = ewk_view_uri_get(win->view); + + if (p < 100) + snprintf(win_title, sizeof(win_title), "(%d%%) %s - " PACKAGE_STRING, + p, view_title); + else + snprintf(win_title, sizeof(win_title), "%s - " PACKAGE_STRING, + view_title); + + elm_win_title_set(win->win, win_title); +} + +static void +on_view_load_progress(void *data, Evas_Object * view __UNUSED__, + void *event_info __UNUSED__) +{ + Browser_Window *win = data; + + win_title_set(win); +} + +static void +on_view_title_changed(void *data, Evas_Object * view __UNUSED__, + void *event_info __UNUSED__) +{ + Browser_Window *win = data; + + win_title_set(win); +} +#endif + + +static void +on_key_down(void *data, Evas * e __UNUSED__, Evas_Object * o __UNUSED__, + void *event_info) +{ + Browser_Window *win = data; + Evas_Object *view = win->current_view; + Evas_Object *frame = ewk_view_frame_main_get(view); + Evas_Event_Key_Down *ev = event_info; + const char *k = ev->keyname; + + INF("keyname=%s, key=%s, string=%s\n", ev->keyname, ev->key, ev->string); + if ((strcmp(k, "Keycode-122") == 0) || (strcmp(k, "F5") == 0)) + { + ev->event_flags &= EVAS_EVENT_FLAG_ON_HOLD; + ewk_frame_scroll_add(frame, 0, 50); + } + else if ((strcmp(k, "Keycode-123") == 0) || (strcmp(k, "F6") == 0)) + { + ev->event_flags &= EVAS_EVENT_FLAG_ON_HOLD; + ewk_frame_scroll_add(frame, 0, -50); + } + else if ((strcmp(k, "Keycode-185") == 0) || (strcmp(k, "F7") == 0)) + { + ev->event_flags &= EVAS_EVENT_FLAG_ON_HOLD; + view_zoom_next_up(view); + } + else if ((strcmp(k, "Keycode-186") == 0) || (strcmp(k, "F8") == 0)) + { + ev->event_flags &= EVAS_EVENT_FLAG_ON_HOLD; + view_zoom_next_down(view); + } +} + +static char * +tab_grid_label_get(const void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__) +{ + if (data) + { + const char *title = ewk_view_title_get(data); + return strdup(title ? title : ""); + } + + return NULL; +} + +static Evas_Object * +tab_grid_icon_get(const void *data, Evas_Object *obj __UNUSED__, const char *part __UNUSED__) +{ + if (data) + { + const Evas_Object *view = data; + Evas *evas = evas_object_evas_get(view); + return view_screenshot_add(evas, view); + } + + return NULL; +} + +static Eina_Bool +tab_grid_state_get(const void *data __UNUSED__, Evas_Object *obj __UNUSED__, const char *part __UNUSED__) +{ + return EINA_FALSE; +} + +static void +tab_grid_del(const void *data, Evas_Object *obj) +{ +} + +Evas_Object * +chrome_add(Browser_Window * win, const char *url) +{ + Evas_Object *chrome = elm_layout_add(win->win); + Evas_Object *ed = elm_layout_edje_get(chrome); + Evas_Object *view; + + if (!elm_layout_file_set(chrome, PACKAGE_DATA_DIR "/default.edj", "chrome")) + { + int err = edje_object_load_error_get(ed); + + const char *msg = edje_load_error_str(err); + + CRITICAL("Could not load chrome theme: %s", msg); + evas_object_del(chrome); + return NULL; + } + + view = view_add(win->win); + if (!view) + { + CRITICAL("Could not create view"); + goto error_view_create; + } + evas_object_focus_set(view, 1); + elm_layout_content_set(chrome, "view", view); + + evas_object_data_set(chrome, "view", view); + evas_object_data_set(chrome, "win", win); + evas_object_data_set(view, "chrome", chrome); + evas_object_data_set(ed, "win", win); + + if (win->app->user_agent) + { + INF("using custom user agent string: %s\n", win->app->user_agent); + ewk_view_setting_user_agent_set(view, win->app->user_agent); + } + ewk_view_setting_enable_plugins_set(view, !win->app->disable_plugins); + + evas_object_event_callback_add(view, EVAS_CALLBACK_KEY_DOWN, on_key_down, + win); + evas_object_smart_callback_add(view, "load,error", on_view_load_error, win); + evas_object_smart_callback_add(view, "download,request", + on_view_download_request, win); + evas_object_smart_callback_add(view, "inputmethods,changed", + on_inputmethods_changed, win->win); +#if 0 + evas_object_smart_callback_add(view, "load,progress", on_view_load_progress, + win); + evas_object_smart_callback_add(view, "title,changed", on_view_title_changed, + win); +#endif + + if (url) + ewk_view_uri_set(view, url); + + Evas_Object *text_url = elm_scrolled_entry_add(ed); + elm_object_style_set(text_url, "ewebkit/url"); + elm_scrolled_entry_single_line_set(text_url, EINA_TRUE); + elm_layout_content_set(chrome, "url-entry", text_url); + evas_object_smart_callback_add + (text_url, "activated", on_action_load_page, view); + + Evas_Object *bookmark_list = elm_list_add(ed); + elm_list_scroller_policy_set(bookmark_list, + ELM_SCROLLER_POLICY_OFF, + ELM_SCROLLER_POLICY_AUTO); + elm_object_style_set(bookmark_list, "ewebkit"); + evas_object_data_set(bookmark_list, "chrome", chrome); + evas_object_data_set(chrome, "bookmark-list", bookmark_list); + elm_layout_content_set(chrome, "bookmark-list-swallow", bookmark_list); + + Evas_Object *tab_grid = elm_gengrid_add(ed); + elm_object_style_set(tab_grid, "ewebkit"); + elm_gengrid_item_size_set(tab_grid, 140, 174); + elm_gengrid_horizontal_set(tab_grid, EINA_FALSE); + elm_gengrid_multi_select_set(tab_grid, EINA_FALSE); + evas_object_data_set(chrome, "tab-grid", tab_grid); + evas_object_data_set(tab_grid, "win", win); + elm_layout_content_set(chrome, "tab-grid-swallow", tab_grid); + evas_object_smart_callback_add(tab_grid, "realized", + on_tab_gengrid_item_realized, win); + + gic_default.func.label_get = tab_grid_label_get; + gic_default.func.icon_get = tab_grid_icon_get; + gic_default.func.state_get = tab_grid_state_get; + gic_default.func.del = tab_grid_del; + + memcpy(&gic_new_page, &gic_default, sizeof(gic_default)); + gic_new_page.item_style = "new_page"; + gic_default.item_style = "default"; + + edje_object_signal_callback_add(ed, "action,back", "back", on_action_back, view); + edje_object_signal_callback_add(ed, "action,forward", "forward", on_action_forward, + view); + edje_object_signal_callback_add(ed, "action,stop", "stop", on_action_pause, + view); + edje_object_signal_callback_add(ed, "action,reload", "reload", on_action_reload, + view); + edje_object_signal_callback_add(ed, "action,home", "home", on_action_home, + view); + + edje_object_signal_callback_add(ed, "action,fav_on", "", on_fav_on, view); + edje_object_signal_callback_add(ed, "action,fav_off", "", on_fav_off, view); + + edje_object_signal_callback_add(ed, "view,mask,visible", "", on_view_mask_visible, win); + edje_object_signal_callback_add(ed, "view,mask,hidden", "", on_view_mask_hidden, win); + + edje_object_signal_callback_add(ed, "bookmark,show", "", + on_action_bookmark_show, chrome); + edje_object_signal_callback_add(ed, "bookmark,hide", "", + on_action_bookmark_hide, chrome); + edje_object_signal_callback_add(ed, "tab,show", "", + on_action_tab_show, chrome); + edje_object_signal_callback_add(ed, "tab,hide", "", + on_action_tab_hide, chrome); + evas_object_smart_callback_add(view, "load,progress", on_view_load_progress, + chrome); + evas_object_smart_callback_add(view, "title,changed", on_view_title_changed, + chrome); + evas_object_smart_callback_add(view, "uri,changed", on_view_uri_changed, + chrome); + evas_object_smart_callback_add(view, "zoom,interactive", + on_view_zoom_interactive, chrome); + evas_object_smart_callback_add(view, "zoom,interactive,start", + on_view_zoom_interactive_start, chrome); + evas_object_smart_callback_add(view, "zoom,interactive,end", + on_view_zoom_interactive_end, chrome); + evas_object_smart_callback_add(view, "statusbar,text,set", + on_view_statusbar_text_set, chrome); + evas_object_smart_callback_add(view, "link,hover,in", on_view_link_hover_in, + chrome); + evas_object_smart_callback_add(view, "link,hover,out", + on_view_link_hover_out, chrome); + evas_object_smart_callback_add(view, "popup,create", on_view_popup_new, + win); + + edje_object_signal_emit(ed, "panels,reset,hide", ""); + _chrome_state_apply(chrome, view); + + elm_pager_content_push(win->pager, chrome); + return chrome; + + error_view_create: + evas_object_del(chrome); + return NULL; +} diff --git a/src/bin/favorite.c b/src/bin/favorite.c new file mode 100644 index 0000000..39a5465 --- /dev/null +++ b/src/bin/favorite.c @@ -0,0 +1,295 @@ +/* This file has been automatically generated by geneet.py */ +/* DO NOT MODIFY */ + +#include +#include +#include +#include +#include + +#include "favorite.h" + +struct _Fav_Item { + const char * url; + const char * title; + unsigned int visit_count; +}; + +struct _Fav { + int version; + Eina_Hash * items; + const char *__eet_filename; +}; + +static const char FAV_ITEM_ENTRY[] = "fav_item"; +static const char FAV_ENTRY[] = "fav"; + +static Eet_Data_Descriptor *_fav_item_descriptor = NULL; +static Eet_Data_Descriptor *_fav_descriptor = NULL; + +static inline void +_fav_item_init(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (_fav_item_descriptor) return; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Fav_Item); + _fav_item_descriptor = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_BASIC(_fav_item_descriptor, Fav_Item, "url", url, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(_fav_item_descriptor, Fav_Item, "title", title, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(_fav_item_descriptor, Fav_Item, "visit_count", visit_count, EET_T_UINT); +} + +static inline void +_fav_item_shutdown(void) +{ + if (!_fav_item_descriptor) return; + eet_data_descriptor_free(_fav_item_descriptor); + _fav_item_descriptor = NULL; +} + +Fav_Item * +fav_item_new(const char * url, const char * title, unsigned int visit_count) +{ + Fav_Item *fav_item = calloc(1, sizeof(Fav_Item)); + + if (!fav_item) + { + fprintf(stderr, "ERROR: could not calloc Fav_Item\n"); + return NULL; + } + + fav_item->url = eina_stringshare_add(url ? url : "about:blank"); + fav_item->title = eina_stringshare_add(title ? title : "Untitled"); + fav_item->visit_count = visit_count; + + return fav_item; +} + +void +fav_item_free(Fav_Item *fav_item) +{ + eina_stringshare_del(fav_item->url); + eina_stringshare_del(fav_item->title); + free(fav_item); +} + +inline const char * +fav_item_url_get(const Fav_Item *fav_item) +{ + return fav_item->url; +} + +inline void +fav_item_url_set(Fav_Item *fav_item, const char *url) +{ + EINA_SAFETY_ON_NULL_RETURN(fav_item); + eina_stringshare_del(fav_item->url); + fav_item->url = eina_stringshare_add(url); +} + +inline const char * +fav_item_title_get(const Fav_Item *fav_item) +{ + return fav_item->title; +} + +inline void +fav_item_title_set(Fav_Item *fav_item, const char *title) +{ + EINA_SAFETY_ON_NULL_RETURN(fav_item); + eina_stringshare_del(fav_item->title); + fav_item->title = eina_stringshare_add(title); +} + +inline unsigned int +fav_item_visit_count_get(const Fav_Item *fav_item) +{ + return fav_item->visit_count; +} + +inline void +fav_item_visit_count_set(Fav_Item *fav_item, unsigned int visit_count) +{ + EINA_SAFETY_ON_NULL_RETURN(fav_item); + fav_item->visit_count = visit_count; +} + + +static inline void +_fav_init(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (_fav_descriptor) return; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Fav); + _fav_descriptor = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_BASIC(_fav_descriptor, Fav, "version", version, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_HASH(_fav_descriptor, Fav, "items", items, _fav_item_descriptor); +} + +static inline void +_fav_shutdown(void) +{ + if (!_fav_descriptor) return; + eet_data_descriptor_free(_fav_descriptor); + _fav_descriptor = NULL; +} + +Fav * +fav_new(int version) +{ + Fav *fav = calloc(1, sizeof(Fav)); + + if (!fav) + { + fprintf(stderr, "ERROR: could not calloc Fav\n"); + return NULL; + } + + fav->version = version; + fav->items = eina_hash_stringshared_new(EINA_FREE_CB(fav_item_free)); + + return fav; +} + +void +fav_free(Fav *fav) +{ + eina_hash_free(fav->items); + free(fav); +} + +inline int +fav_version_get(const Fav *fav) +{ + return fav->version; +} + +inline void +fav_version_set(Fav *fav, int version) +{ + EINA_SAFETY_ON_NULL_RETURN(fav); + fav->version = version; +} + +void +fav_items_add(Fav *fav, const char * url, Fav_Item *fav_item) +{ + EINA_SAFETY_ON_NULL_RETURN(fav); + eina_hash_add(fav->items, url, fav_item); +} + +void +fav_items_del(Fav *fav, const char * url) +{ + EINA_SAFETY_ON_NULL_RETURN(fav); + eina_hash_del(fav->items, url, NULL); +} + +inline Fav_Item * +fav_items_get(const Fav *fav, const char * url) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(fav, NULL); + return eina_hash_find(fav->items, url); +} + +inline Eina_Hash * +fav_items_hash_get(const Fav *fav) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(fav, NULL); + return fav->items; +} + +void +fav_items_modify(Fav *fav, const char * key, void *value) +{ + EINA_SAFETY_ON_NULL_RETURN(fav); + eina_hash_modify(fav->items, key, value); +} + +Fav * +fav_load(const char *filename) +{ + Fav *fav; + Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ); + if (!ef) + { + fprintf(stderr, "ERROR: could not open '%s' for read\n", filename); + return NULL; + } + + fav = eet_data_read(ef, _fav_descriptor, FAV_ENTRY); + fav->__eet_filename = eina_stringshare_add(filename); + + if (!fav->items) fav->items = eina_hash_stringshared_new(EINA_FREE_CB(fav_item_free)); + + eet_close(ef); + return fav; +} + +Eina_Bool +fav_save(Fav *fav, const char *filename) +{ + char tmp[PATH_MAX]; + Eet_File *ef; + Eina_Bool ret; + unsigned int i, len; + struct stat st; + + if (filename) fav->__eet_filename = eina_stringshare_add(filename); + else if (fav->__eet_filename) filename = fav->__eet_filename; + else return EINA_FALSE; + + len = eina_strlcpy(tmp, filename, sizeof(tmp)); + if (len + 12 >= (int)sizeof(tmp)) + { + fprintf(stderr, "ERROR: filename is too big: %s\n", filename); + return EINA_FALSE; + } + + i = 0; + do + { + snprintf(tmp + len, 12, ".%u", i); + i++; + } + while(stat(tmp, &st) == 0); + + ef = eet_open(tmp, EET_FILE_MODE_WRITE); + if (!ef) + { + fprintf(stderr, "ERROR: could not open '%s' for write\n", tmp); + return EINA_FALSE; + } + + ret = !!eet_data_write(ef, _fav_descriptor, FAV_ENTRY, fav, EINA_TRUE); + eet_close(ef); + + if (ret) + { + unlink(filename); + rename(tmp, filename); + } + + return ret; +} + +void +favorite_init(void) +{ + _fav_item_init(); + _fav_init(); +} + +void +favorite_shutdown(void) +{ + _fav_item_shutdown(); + _fav_shutdown(); +} + diff --git a/src/bin/favorite.h b/src/bin/favorite.h new file mode 100644 index 0000000..9a42c92 --- /dev/null +++ b/src/bin/favorite.h @@ -0,0 +1,43 @@ +/* This file has been automatically generated by geneet.py */ +/* DO NOT MODIFY */ + +#ifndef __FAVORITE_H__ +#define __FAVORITE_H__ + +#include +#include + +typedef struct _Fav_Item Fav_Item; +typedef struct _Fav Fav; + +/* Fav_Item */ +Fav_Item *fav_item_new(const char * url, const char * title, unsigned int visit_count); +void fav_item_free(Fav_Item *fav_item); + +void fav_item_url_set(Fav_Item *fav_item, const char * url); +const char * fav_item_url_get(const Fav_Item *fav_item); +void fav_item_title_set(Fav_Item *fav_item, const char * title); +const char * fav_item_title_get(const Fav_Item *fav_item); +void fav_item_visit_count_set(Fav_Item *fav_item, unsigned int visit_count); +unsigned int fav_item_visit_count_get(const Fav_Item *fav_item); + +/* Fav */ +Fav *fav_new(int version); +void fav_free(Fav *fav); + +void fav_version_set(Fav *fav, int version); +int fav_version_get(const Fav *fav); +void fav_items_add(Fav *fav, const char * url, Fav_Item *fav_item); +void fav_items_del(Fav *fav, const char * url); +Fav_Item *fav_items_get(const Fav *fav, const char * key); +Eina_Hash *fav_items_hash_get(const Fav *fav); +void fav_items_modify(Fav *fav, const char * key, void *value); + +Fav *fav_load(const char *filename); +Eina_Bool fav_save(Fav *fav, const char *filename); + +/* Global initializer / shutdown functions */ +void favorite_init(void); +void favorite_shutdown(void); + +#endif /* __FAVORITE_H__ */ diff --git a/src/bin/gettext.h b/src/bin/gettext.h new file mode 100644 index 0000000..597b5b0 --- /dev/null +++ b/src/bin/gettext.h @@ -0,0 +1,268 @@ +/* Convenience header for conditional use of GNU . + Copyright (C) 1995-1998, 2000-2002, 2004-2006 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, + USA. */ + +#ifndef _LIBGETTEXT_H +#define _LIBGETTEXT_H 1 + +#define _(x) gettext(x) +#define N_(x) gettext_noop(x) + +/* NLS can be disabled through the configure --disable-nls option. */ +#if ENABLE_NLS + +/* You can set the DEFAULT_TEXT_DOMAIN macro to specify the domain used by + the gettext() and ngettext() macros. This is an alternative to calling + textdomain(), and is useful for libraries. */ +# ifdef DEFAULT_TEXT_DOMAIN +# undef gettext +# define gettext(Msgid) \ + dgettext (DEFAULT_TEXT_DOMAIN, Msgid) +# undef ngettext +# define ngettext(Msgid1, Msgid2, N) \ + dngettext (DEFAULT_TEXT_DOMAIN, Msgid1, Msgid2, N) +# endif + +#else + +/* Solaris /usr/include/locale.h includes /usr/include/libintl.h, which + chokes if dcgettext is defined as a macro. So include it now, to make + later inclusions of a NOP. We don't include + as well because people using "gettext.h" will not include , + and also including would fail on SunOS 4, whereas + is OK. */ +#if defined(__sun) +# include +#endif + +/* Many header files from the libstdc++ coming with g++ 3.3 or newer include + , which chokes if dcgettext is defined as a macro. So include + it now, to make later inclusions of a NOP. */ +#if defined(__cplusplus) && defined(__GNUG__) && (__GNUC__ >= 3) +# include +#endif + +/* Disabled NLS. + The casts to 'const char *' serve the purpose of producing warnings + for invalid uses of the value returned from these functions. + On pre-ANSI systems without 'const', the config.h file is supposed to + contain "#define const". */ +# define gettext(Msgid) ((const char *) (Msgid)) +# define dgettext(Domainname, Msgid) ((void) (Domainname), gettext (Msgid)) +# define dcgettext(Domainname, Msgid, Category) \ + ((void) (Category), dgettext (Domainname, Msgid)) +# define ngettext(Msgid1, Msgid2, N) \ + ((N) == 1 \ + ? ((void) (Msgid2), (const char *) (Msgid1)) \ + : ((void) (Msgid1), (const char *) (Msgid2))) +# define dngettext(Domainname, Msgid1, Msgid2, N) \ + ((void) (Domainname), ngettext (Msgid1, Msgid2, N)) +# define dcngettext(Domainname, Msgid1, Msgid2, N, Category) \ + ((void) (Category), dngettext(Domainname, Msgid1, Msgid2, N)) +# define textdomain(Domainname) ((const char *) (Domainname)) +# define bindtextdomain(Domainname, Dirname) \ + ((void) (Domainname), (const char *) (Dirname)) +# define bind_textdomain_codeset(Domainname, Codeset) \ + ((void) (Domainname), (const char *) (Codeset)) + +#endif + +/* A pseudo function call that serves as a marker for the automated + extraction of messages, but does not call gettext(). The run-time + translation is done at a different place in the code. + The argument, String, should be a literal string. Concatenated strings + and other string expressions won't work. + The macro's expansion is not parenthesized, so that it is suitable as + initializer for static 'char[]' or 'const char[]' variables. */ +#define gettext_noop(String) String + +/* The separator between msgctxt and msgid in a .mo file. */ +#define GETTEXT_CONTEXT_GLUE "\004" + +/* Pseudo function calls, taking a MSGCTXT and a MSGID instead of just a + MSGID. MSGCTXT and MSGID must be string literals. MSGCTXT should be + short and rarely need to change. + The letter 'p' stands for 'particular' or 'special'. */ +#ifdef DEFAULT_TEXT_DOMAIN +# define pgettext(Msgctxt, Msgid) \ + pgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#else +# define pgettext(Msgctxt, Msgid) \ + pgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#endif +#define dpgettext(Domainname, Msgctxt, Msgid) \ + pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, LC_MESSAGES) +#define dcpgettext(Domainname, Msgctxt, Msgid, Category) \ + pgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, Category) +#ifdef DEFAULT_TEXT_DOMAIN +# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (DEFAULT_TEXT_DOMAIN, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#else +# define npgettext(Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (NULL, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#endif +#define dnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ + npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, LC_MESSAGES) +#define dcnpgettext(Domainname, Msgctxt, Msgid, MsgidPlural, N, Category) \ + npgettext_aux (Domainname, Msgctxt GETTEXT_CONTEXT_GLUE Msgid, Msgid, MsgidPlural, N, Category) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +pgettext_aux (const char *domain, + const char *msg_ctxt_id, const char *msgid, + int category) +{ + const char *translation = dcgettext (domain, msg_ctxt_id, category); + if (translation == msg_ctxt_id) + return msgid; + else + return translation; +} + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +npgettext_aux (const char *domain, + const char *msg_ctxt_id, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) +{ + const char *translation = + dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); + if (translation == msg_ctxt_id || translation == msgid_plural) + return (n == 1 ? msgid : msgid_plural); + else + return translation; +} + +/* The same thing extended for non-constant arguments. Here MSGCTXT and MSGID + can be arbitrary expressions. But for string literals these macros are + less efficient than those above. */ + +#include + +#define _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS \ + (((__GNUC__ >= 3 || __GNUG__ >= 2) && !__STRICT_ANSI__) \ + /* || __STDC_VERSION__ >= 199901L */ ) + +#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS +#include +#endif + +#define pgettext_expr(Msgctxt, Msgid) \ + dcpgettext_expr (NULL, Msgctxt, Msgid, LC_MESSAGES) +#define dpgettext_expr(Domainname, Msgctxt, Msgid) \ + dcpgettext_expr (Domainname, Msgctxt, Msgid, LC_MESSAGES) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +dcpgettext_expr (const char *domain, + const char *msgctxt, const char *msgid, + int category) +{ + size_t msgctxt_len = strlen (msgctxt) + 1; + size_t msgid_len = strlen (msgid) + 1; + const char *translation; +#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + char msg_ctxt_id[msgctxt_len + msgid_len]; +#else + char buf[1024]; + char *msg_ctxt_id = + (msgctxt_len + msgid_len <= sizeof (buf) + ? buf + : (char *) malloc (msgctxt_len + msgid_len)); + if (msg_ctxt_id != NULL) +#endif + { + memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcgettext (domain, msg_ctxt_id, category); +#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + if (msg_ctxt_id != buf) + free (msg_ctxt_id); +#endif + if (translation != msg_ctxt_id) + return translation; + } + return msgid; +} + +#define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ + dcnpgettext_expr (NULL, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) +#define dnpgettext_expr(Domainname, Msgctxt, Msgid, MsgidPlural, N) \ + dcnpgettext_expr (Domainname, Msgctxt, Msgid, MsgidPlural, N, LC_MESSAGES) + +#ifdef __GNUC__ +__inline +#else +#ifdef __cplusplus +inline +#endif +#endif +static const char * +dcnpgettext_expr (const char *domain, + const char *msgctxt, const char *msgid, + const char *msgid_plural, unsigned long int n, + int category) +{ + size_t msgctxt_len = strlen (msgctxt) + 1; + size_t msgid_len = strlen (msgid) + 1; + const char *translation; +#if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + char msg_ctxt_id[msgctxt_len + msgid_len]; +#else + char buf[1024]; + char *msg_ctxt_id = + (msgctxt_len + msgid_len <= sizeof (buf) + ? buf + : (char *) malloc (msgctxt_len + msgid_len)); + if (msg_ctxt_id != NULL) +#endif + { + memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); + msg_ctxt_id[msgctxt_len - 1] = '\004'; + memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); + translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); +#if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS + if (msg_ctxt_id != buf) + free (msg_ctxt_id); +#endif + if (!(translation == msg_ctxt_id || translation == msgid_plural)) + return translation; + } + return (n == 1 ? msgid : msgid_plural); +} + +#endif /* _LIBGETTEXT_H */ diff --git a/src/bin/history.c b/src/bin/history.c new file mode 100644 index 0000000..20e096f --- /dev/null +++ b/src/bin/history.c @@ -0,0 +1,311 @@ +/* This file has been automatically generated by geneet.py */ +/* DO NOT MODIFY */ + +#include +#include +#include +#include +#include + +#include "history.h" + +struct _Hist_Item { + const char * title; + const char * url; + unsigned int visit_count; + double last_visit; +}; + +struct _Hist { + int version; + Eina_Hash * items; + const char *__eet_filename; +}; + +static const char HIST_ITEM_ENTRY[] = "hist_item"; +static const char HIST_ENTRY[] = "hist"; + +static Eet_Data_Descriptor *_hist_item_descriptor = NULL; +static Eet_Data_Descriptor *_hist_descriptor = NULL; + +static inline void +_hist_item_init(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (_hist_item_descriptor) return; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Hist_Item); + _hist_item_descriptor = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_BASIC(_hist_item_descriptor, Hist_Item, "title", title, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(_hist_item_descriptor, Hist_Item, "url", url, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(_hist_item_descriptor, Hist_Item, "visit_count", visit_count, EET_T_UINT); + EET_DATA_DESCRIPTOR_ADD_BASIC(_hist_item_descriptor, Hist_Item, "last_visit", last_visit, EET_T_DOUBLE); +} + +static inline void +_hist_item_shutdown(void) +{ + if (!_hist_item_descriptor) return; + eet_data_descriptor_free(_hist_item_descriptor); + _hist_item_descriptor = NULL; +} + +Hist_Item * +hist_item_new(const char * title, const char * url, unsigned int visit_count, double last_visit) +{ + Hist_Item *hist_item = calloc(1, sizeof(Hist_Item)); + + if (!hist_item) + { + fprintf(stderr, "ERROR: could not calloc Hist_Item\n"); + return NULL; + } + + hist_item->title = eina_stringshare_add(title ? title : "Untitled"); + hist_item->url = eina_stringshare_add(url ? url : "about:blank"); + hist_item->visit_count = visit_count; + hist_item->last_visit = last_visit; + + return hist_item; +} + +void +hist_item_free(Hist_Item *hist_item) +{ + eina_stringshare_del(hist_item->title); + eina_stringshare_del(hist_item->url); + free(hist_item); +} + +inline const char * +hist_item_title_get(const Hist_Item *hist_item) +{ + return hist_item->title; +} + +inline void +hist_item_title_set(Hist_Item *hist_item, const char *title) +{ + EINA_SAFETY_ON_NULL_RETURN(hist_item); + eina_stringshare_del(hist_item->title); + hist_item->title = eina_stringshare_add(title); +} + +inline const char * +hist_item_url_get(const Hist_Item *hist_item) +{ + return hist_item->url; +} + +inline void +hist_item_url_set(Hist_Item *hist_item, const char *url) +{ + EINA_SAFETY_ON_NULL_RETURN(hist_item); + eina_stringshare_del(hist_item->url); + hist_item->url = eina_stringshare_add(url); +} + +inline unsigned int +hist_item_visit_count_get(const Hist_Item *hist_item) +{ + return hist_item->visit_count; +} + +inline void +hist_item_visit_count_set(Hist_Item *hist_item, unsigned int visit_count) +{ + EINA_SAFETY_ON_NULL_RETURN(hist_item); + hist_item->visit_count = visit_count; +} + +inline double +hist_item_last_visit_get(const Hist_Item *hist_item) +{ + return hist_item->last_visit; +} + +inline void +hist_item_last_visit_set(Hist_Item *hist_item, double last_visit) +{ + EINA_SAFETY_ON_NULL_RETURN(hist_item); + hist_item->last_visit = last_visit; +} + + +static inline void +_hist_init(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (_hist_descriptor) return; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Hist); + _hist_descriptor = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_BASIC(_hist_descriptor, Hist, "version", version, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_HASH(_hist_descriptor, Hist, "items", items, _hist_item_descriptor); +} + +static inline void +_hist_shutdown(void) +{ + if (!_hist_descriptor) return; + eet_data_descriptor_free(_hist_descriptor); + _hist_descriptor = NULL; +} + +Hist * +hist_new(int version) +{ + Hist *hist = calloc(1, sizeof(Hist)); + + if (!hist) + { + fprintf(stderr, "ERROR: could not calloc Hist\n"); + return NULL; + } + + hist->version = version; + hist->items = eina_hash_stringshared_new(EINA_FREE_CB(hist_item_free)); + + return hist; +} + +void +hist_free(Hist *hist) +{ + eina_hash_free(hist->items); + free(hist); +} + +inline int +hist_version_get(const Hist *hist) +{ + return hist->version; +} + +inline void +hist_version_set(Hist *hist, int version) +{ + EINA_SAFETY_ON_NULL_RETURN(hist); + hist->version = version; +} + +void +hist_items_add(Hist *hist, const char * url, Hist_Item *hist_item) +{ + EINA_SAFETY_ON_NULL_RETURN(hist); + eina_hash_add(hist->items, url, hist_item); +} + +void +hist_items_del(Hist *hist, const char * url) +{ + EINA_SAFETY_ON_NULL_RETURN(hist); + eina_hash_del(hist->items, url, NULL); +} + +inline Hist_Item * +hist_items_get(const Hist *hist, const char * url) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(hist, NULL); + return eina_hash_find(hist->items, url); +} + +inline Eina_Hash * +hist_items_hash_get(const Hist *hist) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(hist, NULL); + return hist->items; +} + +void +hist_items_modify(Hist *hist, const char * key, void *value) +{ + EINA_SAFETY_ON_NULL_RETURN(hist); + eina_hash_modify(hist->items, key, value); +} + +Hist * +hist_load(const char *filename) +{ + Hist *hist; + Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ); + if (!ef) + { + fprintf(stderr, "ERROR: could not open '%s' for read\n", filename); + return NULL; + } + + hist = eet_data_read(ef, _hist_descriptor, HIST_ENTRY); + hist->__eet_filename = eina_stringshare_add(filename); + + if (!hist->items) hist->items = eina_hash_stringshared_new(EINA_FREE_CB(hist_item_free)); + + eet_close(ef); + return hist; +} + +Eina_Bool +hist_save(Hist *hist, const char *filename) +{ + char tmp[PATH_MAX]; + Eet_File *ef; + Eina_Bool ret; + unsigned int i, len; + struct stat st; + + if (filename) hist->__eet_filename = eina_stringshare_add(filename); + else if (hist->__eet_filename) filename = hist->__eet_filename; + else return EINA_FALSE; + + len = eina_strlcpy(tmp, filename, sizeof(tmp)); + if (len + 12 >= (int)sizeof(tmp)) + { + fprintf(stderr, "ERROR: filename is too big: %s\n", filename); + return EINA_FALSE; + } + + i = 0; + do + { + snprintf(tmp + len, 12, ".%u", i); + i++; + } + while(stat(tmp, &st) == 0); + + ef = eet_open(tmp, EET_FILE_MODE_WRITE); + if (!ef) + { + fprintf(stderr, "ERROR: could not open '%s' for write\n", tmp); + return EINA_FALSE; + } + + ret = !!eet_data_write(ef, _hist_descriptor, HIST_ENTRY, hist, EINA_TRUE); + eet_close(ef); + + if (ret) + { + unlink(filename); + rename(tmp, filename); + } + + return ret; +} + +void +history_init(void) +{ + _hist_item_init(); + _hist_init(); +} + +void +history_shutdown(void) +{ + _hist_item_shutdown(); + _hist_shutdown(); +} + diff --git a/src/bin/history.h b/src/bin/history.h new file mode 100644 index 0000000..04472f2 --- /dev/null +++ b/src/bin/history.h @@ -0,0 +1,45 @@ +/* This file has been automatically generated by geneet.py */ +/* DO NOT MODIFY */ + +#ifndef __HISTORY_H__ +#define __HISTORY_H__ + +#include +#include + +typedef struct _Hist_Item Hist_Item; +typedef struct _Hist Hist; + +/* Hist_Item */ +Hist_Item *hist_item_new(const char * title, const char * url, unsigned int visit_count, double last_visit); +void hist_item_free(Hist_Item *hist_item); + +void hist_item_title_set(Hist_Item *hist_item, const char * title); +const char * hist_item_title_get(const Hist_Item *hist_item); +void hist_item_url_set(Hist_Item *hist_item, const char * url); +const char * hist_item_url_get(const Hist_Item *hist_item); +void hist_item_visit_count_set(Hist_Item *hist_item, unsigned int visit_count); +unsigned int hist_item_visit_count_get(const Hist_Item *hist_item); +void hist_item_last_visit_set(Hist_Item *hist_item, double last_visit); +double hist_item_last_visit_get(const Hist_Item *hist_item); + +/* Hist */ +Hist *hist_new(int version); +void hist_free(Hist *hist); + +void hist_version_set(Hist *hist, int version); +int hist_version_get(const Hist *hist); +void hist_items_add(Hist *hist, const char * url, Hist_Item *hist_item); +void hist_items_del(Hist *hist, const char * url); +Hist_Item *hist_items_get(const Hist *hist, const char * key); +Eina_Hash *hist_items_hash_get(const Hist *hist); +void hist_items_modify(Hist *hist, const char * key, void *value); + +Hist *hist_load(const char *filename); +Eina_Bool hist_save(Hist *hist, const char *filename); + +/* Global initializer / shutdown functions */ +void history_init(void); +void history_shutdown(void); + +#endif /* __HISTORY_H__ */ diff --git a/src/bin/main.c b/src/bin/main.c new file mode 100644 index 0000000..f74d680 --- /dev/null +++ b/src/bin/main.c @@ -0,0 +1,430 @@ +/* + * eve + * + * Copyright (C) 2009, Gustavo Sverzut Barbieri + * + * License LGPL-3, see COPYING file at project folder. + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#ifndef ELM_LIB_QUICKLAUNCH + +#include "favorite.h" +#include "private.h" + +#include +#include +#include +#include "gettext.h" + +int _log_domain = -1; +Fav *fav = NULL; +Hist *hist = NULL; +App app; + +static void +del_win(App * app, Evas_Object * win) +{ + Browser_Window *win_data; + Eina_List *l; + + EINA_LIST_FOREACH(app->windows, l, win_data) if (win_data->win == win) + break; + + evas_object_del(win); + app->windows = eina_list_remove(app->windows, win_data); + free(win_data); + + if (!app->windows) + elm_exit(); +} + +static void +on_win_del_req(void *data, Evas_Object * win, void *event_info __UNUSED__) +{ + del_win(data, win); +} + +/* this should be in elm_win... */ +static void +win_mouse_disable(Evas_Object * win) +{ + Evas *e = evas_object_evas_get(win); + Ecore_Evas *ee = evas_data_attach_get(e); + Evas_Object *cursor = evas_object_rectangle_add(e); + + evas_object_color_set(cursor, 0, 0, 0, 0); + evas_object_resize(cursor, 1, 1); + ecore_evas_object_cursor_set(ee, cursor, EVAS_LAYER_MIN, 0, 0); +} + +Eina_Bool +tab_add(Browser_Window * win, const char *url) +{ + Evas_Object *chrome = chrome_add(win, url); + + if (!chrome) + { + CRITICAL("Could not create chrome."); + goto error_chrome_create; + } + evas_object_size_hint_weight_set(chrome, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(chrome); + + win->chromes = eina_list_append(win->chromes, chrome); + win->current_chrome = chrome; + win->current_view = evas_object_data_get(chrome, "view"); + win->current_tab++; + + return EINA_TRUE; + + error_chrome_create: + evas_object_del(evas_object_data_get(chrome, "view")); + + return EINA_FALSE; +} + +Eina_Bool +tab_focus_chrome(Browser_Window * win, Evas_Object * chrome) +{ + Eina_List *itr; + int n; + + if (!chrome) + return EINA_FALSE; + + for (n = 0, itr = win->chromes; itr->data != chrome; n++, itr = itr->next); + + evas_object_hide(win->current_chrome); + + win->current_chrome = chrome; + win->current_view = evas_object_data_get(chrome, "view"); + win->current_tab = n; + + evas_object_show(win->current_chrome); + evas_object_focus_set(win->current_view, EINA_TRUE); + elm_pager_content_promote(win->pager, win->current_chrome); + + return EINA_TRUE; +} + +Eina_Bool +tab_focus_nth(Browser_Window * win, unsigned int n) +{ + return tab_focus_chrome(win, eina_list_nth(win->chromes, n)); +} + +Eina_Bool +tab_focus_next(Browser_Window * win) +{ + unsigned int n_tabs = eina_list_count(win->chromes); + + if (win->current_tab > n_tabs) + return EINA_FALSE; + return tab_focus_nth(win, win->current_tab + 1); +} + +Eina_Bool +tab_focus_prev(Browser_Window * win) +{ + if (win->current_tab == 0) + return EINA_FALSE; + return tab_focus_nth(win, win->current_tab - 1); +} + +Eina_Bool +tab_close_chrome(Browser_Window * win, Evas_Object * chrome) +{ + Evas_Object *edje; + + EINA_SAFETY_ON_TRUE_RETURN_VAL(!win, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(!chrome, EINA_FALSE); + + if (!win->chromes->next) + { + del_win(win->app, win->win); + return EINA_TRUE; + } + + evas_object_del(chrome); + win->chromes = eina_list_remove(win->chromes, chrome); + if (win->current_chrome == chrome) + tab_focus_nth(win, 0); + + edje = elm_layout_edje_get(win->current_chrome); + edje_object_signal_emit(edje, "hide,tab", ""); + + return EINA_TRUE; +} + +Eina_Bool +tab_close_nth(Browser_Window * win, int n) +{ + return tab_close_chrome(win, eina_list_nth(win->chromes, n)); +} + +Eina_Bool +tab_close_view(Browser_Window * win, Evas_Object *view) +{ + return tab_close_chrome(win, evas_object_data_get(view, "chrome")); +} + +static Browser_Window * +add_win(App * app, const char *url) +{ + Browser_Window *win = malloc(sizeof(*win)); + + if (!win) + { + CRITICAL("Could not create window data."); + goto error_win_data; + } + + win->app = app; + win->chromes = NULL; + win->current_chrome = NULL; + win->current_view = NULL; + win->current_tab = 0; + win->list_history = NULL; + win->list_history_titles = NULL; + + win->win = elm_win_add(NULL, "eve", ELM_WIN_BASIC); + if (!win->win) + { + CRITICAL("Could not create window."); + goto error_win_create; + } + + elm_win_title_set(win->win, PACKAGE_STRING); + elm_win_fullscreen_set(win->win, app->is_fullscreen); + if (app->disable_mouse) + win_mouse_disable(win->win); + + win->bg = edje_object_add(evas_object_evas_get(win->win)); + if (!win->bg) + { + CRITICAL("Could not create background."); + goto error_bg_create; + } + if (!edje_object_file_set(win->bg, PACKAGE_DATA_DIR "/default.edj", "bg")) + { + int err = edje_object_load_error_get(win->bg); + + const char *msg = edje_load_error_str(err); + + CRITICAL("Could not load background theme: %s", msg); + goto error_bg_theme_set; + } + evas_object_size_hint_weight_set(win->bg, EVAS_HINT_EXPAND, + EVAS_HINT_EXPAND); + elm_win_resize_object_add(win->win, win->bg); + evas_object_layer_set(win->bg, EVAS_LAYER_MIN); + evas_object_show(win->bg); + + win->pager = elm_pager_add(win->win); + if (!win->pager) + { + CRITICAL("Could not create pager"); + goto error_pager_create; + } + elm_object_style_set(win->pager, "ewebkit"); + evas_object_size_hint_weight_set(win->pager, EVAS_HINT_EXPAND, + EVAS_HINT_EXPAND); + elm_win_resize_object_add(win->win, win->pager); + evas_object_show(win->pager); + + if (!tab_add(win, url)) + goto error_tab_add; + + app->windows = eina_list_append(app->windows, win); + evas_object_smart_callback_add + (win->win, "delete-request", on_win_del_req, app); + + evas_object_resize(win->win, 480, 800); + evas_object_show(win->win); + + return win; + + error_bg_theme_set: + evas_object_del(win->bg); + error_bg_create: + evas_object_del(win->win); + error_win_create: + free(win); + error_win_data: + error_tab_add: + error_pager_create: + return NULL; +} + +/** + * Creates a new window, without any url to load, calling add_win(). + * + * @return If a window was successfully created, it returns the correspondent view + * object. + */ +Evas_Object * +window_create() +{ + Browser_Window *win = add_win(&app, NULL); + + if (!win) + return NULL; + + return win->current_view; +} + +static const Ecore_Getopt options = { + PACKAGE_NAME, + "%prog [options] [url]", + PACKAGE_VERSION, + "(C) 2000 ProFUSION embedded systems", + "LGPL-3", + "WebKit-EFL demo browser for mobile systems with touchscreen.", + EINA_TRUE, + { + ECORE_GETOPT_STORE_DEF_BOOL('F', "fullscreen", "start in fullscreen.", 1), + ECORE_GETOPT_STORE_DEF_BOOL('P', "disable-plugins", + "disable plugins (flash, etc).", 1), + ECORE_GETOPT_STORE_DEF_BOOL('M', "disable-mouse", + "disable mouse (hide it).", 1), + ECORE_GETOPT_STORE_STR('U', "user-agent", + "user agent string to use. Special case=iphone."), + ECORE_GETOPT_VERSION('V', "version"), + ECORE_GETOPT_COPYRIGHT('R', "copyright"), + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL} +}; + +EAPI int +elm_main(int argc, char **argv) +{ + int r = 0, args; + const char *home; + const char *url; + char path[PATH_MAX]; + Eina_Bool quit_option = EINA_FALSE; + char *user_agent = NULL; + + Ecore_Getopt_Value values[] = { + ECORE_GETOPT_VALUE_BOOL(app.is_fullscreen), + ECORE_GETOPT_VALUE_BOOL(app.disable_plugins), + ECORE_GETOPT_VALUE_BOOL(app.disable_mouse), + ECORE_GETOPT_VALUE_STR(user_agent), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_NONE + }; + +#if ENABLE_NLS + setlocale(LC_ALL, ""); + bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); + textdomain(GETTEXT_PACKAGE); +#endif + + _log_domain = eina_log_domain_register("eve", NULL); + if (_log_domain < 0) + { + EINA_LOG_CRIT("could not create log domain 'eve'."); + return -1; + } + + args = ecore_getopt_parse(&options, values, argc, argv); + if (args < 0) + { + ERR("Could not parse command line options."); + return -1; + } + + if (quit_option) + { + DBG("Command lines option requires quit."); + return 0; + } + + if (args < argc) + url = argv[args]; + else + url = DEFAULT_URL; + + if (user_agent && strcasecmp(user_agent, "iphone") == 0) + user_agent = + "Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3"; + + app.user_agent = eina_stringshare_add(user_agent); + + elm_theme_extension_add(NULL, PACKAGE_DATA_DIR "/default.edj"); + ewk_init(); + favorite_init(); + history_init(); + + home = getenv("HOME"); + if (!home || !home[0]) + { + CRITICAL("Could not get $HOME"); + r = -1; + goto end; + } + + snprintf(path, sizeof(path), "%s/.config/ewebkit", home); + if (!ecore_file_mkpath(path)) + { + ERR("Could not create %s", path); + r = -1; + goto end; + } + if (!ewk_settings_icon_database_path_set(path)) + { + ERR("Could not set icon database path to %s", path); + r = -1; + goto end; + } + + snprintf(path, sizeof(path), "%s/.config/ewebkit/favorites.db", home); + fav = fav_load(path); + if (!fav) + { + fav = fav_new(0); + fav_save(fav, path); + } + + snprintf(path, sizeof(path), "%s/.config/ewebkit/history.db", home); + hist = hist_load(path); + if (!hist) + { + hist = hist_new(0); + hist_save(hist, path); + } + + if (!add_win(&app, url)) + { + r = -1; + goto end; + } + + elm_run(); + end: + fav_save(fav, NULL); + fav_free(fav); + + hist_save(hist, NULL); + hist_free(hist); + + eina_stringshare_del(app.user_agent); + + eina_log_domain_unregister(_log_domain); + _log_domain = -1; + elm_shutdown(); + ewk_shutdown(); + favorite_shutdown(); + history_shutdown(); + return r; +} +#endif +ELM_MAIN() diff --git a/src/bin/private.h b/src/bin/private.h new file mode 100644 index 0000000..282b625 --- /dev/null +++ b/src/bin/private.h @@ -0,0 +1,98 @@ +#ifndef EWEBKIT_DEMO_PRIVATE_H +#define EWEBKIT_DEMO_PRIVATE_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "favorite.h" +#include "history.h" + +typedef struct _App App; +typedef struct _Browser_Window Browser_Window; +typedef struct _View_Zoom_Interactive View_Zoom_Interactive; + +extern int _log_domain; +extern Fav *fav; +extern Hist *hist; +extern App app; + +#define CRITICAL(...) EINA_LOG_DOM_CRIT(_log_domain, __VA_ARGS__) +#define ERR(...) EINA_LOG_DOM_ERR(_log_domain, __VA_ARGS__) +#define WRN(...) EINA_LOG_DOM_WARN(_log_domain, __VA_ARGS__) +#define INF(...) EINA_LOG_DOM_INFO(_log_domain, __VA_ARGS__) +#define DBG(...) EINA_LOG_DOM_DBG(_log_domain, __VA_ARGS__) + +#define DEFAULT_URL "http://www.google.com" + +/* TODO: Move all tab related stuff to its own struct */ +struct _Browser_Window +{ + App *app; + + Evas_Object *win; + Evas_Object *bg; + Evas_Object *pager; + + Eina_List *chromes; + + Eina_List *list_history; + Eina_List *list_history_titles; + + Evas_Object *current_chrome; + Evas_Object *current_view; + + unsigned int current_tab; +}; + +struct _App +{ + Eina_List *windows; + const char *user_agent; + + Eina_Bool is_fullscreen; + Eina_Bool disable_plugins; + Eina_Bool disable_mouse; +}; + +struct _View_Zoom_Interactive +{ + Evas_Coord x, y; + float zoom; +}; + +/** + * Create new view object. + * + * Signals: + * + * * "zoom,interactive" View_Zoom_Interactive: zoom interactive + * requested a new level specified in given event information. + * + * * "zoom,interactive,start" void: report zoom interactive started. + * * "zoom,interactive,end" void: report zoom interactive is finished. + */ + +Evas_Object *window_create(); +Evas_Object *view_add(Evas_Object *parent); +void view_zoom_next_up(Evas_Object *view); +void view_zoom_next_down(Evas_Object *view); +Eina_Bool view_context_menu_set(Evas_Object *view, Evas_Object *widget, Ewk_Context_Menu *menu); +Evas_Object *view_context_menu_widget_get(Evas_Object *view); +Ewk_Context_Menu *view_context_menu_get(Evas_Object *view); + +Evas_Object *chrome_add(Browser_Window *win, const char *url); + +Eina_Bool tab_add(Browser_Window *win, const char *url); +Eina_Bool tab_focus_nth(Browser_Window *win, unsigned int n); +Eina_Bool tab_focus_chrome(Browser_Window * win, Evas_Object * chrome); +Eina_Bool tab_focus_next(Browser_Window *win); +Eina_Bool tab_focus_prev(Browser_Window *win); +Eina_Bool tab_close_nth(Browser_Window *win, int n); +Eina_Bool tab_close_view(Browser_Window *win, Evas_Object * view); +Eina_Bool tab_close_chrome(Browser_Window * win, Evas_Object * chrome); + +#endif diff --git a/src/bin/view.c b/src/bin/view.c new file mode 100644 index 0000000..904667b --- /dev/null +++ b/src/bin/view.c @@ -0,0 +1,1602 @@ +#include "private.h" +#include +#include + +#define HACK_FLUSH_EVENTS_DURING_LONG_CALCULATE 1 +#ifdef HACK_FLUSH_EVENTS_DURING_LONG_CALCULATE +static const double LONG_CALCULATE_TIMEOUT = 0.6; +#include +#include +#endif + + +/* value to consider as double/float error, differences smaller than + * this are ignored + */ +static const double DOUBLE_ERROR = 0.00001; + +/* constant to multiply offsets. + * + * The smaller the value, the faster it will stop. + */ +static const double KINETIC_FRICTION = 1.0; + +/* Minimum value to consider velocity worth doing kinetic animation */ +static const Evas_Coord KINETIC_VELOCITY_THRESHOLD = 20; + + + +/* How long the auto zoom animation should take, in seconds */ +static const double ZOOM_AUTO_ANIMATION_DURATION = 0.5; + +/* Timeout in seconds to consider double-click an auto zoom */ +static const double ZOOM_AUTO_TIMEOUT = 0.2; + +/* Padding in pixels around object being zoomed */ +static const Evas_Coord ZOOM_AUTO_PADDING = 15; + +static const float ZOOM_AUTO_MIN = 0.3; +static const float ZOOM_AUTO_MAX = 4.0; +static const float ZOOM_AUTO_MIN_DIFFERENCE = 0.01; + + +/* How long the interactive zoom animation should take, in seconds */ +static const double ZOOM_STEP_ANIMATION_DURATION = 0.8; + +/* Threshold in pixels to change zoom step. */ +static const Evas_Coord ZOOM_STEP_THRESHOLD = 50; +static const float ZOOM_STEPS[] = { + 0.3, 0.5, 0.67, 0.8, 0.9, 1.0, 1.1, 1.2, 1.33, 1.5, 1.7, 2.0, 2.4, 3.0, +}; +static const unsigned int ZOOM_STEPS_LAST = sizeof(ZOOM_STEPS)/sizeof(ZOOM_STEPS[0]); + +/* + * Structure filled by ewk_view_single_smart_set() from + * view_add(). This contains the pointers to vanilla/pristine + * ewk_view_single, which will be used to implement super() behavior + * in C. + */ +static Ewk_View_Smart_Class _parent_sc = EWK_VIEW_SMART_CLASS_INIT_NULL; + +typedef struct _View_Smart_Data View_Smart_Data; + +#define VIEW_SD_GET_OR_RETURN(o, sd, ...) \ + View_Smart_Data *sd = evas_object_smart_data_get(o); \ + if (!sd) \ + { \ + CRITICAL("no smart data for object %p [%s]", \ + o, evas_object_type_get(o)); \ + return __VA_ARGS__; \ + } + +#define EWK_VIEW_SD_GET_OR_RETURN(o, sd, ...) \ + Ewk_View_Smart_Data *sd = evas_object_smart_data_get(o); \ + if (!sd) \ + { \ + CRITICAL("no smart data for object %p [%s]", \ + o, evas_object_type_get(o)); \ + return __VA_ARGS__; \ + } + +struct point_history +{ + Evas_Coord x, y; + double timestamp; +}; + +/* Extends Ewk_View_Smart_Data to add some members we'll need */ +struct _View_Smart_Data +{ + /* Original type must be the first, so ewk_view and ewk_view_single know + * how to access it (the memory offsets will remain the same). + */ + Ewk_View_Smart_Data base; + + /* where to keep track of our animators */ + struct + { + Ecore_Animator *pan; + Ecore_Animator *zoom; + Ecore_Animator *kinetic; + } animator; + Ecore_Idler *idler_close_window; + + /* context used during pan/scroll animator */ + struct + { + /* circular array with collected samples (see _view_smart_mouse_move()) */ +#define PAN_HISTORY_SIZE (20) + struct point_history history[PAN_HISTORY_SIZE]; + unsigned int idx; /* index in the circular buffer of the last stored value */ + unsigned int count; /* total number of samples collected */ + + struct point_history last_move; /* used by _view_animator_pan() */ + } pan; + + Evas_Event_Mouse_Down mouse_down_copy; /* copy of down event, used by _view_smart_mouse_up() */ + + struct + { + struct + { + float zoom; + Evas_Coord x, y; + double timestamp; + int step_idx; + } start; + + struct + { + Evas_Coord y; + float zoom; + double timestamp; + int step_idx; + } last, next; + + struct + { + float zoom; + double time; + } diff; + + float min_zoom; + + Eina_Bool interactive:1; + } zoom; + + /* context used during kinetic animator */ + struct + { + /* starting point */ + struct + { + Evas_Coord dx, dy; + double timestamp; + } start; + + /* last run */ + struct + { + Evas_Coord dx, dy; + } last; + + /* flags to state we ended animation in those axis */ + struct + { + Eina_Bool x:1; + Eina_Bool y:1; + } done; + } kinetic; + + /* general flags */ + struct + { + Eina_Bool first_calculate:1; + Eina_Bool animated_zoom:1; + } flags; + + Evas_Object *context_menu; +}; + + +/*********************************************************************** + * Helper functions * + **********************************************************************/ + +/* calculates one good zoom level to fit given hit test result */ +static float +_view_zoom_fits_hit(View_Smart_Data *sd, const Ewk_Hit_Test *hit_test) +{ + Evas_Coord x, y; /* hit test point */ + Evas_Coord bx, by, bw, bh, bw1, bw2, bh1, bh2; /* bounding box */ + Evas_Coord vx, vy, vw, vh, vw1, vw2, vh1, vh2; /* visible content */ + Evas_Coord cw, ch; + float zx, zy, z, old_zoom, zx1, zx2, zy1, zy2; + + if (!hit_test) + return 0.0; + + old_zoom = ewk_frame_zoom_get(sd->base.main_frame); + + /* save some typing */ + x = hit_test->x; + y = hit_test->y; + + bx = hit_test->bounding_box.x; + by = hit_test->bounding_box.y; + bw = hit_test->bounding_box.w; + bh = hit_test->bounding_box.h; + + if ((bw <= 0) || (bh <= 0)) + return 0.0; + + ewk_frame_visible_content_geometry_get + (sd->base.main_frame, EINA_FALSE, &vx, &vy, &vw, &vh); + if ((vw <= 0) || (vh <= 0)) + return 0.0; + + ewk_frame_contents_size_get(sd->base.main_frame, &cw, &ch); + if ((cw <= 0) || (ch <= 0)) + return 0.0; + + /* split width of left and right parts from hit test position */ + bw1 = x - bx; + bw2 = bw - bw1; + + /* split height of top and bottom parts from hit test position */ + bh1 = y - by; + bh2 = bh - bh1; + + /* split size of viewport as well. We'll use this as the available space */ + vw1 = x - vx; + vw2 = vw - vw1; + + vh1 = y - vy; + vh2 = vh - vh1; + + /* check if we can add padding around those sizes, "adding" if possible + * (we actually substract as adding a pad is removing available space) + */ + if (vw1 > ZOOM_AUTO_PADDING) + vw1 -= ZOOM_AUTO_PADDING; + if (vw2 > ZOOM_AUTO_PADDING) + vw2 -= ZOOM_AUTO_PADDING; + + if (vh1 > ZOOM_AUTO_PADDING) + vh1 -= ZOOM_AUTO_PADDING; + if (vh2 > ZOOM_AUTO_PADDING) + vh2 -= ZOOM_AUTO_PADDING; + + /* check individual zoom to fit each part */ + zx1 = (bw1 > 0) ? (vw1 / (float)bw1) : 0.0; + zx2 = (bw2 > 0) ? (vw2 / (float)bw2) : 0.0; + + zy1 = (bh1 > 0) ? (vh1 / (float)bh1) : 0.0; + zy2 = (bh2 > 0) ? (vh2 / (float)bh2) : 0.0; + + if ((zx1 >= ZOOM_AUTO_MIN_DIFFERENCE) && (zx2 >= ZOOM_AUTO_MIN_DIFFERENCE)) + zx = (zx1 < zx2) ? zx1 : zx2; + else if (zx1 >= ZOOM_AUTO_MIN_DIFFERENCE) + zx = zx1; + else + zx = zx2; + + if ((zy1 >= ZOOM_AUTO_MIN_DIFFERENCE) && (zy2 >= ZOOM_AUTO_MIN_DIFFERENCE)) + zy = (zy1 < zy2) ? zy1 : zy2; + else if (zy1 >= ZOOM_AUTO_MIN_DIFFERENCE) + zy = zy1; + else + zy = zy2; + + if ((zx >= ZOOM_AUTO_MIN_DIFFERENCE) && (zy >= ZOOM_AUTO_MIN_DIFFERENCE)) + z = (zx < zy) ? zx : zy; + else if (zx >= ZOOM_AUTO_MIN_DIFFERENCE) + z = zx; + else + z = zy; + + /* zoom will make contents be smaller than viewport, limit it */ + if (((int)(z * old_zoom * cw) < vw) || ((int)(z * old_zoom * ch) < vh)) + { + float ac = cw / (float)ch; + float av = vw / (float)vh; + + if (ac < av) + z = vw / (float)cw; + else + z = vh / (float)ch; + } + +#if 0 + /* debug */ + printf(">>> fit: center=%3d,%3d box=%3d,%3d+%3dx%3d\n" + " x: %3d = %3d + %3d, %3d = %3d + %3d, %2.4f %2.4f -> %2.4f\n" + " y: %3d = %3d + %3d, %3d = %3d + %3d, %2.4f %2.4f -> %2.4f\n" + " final: %2.4f %2.4f (old=%0.3f, difference=%0.3f)\n" + " contents: %4dx%4d -> %4dx%4d\n" + "\n", + x, y, bx, by, bw, bh, + bw, bw1, bw2, vw, vw1, vw2, zx1, zx2, zx, + bh, bh1, bh2, vh, vh1, vh2, zy1, zy2, zy, + z, old_zoom * z, old_zoom, fabs(old_zoom - z), + cw, ch, (int)(z * old_zoom * cw), (int)(z * old_zoom * ch)); +#endif + + z *= old_zoom; + + if (z < ZOOM_AUTO_MIN) + z = ZOOM_AUTO_MIN; + else if (z > ZOOM_AUTO_MAX) + z = ZOOM_AUTO_MAX; + + if (fabs(old_zoom - z) < ZOOM_AUTO_MIN_DIFFERENCE) + return 0.0; + + return z; +} + +/* remove flag saying that object is animating zoom */ +static void +_view_zoom_animated_end(void *data, Evas_Object *view __UNUSED__, void *event_info __UNUSED__) +{ + View_Smart_Data *sd = data; + sd->flags.animated_zoom = EINA_FALSE; +} + +/* ask for pre-render when load finished */ +static void +_view_load_finished(void *data, Evas_Object *view, void *event_info __UNUSED__) +{ + View_Smart_Data *sd = data; + float zoom = ewk_frame_zoom_get(sd->base.main_frame); + Evas_Coord x, y, w, h; + ewk_frame_visible_content_geometry_get + (sd->base.main_frame, EINA_TRUE, &x, &y, &w, &h); + + w *= 2; + h *= 2; + + INF("load finished, pre-render %d,%d+%dx%d at %0.2f", x, y, w, h, zoom); + ewk_view_pre_render_region(view, x, y, w, h, zoom); +} + +/* stop animators, we changed page */ +static void +_view_uri_changed(void *data, Evas_Object *view, void *event_info __UNUSED__) +{ + View_Smart_Data *sd = data; + + if (sd->animator.pan) + { + ecore_animator_del(sd->animator.pan); + sd->animator.pan = NULL; + } + + if (sd->animator.kinetic) + { + ecore_animator_del(sd->animator.kinetic); + sd->animator.kinetic = NULL; + } + + if (sd->animator.zoom) + { + /* inform ewk_view that we finished performing zoom animation */ + ewk_view_zoom_animated_mark_stop(view); + evas_object_smart_callback_call(view, "zoom,interactive,end", NULL); + ecore_animator_del(sd->animator.zoom); + sd->animator.zoom = NULL; + } +} + +/* ask ewk_view to pre render in the given direction. + * + * This uses a heuristics to create a pre-render region using the + * given motion vector. + */ +static void +_view_pan_pre_render(View_Smart_Data *sd, Evas_Coord dx, Evas_Coord dy) +{ + float zoom = ewk_frame_zoom_get(sd->base.main_frame); + double weightx, weighty; + Evas_Coord x, y, w, h, px, py, pw, ph; + unsigned int vx, vy; + + /* where are we now */ + ewk_frame_visible_content_geometry_get + (sd->base.main_frame, EINA_TRUE, &x, &y, &w, &h); + + /* get absolute value for dx and dy, remove it's precision */ + vx = abs(dx) >> 4; + vy = abs(dy) >> 4; + + if (vx == 0 && vy == 0) + return; /* motion vector is not significant, don't pre-render */ + else if (vx < vy) + { + /* moving more on Y-axis than X. */ + weightx = 0.5; + weighty = 1.0; + } + else if (vx > vy) + { + /* moving more on X-axis than X. */ + weightx = 1.0; + weighty = 0.5; + } + else + { + /* moving equally on both axis, be more conservative */ + weightx = 0.6; + weighty = 0.6; + } + + /* if values were not significant, zero their extra weight */ + if (vx == 0) + weightx = 0.0; + else if (vy == 0) + weighty = 0.0; + + /* use single region that includes existing viewport. + * + * This is simple and should work. Another option is to do more + * detailed analysis and possible create special cases for + * vertical, horizontal and diagonal moves, with diagonal being + * smarter and rendering less than we do now. + */ + pw = w * (1.0 + weightx); + ph = h * (1.0 + weighty); + + px = x; + py = y; + + if (dx > 0) + px -= (pw - w); + if (dy > 0) + py -= (ph - h); + + INF("pre-render region %d,%d+%dx%d at %0.2f (viewport=%d,%d+%dx%d)", + px, py, pw, ph, zoom, x, y, w, h); + ewk_view_pre_render_region(sd->base.self, px, py, pw, ph, zoom); +} + +static unsigned int +_view_zoom_closest_index_find(float zoom) +{ + unsigned int i, close_idx; + float close_zoom; + + close_idx = 0; + close_zoom = 999999.99; + for (i = 0; i < ZOOM_STEPS_LAST; i++) + { + float cur = fabs(zoom - ZOOM_STEPS[i]); + if (cur < close_zoom) + { + close_idx = i; + close_zoom = cur; + if (cur < DOUBLE_ERROR) /* close enough */ + break; + } + } + + return close_idx; +} + +/*********************************************************************** + * Animators: shared timers at fixed frame rate/interval. * + **********************************************************************/ + +/* Animator that implements the kinetic animation (momentum). + * + * This is started by _view_smart_mouse_up() if it is worth doing the + * animation. + * + * Code is heavily based on els_scroller.c from Elementary. + */ +static Eina_Bool +_view_animator_kinetic(void *data) +{ + View_Smart_Data *sd = data; + double p, dt, now = ecore_loop_time_get(); + Evas_Coord x, y, sx, sy, sw, sh; + + dt = now - sd->kinetic.start.timestamp; + /* time difference is too small, ignore it */ + if (dt <= DOUBLE_ERROR) + goto end; + + dt = dt / KINETIC_FRICTION; + if (dt > 1.0) + dt = 1.0; + + p = 1.0 - ((1.0 - dt) * (1.0 - dt)); + + /* query scroll area and current position */ + ewk_frame_scroll_pos_get(sd->base.main_frame, &sx, &sy); + ewk_frame_scroll_size_get(sd->base.main_frame, &sw, &sh); + + if (!sd->kinetic.done.x) + { + /* we're not done on x-axis yet, calculate new displacement */ + Evas_Coord dx = sd->kinetic.start.dx * KINETIC_FRICTION * p; + x = sd->kinetic.last.dx - dx; + sd->kinetic.last.dx = dx; + + /* check if new displacement fit in scroll area */ + if (sx + x < 0) + { + x = - sx; + sd->kinetic.done.x = EINA_TRUE; + } + else if (sx + x >= sw) + { + x = sw - sx; + sd->kinetic.done.x = EINA_TRUE; + } + } + else + x = 0; + + if (!sd->kinetic.done.y) + { + /* we're not done on y-axis yet, calculate new displacement */ + Evas_Coord dy = sd->kinetic.start.dy * KINETIC_FRICTION * p; + y = sd->kinetic.last.dy - dy; + sd->kinetic.last.dy = dy; + + /* check if new displacement fit in scroll area */ + if (sy + y < 0) + { + y = - sy; + sd->kinetic.done.y = EINA_TRUE; + } + else if (sy + y >= sh) + { + y = sh - sy; + sd->kinetic.done.y = EINA_TRUE; + } + } + else + y = 0; + + /* if there is anything to scroll, ask it */ + if (x != 0 || y != 0) + ewk_frame_scroll_add(sd->base.main_frame, x, y); + + /* if we finished our work, just stop the animator */ + if (dt >= 1.0 || (sd->kinetic.done.x && sd->kinetic.done.y)) + { + _view_pan_pre_render(sd, sd->kinetic.start.dx, sd->kinetic.start.dy); + sd->animator.kinetic = NULL; + return ECORE_CALLBACK_CANCEL; + } + + end: + return ECORE_CALLBACK_RENEW; /* keep running until we finish */ +} + +/* Animator to apply scroll/pan at fixed frame rate. + * + * If pointer (mouse) was moved since last run, then request main + * frame to scroll. + */ +static Eina_Bool +_view_animator_pan(void *data) +{ + View_Smart_Data *sd = data; + Evas_Coord x, y, dx, dy; + double timestamp; + + evas_pointer_canvas_xy_get(sd->base.base.evas, &x, &y); + + /* webkit is swapped */ + dx = sd->pan.last_move.x - x; + dy = sd->pan.last_move.y - y; + + /* ignore this sample if it did not change */ + if ((dx == 0) && (dy == 0)) + goto end; + + timestamp = ecore_loop_time_get(); + if (timestamp <= sd->pan.last_move.timestamp) /* did time went backwards?! */ + goto end; + + /* request scroll by same displacement */ + ewk_frame_scroll_add(sd->base.main_frame, dx, dy); + + /* save new last position */ + sd->pan.last_move.x = x; + sd->pan.last_move.y = y; + sd->pan.last_move.timestamp = timestamp; + + end: + return ECORE_CALLBACK_RENEW; /* keep running until something else remove */ +} + +/* start pan/scroll animation */ +static void +_view_pan_start(View_Smart_Data *sd, const Evas_Event_Mouse_Down *ev) +{ + struct point_history *p; + + /* not really required, but let's clean it */ + memset(&sd->pan, 0, sizeof(sd->pan)); + + /* start history with one sample being the down position */ + sd->pan.idx = 0; + sd->pan.count = 1; + p = sd->pan.history; + p->x = ev->canvas.x; + p->y = ev->canvas.y; + p->timestamp = ecore_loop_time_get(); + + sd->pan.last_move = *p; + + ewk_view_pre_render_cancel(sd->base.self); + + /* register function to collect samples and apply scrolls at fixed interval*/ + if (!sd->animator.pan) + sd->animator.pan = ecore_animator_add(_view_animator_pan, sd); +} + +/* stop pan animation and possible schedule a kinetic scrolling. + * + * @return @c EINA_TRUE if event was handled inside this function and + * should not be used by calling function or @c EINA_FALSE if + * event is unused and should be forwarded by caller. + */ +static Eina_Bool +_view_pan_stop(View_Smart_Data *sd, const Evas_Event_Mouse_Up *ev) +{ + double t, at; + Evas_Coord ax, ay, dx, dy, vel; + unsigned int i, todo, samples; + + /* Stop pan animator, we're done already. */ + if (sd->animator.pan) + { + ecore_animator_del(sd->animator.pan); + sd->animator.pan = NULL; + } + + /* If we do not have enough samples, just assume it was a click */ + if (sd->pan.count < 2) + return EINA_FALSE; + + /* the following code is heavily based on els_scroller.c from Elementary. + * + * It will check the samples from history and get the average point. + */ + t = ecore_loop_time_get(); + + ax = ev->canvas.x; + ay = ev->canvas.y; + at = 0.0; + + i = sd->pan.idx; + todo = sd->pan.count > PAN_HISTORY_SIZE ? PAN_HISTORY_SIZE : sd->pan.count; + samples = 0; + + for (; todo > 0; todo--) + { + struct point_history *p = sd->pan.history + i; + double dt = t - p->timestamp; + + if (dt > 0.2 && samples > 0) + break; + + at += dt; + ax += p->x; + ay += p->y; + samples++; + + if (i > 0) + i--; + else + i = PAN_HISTORY_SIZE - 1; + } + + /* time was too short, consider it a click */ + if (at <= DOUBLE_ERROR) + return EINA_FALSE; + + ax /= samples + 1; + ay /= samples + 1; + at *= 4.0; + + dx = ev->canvas.x - ax; + dy = ev->canvas.y - ay; + + vel = sqrt((dx * dx) + (dy * dy)) / at; + /* velocity was too short, consider it a click */ + if (vel <= KINETIC_VELOCITY_THRESHOLD) + { + _view_pan_pre_render(sd, dx, dy); + return EINA_FALSE; + } + + /* it's really woth animating. setup kinetic animation context and start + * animator function. + */ + sd->kinetic.start.timestamp = t; + sd->kinetic.start.dx = dx; + sd->kinetic.start.dy = dy; + sd->kinetic.last.dx = 0; + sd->kinetic.last.dy = 0; + sd->kinetic.done.x = EINA_FALSE; + sd->kinetic.done.y = EINA_FALSE; + + sd->animator.kinetic = ecore_animator_add(_view_animator_kinetic, sd); + return EINA_TRUE; +} + +/* Animator to collect mouse position and apply zoom at fixed frame rate. + * + * This animator works in two parts: + * + * 1. check if mouse moved up/down enough to change the zoom level + * to another band. We move in bands specified in ZOOM_STEPS every + * ZOOM_STEP_THRESHOLD pixels, up or down. + * + * 2. interpolates zoom level using weak zoom progressively until + * we reach desired level (sd->zoom.next.zoom) in calculated + * time slot (based on ZOOM_STEP_ANIMATION_DURATION). + */ +static Eina_Bool +_view_animator_zoom(void *data) +{ + View_Smart_Data *sd = data; + Evas_Object *o = sd->base.self; + Evas_Coord y, dy; + double timestamp = ecore_loop_time_get(); + int step_inc, idx; + + /* wait to know if we're in auto zoom or interactive zooming */ + if (timestamp - sd->zoom.start.timestamp <= ZOOM_AUTO_TIMEOUT) + goto end; + + if (!sd->zoom.interactive) + { + evas_object_smart_callback_call(o, "zoom,interactive,start", NULL); + sd->zoom.interactive = EINA_TRUE; + } + + evas_pointer_canvas_xy_get(sd->base.base.evas, NULL, &y); + dy = y - sd->zoom.start.y; + step_inc = dy / ZOOM_STEP_THRESHOLD; + + /* find out new step */ + idx = step_inc + sd->zoom.start.step_idx; + + /* check for out of bounds access */ + if (idx < 0) + idx = 0; + else if (idx >= (int)ZOOM_STEPS_LAST) + idx = ZOOM_STEPS_LAST - 1; + + if (ZOOM_STEPS[idx] < sd->zoom.min_zoom) + idx = sd->zoom.next.step_idx; + + /* Part 1. check if mouse moved enough to change zoom level band */ + if (idx != sd->zoom.next.step_idx) + { + View_Zoom_Interactive data; + /* new target (next) values */ + sd->zoom.next.step_idx = idx; + sd->zoom.next.zoom = ZOOM_STEPS[idx]; + sd->zoom.next.timestamp = timestamp + ZOOM_STEP_ANIMATION_DURATION; + sd->zoom.diff.zoom = sd->zoom.next.zoom - sd->zoom.last.zoom; + sd->zoom.diff.time = sd->zoom.next.timestamp - sd->zoom.last.timestamp; + + /* we'll animated, disable smooth scaling in evas so it's faster */ + ewk_view_zoom_weak_smooth_scale_set(o, EINA_FALSE); + + /* inform user that new level was requested */ + data.x = sd->zoom.start.x; + data.y = sd->zoom.start.y; + data.zoom = sd->zoom.next.zoom; + evas_object_smart_callback_call(o, "zoom,interactive", &data); + } + + if (sd->zoom.next.timestamp < DOUBLE_ERROR) + goto end; /* sd->zoom.next.timestamp is zero, we're stopped */ + + /* Part 2. interpolate values to animate zoom change */ + else if (timestamp >= sd->zoom.next.timestamp) + { + /* we're done, enable smooth scaling so the still image looks better + * and apply the final zoom level + */ + ewk_view_zoom_weak_smooth_scale_set(o, EINA_TRUE); + ewk_view_zoom_weak_set + (o, sd->zoom.next.zoom, sd->zoom.start.x, sd->zoom.start.y); + + sd->zoom.last = sd->zoom.next; + sd->zoom.next.timestamp = 0.0; /* say we're stopped, see above */ + } + else if (sd->zoom.diff.time > 0.0) + { + /* regular intermediate animation frame, interpolate and apply */ + float zoom, p; + + p = (timestamp - sd->zoom.last.timestamp) / sd->zoom.diff.time; + zoom = sd->zoom.last.zoom + sd->zoom.diff.zoom * p; + + ewk_view_zoom_weak_set(o, zoom, sd->zoom.start.x, sd->zoom.start.y); + } + + end: + return ECORE_CALLBACK_RENEW; /* keep running until something else remove */ +} + +/* start zoom animation */ +static void +_view_zoom_start(View_Smart_Data *sd, const Evas_Event_Mouse_Down *ev) +{ + Evas_Object *frame = sd->base.main_frame; + Evas_Coord cw, ch, vw, vh; + float z, zx, zy; + + ewk_view_pre_render_cancel(sd->base.self); + + /* remember starting point so we have a reference */ + sd->zoom.start.zoom = ewk_frame_zoom_get(frame); + sd->zoom.start.x = ev->canvas.x; + sd->zoom.start.y = ev->canvas.y; + sd->zoom.start.timestamp = ecore_loop_time_get(); + + /* find out which zoom level band we're in, closest match */ + sd->zoom.start.step_idx = _view_zoom_closest_index_find(sd->zoom.start.zoom); + + sd->zoom.last.y = sd->zoom.start.x; + sd->zoom.last.zoom = sd->zoom.start.zoom; + sd->zoom.last.timestamp = sd->zoom.start.timestamp; + + sd->zoom.next.y = sd->zoom.start.x; + sd->zoom.next.zoom = sd->zoom.start.zoom; + sd->zoom.next.timestamp = 0.0; /* this means we're stopped */ + + sd->zoom.diff.zoom = 0.0; + sd->zoom.diff.time = 0.0; + + sd->zoom.interactive = EINA_FALSE; + + /* find out the minimum zoom level that contents is greater or equal + * viewport size + */ + ewk_frame_visible_content_geometry_get(frame, 0, NULL, NULL, &vw, &vh); + ewk_frame_contents_size_get(frame, &cw, &ch); + + zx = vw / (float)cw; + zy = vh / (float)ch; + z = (zx > zy) ? zx : zy; + z *= sd->zoom.start.zoom; + if (z >= ZOOM_STEPS[0]) + sd->zoom.min_zoom = z; + else + sd->zoom.min_zoom = ZOOM_STEPS[0]; + + /* inform ewk_view that we'll perform an animation with zoom */ + ewk_view_zoom_animated_mark_start(sd->base.self, sd->zoom.start.zoom); + + /* register function to query pointer position and apply new zoom */ + if (!sd->animator.zoom) + sd->animator.zoom = ecore_animator_add(_view_animator_zoom, sd); +} + +/* stop zoom animation. + * + * @return @c EINA_TRUE if event was handled inside this function and + * should not be used by calling function or @c EINA_FALSE if + * event is unused and should be forwarded by caller. + */ +static Eina_Bool +_view_zoom_stop(View_Smart_Data *sd, const Evas_Event_Mouse_Up *ev __UNUSED__) +{ + double timestamp = ecore_loop_time_get(); + Evas_Object *view = sd->base.self; + Evas_Object *frame = sd->base.main_frame; + const Evas_Coord x = sd->zoom.start.x, y = sd->zoom.start.y; + + /* Stop zoom animator, we're done already. */ + if (sd->animator.zoom) + { + ecore_animator_del(sd->animator.zoom); + sd->animator.zoom = NULL; + } + + /* inform ewk_view that we finished performing zoom animation */ + ewk_view_zoom_animated_mark_stop(view); + evas_object_smart_callback_call(view, "zoom,interactive,end", NULL); + + /* if it was an auto zoom (zoom to fit some element) */ + if (timestamp - sd->zoom.last.timestamp < ZOOM_AUTO_TIMEOUT) + { + Ewk_Hit_Test *hit_test = ewk_frame_hit_test_new(frame, x, y); + float zoom = _view_zoom_fits_hit(sd, hit_test); + ewk_frame_hit_test_free(hit_test); + + if (zoom > 0.0) + { + /* wait until animation ends (see _view_zoom_animated_end) */ + sd->flags.animated_zoom = EINA_TRUE; + ewk_view_zoom_animated_set + (view, zoom, ZOOM_AUTO_ANIMATION_DURATION, x, y); + } + return EINA_TRUE; + } + + /* otherwise, apply definitive zoom */ + ewk_view_zoom_set(view, sd->zoom.next.zoom, x, y); + + return EINA_TRUE; +} + +/************** Event handlers *****************/ + +static Eina_Bool +_view_contextmenu_free(void *data) +{ + Evas_Object *notify = data; + evas_object_del(notify); + return EINA_FALSE; +} + +static void +_view_contextmenu_item_selected(void *data, Evas_Object *li, void *event_info) +{ + Ewk_Context_Menu_Item *item = data; + Evas_Object *view = evas_object_data_get(li, "view"); + Ewk_Context_Menu *menu = view_context_menu_get(view); + + ewk_context_menu_item_select(menu, item); + ewk_context_menu_destroy(menu); +} + +static void +_view_contextmenu_cancel(void *data, Evas_Object *notify __UNUSED__, void *event_info __UNUSED__) +{ + Ewk_Context_Menu *menu = data; + ewk_context_menu_destroy(menu); +} + +static void +on_view_contextmenu_show(void *data __UNUSED__, Evas_Object *view, void *event_info) +{ + Ewk_Context_Menu *menu = event_info; + const Eina_List *l, *items = ewk_context_menu_item_list_get(menu); + Ewk_Context_Menu_Item *item; + Evas_Object *chrome = evas_object_data_get(view, "chrome"); + Evas_Object *notify, *li; + Elm_List_Item *it; + + if (eina_list_count(items) == 0) + { + WRN("Context Menu with no items. Aborting operation."); + ewk_context_menu_destroy(menu); + } + + notify = elm_notify_add(chrome); + elm_object_style_set(notify, "ewebkit"); + evas_object_size_hint_weight_set(notify, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_notify_repeat_events_set(notify, EINA_FALSE); + elm_notify_orient_set(notify, ELM_NOTIFY_ORIENT_BOTTOM); + + li = elm_list_add(view); + elm_object_style_set(li, "ewebkit"); + elm_list_always_select_mode_set(li, 1); + evas_object_size_hint_weight_set(li, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_fill_set(li, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_min_set(li, 200, 200); + elm_notify_content_set(notify, li); + + evas_object_smart_callback_add(notify, "block,clicked", + _view_contextmenu_cancel, menu); + evas_object_data_set(li, "view", view); + EINA_LIST_FOREACH(items, l, item) + { + it = elm_list_item_append(li, ewk_context_menu_item_title_get(item), 0, 0, + _view_contextmenu_item_selected, item); + elm_list_item_separator_set(it, ewk_context_menu_item_type_get(item) == EWK_SEPARATOR_TYPE); + } + view_context_menu_set(view, notify, menu); + elm_list_go(li); + evas_object_show(notify); +} + +static void +on_view_contextmenu_new(void *data, Evas_Object *view __UNUSED__, void *event_info) +{ + DBG("menu=%p sd=%p", event_info, data); + Ewk_Context_Menu *menu = event_info; + ewk_context_menu_ref(menu); +} + +static void +on_view_contextmenu_freed(void *data, Evas_Object *view, void *event_info) +{ + DBG("menu=%p view=%p", event_info, data); + Ewk_Context_Menu *menu = event_info; + Evas_Object *notify = view_context_menu_widget_get(view); + + view_context_menu_set(view, NULL, NULL); + ewk_context_menu_unref(menu); + ecore_idler_add(_view_contextmenu_free, notify); +} + + +/*********************************************************************** + * Smart Class Methods: * + * * + * Implements callback interface defined by Evas with Evas_Smart_Class * + * and WebKit-EFL with Ewk_View_Smart_Class, a super-set of Evas. * + * * + * This allow us to inherit the class to override or extend, such as * + * creating a bigger smart data structure to account our animators and * + * other context data and automatically apply fixed layout size when * + * object size changes. + **********************************************************************/ + +/* object constructor. receives new object to set its internal state */ +static void +_view_smart_add(Evas_Object *o) +{ + /* Create our extension of Ewk_View_Smart_Data so we can have our own + * context, such as the animators and extra flags. + */ + View_Smart_Data *sd = calloc(1, sizeof(View_Smart_Data)); + evas_object_smart_data_set(o, sd); + sd->flags.first_calculate = EINA_TRUE; + + /* call parent and let it do the whole thing */ + _parent_sc.sc.add(o); + + /* set some common properties, such as theme and default zoom weak method */ + ewk_view_theme_set(o, PACKAGE_DATA_DIR "/ewebkit.edj"); + ewk_view_zoom_weak_smooth_scale_set(o, EINA_FALSE); + + evas_object_smart_callback_add + (o, "zoom,animated,end", _view_zoom_animated_end, sd); + evas_object_smart_callback_add + (o, "load,finished", _view_load_finished, sd); + evas_object_smart_callback_add + (o, "uri,changed", _view_uri_changed, sd); + + evas_object_smart_callback_add + (o, "contextmenu,new", on_view_contextmenu_new, sd); + evas_object_smart_callback_add + (o, "contextmenu,free", on_view_contextmenu_freed, sd); + evas_object_smart_callback_add + (o, "contextmenu,show", on_view_contextmenu_show, sd); +} + +/* object destructor. receives object that dies when this function returns */ +static void +_view_smart_del(Evas_Object *o) +{ + VIEW_SD_GET_OR_RETURN(o, sd); + + /* Must delete all extra fields before calling parent method, + * as parent's will free View_Smart_Data. + */ + if (sd->animator.pan) + ecore_animator_del(sd->animator.pan); + if (sd->animator.zoom) + ecore_animator_del(sd->animator.zoom); + if (sd->animator.kinetic) + ecore_animator_del(sd->animator.kinetic); + if (sd->idler_close_window) + ecore_idler_del(sd->idler_close_window); + + _parent_sc.sc.del(o); +} + +/* calculate is called on dirty objects (evas_object_smart_changed()) + * right before Evas paints the new scene. + * + * It is a good place to do last-minute calculations and checks, + * allowing one to postpone such tasks as much as possible. + * + * For example, if user do for (i=0; i<1000; i++) + * evas_object_resize(o, w, h), then Evas will just use the last value + * when painting, however it will call Evas_Smart_Class::resize() lots + * of times, as well as EVAS_CALLBACK_RESIZE. Thus if we apply + * ewk_view_fixed_layout_size_set() on these callbacks, we'd apply 999 + * useless values! By postponing it to calculate(), we know we'll + * apply just what matters. + */ +static void +_view_smart_calculate(Evas_Object *o) +{ + VIEW_SD_GET_OR_RETURN(o, sd); + +#ifdef HACK_FLUSH_EVENTS_DURING_LONG_CALCULATE + Display *dpy = ecore_x_display_get(); + double before = ecore_time_get(); + XSync(dpy, False); /* force processing all events */ +#endif + + /* call parent smart calculate and let ewk_view do all its work */ + _parent_sc.sc.calculate(o); + +#ifdef HACK_FLUSH_EVENTS_DURING_LONG_CALCULATE + double now = ecore_time_get(); + double elapsed = now - before; + if (elapsed > LONG_CALCULATE_TIMEOUT) + { + WRN("calulate took too long (%0.3f of %0.3f), ignoring events.", + elapsed, LONG_CALCULATE_TIMEOUT); + XSync(dpy, True); /* throw away events received during this timeout */ + } +#endif +} + +/* called by ewk_view when mouse down events happen. + * + * here we'll check if we should start a pan/scroll if user move mouse + * (drag) or if we should forward this event to parent method, that + * feeds it to WebKit-EFL. + * + * The way we do it here breaks drag&drop of elements required by some + * JavaScript websites such as GMail and Yahoo! Mail. We should do it + * in a way that WebKit says if element can be dragged or not, but it + * is not exposed by WebKit now. + */ +static Eina_Bool +_view_smart_mouse_down(Ewk_View_Smart_Data *esd, const Evas_Event_Mouse_Down *ev) +{ + View_Smart_Data *sd = (View_Smart_Data *)esd; + + /* do not handle down when doing animated zoom */ + if (sd->flags.animated_zoom) + return EINA_FALSE; + + /* mouse down immediately cancels previous kinetic animation */ + if (sd->animator.kinetic) + { + ecore_animator_del(sd->animator.kinetic); + sd->animator.kinetic = NULL; + } + + /* we just want to start pan on button 1 (left) and not triple click */ + if (ev->button != 1) + goto forward_event; + if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK) + goto forward_event; + +#if 0 // at the end, this is not good usability. + /* no pan or zoom if click over editable or links */ + Ewk_Hit_Test *hit_test = ewk_frame_hit_test_new + (esd->main_frame, ev->canvas.x, ev->canvas.y); + if (hit_test) + { + Eina_Bool skip = (hit_test->flags.editable || + (hit_test->link.url && hit_test->link.url[0])); + ewk_frame_hit_test_free(hit_test); + if (skip && !(ev->flags & EVAS_BUTTON_DOUBLE_CLICK)) + goto forward_event; + } +#endif + + /* cancel previous animators, if any (there should be none) */ + if (sd->animator.pan) + { + ecore_animator_del(sd->animator.pan); + sd->animator.pan = NULL; + } + if (sd->animator.zoom) + { + ecore_animator_del(sd->animator.zoom); + sd->animator.zoom = NULL; + } + + /* choose if we're zooming or panning */ + if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK) + _view_zoom_start(sd, ev); + else + _view_pan_start(sd, ev); + + /* keep a copy in the case we notice a click instead of drag to pan/scroll */ + sd->mouse_down_copy = *ev; + + return EINA_TRUE; + + forward_event: + if (ev->button == 3) // forward of context menu event is special + return ewk_view_context_menu_forward_event(sd->base.self, ev); + /* If we should forward/feed event using parent class method, then + * just do it and do NOT create an animator. See _view_smart_mouse_up(). + */ + return _parent_sc.mouse_down(esd, ev); +} + +/* called by ewk_view when mouse up events happen. + * + * This pairs with _view_smart_mouse_down(), forwarding events if + * required, feeding saved mouse down event or even starting the + * kinetic animation. + */ +static Eina_Bool +_view_smart_mouse_up(Ewk_View_Smart_Data *esd, const Evas_Event_Mouse_Up *ev) +{ + View_Smart_Data *sd = (View_Smart_Data *)esd; + Eina_Bool used; + + /* cancel any previous kinetic animation (but should have none) */ + if (sd->animator.kinetic) + { + ecore_animator_del(sd->animator.kinetic); + sd->animator.kinetic = NULL; + } + + /* do not handle up when doing animated zoom */ + if (sd->flags.animated_zoom) + return EINA_FALSE; + + /* if it was not doing pan or zoom (see _view_smart_mouse_down()), + * then we just feed mouse_up using parent method. + */ + if (sd->animator.pan) + used = _view_pan_stop(sd, ev); + else if (sd->animator.zoom) + used = _view_zoom_stop(sd, ev); + else + return _parent_sc.mouse_up(esd, ev); + + if (used) + return EINA_TRUE; + + /* it was not used, so just feed the saved down then + * mouse up event. This is required to let WebKit process the + * sequence correctly. + */ + _parent_sc.mouse_down(esd, &sd->mouse_down_copy); + return _parent_sc.mouse_up(esd, ev); +} + +/* called by ewk_view when mouse move events happen. + * + * Let's just ignore mouse move events while doing pan/scrolling or zooming. + */ +static Eina_Bool +_view_smart_mouse_move(Ewk_View_Smart_Data *esd, const Evas_Event_Mouse_Move *ev) +{ + View_Smart_Data *sd = (View_Smart_Data *)esd; + + if (sd->animator.pan) + { + /* account sample in circular array */ + struct point_history *p; + unsigned int next_idx = (sd->pan.idx + 1) % PAN_HISTORY_SIZE; + p = sd->pan.history + next_idx; + p->x = ev->cur.canvas.x; + p->y = ev->cur.canvas.y; + p->timestamp = ecore_loop_time_get(); + + sd->pan.idx = next_idx; + sd->pan.count++; + + return EINA_FALSE; + } + + if (sd->animator.zoom) + return EINA_FALSE; + + return _parent_sc.mouse_move(esd, ev); +} + +/* called by ewk_view when something goes to console + * + * We just print message to stdout + */ +static void +_view_smart_add_console_message(Ewk_View_Smart_Data *esd, const char *message, unsigned int lineNumber, const char *sourceID) +{ + printf("BROWSER console: %s @%d: %s\n", sourceID, lineNumber, message); +} + +enum dialog_type +{ + DIALOG_ALERT, + DIALOG_CONFIRM, + DIALOG_PROMPT +}; + +struct _dialog_data +{ + Evas_Object *notify; + Evas_Object *bt_ok, *bt_cancel; + Evas_Object *entry; + + Eina_Bool *response; +}; + +static void +_bt_close(void *data, Evas_Object *obj, void *event_info) +{ + struct _dialog_data *d = data; + + *d->response = (obj == d->bt_ok); + evas_object_hide(d->notify); + ecore_main_loop_quit(); +} + +static Eina_Bool +_run_dialog(Evas_Object *parent, enum dialog_type type, const char *message, const char *default_entry_value, char **entry_value) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL((type != DIALOG_PROMPT) && (default_entry_value != NULL), EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL((type != DIALOG_PROMPT) && (entry_value != NULL), EINA_FALSE); + + struct _dialog_data *dialog_data = calloc(1, sizeof(*dialog_data)); + Eina_Bool response = EINA_FALSE; + + Evas_Object *bx_v, *lb; + + dialog_data->notify = elm_notify_add(parent); + evas_object_size_hint_weight_set(dialog_data->notify, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_notify_repeat_events_set(dialog_data->notify, EINA_FALSE); + + bx_v = elm_box_add(parent); + elm_notify_content_set(dialog_data->notify, bx_v); + elm_box_horizontal_set(bx_v, 0); + evas_object_size_hint_weight_set(bx_v, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bx_v); + + lb = elm_label_add(bx_v); + elm_label_label_set(lb, message); + elm_box_pack_end(bx_v, lb); + evas_object_show(lb); + + dialog_data->response = &response; + + if (type == DIALOG_ALERT) + { + dialog_data->bt_ok = elm_button_add(bx_v); + elm_button_label_set(dialog_data->bt_ok, "Close"); + elm_box_pack_end(bx_v, dialog_data->bt_ok); + evas_object_size_hint_align_set(dialog_data->bt_ok, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(dialog_data->bt_ok, "clicked", _bt_close, dialog_data); + evas_object_show(dialog_data->bt_ok); + } + else + { + if (type == DIALOG_PROMPT) + { + dialog_data->entry = elm_entry_add(bx_v); + elm_entry_entry_set(dialog_data->entry, default_entry_value); + elm_box_pack_end(bx_v, dialog_data->entry); + evas_object_show(dialog_data->entry); + } + if (type == DIALOG_PROMPT || type == DIALOG_CONFIRM) + { + Evas_Object *bx_h = elm_box_add(bx_v); + elm_box_horizontal_set(bx_h, 1); + elm_box_pack_end(bx_v, bx_h); + evas_object_size_hint_weight_set(bx_h, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(bx_h, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_show(bx_h); + + dialog_data->bt_cancel = elm_button_add(bx_h); + elm_button_label_set(dialog_data->bt_cancel, "Cancel"); + elm_box_pack_end(bx_h, dialog_data->bt_cancel); + evas_object_size_hint_weight_set(dialog_data->bt_cancel, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(dialog_data->bt_cancel, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(dialog_data->bt_cancel, "clicked", _bt_close, dialog_data); + evas_object_show(dialog_data->bt_cancel); + + dialog_data->bt_ok = elm_button_add(bx_h); + elm_button_label_set(dialog_data->bt_ok, "Ok"); + elm_box_pack_end(bx_h, dialog_data->bt_ok); + evas_object_size_hint_weight_set(dialog_data->bt_ok, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(dialog_data->bt_ok, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_smart_callback_add(dialog_data->bt_ok, "clicked", _bt_close, dialog_data); + evas_object_show(dialog_data->bt_ok); + } + else + return EINA_FALSE; + } + + evas_object_show(dialog_data->notify); + ecore_main_loop_begin(); + + if ((type == DIALOG_PROMPT) && (response == EINA_TRUE)) + *entry_value = strdup(elm_entry_entry_get(dialog_data->entry)); + + evas_object_del(dialog_data->notify); + free(dialog_data); + + return response; +} + +/* called by ewk_view when javascript called alert() + * + */ +static void +_view_smart_run_javascript_alert(Ewk_View_Smart_Data *esd, Evas_Object *frame, const char *message) +{ + View_Smart_Data *sd = (View_Smart_Data *)esd; + Evas_Object *view = sd->base.self; + + _run_dialog(view, DIALOG_ALERT, message, NULL, NULL); +} + +/* called by ewk_view when javascript called confirm() + * + */ +static Eina_Bool +_view_smart_run_javascript_confirm(Ewk_View_Smart_Data *esd, Evas_Object *frame, const char *message) +{ + View_Smart_Data *sd = (View_Smart_Data *)esd; + Evas_Object *view = sd->base.self; + + return _run_dialog(view, DIALOG_CONFIRM, message, NULL, NULL); +} + +/* called by ewk_view when javascript called confirm() + * + */ +static Eina_Bool +_view_smart_run_javascript_prompt(Ewk_View_Smart_Data *esd, Evas_Object *frame, const char *message, const char *default_value, char **value) +{ + View_Smart_Data *sd = (View_Smart_Data *)esd; + Evas_Object *view = sd->base.self; + Eina_Bool confirm; + + confirm = _run_dialog(view, DIALOG_PROMPT, message, default_value, value); + if (!confirm) + *value = NULL; + + return EINA_TRUE; +} + +/** + * Called by webkit when a new window is requested to be created + * + * @param sd Smart Data of current view. + * + * @return a new view, owned by the window just created or @c NULL on error. + */ +static Evas_Object * +_view_smart_window_create(Ewk_View_Smart_Data *sd __UNUSED__, Eina_Bool javascript __UNUSED__, const Ewk_Window_Features *window_features __UNUSED__) +{ + return window_create(); +} + +static Eina_Bool +_window_close_delayed(void *data) +{ + View_Smart_Data *sd = data; + sd->idler_close_window = NULL; + Evas_Object *view = sd->base.self; + Evas_Object *chrome = evas_object_data_get(view, "chrome"); + Browser_Window *win = evas_object_data_get(chrome, "win"); + + tab_close_chrome(win, chrome); + return EINA_FALSE; +} + +/** + * Called by webkit when a window is requested to be closed + * + * @param sd Smart Data of view to be closed. + */ +static void +_view_smart_window_close(Ewk_View_Smart_Data *esd) +{ + View_Smart_Data *sd = (View_Smart_Data *)esd; + EINA_SAFETY_ON_TRUE_RETURN(sd->idler_close_window != NULL); + sd->idler_close_window = ecore_idler_add(_window_close_delayed, sd); +} + +/** + * Creates a new view object given the parent. + * + * @param parent object to use as parent. + * + * @return newly added Evas_Object or @c NULL on errors. + */ +Evas_Object * +view_add(Evas_Object *parent) +{ + static Evas_Smart *smart = NULL; + Evas *canvas = evas_object_evas_get(parent); + Evas_Object *view; + + if (!smart) + { + /* create ewk_view_single subclass, this is done only once! */ + static Ewk_View_Smart_Class api = EWK_VIEW_SMART_CLASS_INIT_NAME_VERSION("EWK_View_Single_Demo"); + + /* set current and parent apis to vanilla ewk_view_single methods */ + ewk_view_single_smart_set(&api); + ewk_view_single_smart_set(&_parent_sc); + + /* override methods we want custom behavior */ + api.sc.add = _view_smart_add; + api.sc.del = _view_smart_del; + api.sc.calculate = _view_smart_calculate; + api.mouse_down = _view_smart_mouse_down; + api.mouse_up = _view_smart_mouse_up; + api.mouse_move = _view_smart_mouse_move; + api.add_console_message = _view_smart_add_console_message; + api.window_create = _view_smart_window_create; + api.window_close = _view_smart_window_close; + api.run_javascript_alert = _view_smart_run_javascript_alert; + api.run_javascript_confirm = _view_smart_run_javascript_confirm; + api.run_javascript_prompt = _view_smart_run_javascript_prompt; + + /* create Evas_Smart class for this new smart object type. */ + smart = evas_smart_class_new(&api.sc); + if (!smart) + { + CRITICAL("Could not create smart class"); + return NULL; + } + } + view = evas_object_smart_add(canvas, smart); + if (!view) + { + ERR("Could not create smart object object for view"); + return NULL; + } + + return view; +} + +void view_zoom_next_up(Evas_Object *view) +{ + VIEW_SD_GET_OR_RETURN(view, sd); + float zoom = ewk_frame_zoom_get(sd->base.main_frame); + unsigned int idx = _view_zoom_closest_index_find(zoom); + Evas_Coord w, h; + if (sd->flags.animated_zoom || sd->animator.pan || sd->animator.zoom) + return; + if (idx + 1 >= ZOOM_STEPS_LAST) + return; + if (sd->animator.kinetic) + { + ecore_animator_del(sd->animator.kinetic); + sd->animator.kinetic = NULL; + } + + idx++; + zoom = ZOOM_STEPS[idx]; + sd->flags.animated_zoom = EINA_TRUE; + ewk_frame_visible_content_geometry_get + (sd->base.main_frame, EINA_FALSE, NULL, NULL, &w, &h); + ewk_view_zoom_animated_set + (view, zoom, ZOOM_AUTO_ANIMATION_DURATION, w / 2, h / 2); +} + +void view_zoom_next_down(Evas_Object *view) +{ + VIEW_SD_GET_OR_RETURN(view, sd); + float zoom = ewk_frame_zoom_get(sd->base.main_frame); + unsigned int idx = _view_zoom_closest_index_find(zoom); + Evas_Coord w, h; + if (sd->flags.animated_zoom || sd->animator.pan || sd->animator.zoom) + return; + if (idx == 0) + return; + if (sd->animator.kinetic) + { + ecore_animator_del(sd->animator.kinetic); + sd->animator.kinetic = NULL; + } + idx--; + zoom = ZOOM_STEPS[idx]; + sd->flags.animated_zoom = EINA_TRUE; + ewk_frame_visible_content_geometry_get + (sd->base.main_frame, EINA_FALSE, NULL, NULL, &w, &h); + ewk_view_zoom_animated_set + (view, zoom, ZOOM_AUTO_ANIMATION_DURATION, w / 2, h / 2); +} + +Eina_Bool view_context_menu_set(Evas_Object *view, Evas_Object *widget, Ewk_Context_Menu *menu) +{ + VIEW_SD_GET_OR_RETURN(view, sd, EINA_FALSE); + if (widget && sd->context_menu) + { + CRITICAL("Trying to overwrite existing menu"); + return EINA_FALSE; + } + + sd->context_menu = widget; + if (menu) + evas_object_data_set(view, "context-menu", menu); + else + evas_object_data_del(view, "context-menu"); + + return EINA_TRUE; +} + +Evas_Object *view_context_menu_widget_get(Evas_Object *view) +{ + VIEW_SD_GET_OR_RETURN(view, sd, NULL); + return sd->context_menu; +} + +Ewk_Context_Menu *view_context_menu_get(Evas_Object *view) +{ + return evas_object_data_get(view, "context-menu"); +} diff --git a/test/test-combo.html b/test/test-combo.html new file mode 100644 index 0000000..21e43bd --- /dev/null +++ b/test/test-combo.html @@ -0,0 +1,18 @@ + + + + + Test combobox + + + + + + + diff --git a/test/test-js-alert.html b/test/test-js-alert.html new file mode 100644 index 0000000..79016e7 --- /dev/null +++ b/test/test-js-alert.html @@ -0,0 +1,25 @@ + + + + + Test JS alert message + + + + +

test JS alert message

+
+This test should send a message using alert() on javascript. This tipically means +a popup showing the message with a button to close it. + + +

+ + + diff --git a/test/test-js-confirm.html b/test/test-js-confirm.html new file mode 100644 index 0000000..074e966 --- /dev/null +++ b/test/test-js-confirm.html @@ -0,0 +1,26 @@ + + + + + Test JS confirm message + + + + +

test js confirm messsage

+
+This test shows a confirm message, waiting for user to answer OK or CANCEL. Tipically it is implemented +as a dialog. The default handling function is to print to stdout and confirm. + +

+ + diff --git a/test/test-js-console-message.html b/test/test-js-console-message.html new file mode 100644 index 0000000..dd45272 --- /dev/null +++ b/test/test-js-console-message.html @@ -0,0 +1,21 @@ + + + + Test JS console message + + + + + +

test js console messsage

+
+ This test should send a message to console. The default handling function is to print + to stdout. + + diff --git a/test/test-js-prompt.html b/test/test-js-prompt.html new file mode 100644 index 0000000..e8d7ab3 --- /dev/null +++ b/test/test-js-prompt.html @@ -0,0 +1,23 @@ + + + + Test JS prompt + + + +

test JS prompt

+
+ This test shows a prompt message, asking for user to enter text. Tipically it is implemented + as a dialog. The default handling function is to print to stdout and answer 'test'. + + +

+ + diff --git a/test/test-newindow.html b/test/test-newindow.html new file mode 100644 index 0000000..a819b53 --- /dev/null +++ b/test/test-newindow.html @@ -0,0 +1,13 @@ + + + + + Test -- Link will open a new window + + + +Go to Google + + + diff --git a/test/test-should-interrupt-js.html b/test/test-should-interrupt-js.html new file mode 100644 index 0000000..342f993 --- /dev/null +++ b/test/test-should-interrupt-js.html @@ -0,0 +1,23 @@ + + + +

test should interrupt javascript

+
+This test shows a prompt message, asking for user to enter text. Tipically it is implemented +as a dialog. The default handling function is to print to stdout and answer 'test'. + + +

+ +