main.c 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043
  1. /*
  2. * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
  3. * Copyright (C) 2009, 2010 ProFUSION embedded systems
  4. * Copyright (C) 2009, 2010, 2011 Samsung Electronics
  5. * Copyright (C) 2012 Intel Corporation
  6. *
  7. * All rights reserved.
  8. *
  9. * Redistribution and use in source and binary forms, with or without
  10. * modification, are permitted provided that the following conditions
  11. * are met:
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in the
  16. * documentation and/or other materials provided with the distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  21. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
  22. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  23. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  24. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  25. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  26. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. #include "EWebKit.h"
  31. #include "url_bar.h"
  32. #include "url_utils.h"
  33. #include <Ecore.h>
  34. #include <Ecore_Evas.h>
  35. #include <Ecore_File.h>
  36. #include <Ecore_Getopt.h>
  37. #include <Ecore_X.h>
  38. #include <Edje.h>
  39. #include <Evas.h>
  40. #include <ctype.h>
  41. #include <inttypes.h>
  42. #include <limits.h>
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <sys/stat.h>
  47. #include <sys/types.h>
  48. #include <unistd.h>
  49. #define DEFAULT_WIDTH 800
  50. #define DEFAULT_HEIGHT 600
  51. #define DEFAULT_ZOOM_INIT 1.0
  52. #define info(format, args...) \
  53. do { \
  54. if (verbose) \
  55. printf(format"\n", ##args); \
  56. } while (0)
  57. #define MIN_ZOOM_LEVEL 0
  58. #define DEFAULT_ZOOM_LEVEL 5
  59. #define MAX_ZOOM_LEVEL 13
  60. static int currentZoomLevel = DEFAULT_ZOOM_LEVEL;
  61. static float currentZoom = 1.0;
  62. // the zoom values are chosen to be like in Mozilla Firefox 3
  63. static int zoomLevels[] = {30, 50, 67, 80, 90,
  64. 100,
  65. 110, 120, 133, 150, 170, 200, 240, 300};
  66. static int verbose = 0;
  67. static Eina_List *windows = NULL;
  68. static char *themePath = NULL;
  69. static const char *backingStores[] = {
  70. "tiled",
  71. "single",
  72. NULL
  73. };
  74. typedef struct _Window_Properties {
  75. Eina_Bool toolbarsVisible:1;
  76. Eina_Bool statusbarVisible:1;
  77. Eina_Bool scrollbarsVisible:1;
  78. Eina_Bool menubarVisible:1;
  79. } Window_Properties;
  80. Window_Properties windowProperties = { /* Pretend we have them and they are initially visible */
  81. EINA_TRUE,
  82. EINA_TRUE,
  83. EINA_TRUE,
  84. EINA_TRUE
  85. };
  86. static const Ecore_Getopt options = {
  87. "EWebLauncher",
  88. "%prog [options] [url]",
  89. "0.0.1",
  90. "(C)2008 INdT (The Nokia Technology Institute)\n"
  91. "(C)2009, 2010 ProFUSION embedded systems\n"
  92. "(C)2009, 2010, 2011 Samsung Electronics\n"
  93. "(C)2012 Intel Corporation\n",
  94. "GPL",
  95. "Test Web Browser using the Enlightenment Foundation Libraries of WebKit",
  96. EINA_TRUE, {
  97. ECORE_GETOPT_STORE_STR
  98. ('e', "engine", "ecore-evas engine to use."),
  99. ECORE_GETOPT_CALLBACK_NOARGS
  100. ('E', "list-engines", "list ecore-evas engines.",
  101. ecore_getopt_callback_ecore_evas_list_engines, NULL),
  102. ECORE_GETOPT_CHOICE
  103. ('b', "backing-store", "choose backing store to use.", backingStores),
  104. ECORE_GETOPT_STORE_DEF_BOOL
  105. ('c', "encoding-detector", "enable/disable encoding detector", 0),
  106. ECORE_GETOPT_STORE_DEF_BOOL
  107. ('f', "flattening", "frame flattening.", 0),
  108. ECORE_GETOPT_STORE_DEF_BOOL
  109. ('F', "fullscreen", "fullscreen mode.", 0),
  110. ECORE_GETOPT_CALLBACK_ARGS
  111. ('g', "geometry", "geometry to use in x:y:w:h form.", "X:Y:W:H",
  112. ecore_getopt_callback_geometry_parse, NULL),
  113. ECORE_GETOPT_STORE_STR
  114. ('t', "theme", "path to read the theme file from."),
  115. ECORE_GETOPT_STORE_DEF_BOOL
  116. ('T', "tiled-backing-store", "enable/disable WebCore's tiled backingstore(ewk_view_single only)", 0),
  117. ECORE_GETOPT_STORE_STR
  118. ('U', "user-agent", "custom user agent string to use."),
  119. ECORE_GETOPT_COUNT
  120. ('v', "verbose", "be more verbose."),
  121. ECORE_GETOPT_VERSION
  122. ('V', "version"),
  123. ECORE_GETOPT_COPYRIGHT
  124. ('R', "copyright"),
  125. ECORE_GETOPT_LICENSE
  126. ('L', "license"),
  127. ECORE_GETOPT_HELP
  128. ('h', "help"),
  129. ECORE_GETOPT_SENTINEL
  130. }
  131. };
  132. typedef struct _User_Arguments {
  133. char *engine;
  134. Eina_Bool quitOption;
  135. char *backingStore;
  136. Eina_Bool enableEncodingDetector;
  137. Eina_Bool enableTiledBackingStore;
  138. Eina_Bool isFlattening;
  139. Eina_Bool isFullscreen;
  140. Eina_Rectangle geometry;
  141. char *theme;
  142. char *userAgent;
  143. char *databasePath;
  144. } User_Arguments;
  145. typedef struct _ELauncher {
  146. Ecore_Evas *ee;
  147. Evas *evas;
  148. Evas_Object *browser;
  149. Url_Bar *url_bar;
  150. User_Arguments *userArgs;
  151. } ELauncher;
  152. static void windowDestroy(Ecore_Evas *ee);
  153. static void closeWindow(Ecore_Evas *ee);
  154. static int browserCreate(const char *url, User_Arguments *userArgs);
  155. static int webInspectorCreate(ELauncher *appBrowser);
  156. static ELauncher *windowCreate(User_Arguments *userArgs);
  157. static ELauncher *
  158. find_app_from_ee(Ecore_Evas *ee)
  159. {
  160. Eina_List *l;
  161. void *data;
  162. EINA_LIST_FOREACH(windows, l, data)
  163. {
  164. ELauncher *app = (ELauncher *) data;
  165. if (app->ee == ee)
  166. return app;
  167. }
  168. return NULL;
  169. }
  170. static void
  171. print_history(Eina_List *list)
  172. {
  173. Eina_List *l;
  174. void *d;
  175. if (!verbose)
  176. return;
  177. printf("Session history contains:\n");
  178. EINA_LIST_FOREACH(list, l, d) {
  179. Ewk_History_Item *item = (Ewk_History_Item*)d;
  180. cairo_surface_t *cs = ewk_history_item_icon_surface_get(item);
  181. char buf[PATH_MAX];
  182. int s = snprintf(buf, sizeof(buf), "/tmp/favicon-%s.png", ewk_history_item_uri_original_get(item));
  183. for (s--; s >= (int)sizeof("/tmp/favicon-"); s--) {
  184. if (!isalnum(buf[s]) && buf[s] != '.')
  185. buf[s] = '_';
  186. }
  187. cs = ewk_history_item_icon_surface_get(item);
  188. if (cs && cairo_surface_status(cs) == CAIRO_STATUS_SUCCESS)
  189. cairo_surface_write_to_png(cs, buf);
  190. else
  191. buf[0] = '\0';
  192. printf("* '%s' title='%s' icon='%s'\n",
  193. ewk_history_item_uri_original_get(item),
  194. ewk_history_item_title_get(item), buf);
  195. }
  196. }
  197. static int
  198. nearest_zoom_level_get(float factor)
  199. {
  200. int i, intFactor = (int)(factor * 100.0);
  201. for (i = 0; zoomLevels[i] <= intFactor; i++) { }
  202. printf("factor=%f, intFactor=%d, zoomLevels[%d]=%d, zoomLevels[%d]=%d\n",
  203. factor, intFactor, i-1, zoomLevels[i-1], i, zoomLevels[i]);
  204. if (intFactor - zoomLevels[i-1] < zoomLevels[i] - intFactor)
  205. return i - 1;
  206. return i;
  207. }
  208. static Eina_Bool
  209. zoom_level_set(Evas_Object *webview, int level)
  210. {
  211. float factor = ((float) zoomLevels[level]) / 100.0;
  212. Evas_Coord ox, oy, mx, my, cx, cy;
  213. evas_pointer_canvas_xy_get(evas_object_evas_get(webview), &mx, &my);
  214. evas_object_geometry_get(webview, &ox, &oy, NULL, NULL);
  215. cx = mx - ox;
  216. cy = my - oy;
  217. return ewk_view_zoom_animated_set(webview, factor, 0.5, cx, cy);
  218. }
  219. static void
  220. on_browser_ecore_evas_resize(Ecore_Evas *ee)
  221. {
  222. ELauncher *app;
  223. Evas_Object *webview;
  224. int w, h;
  225. ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
  226. /* Resize URL bar */
  227. app = find_app_from_ee(ee);
  228. url_bar_width_set(app->url_bar, w);
  229. webview = evas_object_name_find(ecore_evas_get(ee), "browser");
  230. evas_object_move(webview, 0, URL_BAR_HEIGHT);
  231. evas_object_resize(webview, w, h - URL_BAR_HEIGHT);
  232. }
  233. static void
  234. on_inspector_ecore_evas_resize(Ecore_Evas *ee)
  235. {
  236. Evas_Object *webview;
  237. int w, h;
  238. ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
  239. webview = evas_object_name_find(ecore_evas_get(ee), "inspector");
  240. evas_object_move(webview, 0, 0);
  241. evas_object_resize(webview, w, h);
  242. }
  243. static void
  244. title_set(Ecore_Evas *ee, const Ewk_Text_With_Direction *title, int progress)
  245. {
  246. const char *appname = "EFL Test Launcher";
  247. const char *separator = " - ";
  248. char label[4096];
  249. int size;
  250. if (!title || !title->string || !strcmp(title->string, "")) {
  251. ecore_evas_title_set(ee, appname);
  252. return;
  253. }
  254. if (progress < 100)
  255. size = snprintf(label, sizeof(label), "%s (%d%%)%s%s", title->string, progress, separator, appname);
  256. else
  257. size = snprintf(label, sizeof(label), "%s %s%s", title->string, separator, appname);
  258. if (size >= (int)sizeof(label))
  259. return;
  260. ecore_evas_title_set(ee, label);
  261. }
  262. static void
  263. on_title_changed(void *user_data, Evas_Object *webview, void *event_info)
  264. {
  265. ELauncher *app = (ELauncher *)user_data;
  266. const Ewk_Text_With_Direction *title = (const Ewk_Text_With_Direction *)event_info;
  267. title_set(app->ee, title, 100);
  268. }
  269. static void
  270. on_progress(void *user_data, Evas_Object *webview, void *event_info)
  271. {
  272. ELauncher *app = (ELauncher *)user_data;
  273. double *progress = (double *)event_info;
  274. title_set(app->ee, ewk_view_title_get(app->browser), *progress * 100);
  275. }
  276. static void
  277. on_load_finished(void *user_data, Evas_Object *webview, void *event_info)
  278. {
  279. const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
  280. if (!err)
  281. info("Succeeded loading page.");
  282. else if (err->is_cancellation)
  283. info("Load was cancelled.");
  284. else
  285. info("Failed loading page: %d %s \"%s\", url=%s",
  286. err->code, err->domain, err->description, err->failing_url);
  287. currentZoom = ewk_view_zoom_get(webview);
  288. currentZoomLevel = nearest_zoom_level_get(currentZoom);
  289. info("WebCore Zoom=%f, currentZoomLevel=%d", currentZoom, currentZoomLevel);
  290. }
  291. static void
  292. on_load_error(void *user_data, Evas_Object *webview, void *event_info)
  293. {
  294. const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
  295. char message[1024];
  296. snprintf(message, 1024, "<html><body><div style=\"color:#ff0000\">ERROR!</div><br><div>Code: %d<br>Domain: %s<br>Description: %s<br>URL: %s</div></body</html>",
  297. err->code, err->domain, err->description, err->failing_url);
  298. ewk_frame_contents_set(err->frame, message, 0, "text/html", "UTF-8", err->failing_url);
  299. }
  300. static void
  301. on_toolbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
  302. {
  303. Eina_Bool *visible = (Eina_Bool *)event_info;
  304. if (*visible) {
  305. info("Toolbars visible changed: show");
  306. windowProperties.toolbarsVisible = EINA_TRUE;
  307. } else {
  308. info("Toolbars visible changed: hide");
  309. windowProperties.toolbarsVisible = EINA_FALSE;
  310. }
  311. }
  312. static void
  313. on_toolbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
  314. {
  315. Eina_Bool *visible = (Eina_Bool *)event_info;
  316. *visible = windowProperties.toolbarsVisible;
  317. }
  318. static void
  319. on_statusbar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
  320. {
  321. Eina_Bool *visible = (Eina_Bool *)event_info;
  322. if (*visible) {
  323. info("Statusbar visible changed: show");
  324. windowProperties.statusbarVisible = EINA_TRUE;
  325. } else {
  326. info("Statusbar visible changed: hide");
  327. windowProperties.statusbarVisible = EINA_FALSE;
  328. }
  329. }
  330. static void
  331. on_statusbar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
  332. {
  333. Eina_Bool *visible = (Eina_Bool *)event_info;
  334. *visible = windowProperties.statusbarVisible;
  335. }
  336. static void
  337. on_scrollbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
  338. {
  339. Eina_Bool *visible = (Eina_Bool *)event_info;
  340. if (*visible) {
  341. info("Scrollbars visible changed: show");
  342. windowProperties.scrollbarsVisible = EINA_TRUE;
  343. } else {
  344. info("Scrollbars visible changed: hide");
  345. windowProperties.scrollbarsVisible = EINA_FALSE;
  346. }
  347. }
  348. static void
  349. on_scrollbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
  350. {
  351. Eina_Bool *visible = (Eina_Bool *)event_info;
  352. *visible = windowProperties.scrollbarsVisible;
  353. }
  354. static void
  355. on_menubar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
  356. {
  357. Eina_Bool *visible = (Eina_Bool *)event_info;
  358. if (*visible) {
  359. info("Menubar visible changed: show");
  360. windowProperties.menubarVisible = EINA_TRUE;
  361. } else {
  362. info("Menubar visible changed: hide");
  363. windowProperties.menubarVisible = EINA_FALSE;
  364. }
  365. }
  366. static void
  367. on_menubar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
  368. {
  369. Eina_Bool *visible = (Eina_Bool *)event_info;
  370. *visible = windowProperties.menubarVisible;
  371. }
  372. static void
  373. on_tooltip_text_set(void* user_data, Evas_Object* webview, void* event_info)
  374. {
  375. const char *text = (const char *)event_info;
  376. info("Tooltip is set: %s", text);
  377. }
  378. static void
  379. on_tooltip_text_unset(void* user_data, Evas_Object* webview, void* event_info)
  380. {
  381. info("Tooltip is unset");
  382. }
  383. static void
  384. on_inputmethod_changed(void* user_data, Evas_Object* webview, void* event_info)
  385. {
  386. Eina_Bool active = (Eina_Bool)(long)event_info;
  387. unsigned int imh;
  388. info("Keyboard changed: %d", active);
  389. if (!active)
  390. return;
  391. imh = ewk_view_imh_get(webview);
  392. info(" Keyboard flags: %#.2x", imh);
  393. }
  394. static void
  395. on_url_changed(void* user_data, Evas_Object* webview, void* event_info)
  396. {
  397. ELauncher *app = (ELauncher *)user_data;
  398. url_bar_url_set(app->url_bar, ewk_view_uri_get(app->browser));
  399. }
  400. static void
  401. on_mouse_down(void* data, Evas* e, Evas_Object* webview, void* event_info)
  402. {
  403. Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
  404. if (ev->button == 1)
  405. evas_object_focus_set(webview, EINA_TRUE);
  406. else if (ev->button == 2)
  407. evas_object_focus_set(webview, !evas_object_focus_get(webview));
  408. }
  409. static void
  410. on_focus_out(void *data, Evas *e, Evas_Object *obj, void *event_info)
  411. {
  412. info("the webview lost keyboard focus");
  413. }
  414. static void
  415. on_focus_in(void *data, Evas *e, Evas_Object *obj, void *event_info)
  416. {
  417. info("the webview gained keyboard focus");
  418. }
  419. static void
  420. on_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
  421. {
  422. Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
  423. ELauncher *app = data;
  424. static const char *encodings[] = {
  425. "ISO-8859-1",
  426. "UTF-8",
  427. NULL
  428. };
  429. static int currentEncoding = -1;
  430. Eina_Bool ctrlPressed = evas_key_modifier_is_set(evas_key_modifier_get(e), "Control");
  431. if (!strcmp(ev->key, "Escape")) {
  432. closeWindow(app->ee);
  433. } else if (!strcmp(ev->key, "F1")) {
  434. info("Back (F1) was pressed");
  435. if (ewk_view_back_possible(obj)) {
  436. Ewk_History *history = ewk_view_history_get(obj);
  437. Eina_List *list = ewk_history_back_list_get(history);
  438. print_history(list);
  439. ewk_history_item_list_free(list);
  440. ewk_view_back(obj);
  441. } else
  442. info("Back ignored: No back history");
  443. } else if (!strcmp(ev->key, "F2")) {
  444. info("Forward (F2) was pressed");
  445. if (ewk_view_forward_possible(obj)) {
  446. Ewk_History *history = ewk_view_history_get(obj);
  447. Eina_List *list = ewk_history_forward_list_get(history);
  448. print_history(list);
  449. ewk_history_item_list_free(list);
  450. ewk_view_forward(obj);
  451. } else
  452. info("Forward ignored: No forward history");
  453. } else if (!strcmp(ev->key, "F3")) {
  454. currentEncoding++;
  455. currentEncoding %= (sizeof(encodings) / sizeof(encodings[0]));
  456. info("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
  457. ewk_view_setting_encoding_custom_set(obj, encodings[currentEncoding]);
  458. } else if (!strcmp(ev->key, "F4")) {
  459. Evas_Object *frame = ewk_view_frame_main_get(obj);
  460. Evas_Coord x, y;
  461. Ewk_Hit_Test *ht;
  462. evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x, &y);
  463. ht = ewk_frame_hit_test_new(frame, x, y);
  464. if (!ht)
  465. printf("No hit test returned for point %d,%d\n", x, y);
  466. else {
  467. printf("Hit test for point %d,%d\n"
  468. " pos=%3d,%3d\n"
  469. " bounding_box=%d,%d + %dx%d\n"
  470. " title='%s'\n"
  471. " alternate_text='%s'\n"
  472. " frame=%p (%s)\n"
  473. " link {\n"
  474. " text='%s'\n"
  475. " url='%s'\n"
  476. " title='%s'\n"
  477. " target frame=%p (%s)\n"
  478. " }\n"
  479. "context:\n"
  480. "%s"
  481. "%s"
  482. "%s"
  483. "%s"
  484. "%s\n",
  485. x, y,
  486. ht->x, ht->y,
  487. ht->bounding_box.x, ht->bounding_box.y, ht->bounding_box.w, ht->bounding_box.h,
  488. ht->title.string,
  489. ht->alternate_text,
  490. ht->frame, evas_object_name_get(ht->frame),
  491. ht->link.text,
  492. ht->link.url,
  493. ht->link.title,
  494. ht->link.target_frame, evas_object_name_get(ht->link.target_frame),
  495. ht->context & EWK_HIT_TEST_RESULT_CONTEXT_LINK ? " LINK\n" : "",
  496. ht->context & EWK_HIT_TEST_RESULT_CONTEXT_IMAGE ? " IMAGE\n" : "",
  497. ht->context & EWK_HIT_TEST_RESULT_CONTEXT_MEDIA ? " MEDIA\n" : "",
  498. ht->context & EWK_HIT_TEST_RESULT_CONTEXT_SELECTION ? " SELECTION\n" : "",
  499. ht->context & EWK_HIT_TEST_RESULT_CONTEXT_EDITABLE ? " EDITABLE" : "");
  500. ewk_frame_hit_test_free(ht);
  501. }
  502. } else if (!strcmp(ev->key, "F5")) {
  503. info("Reload (F5) was pressed, reloading.");
  504. ewk_view_reload(obj);
  505. } else if (!strcmp(ev->key, "F6")) {
  506. info("Stop (F6) was pressed, stop loading.");
  507. ewk_view_stop(obj);
  508. } else if (!strcmp(ev->key, "F12")) {
  509. Eina_Bool status = ewk_view_setting_spatial_navigation_get(obj);
  510. ewk_view_setting_spatial_navigation_set(obj, !status);
  511. info("Command::keyboard navigation toggle");
  512. } else if ((!strcmp(ev->key, "minus") || !strcmp(ev->key, "KP_Subtract")) && ctrlPressed) {
  513. if (currentZoomLevel > MIN_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel - 1))
  514. currentZoomLevel--;
  515. info("Zoom out (Ctrl + '-') was pressed, zoom level became %.2f", zoomLevels[currentZoomLevel] / 100.0);
  516. } else if ((!strcmp(ev->key, "equal") || !strcmp(ev->key, "KP_Add")) && ctrlPressed) {
  517. if (currentZoomLevel < MAX_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel + 1))
  518. currentZoomLevel++;
  519. info("Zoom in (Ctrl + '+') was pressed, zoom level became %.2f", zoomLevels[currentZoomLevel] / 100.0);
  520. } else if (!strcmp(ev->key, "0") && ctrlPressed) {
  521. if (zoom_level_set(obj, DEFAULT_ZOOM_LEVEL))
  522. currentZoomLevel = DEFAULT_ZOOM_LEVEL;
  523. info("Zoom to default (Ctrl + '0') was pressed, zoom level became %.2f", zoomLevels[currentZoomLevel] / 100.0);
  524. } else if (!strcmp(ev->key, "n") && ctrlPressed) {
  525. info("Create new window (Ctrl+n) was pressed.");
  526. browserCreate("http://www.google.com", app->userArgs);
  527. } else if (!strcmp(ev->key, "g") && ctrlPressed ) {
  528. Evas_Coord x, y, w, h;
  529. Evas_Object *frame = ewk_view_frame_main_get(obj);
  530. float zoom = zoomLevels[currentZoomLevel] / 100.0;
  531. ewk_frame_visible_content_geometry_get(frame, EINA_FALSE, &x, &y, &w, &h);
  532. x -= w;
  533. y -= h;
  534. w *= 4;
  535. h *= 4;
  536. info("Pre-render %d,%d + %dx%d", x, y, w, h);
  537. ewk_view_pre_render_region(obj, x, y, w, h, zoom);
  538. } else if (!strcmp(ev->key, "r") && ctrlPressed) {
  539. info("Pre-render 1 extra column/row with current zoom");
  540. ewk_view_pre_render_relative_radius(obj, 1);
  541. } else if (!strcmp(ev->key, "p") && ctrlPressed) {
  542. info("Pre-rendering start");
  543. ewk_view_pre_render_start(obj);
  544. } else if (!strcmp(ev->key, "d") && ctrlPressed) {
  545. info("Render suspended");
  546. ewk_view_disable_render(obj);
  547. } else if (!strcmp(ev->key, "e") && ctrlPressed) {
  548. info("Render resumed");
  549. ewk_view_enable_render(obj);
  550. } else if (!strcmp(ev->key, "s") && ctrlPressed) {
  551. Evas_Object *frame = ewk_view_frame_main_get(obj);
  552. Ewk_Security_Origin *origin = ewk_frame_security_origin_get(frame);
  553. printf("Security origin information:\n"
  554. " protocol=%s\n"
  555. " host=%s\n"
  556. " port=%d\n"
  557. " web database quota=%" PRIu64 "\n",
  558. ewk_security_origin_protocol_get(origin),
  559. ewk_security_origin_host_get(origin),
  560. ewk_security_origin_port_get(origin),
  561. ewk_security_origin_web_database_quota_get(origin));
  562. Eina_List *databaseList = ewk_security_origin_web_database_get_all(origin);
  563. Eina_List *listIterator = 0;
  564. Ewk_Web_Database *database;
  565. EINA_LIST_FOREACH(databaseList, listIterator, database)
  566. printf("Database information:\n"
  567. " name=%s\n"
  568. " display name=%s\n"
  569. " filename=%s\n"
  570. " expected size=%" PRIu64 "\n"
  571. " size=%" PRIu64 "\n",
  572. ewk_web_database_name_get(database),
  573. ewk_web_database_display_name_get(database),
  574. ewk_web_database_filename_get(database),
  575. ewk_web_database_expected_size_get(database),
  576. ewk_web_database_size_get(database));
  577. ewk_security_origin_free(origin);
  578. ewk_web_database_list_free(databaseList);
  579. } else if (!strcmp(ev->key, "i") && ctrlPressed) {
  580. Evas_Object *inspector_view = ewk_view_inspector_view_get(obj);
  581. if (inspector_view) {
  582. info("Web Inspector close");
  583. ewk_view_inspector_close(obj);
  584. } else {
  585. info("Web Inspector show");
  586. ewk_view_inspector_show(obj);
  587. }
  588. }
  589. }
  590. static void
  591. on_browser_del(void *data, Evas *evas, Evas_Object *browser, void *event)
  592. {
  593. ELauncher *app = (ELauncher*) data;
  594. evas_object_event_callback_del(app->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down);
  595. evas_object_event_callback_del(app->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down);
  596. evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in);
  597. evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out);
  598. evas_object_event_callback_del(app->browser, EVAS_CALLBACK_DEL, on_browser_del);
  599. }
  600. static void
  601. on_inspector_view_create(void *user_data, Evas_Object *webview, void *event_info)
  602. {
  603. ELauncher *app_browser = (ELauncher *)user_data;
  604. webInspectorCreate(app_browser);
  605. }
  606. static void
  607. on_inspector_view_close(void *user_data, Evas_Object *webview, void *event_info)
  608. {
  609. Eina_List *l;
  610. void *app;
  611. ELauncher *app_browser = (ELauncher *)user_data;
  612. Evas_Object *inspector_view = (Evas_Object *)event_info;
  613. ewk_view_inspector_view_set(app_browser->browser, NULL);
  614. EINA_LIST_FOREACH(windows, l, app)
  615. if (((ELauncher *)app)->browser == inspector_view)
  616. break;
  617. windows = eina_list_remove(windows, app);
  618. windowDestroy(((ELauncher *)app)->ee);
  619. free(app);
  620. }
  621. static void
  622. on_inspector_view_destroyed(Ecore_Evas *ee)
  623. {
  624. ELauncher *app;
  625. app = find_app_from_ee(ee);
  626. evas_object_smart_callback_call(app->browser, "inspector,view,destroy", NULL);
  627. }
  628. static int
  629. quit(Eina_Bool success, const char *msg)
  630. {
  631. edje_shutdown();
  632. ecore_evas_shutdown();
  633. ecore_file_shutdown();
  634. if (msg)
  635. fputs(msg, (success) ? stdout : stderr);
  636. if (themePath) {
  637. free(themePath);
  638. themePath = NULL;
  639. }
  640. if (!success)
  641. return EXIT_FAILURE;
  642. return EXIT_SUCCESS;
  643. }
  644. static int
  645. browserCreate(const char *url, User_Arguments *userArgs)
  646. {
  647. ELauncher *appBrowser = windowCreate(userArgs);
  648. if (!appBrowser)
  649. return quit(EINA_FALSE, "ERROR: could not create a browser window\n");
  650. ecore_evas_title_set(appBrowser->ee, "EFL Test Launcher");
  651. ecore_evas_callback_resize_set(appBrowser->ee, on_browser_ecore_evas_resize);
  652. ecore_evas_callback_delete_request_set(appBrowser->ee, closeWindow);
  653. evas_object_name_set(appBrowser->browser, "browser");
  654. evas_object_smart_callback_add(appBrowser->browser, "inputmethod,changed", on_inputmethod_changed, appBrowser);
  655. evas_object_smart_callback_add(appBrowser->browser, "inspector,view,close", on_inspector_view_close, appBrowser);
  656. evas_object_smart_callback_add(appBrowser->browser, "inspector,view,create", on_inspector_view_create, appBrowser);
  657. evas_object_smart_callback_add(appBrowser->browser, "load,error", on_load_error, appBrowser);
  658. evas_object_smart_callback_add(appBrowser->browser, "load,finished", on_load_finished, appBrowser);
  659. evas_object_smart_callback_add(appBrowser->browser, "load,progress", on_progress, appBrowser);
  660. evas_object_smart_callback_add(appBrowser->browser, "menubar,visible,get", on_menubar_visible_get, appBrowser);
  661. evas_object_smart_callback_add(appBrowser->browser, "menubar,visible,set", on_menubar_visible_set, appBrowser);
  662. evas_object_smart_callback_add(appBrowser->browser, "scrollbars,visible,get", on_scrollbars_visible_get, appBrowser);
  663. evas_object_smart_callback_add(appBrowser->browser, "scrollbars,visible,set", on_scrollbars_visible_set, appBrowser);
  664. evas_object_smart_callback_add(appBrowser->browser, "statusbar,visible,get", on_statusbar_visible_get, appBrowser);
  665. evas_object_smart_callback_add(appBrowser->browser, "statusbar,visible,set", on_statusbar_visible_set, appBrowser);
  666. evas_object_smart_callback_add(appBrowser->browser, "title,changed", on_title_changed, appBrowser);
  667. evas_object_smart_callback_add(appBrowser->browser, "toolbars,visible,get", on_toolbars_visible_get, appBrowser);
  668. evas_object_smart_callback_add(appBrowser->browser, "toolbars,visible,set", on_toolbars_visible_set, appBrowser);
  669. evas_object_smart_callback_add(appBrowser->browser, "tooltip,text,set", on_tooltip_text_set, appBrowser);
  670. evas_object_smart_callback_add(appBrowser->browser, "tooltip,text,unset", on_tooltip_text_unset, appBrowser);
  671. evas_object_smart_callback_add(appBrowser->browser, "uri,changed", on_url_changed, appBrowser);
  672. evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_DEL, on_browser_del, appBrowser);
  673. evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in, appBrowser);
  674. evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out, appBrowser);
  675. evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down, appBrowser);
  676. evas_object_event_callback_add(appBrowser->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down, appBrowser);
  677. ewk_view_setting_enable_developer_extras_set(appBrowser->browser, EINA_TRUE);
  678. appBrowser->url_bar = url_bar_add(appBrowser->browser, DEFAULT_WIDTH);
  679. evas_object_move(appBrowser->browser, 0, URL_BAR_HEIGHT);
  680. evas_object_resize(appBrowser->browser, userArgs->geometry.w, userArgs->geometry.h - URL_BAR_HEIGHT);
  681. ewk_view_uri_set(appBrowser->browser, url);
  682. evas_object_show(appBrowser->browser);
  683. ecore_evas_show(appBrowser->ee);
  684. evas_object_focus_set(appBrowser->browser, EINA_TRUE);
  685. return 1;
  686. }
  687. static int
  688. webInspectorCreate(ELauncher *appBrowser)
  689. {
  690. ELauncher *appInspector = windowCreate(appBrowser->userArgs);
  691. if (!appInspector)
  692. return quit(EINA_FALSE, "ERROR: could not create an inspector window\n");
  693. ecore_evas_title_set(appInspector->ee, "Web Inspector");
  694. ecore_evas_callback_resize_set(appInspector->ee, on_inspector_ecore_evas_resize);
  695. ecore_evas_callback_delete_request_set(appInspector->ee, on_inspector_view_destroyed);
  696. evas_object_name_set(appInspector->browser, "inspector");
  697. evas_object_move(appInspector->browser, 0, 0);
  698. evas_object_resize(appInspector->browser, appInspector->userArgs->geometry.w, appInspector->userArgs->geometry.h);
  699. evas_object_show(appInspector->browser);
  700. ecore_evas_show(appInspector->ee);
  701. evas_object_focus_set(appInspector->browser, EINA_TRUE);
  702. ewk_view_inspector_view_set(appBrowser->browser, appInspector->browser);
  703. return 1;
  704. }
  705. static ELauncher *
  706. windowCreate(User_Arguments *userArgs)
  707. {
  708. ELauncher *app = (ELauncher *)malloc(sizeof(ELauncher));
  709. if (!app) {
  710. quit(EINA_FALSE, "ERROR: could not create an ELauncher\n");
  711. return NULL;
  712. }
  713. #if defined(WTF_USE_ACCELERATED_COMPOSITING) && defined(HAVE_ECORE_X)
  714. if (userArgs->engine)
  715. #endif
  716. app->ee = ecore_evas_new(userArgs->engine, 0, 0, userArgs->geometry.w, userArgs->geometry.h, NULL);
  717. #if defined(WTF_USE_ACCELERATED_COMPOSITING) && defined(HAVE_ECORE_X)
  718. else {
  719. const char* engine = "opengl_x11";
  720. app->ee = ecore_evas_new(engine, 0, 0, userArgs->geometry.w, userArgs->geometry.h, NULL);
  721. }
  722. #endif
  723. if (!app->ee) {
  724. quit(EINA_FALSE, "ERROR: could not construct evas-ecore\n");
  725. return NULL;
  726. }
  727. if (userArgs->isFullscreen)
  728. ecore_evas_fullscreen_set(app->ee, EINA_TRUE);
  729. app->evas = ecore_evas_get(app->ee);
  730. if (!app->evas) {
  731. quit(EINA_FALSE, "ERROR: could not get evas from evas-ecore\n");
  732. return NULL;
  733. }
  734. if (userArgs->backingStore && !strcasecmp(userArgs->backingStore, "tiled")) {
  735. app->browser = ewk_view_tiled_add(app->evas);
  736. info("backing store: tiled");
  737. } else {
  738. app->browser = ewk_view_single_add(app->evas);
  739. info("backing store: single");
  740. ewk_view_setting_tiled_backing_store_enabled_set(app->browser, userArgs->enableTiledBackingStore);
  741. }
  742. ewk_view_theme_set(app->browser, themePath);
  743. if (userArgs->userAgent)
  744. ewk_view_setting_user_agent_set(app->browser, userArgs->userAgent);
  745. ewk_view_setting_local_storage_database_path_set(app->browser, userArgs->databasePath);
  746. ewk_view_setting_enable_frame_flattening_set(app->browser, userArgs->isFlattening);
  747. ewk_view_setting_encoding_detector_set(app->browser, userArgs->enableEncodingDetector);
  748. app->userArgs = userArgs;
  749. app->url_bar = NULL;
  750. windows = eina_list_append(windows, app);
  751. return app;
  752. }
  753. static void
  754. windowDestroy(Ecore_Evas *ee)
  755. {
  756. ecore_evas_free(ee);
  757. if (!eina_list_count(windows))
  758. ecore_main_loop_quit();
  759. }
  760. static void
  761. closeWindow(Ecore_Evas *ee)
  762. {
  763. ELauncher *app;
  764. app = find_app_from_ee(ee);
  765. ewk_view_inspector_close(app->browser);
  766. windows = eina_list_remove(windows, app);
  767. url_bar_del(app->url_bar);
  768. windowDestroy(ee);
  769. free(app);
  770. }
  771. static Eina_Bool
  772. main_signal_exit(void *data, int ev_type, void *ev)
  773. {
  774. ELauncher *app;
  775. while (windows) {
  776. app = (ELauncher*) eina_list_data_get(windows);
  777. ewk_view_inspector_close(app->browser);
  778. ecore_evas_free(app->ee);
  779. windows = eina_list_remove(windows, app);
  780. }
  781. if (!eina_list_count(windows))
  782. ecore_main_loop_quit();
  783. return EINA_TRUE;
  784. }
  785. static char *
  786. findThemePath(const char *theme)
  787. {
  788. const char *default_theme = TEST_THEME_DIR "/default.edj";
  789. char *rpath;
  790. struct stat st;
  791. if (!theme)
  792. theme = default_theme;
  793. rpath = ecore_file_realpath(theme);
  794. if (!strlen(rpath) || stat(rpath, &st)) {
  795. free(rpath);
  796. return NULL;
  797. }
  798. return rpath;
  799. }
  800. int
  801. parseUserArguments(int argc, char *argv[], User_Arguments *userArgs)
  802. {
  803. int args;
  804. userArgs->engine = NULL;
  805. userArgs->quitOption = EINA_FALSE;
  806. userArgs->backingStore = (char *)backingStores[1];
  807. userArgs->enableEncodingDetector = EINA_FALSE;
  808. userArgs->enableTiledBackingStore = EINA_FALSE;
  809. userArgs->isFlattening = EINA_FALSE;
  810. userArgs->isFullscreen = EINA_FALSE;
  811. userArgs->geometry.x = 0;
  812. userArgs->geometry.y = 0;
  813. userArgs->geometry.w = 0;
  814. userArgs->geometry.h = 0;
  815. userArgs->theme = NULL;
  816. userArgs->userAgent = NULL;
  817. Ecore_Getopt_Value values[] = {
  818. ECORE_GETOPT_VALUE_STR(userArgs->engine),
  819. ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
  820. ECORE_GETOPT_VALUE_STR(userArgs->backingStore),
  821. ECORE_GETOPT_VALUE_BOOL(userArgs->enableEncodingDetector),
  822. ECORE_GETOPT_VALUE_BOOL(userArgs->isFlattening),
  823. ECORE_GETOPT_VALUE_BOOL(userArgs->isFullscreen),
  824. ECORE_GETOPT_VALUE_PTR_CAST(userArgs->geometry),
  825. ECORE_GETOPT_VALUE_STR(userArgs->theme),
  826. ECORE_GETOPT_VALUE_BOOL(userArgs->enableTiledBackingStore),
  827. ECORE_GETOPT_VALUE_STR(userArgs->userAgent),
  828. ECORE_GETOPT_VALUE_INT(verbose),
  829. ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
  830. ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
  831. ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
  832. ECORE_GETOPT_VALUE_BOOL(userArgs->quitOption),
  833. ECORE_GETOPT_VALUE_NONE
  834. };
  835. ecore_app_args_set(argc, (const char**) argv);
  836. args = ecore_getopt_parse(&options, values, argc, argv);
  837. themePath = findThemePath(userArgs->theme);
  838. if ((userArgs->geometry.w <= 0) || (userArgs->geometry.h <= 0)) {
  839. userArgs->geometry.w = DEFAULT_WIDTH;
  840. userArgs->geometry.h = DEFAULT_HEIGHT;
  841. }
  842. return args;
  843. }
  844. int
  845. main(int argc, char *argv[])
  846. {
  847. const char *default_url = "http://www.google.com/";
  848. const char *tmp;
  849. const char *proxyUri;
  850. char path[PATH_MAX];
  851. int args;
  852. User_Arguments userArgs;
  853. if (!ewk_init())
  854. return EXIT_FAILURE;
  855. if (!ecore_file_init()) {
  856. ewk_shutdown();
  857. return EXIT_FAILURE;
  858. }
  859. args = parseUserArguments(argc, argv, &userArgs);
  860. if (args < 0)
  861. return quit(EINA_FALSE, "ERROR: could not parse options.\n");
  862. if (userArgs.quitOption)
  863. return quit(EINA_TRUE, NULL);
  864. if (!themePath)
  865. return quit(EINA_FALSE, "ERROR: could not find theme.\n");
  866. tmp = getenv("TMPDIR");
  867. if (!tmp)
  868. tmp = "/tmp";
  869. snprintf(path, sizeof(path), "%s/.ewebkit-%u", tmp, getuid());
  870. if (!ecore_file_mkpath(path))
  871. return quit(EINA_FALSE, "ERROR: could not create settings database directory.\n");
  872. userArgs.databasePath = path;
  873. ewk_settings_icon_database_path_set(path);
  874. ewk_settings_web_database_path_set(path);
  875. proxyUri = getenv("http_proxy");
  876. if (proxyUri)
  877. ewk_network_proxy_uri_set(proxyUri);
  878. if (args < argc) {
  879. char *url = url_from_user_input(argv[args]);
  880. browserCreate(url, &userArgs);
  881. free(url);
  882. } else
  883. browserCreate(default_url, &userArgs);
  884. ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, main_signal_exit, &windows);
  885. ecore_main_loop_begin();
  886. ecore_file_shutdown();
  887. ewk_shutdown();
  888. return quit(EINA_TRUE, NULL);
  889. }