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 62 static int currentZoomLevel = DEFAULT_ZOOM_LEVEL; 63 static float currentZoom = 1.0; 64 65 // the zoom values are chosen to be like in Mozilla Firefox 3 66 static int zoomLevels[] = {30, 50, 67, 80, 90, 67 100, 68 110, 120, 133, 150, 170, 200, 240, 300}; 69 70 static int verbose = 0; 71 72 static Eina_List *windows = NULL; 73 74 static char *themePath = NULL; 75 76 static const char *backingStores[] = { 77 "tiled", 78 "single", 79 NULL 80 }; 81 82 typedef 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 89 Window_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 96 static 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 140 typedef 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 150 typedef 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 162 static void browserDestroy(Ecore_Evas *ee); 163 static void closeWindow(Ecore_Evas *ee); 164 static 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 166 static void 167 print_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 199 static int 200 nearest_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 211 static Eina_Bool 212 zoom_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 223 static void 224 on_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 241 static void 242 title_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 */ 269 static void 270 viewport_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 282 static void 283 on_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 291 static void 292 on_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 300 static void 301 on_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 318 static void 319 on_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 331 static void 332 on_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 338 static void 339 on_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 351 static void 352 on_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 358 static void 359 on_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 371 static void 372 on_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 378 static void 379 on_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 391 static void 392 on_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 398 static void 399 on_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 406 static void 407 on_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 */ 430 static void 431 on_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 468 static void 469 on_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 476 static void 477 on_focus_out(void *data, Evas *e, Evas_Object *obj, void *event_info) 478 { 479 info("the webview lost keyboard focus\n"); 480 } 481 482 static void 483 on_focus_in(void *data, Evas *e, Evas_Object *obj, void *event_info) 484 { 485 info("the webview gained keyboard focus\n"); 486 } 487 488 static void 489 on_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 616 static void 617 on_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 628 static void 629 on_closeWindow(Ecore_Evas *ee) 630 { 631 browserDestroy(ee); 632 } 633 634 static int 635 quit(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 654 static int 655 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) 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 752 static void 753 browserDestroy(Ecore_Evas *ee) 754 { 755 ecore_evas_free(ee); 756 if (!eina_list_count(windows)) 757 ecore_main_loop_quit(); 758 } 759 760 static void 761 closeWindow(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 775 static Eina_Bool 776 main_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 789 static char * 790 findThemePath(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 811 int 812 main(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