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