view.c

Go to the documentation of this file.
00001 /*
00002  * File Name: view.c
00003  */
00004 
00005 /*
00006  * This file is part of erbrowser.
00007  *
00008  * erbrowser is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * erbrowser is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2006, 2007 Apple Inc.
00024  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
00025  * Copyright (C) 2008 Collabora Ltd.
00026  * Copyright (C) 2009 iRex Technologies B.V.
00027  * All rights reserved.
00028  */
00029 
00030 //----------------------------------------------------------------------------
00031 // Include Files
00032 //----------------------------------------------------------------------------
00033 
00034 #include "config.h"
00035 
00036 // system include files, between < >
00037 #include <glib.h>
00038 #include <gtk/gtk.h>
00039 #include <stdlib.h>
00040 #include <math.h>
00041 #include <unistd.h>
00042 #include <gdk/gdkkeysyms.h>
00043 #include <webkit/webkit.h>
00044 
00045 // ereader include files, between < >
00046 #include <libergtk/ergtk.h>
00047 #include <liberutils/display_utils.h>
00048 #include <liberkeyb/erkeyb-client.h>
00049  
00050 // local include files, between " "
00051 #include "log.h"
00052 #include "download.h"
00053 #include "i18n.h"
00054 #include "ipc.h"
00055 #include "menu.h"
00056 #include "metadata.h"
00057 
00058 
00059 //----------------------------------------------------------------------------
00060 // Type Declarations
00061 //----------------------------------------------------------------------------
00062 
00063 // columns in file model
00064 #define MAX_BUF_LEN     512
00065 typedef enum
00066 {
00067     COL_TITLE = 0,
00068     COL_SUBTITLE,
00069     COL_THUMBNAIL,
00070     N_COLUMNS
00071 } column_t;
00072 
00073 #define COLUMN_TYPES                             \
00074         G_TYPE_STRING,      /* COL_TITLE     */  \
00075         G_TYPE_STRING,      /* COL_SUBTITLE  */  \
00076         GDK_TYPE_PIXBUF,    /* COL_THUMBNAIL */  \
00077         NULL  /* end of list */
00078 
00079 #define EBOOK_MALL_HOME  "http://redirect.irexnet.com/mall/"
00080 
00081 
00082 //----------------------------------------------------------------------------
00083 // Global Constants
00084 //----------------------------------------------------------------------------
00085  
00086 static const gint  WEBVIEW_MARGIN           = 5;
00087 static const gint  BUSY_DIALOG_DELAY_MS     = 500;
00088 static const gint  MULTIPLE_PAGES           = 5;
00089 static const gint  PAGE_OVERLAP             = 5; // in percent, like UDS
00090 
00091 static const gint BACK_H_PADDING            = 12;
00092 static const gint BACK_T_PADDING            = 10;
00093 static const gint BACK_B_PADDING            = 5;
00094 
00095 
00096 //----------------------------------------------------------------------------
00097 // Static Variables
00098 //---------------------------------------------------------------------------- 
00099 
00100 static BrowserWindow     *g_browser          = NULL;
00101 static gboolean          g_page_loaded       = FALSE;
00102 static GtkWidget         *cancel_button      = NULL;
00103 static GtkWidget         *busy_dialog        = NULL;
00104 static gchar             *g_ebook_mall_home  = NULL;
00105 
00106 
00107 //============================================================================
00108 // Local Function Definitions
00109 //============================================================================
00110 
00111 static BrowserWindow *create_window     (void);
00112 
00113 static void     go_back_cb              (GtkWidget *item, BrowserWindow *window);
00114 static void     go_forward_cb           (GtkWidget *item, BrowserWindow *window);
00115 static void     go_emall_cb             (GtkWidget *item, BrowserWindow *window);
00116 static void     reload_cb               (GtkWidget *item, BrowserWindow *window);
00117 static void     stop_cb                 (GtkWidget *item, BrowserWindow *window);
00118 
00119 static void     create_locationbar      (BrowserWindow *window);
00120 static void     create_toolbar          (BrowserWindow *window);
00121 static void     create_web_view         (BrowserWindow *window);
00122 static GtkWidget * create_back          (BrowserWindow *window);
00123 static GtkWidget * create_back_listview (GtkListStore * model);
00124 static void     update_back_liststore   (GtkWidget *listview, GtkListStore * model);
00125 static void     on_back_activated       (GtkTreeView       *view,
00126                                          GtkTreePath       *path,
00127                                          GtkTreeViewColumn *column,
00128                                          gpointer          user_data);
00129 
00130 static void     notify_vadjustment_cb   (BrowserWindow *window);
00131 static void     notify_hadjustment_cb   (BrowserWindow *window);
00132 static void     destroy_cb              (GtkWidget *widget,         BrowserWindow *window);
00133 static void     activate_uri_entry_cb   (GtkWidget *entry,          BrowserWindow *window);
00134 static void     hadjustment_changed_cb  (GtkAdjustment *adjustment, BrowserWindow *window);
00135 static void     vadjustment_changed_cb  (GtkAdjustment *adjustment, BrowserWindow *window);
00136 static void     load_progress_cb        (WebKitWebView *web_view, gint progress, BrowserWindow *window);
00137 static void     load_started_cb         (WebKitWebView *web_view, WebKitWebFrame *frame, BrowserWindow *window);
00138 static void     load_finished_cb        (WebKitWebView *web_view, WebKitWebFrame *frame, BrowserWindow *window);
00139 static gboolean load_error_cb           (WebKitWebView  *web_view,
00140                                          WebKitWebFrame *web_frame,
00141                                          const gchar    *uri,
00142                                          GError         *error,
00143                                          BrowserWindow  *window);
00144 static gboolean key_event_cb            (WebKitWebView             *web_view,
00145                                          GdkEventKey               *event,
00146                                          BrowserWindow             *window);
00147 static WebKitWebView *create_web_view_cb(WebKitWebView             *web_view,
00148                                          WebKitWebFrame            *frame, 
00149                                          BrowserWindow             *window);
00150 static gboolean navigation_requested_cb (WebKitWebView             *web_view,
00151                                          WebKitWebFrame            *frame,
00152                                          WebKitNetworkRequest      *request,
00153                                          WebKitWebNavigationAction *navigation_action,
00154                                          WebKitWebPolicyDecision   *policy_decision,                                         
00155                                          BrowserWindow             *window);
00156 static gboolean mime_type_requested_cb  (WebKitWebView             *web_view,
00157                                          WebKitWebFrame            *frame,
00158                                          WebKitNetworkRequest      *request,
00159                                          const gchar               *mime_type,
00160                                          WebKitWebPolicyDecision   *policy_decision,                                         
00161                                          BrowserWindow             *window);
00162 static void     notify_title_cb         (WebKitWebView *web_view,  GParamSpec *pspec, BrowserWindow *window);
00163 static void     notify_uri_cb           (WebKitWebView *web_view,  GParamSpec *pspec, BrowserWindow *window);
00164 static void     update_title            (BrowserWindow *window, const gchar *title);
00165  
00166 static void     go_to_page              (BrowserWindow *window, GtkAdjustment *adjustment, gint page);
00167 static gint     get_current_page        (BrowserWindow *window, GtkAdjustment *adjustment);
00168 static void     show_busy_loading       (gboolean show);
00169 static void     show_busy               (gboolean show);
00170 static gchar    *magic_uri              (const gchar   *uri);
00171 static void     load_error_page         (const gchar   *uri, GError *error);
00172 static void     set_browser_uri         (const gchar   *uri);
00173 static void     create_show_busy_loading(void);
00174 static gchar*   get_file_content        (const gchar* file_path);
00175 static gchar*   get_ebook_mall_home     (void);
00176 
00177 
00178 //============================================================================
00179 // Functions Implementation
00180 //============================================================================
00181  
00182 BrowserWindow *view_create()
00183 {
00184     LOGPRINTF("entry");
00185 
00186     meta_initialize();
00187 
00188     g_browser = create_window();
00189     create_show_busy_loading();
00190     g_ebook_mall_home = get_ebook_mall_home();
00191     
00192     return g_browser;
00193 }
00194  
00195 
00196 void view_destroy(void)
00197 {
00198     LOGPRINTF("entry");
00199 
00200     if (g_browser)
00201     {
00202         gchar * application = g_object_get_data(G_OBJECT(g_browser->back_listview), "application");
00203         if (application)
00204         {
00205             g_free(application);
00206         }
00207         
00208         if (g_browser->window)
00209         {
00210          LOGPRINTF("destroy window");
00211             gtk_widget_destroy(g_browser->window);
00212             g_browser->window = NULL;
00213         }
00214     }
00215 
00216     LOGPRINTF("clearing cache");
00217     system("rm -rf /var/cache/webkit");
00218     
00219     g_free(g_ebook_mall_home);
00220 }
00221 
00222 
00223 void view_show_error(const gchar *title, const gchar *message)
00224 {
00225     LOGPRINTF("entry");
00226     
00227     gchar *back = NULL;
00228     gchar *data = NULL;
00229         
00230     if (webkit_web_view_can_go_back(WEBKIT_WEB_VIEW(g_browser->web_view)))
00231     {
00232         back = g_strdup_printf("<a href=\"javascript:history.go(-1)\">%s</a>",
00233                                _("Return to the previous page"));
00234     }
00235     else
00236     {
00237         back = g_strdup("");
00238     }
00239         
00240     data = g_strdup_printf(
00241         "<html><title>%s</title><body>"
00242         "<b>%s</b>"
00243         "<p />%s"
00244         "<p />"
00245         "<p />%s"
00246         "</body></html>",
00247         title, 
00248         title, 
00249         message,
00250         back);
00251     
00252     webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(g_browser->web_view), data, NULL);
00253     
00254     g_free(data);
00255     g_free(back);
00256 }
00257 
00258 
00259 void view_zoom_in()
00260 {
00261     LOGPRINTF("entry");
00262     
00263     show_busy(TRUE);
00264     webkit_web_view_zoom_in(WEBKIT_WEB_VIEW(g_browser->web_view));
00265     
00266     gfloat zoom_level = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(g_browser->web_view));
00267     meta_set_zoom_level(zoom_level);
00268     show_busy(FALSE);
00269 }
00270 
00271 
00272 void view_zoom_out()
00273 {
00274     LOGPRINTF("entry");
00275     
00276     show_busy(TRUE);
00277     webkit_web_view_zoom_out(WEBKIT_WEB_VIEW(g_browser->web_view));
00278     
00279     gfloat zoom_level = webkit_web_view_get_zoom_level(WEBKIT_WEB_VIEW(g_browser->web_view));
00280     meta_set_zoom_level(zoom_level);
00281     show_busy(FALSE);
00282 }
00283 
00284 
00285 void view_set_zoom_level(gfloat zoom_level)
00286 {
00287     LOGPRINTF("entry: %f", zoom_level);
00288     
00289     show_busy(TRUE);
00290     webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(g_browser->web_view), zoom_level);
00291     menu_set_zoom_level(zoom_level);
00292     meta_set_zoom_level(zoom_level);
00293     show_busy(FALSE);
00294 }
00295 
00296 
00297 void view_full_screen(gboolean mode)
00298 {
00299     LOGPRINTF("entry: %d", mode);
00300     
00301     g_object_set(G_OBJECT(webkit_web_view_get_window_features(WEBKIT_WEB_VIEW(g_browser->web_view))),
00302                   "fullscreen", mode,
00303                   NULL);
00304     if (mode)
00305     {
00306         gtk_window_fullscreen(GTK_WINDOW(g_main_window));
00307     }
00308     else
00309     {
00310         gtk_window_unfullscreen(GTK_WINDOW(g_main_window));
00311     }
00312 
00313     menu_set_full_screen(mode);
00314     meta_set_full_screen(mode);
00315 }
00316 
00317 
00318 void view_go_back()
00319 {
00320     LOGPRINTF("entry");
00321     go_back_cb(NULL, g_browser);
00322 }
00323     
00324 
00325 void view_go_forward()
00326 {
00327     LOGPRINTF("entry");
00328     go_forward_cb(NULL, g_browser);
00329 }
00330 
00331 
00332 void view_reload()
00333 {
00334     LOGPRINTF("entry");
00335     reload_cb(NULL, g_browser);
00336 }
00337 
00338 
00339 
00340 static gboolean is_local_file(const gchar *uri)
00341 {
00342     return uri && g_str_has_prefix(uri, "file://");
00343 }
00344 
00345 
00346 static gboolean is_local_uri(const gchar *uri)
00347 {
00348     return uri && ( g_str_has_prefix(uri, "file://") ||
00349                     g_str_has_prefix(uri, "http://localhost") ||
00350                     g_str_has_prefix(uri, "http://127.0.0.1") );
00351 }
00352 
00353 
00354 void view_open_last()
00355 {
00356     webkit_web_view_open(WEBKIT_WEB_VIEW(g_browser->web_view), g_browser->uri);
00357 }
00358 
00359 
00360 void view_open_uri(const char *uri)
00361 {
00362     LOGPRINTF("entry: %s", uri);
00363     
00364     gchar *full_uri;
00365     full_uri = magic_uri(uri);
00366     
00367     gboolean is_file = is_local_file(full_uri);
00368     if (is_file)
00369     {
00370         gchar *file_path = full_uri+strlen("file://");
00371         if (!g_file_test(file_path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
00372         {
00373             load_error_page(full_uri, NULL);
00374             goto err;
00375         }
00376                                            
00377         // read application meta data
00378         meta_file_open(file_path);
00379     }
00380     
00381     set_browser_uri(full_uri);
00382     webkit_web_view_open(WEBKIT_WEB_VIEW(g_browser->web_view), full_uri);
00383     
00384     if (is_file)
00385     {
00386         // apply application meta data
00387         view_set_zoom_level(meta_get_zoom_level());
00388 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00389         view_full_screen   (meta_get_full_screen());
00390 #endif
00391     }
00392 
00393 err:                                        
00394     g_free(full_uri);
00395 }
00396 
00397 
00398 void view_show_busy(gboolean show)
00399 {
00400     LOGPRINTF("entry");
00401     show_busy(show);
00402 }
00403 
00404 
00405 void view_set_text(void)
00406 {
00407     LOGPRINTF("entry");
00408     if (!g_browser || !g_browser->back_liststore)
00409     {
00410         return;
00411     }
00412 
00413     gtk_list_store_clear(g_browser->back_liststore);
00414     update_back_liststore(g_browser->back_listview, g_browser->back_liststore);
00415 }
00416 
00417 
00418 void view_deactivated(void)
00419 {
00420     LOGPRINTF("entry");
00421     if (!g_browser)
00422     {
00423         return;
00424     }
00425 
00426     main_quit();
00427 }
00428 
00429 
00430 gboolean view_is_page_loaded(void)
00431 {
00432     return g_page_loaded;
00433 }
00434 
00435 
00436 void view_open_emall(void)
00437 {
00438     view_open_uri(g_ebook_mall_home);
00439 }
00440 
00441 
00442 //============================================================================
00443 // Local Functions Implementation
00444 //============================================================================
00445 
00446 static gboolean on_webview_focus_out_cb(GtkWidget* widget, gpointer data)
00447 {
00448     gboolean locationbar_visible = FALSE; 
00449     g_object_get(G_OBJECT(webkit_web_view_get_window_features(WEBKIT_WEB_VIEW(widget))),
00450                   "locationbar-visible", &locationbar_visible,
00451                   NULL);
00452     
00453     if (!locationbar_visible) 
00454     { 
00455         // prevent toolbar from getting focus
00456         gtk_widget_grab_focus(widget);
00457         return TRUE;
00458     }
00459 
00460     // allow focus on locationbar
00461     return FALSE;
00462 }
00463 
00464 static BrowserWindow *create_window()
00465 {
00466     LOGPRINTF("enter");
00467     GtkWidget     *alignment = NULL;
00468     GtkWidget     *back      = NULL;
00469 
00470     // object hierarchy:
00471     // window (BrowserWindow)
00472     //    window->window (GtkWindow)
00473     //       |--window->vbox
00474     //          |--back
00475     //          |--window->locationbar
00476     //          |--window->tooolbar
00477     //          |--alignment
00478     //             |--window->scrolled_window
00479     //                |--window->web_view (WebKit GTK+)
00480     // 
00481 
00482     BrowserWindow *window = g_new0(BrowserWindow, 1);
00483 
00484     back = create_back(window);
00485     create_locationbar(window);
00486     create_toolbar(window);
00487     create_web_view(window);
00488 
00489     window->scrolled_window = gtk_scrolled_window_new(NULL, NULL);
00490     gtk_container_add(GTK_CONTAINER(window->scrolled_window), window->web_view);
00491     
00492     alignment = gtk_alignment_new(0, 0, 1, 1); 
00493     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), WEBVIEW_MARGIN, WEBVIEW_MARGIN, WEBVIEW_MARGIN, WEBVIEW_MARGIN);
00494     gtk_container_add(GTK_CONTAINER(alignment), window->scrolled_window);    
00495     gtk_widget_show(alignment);
00496 
00497     g_signal_connect(G_OBJECT(window->scrolled_window), "notify::hadjustment",
00498                              G_CALLBACK(notify_hadjustment_cb), window);
00499     g_signal_connect(G_OBJECT(window->scrolled_window), "notify::vadjustment",
00500                              G_CALLBACK(notify_vadjustment_cb), window);
00501     notify_hadjustment_cb(window);
00502     notify_vadjustment_cb(window);
00503 
00504     window->vbox = gtk_vbox_new(FALSE, 0);
00505     gtk_box_pack_start(GTK_BOX(window->vbox), back, FALSE, FALSE, 0);
00506     gtk_box_pack_start(GTK_BOX(window->vbox), window->locationbar, FALSE, FALSE, 0);
00507     gtk_box_pack_start(GTK_BOX(window->vbox), window->toolbar, FALSE, FALSE, 0);
00508     gtk_box_pack_start(GTK_BOX(window->vbox), alignment, TRUE, TRUE, 0);
00509 
00510     window->window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
00511     g_signal_connect_swapped(G_OBJECT(window->window), "destroy", G_CALLBACK(destroy_cb), window);
00512     gtk_container_add(GTK_CONTAINER(window->window), window->vbox);
00513     gtk_widget_grab_focus(window->web_view);
00514 
00515     g_signal_connect(G_OBJECT(window->web_view), "focus-out-event",
00516                              G_CALLBACK(on_webview_focus_out_cb), NULL);
00517  
00518     return window;
00519 }
00520 
00521 
00522 static void go_back_cb(GtkWidget *item, BrowserWindow *window)
00523 {
00524     LOGPRINTF("entry");
00525 
00526     erkeyb_client_hide(); // hide keyboard
00527 
00528     if (window->web_view) {
00529       webkit_web_view_go_back(WEBKIT_WEB_VIEW(window->web_view));
00530     }
00531 }
00532 
00533 
00534 static void go_forward_cb(GtkWidget *item, BrowserWindow *window)
00535 {
00536     LOGPRINTF("entry");
00537 
00538     erkeyb_client_hide(); // hide keyboard
00539 
00540     if (window->web_view) {
00541       webkit_web_view_go_forward(WEBKIT_WEB_VIEW(window->web_view));
00542     }
00543 }
00544 
00545 
00546 static void go_emall_cb(GtkWidget *item, BrowserWindow *window)
00547 {
00548     LOGPRINTF("entry");
00549 
00550     erkeyb_client_hide(); // hide keyboard
00551 
00552     view_open_emall();
00553 }
00554 
00555 
00556 static void reload_cb(GtkWidget *item, BrowserWindow *window)
00557 {
00558     LOGPRINTF("entry");
00559     if (window->web_view) {
00560       webkit_web_view_reload_bypass_cache(WEBKIT_WEB_VIEW(window->web_view));
00561     }
00562 }
00563 
00564 
00565 static void stop_cb(GtkWidget *item, BrowserWindow *window)
00566 {
00567     LOGPRINTF("entry");
00568     webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(window->web_view));
00569 }
00570 
00571 
00572 // |--alignment
00573 //    |--window->back_listview
00574 static GtkWidget * create_back(BrowserWindow * window)
00575 {
00576     LOGPRINTF("entry");
00577 
00578     GtkWidget * alignment = NULL;
00579 
00580     alignment = gtk_alignment_new(0, 0, 1, 1); 
00581     gtk_alignment_set_padding(GTK_ALIGNMENT(alignment),
00582             BACK_T_PADDING, BACK_B_PADDING, BACK_H_PADDING, BACK_H_PADDING);
00583     gtk_widget_show(alignment);
00584 
00585     window->back_liststore = gtk_list_store_new(N_COLUMNS, COLUMN_TYPES);
00586     window->back_listview = create_back_listview(window->back_liststore);
00587     gtk_container_add(GTK_CONTAINER(alignment), window->back_listview);    
00588 
00589     g_signal_connect(window->back_listview, "row-activated", 
00590             G_CALLBACK(on_back_activated), NULL);
00591     
00592     return alignment;
00593 }
00594 
00595 
00596 static GtkWidget * create_back_listview(GtkListStore * model)
00597 {
00598     LOGPRINTF("entry");
00599 
00600     GtkWidget * view = ergtk_list_view_new_with_model(GTK_TREE_MODEL(model));
00601     gtk_widget_set_name(view, "contentview-irex-settings");
00602 
00603     GtkTreeView * treeview = GTK_TREE_VIEW(view);
00604     erGtkListView * er_listview = ERGTK_LIST_VIEW(view);
00605     
00606     gtk_tree_view_set_headers_visible(treeview, FALSE);
00607     ergtk_list_view_set_focus_mode(er_listview, TRUE, FALSE);
00608     GtkTreeSelection * selection = gtk_tree_view_get_selection(treeview);
00609     gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
00610 
00611     // icon column
00612     GtkCellRenderer * renderer = gtk_cell_renderer_pixbuf_new();
00613     g_object_set(G_OBJECT(renderer),
00614                   "xpad",   10,
00615                   "ypad",   0,
00616                   "xalign", 0.5,
00617                   "yalign", 0.5,
00618                   NULL);
00619     GtkTreeViewColumn * column = 
00620         gtk_tree_view_column_new_with_attributes("", renderer,
00621                                                  "pixbuf", COL_THUMBNAIL, 
00622                                                  NULL);
00623     g_object_set( G_OBJECT(column),
00624                   "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE,
00625                   "expand", FALSE,
00626                   NULL );
00627     ergtk_list_view_append_column(er_listview, column);
00628 
00629     // title + subtitle column
00630     renderer = ergtk_cell_renderer_text_new(2);
00631     g_object_set( G_OBJECT(renderer),
00632                   "xpad",          0,
00633                   "ypad",          0,
00634                   "xalign",        0.0, // left
00635                   "yalign",        1.0, // bottom
00636                   "ellipsize",     PANGO_ELLIPSIZE_END,
00637                   "ellipsize-set", TRUE,
00638                   "font-0",        "Normal 10",
00639                   "font-1",        "Normal italic 9",
00640                   "height-0",      32,
00641                   "height-1",      22,
00642                   "foreground-0",  "black",
00643                   "foreground-1",  "#555555",
00644                   NULL );
00645     column = 
00646         gtk_tree_view_column_new_with_attributes("", renderer,
00647                                                  "text-0", COL_TITLE,
00648                                                  "text-1", COL_SUBTITLE,
00649                                                  NULL );
00650     g_object_set( G_OBJECT(column),
00651                   "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE,
00652                   "expand", TRUE,
00653                   NULL );
00654     ergtk_list_view_append_column(er_listview, column);
00655 
00656     // border column (invisible)
00657     // Note: add this to the GtkTreeView to avoid separator column from erGtkListView
00658     renderer = ergtk_cell_renderer_border_new();
00659     g_object_set( G_OBJECT(renderer),
00660                   "xpad",          0,
00661                   "ypad",          0,
00662                   "xalign",        0.0,
00663                   "yalign",        0.5,
00664                   "border-width",  2,
00665                   "border-offset", 3,
00666                   "border-color",  "dark grey",
00667                   NULL );
00668     column = gtk_tree_view_column_new_with_attributes("", renderer, NULL);
00669     g_object_set( G_OBJECT(column),
00670                   "sizing", GTK_TREE_VIEW_COLUMN_AUTOSIZE,
00671                   "expand", FALSE,
00672                   NULL );
00673     ergtk_list_view_append_column(er_listview, column);
00674 
00675     return view;
00676 }
00677 
00678 
00679 static void update_back_liststore(GtkWidget * listview, GtkListStore * model)
00680 { 
00681     LOGPRINTF("entry");
00682 
00683     char iconfile[MAX_BUF_LEN + 1];
00684     GdkPixbuf * pixbuf = NULL;
00685     GError * err = NULL;
00686     char title[MAX_BUF_LEN + 1], subtitle[MAX_BUF_LEN + 1];
00687     char * application = NULL;
00688    
00689     snprintf(iconfile , MAX_BUF_LEN, "%s/%s", DATADIR, "icon-back-small.png");
00690     pixbuf = gdk_pixbuf_new_from_file (  iconfile, &err );
00691     if (pixbuf == NULL)
00692     {
00693         ERRORPRINTF("cannot load iconfile [%s] error [%s]", iconfile, err->message);
00694         g_clear_error(&err);
00695     }
00696 
00697     application = (char *)g_object_get_data(G_OBJECT(listview), "application");
00698     g_snprintf(title, MAX_BUF_LEN,"to %s", application);
00699     g_snprintf(subtitle, MAX_BUF_LEN, "Return to %s screen", application); 
00700     gtk_list_store_insert_with_values(model, NULL, -1,
00701             COL_TITLE, title,
00702             COL_SUBTITLE, subtitle,
00703             COL_THUMBNAIL, pixbuf, 
00704             -1);
00705     
00706     g_object_unref(pixbuf);
00707 }
00708 
00709 
00710 static void on_back_activated(GtkTreeView       *view,
00711                               GtkTreePath       *path,
00712                               GtkTreeViewColumn *column,
00713                               gpointer          user_data )
00714 {
00715     LOGPRINTF("entry");
00716     main_quit();
00717 }
00718 
00719 
00720 static void create_locationbar(BrowserWindow *window)
00721 {
00722     LOGPRINTF("entry");
00723     GtkToolItem *item      = NULL;
00724 
00725     window->locationbar = gtk_toolbar_new();
00726     
00727     gtk_toolbar_set_orientation(GTK_TOOLBAR(window->locationbar), GTK_ORIENTATION_HORIZONTAL);
00728     gtk_toolbar_set_tooltips(GTK_TOOLBAR(window->locationbar), FALSE);
00729     gtk_toolbar_set_show_arrow(GTK_TOOLBAR(window->locationbar), FALSE);
00730     gtk_toolbar_set_style(GTK_TOOLBAR(window->locationbar), GTK_TOOLBAR_ICONS);
00731    
00732     // Tools
00733     item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
00734     g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(go_back_cb), window);
00735     gtk_toolbar_insert(GTK_TOOLBAR(window->locationbar), item, -1);
00736 
00737     item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
00738     g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(go_forward_cb), window);
00739     gtk_toolbar_insert(GTK_TOOLBAR(window->locationbar), item, -1);
00740     
00741     item = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH);
00742     g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(reload_cb), window);
00743     gtk_toolbar_insert(GTK_TOOLBAR(window->locationbar), item, -1);
00744     
00745     item = gtk_tool_button_new_from_stock(GTK_STOCK_STOP);
00746     g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(stop_cb), window);
00747     gtk_toolbar_insert(GTK_TOOLBAR(window->locationbar), item, -1);
00748 
00749     // Location entry
00750     item = gtk_tool_item_new();
00751     gtk_tool_item_set_expand(item, TRUE);
00752     window->uri_entry = gtk_entry_new();
00753     g_signal_connect(G_OBJECT(window->uri_entry), "activate", G_CALLBACK(activate_uri_entry_cb), window);
00754     gtk_container_add(GTK_CONTAINER(item), window->uri_entry);
00755     gtk_toolbar_insert(GTK_TOOLBAR(window->locationbar), item, -1);
00756 
00757     // More tools
00758     item = gtk_tool_button_new_from_stock(GTK_STOCK_OK);
00759     g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(activate_uri_entry_cb), window);
00760     gtk_toolbar_insert(GTK_TOOLBAR(window->locationbar), item, -1);
00761     
00762 }
00763 
00764 
00765 static void create_toolbar(BrowserWindow *window)
00766 {
00767     LOGPRINTF("entry");
00768     GtkToolItem *item      = NULL;
00769     GtkWidget *icon_widget = NULL;
00770     gchar *filename        = NULL;
00771 
00772     window->toolbar = gtk_toolbar_new();
00773     
00774     gtk_toolbar_set_orientation(GTK_TOOLBAR(window->toolbar), GTK_ORIENTATION_HORIZONTAL);
00775     gtk_toolbar_set_tooltips(GTK_TOOLBAR(window->toolbar), FALSE);
00776     gtk_toolbar_set_show_arrow(GTK_TOOLBAR(window->toolbar), FALSE);
00777     gtk_toolbar_set_style(GTK_TOOLBAR(window->toolbar), GTK_TOOLBAR_BOTH_HORIZ);
00778 
00779     // back button
00780     filename = g_strconcat(DATADIR, "/", "back.png", NULL);
00781     icon_widget = gtk_image_new_from_file(filename);
00782     g_object_ref(G_OBJECT(icon_widget));
00783     g_free(filename);
00784     item = gtk_tool_button_new(icon_widget, NULL);
00785     gtk_tool_item_set_homogeneous(item, FALSE);
00786     g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(go_back_cb), window);
00787     gtk_toolbar_insert(GTK_TOOLBAR(window->toolbar), item, -1);
00788 
00789     // forward button
00790     filename = g_strconcat(DATADIR, "/", "forward.png", NULL);
00791     icon_widget = gtk_image_new_from_file(filename);
00792     g_object_ref(G_OBJECT(icon_widget));
00793     g_free(filename);
00794     item = gtk_tool_button_new(icon_widget, NULL);
00795     gtk_tool_item_set_homogeneous(item, FALSE);
00796     g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(go_forward_cb), window);
00797     gtk_toolbar_insert(GTK_TOOLBAR(window->toolbar), item, -1);
00798 
00799     // emall button with markup label
00800     filename = g_strconcat(DATADIR, "/", "emall-home.png", NULL);
00801     icon_widget = gtk_image_new_from_file(filename);
00802     g_object_ref(G_OBJECT(icon_widget));
00803     g_free(filename);
00804     item = gtk_tool_button_new(icon_widget, NULL);
00805     GtkWidget *emall_label = gtk_label_new(NULL);
00806     gtk_label_set_use_markup(GTK_LABEL(emall_label), TRUE);
00807     gchar *label_markup = g_markup_printf_escaped ("<u>%s</u>", _("eBook Mall"));
00808     gtk_label_set_markup(GTK_LABEL(emall_label), label_markup);
00809     g_free (label_markup);
00810     gtk_tool_button_set_label_widget(GTK_TOOL_BUTTON(item), emall_label);
00811     gtk_widget_set_name(GTK_WIDGET(item), "irex-mall-button");
00812     gtk_tool_item_set_is_important(item, TRUE); /* show label */
00813     gtk_tool_item_set_homogeneous(item, FALSE);
00814     g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(go_emall_cb), window);
00815     gtk_toolbar_insert(GTK_TOOLBAR(window->toolbar), item, -1);
00816 
00817     // seperator
00818     item = gtk_separator_tool_item_new();
00819     gtk_toolbar_insert(GTK_TOOLBAR(window->toolbar), item, -1);   
00820 
00821     // web page title
00822     item = gtk_tool_item_new();
00823     gtk_tool_item_set_expand(item, TRUE);
00824     gtk_tool_item_set_homogeneous(item, FALSE);
00825     window->title = gtk_label_new(NULL);
00826     gtk_misc_set_alignment(GTK_MISC(window->title), 0.0, 0.5); /* align left */
00827     gtk_label_set_ellipsize(GTK_LABEL(window->title), PANGO_ELLIPSIZE_END);
00828     gtk_container_add(GTK_CONTAINER(item), window->title);
00829     gtk_toolbar_insert(GTK_TOOLBAR(window->toolbar), item, -1);
00830 }
00831 
00832 
00833 static void create_web_view(BrowserWindow *window)
00834 {
00835     LOGPRINTF("entry");
00836     
00837     // window signal
00838     window->web_view = webkit_web_view_new();
00839     g_signal_connect(G_OBJECT(window->web_view), "load-progress-changed", G_CALLBACK(load_progress_cb), NULL);
00840     g_signal_connect(G_OBJECT(window->web_view), "load-started", G_CALLBACK(load_started_cb), window);
00841     g_signal_connect(G_OBJECT(window->web_view), "load-finished", G_CALLBACK(load_finished_cb), window);
00842     g_signal_connect(G_OBJECT(window->web_view), "load-error", G_CALLBACK(load_error_cb), window);
00843     g_signal_connect(G_OBJECT(window->web_view), "create-web-view", G_CALLBACK(create_web_view_cb), window);
00844     g_signal_connect(G_OBJECT(window->web_view), "key-press-event", G_CALLBACK(key_event_cb), window);
00845     g_signal_connect(G_OBJECT(window->web_view), "download-requested", G_CALLBACK(download_requested_cb), window);
00846     g_signal_connect(G_OBJECT(window->web_view), "navigation-policy-decision-requested", G_CALLBACK(navigation_requested_cb), window);
00847     g_signal_connect(G_OBJECT(window->web_view), "mime-type-policy-decision-requested", G_CALLBACK(mime_type_requested_cb), window);
00848     g_signal_connect(G_OBJECT(window->web_view), "notify::title", G_CALLBACK(notify_title_cb), window);
00849     g_signal_connect(G_OBJECT(window->web_view), "notify::uri", G_CALLBACK(notify_uri_cb), window);
00850 
00851 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800S || MACHINE_IS_DR800SW
00852     webkit_web_view_set_full_content_zoom(WEBKIT_WEB_VIEW(window->web_view), FALSE); 
00853 #elif MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
00854     // scale the full content of the view, including images, when zooming
00855     webkit_web_view_set_full_content_zoom(WEBKIT_WEB_VIEW(window->web_view), TRUE); 
00856 #else
00857 #error Unhandled machine type
00858 #endif
00859 }
00860 
00861 
00862 static void activate_uri_entry_cb(GtkWidget *entry, BrowserWindow *window)
00863 {
00864     LOGPRINTF("entry");
00865   
00866     view_open_uri(gtk_entry_get_text(GTK_ENTRY(window->uri_entry)));
00867 }
00868 
00869 
00870 static void load_progress_cb(WebKitWebView *web_view, gint progress, BrowserWindow *window)
00871 {
00872     LOGPRINTF("entry... progress %d", progress);
00873 }
00874 
00875 
00876 static void load_started_cb(WebKitWebView *web_view, WebKitWebFrame *frame, BrowserWindow *window)
00877 {
00878     LOGPRINTF("entry [%s]", g_browser ? g_browser->uri : "");
00879 
00880     erkeyb_client_hide(); // hide keyboard
00881     
00882     if (!window->uri_entry)
00883     {
00884         LOGPRINTF("uri bar is empty, return");
00885         return;
00886     }
00887 
00888     // update url in location bar
00889     if (g_browser->uri)
00890     {
00891         gtk_entry_set_text(GTK_ENTRY(window->uri_entry), g_browser->uri);
00892     }
00893     
00894     show_busy(TRUE);
00895 }
00896 
00897 
00898 static void load_finished_cb(WebKitWebView *web_view, WebKitWebFrame *frame, BrowserWindow *window)
00899 {
00900     LOGPRINTF("entry");
00901     
00902     if (!window->uri_entry)
00903         return;
00904 /*
00905     // restore previous scroll position
00906     // TODO fix this so works for local files only  
00907     gdouble hpos = meta_get_h_position();
00908     gdouble vpos = meta_get_v_position();
00909     if (hpos > 0.0) gtk_adjustment_set_value(g_browser->hadjustment, hpos);
00910     if (vpos > 0.0) gtk_adjustment_set_value(g_browser->vadjustment, vpos);
00911 */
00912     show_busy(FALSE);
00913     g_page_loaded = TRUE;
00914 }
00915 
00916 
00917 static gboolean load_error_cb(WebKitWebView  *web_view,
00918                               WebKitWebFrame *web_frame,
00919                               const gchar    *uri,
00920                               GError         *error,
00921                               BrowserWindow  *window)
00922 {
00923     LOGPRINTF("entry uri [%s] window uri [%s]", uri, window ? window->uri : "");
00924 
00925     if (error && error->message)
00926     {
00927         WARNPRINTF("Webkit returned error [%d] [%s]", error->code, error->message);
00928     }
00929 
00930     if (window && window->uri && (strcmp(window->uri, "about:blank") != 0))
00931     {
00932         load_error_page(window->uri, error);
00933     }
00934 
00935     show_busy(FALSE);
00936 
00937     // stop error handling
00938     return TRUE;
00939 }
00940 
00941 
00942 static gchar *page_html(const gchar *title, const gchar *description, const gchar *link)
00943 {
00944     gchar *data = g_strconcat(
00945             "<html><head><title>", title, "</title></head><body><br/><br/><br/><br/>"
00946             "<div style=\"display:block; width:500px; margin:auto; border:10px solid #fff; "
00947             "outline:3px solid black; outline-radius:12px; -webkit-outline-radius:12px\">"
00948             "<h3>", title, "</h3><p>", description, "</p>", link, "</div>"
00949             "</body></html>", NULL);
00950     return data;
00951 }
00952 
00953 
00954 static gchar *link_html(const gchar *url, const gchar *title)
00955 {
00956     gchar *data = g_strdup_printf("<a href=\"%s\">%s</a>", url, title);
00957     return data;
00958 }
00959 
00960 
00961 static void load_error_page(const gchar *uri, GError *error)
00962 {
00963     LOGPRINTF("entry");
00964 
00965     gboolean toolbar_visible = FALSE; 
00966     g_object_get(G_OBJECT(webkit_web_view_get_window_features(WEBKIT_WEB_VIEW(g_browser->web_view))),
00967                  "toolbar-visible", &toolbar_visible, NULL);
00968     
00969     if (toolbar_visible) 
00970     { 
00971         // ebook mall error page
00972         //
00973         gchar *link = NULL;
00974         gchar *page = NULL;
00975         
00976         // catch known errors and provide help
00977         if (error)
00978         {
00979             switch (error->code)
00980             {
00981             case SOUP_STATUS_IO_ERROR:
00982                 link = link_html("javascript:history.go(0)",
00983                                  _("Reload the page"));
00984                 page = page_html(_("The connection has terminated unexpectedly"), 
00985                                  _("The signal may be too weak. Try reloading the page by choosing Reload Page from the Menu."),
00986                                  link);
00987                 break;
00988             }
00989         }
00990         
00991         // fall back to generic help when not handled above
00992         if (!page)
00993         {
00994             gboolean can_go_back = webkit_web_view_can_go_back(WEBKIT_WEB_VIEW(g_browser->web_view));
00995             if (can_go_back)
00996             {
00997                 link = link_html("javascript:history.go(-1)",
00998                                  _("Return to the previous page"));
00999             }
01000             else
01001             {
01002                 link = link_html(g_ebook_mall_home,
01003                                  _("Go to eBook Mall home"));
01004             }
01005             page = page_html(_("Page not found"), 
01006                              _("The page you were trying to retrieve does not exist in the eBook Mall."),
01007                              link);
01008         }
01009         
01010         webkit_web_view_load_html_string(WEBKIT_WEB_VIEW(g_browser->web_view), page, NULL);        
01011         g_free(link);
01012         g_free(page);
01013     }
01014     else
01015     {
01016         // generic error page
01017         gchar *title;
01018         title = g_strdup_printf(_("Error loading %s"), uri);
01019 
01020         gchar *message;
01021         message = g_strconcat( _("The requested page could not be found. This may have happened because:"),
01022                               "<ul><li>",
01023                                _("The URL is incorrect"),
01024                               "</li><li>",
01025                                _("The page has been moved or renamed"),
01026                               "</li><li>",
01027                                _("The page no longer exists"),
01028                               "</li></ul>",
01029                               NULL);
01030         view_show_error(title, message);
01031         g_free(message);
01032         g_free(title);
01033     }
01034 }
01035 
01036 
01037 static WebKitWebView *create_web_view_cb(WebKitWebView *web_view, WebKitWebFrame *frame, BrowserWindow *window)
01038 {
01039     LOGPRINTF("entry");
01040     set_browser_uri("");
01041     return web_view;
01042 }
01043 
01044 
01045 static gboolean navigation_requested_cb(WebKitWebView             *web_view,
01046                                         WebKitWebFrame            *frame,
01047                                         WebKitNetworkRequest      *request,
01048                                         WebKitWebNavigationAction *navigation_action,
01049                                         WebKitWebPolicyDecision   *policy_decision,
01050                                         BrowserWindow             *window)
01051 {
01052     LOGPRINTF("entry");
01053     
01054 #if (LOGGING_ON)
01055     static const gchar *reason_str[] =
01056         {
01057             [WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED]         = "LINK_CLICKED",
01058             [WEBKIT_WEB_NAVIGATION_REASON_FORM_SUBMITTED]       = "FORM_SUBMITTED",
01059             [WEBKIT_WEB_NAVIGATION_REASON_BACK_FORWARD]         = "BACK_FORWARD",
01060             [WEBKIT_WEB_NAVIGATION_REASON_RELOAD]               = "RELOAD",
01061             [WEBKIT_WEB_NAVIGATION_REASON_FORM_RESUBMITTED]     = "FORM_RESUBMITTED",
01062             [WEBKIT_WEB_NAVIGATION_REASON_OTHER]                = "OTHER"
01063         };
01064 #endif
01065 
01066     WebKitWebNavigationReason reason = webkit_web_navigation_action_get_reason(navigation_action);
01067     const gchar *uri = webkit_web_navigation_action_get_original_uri(navigation_action);
01068         
01069     LOGPRINTF("original uri [%s]", uri);
01070     LOGPRINTF("window uri   [%s]", window ? window->uri : NULL);
01071 
01072     if (reason == WEBKIT_WEB_NAVIGATION_REASON_RELOAD && window && window->uri)
01073     {
01074         // reload uri before redirection
01075         uri = window->uri;
01076         webkit_web_navigation_action_set_original_uri(navigation_action, uri);
01077     }
01078     else
01079     {
01080         set_browser_uri(uri);
01081     }
01082 
01083     LOGPRINTF("load uri [%s] reason [%s]", uri, reason_str[reason]);
01084 
01085     gchar *application = g_object_get_data(G_OBJECT(g_browser->back_listview), "application");
01086     gboolean toolbar_visible = FALSE;
01087     g_object_get(G_OBJECT(webkit_web_view_get_window_features(WEBKIT_WEB_VIEW(web_view))),
01088              "toolbar-visible", &toolbar_visible, NULL);
01089 
01090     // handle special cases
01091     //
01092     if (uri && strcmp(uri, "about:blank") == 0)
01093     {
01094         LOGPRINTF("empty page, skipped");
01095         webkit_web_policy_decision_ignore(policy_decision);
01096         return TRUE;
01097     }
01098     else if (is_local_uri(uri))
01099     {
01100         // local uri, no network needed
01101     }
01102     else
01103     {
01104         gboolean connect = toolbar_visible || application;
01105         if (!connect)
01106         {
01107             ERRORPRINTF("Cannot open web links while browsing offline [%s]", uri);
01108 
01109             gchar *msg = g_strdup_printf(_("This link cannot be opened because the reader is not able to open internet links."));
01110             GtkWidget *widget = gtk_message_dialog_new(GTK_WINDOW(g_browser->window),
01111                                         GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
01112                                         GTK_MESSAGE_INFO,
01113                                         GTK_BUTTONS_OK,
01114                                         msg);
01115             gtk_dialog_run(GTK_DIALOG(widget));
01116             gtk_widget_destroy(widget);
01117             g_free(msg);
01118         }
01119         
01120         if (!connect || (connect && main_request_connection()))
01121         {
01122             LOGPRINTF("ignore loading page");
01123             webkit_web_policy_decision_ignore(policy_decision);
01124             return TRUE;
01125         }
01126     }
01127 
01128     // check if toolbar must be shown or not
01129     //
01130     if (toolbar_visible)
01131     {
01132         static gboolean was_hidden = FALSE;
01133 
01134         if (g_strstr_len(uri, strlen(uri), "EBM_NO_NAVIGATION") != NULL)
01135         {
01136             if (!was_hidden)
01137             {
01138                 gtk_widget_hide(window->toolbar);
01139                 was_hidden = TRUE;
01140             }
01141         }
01142         else 
01143         {
01144             if (was_hidden)
01145             {
01146                 gtk_widget_show(window->toolbar);
01147                 was_hidden = FALSE;
01148             }
01149         }
01150     }
01151     
01152     // FALSE to have default behaviour (let browser decide)
01153     return FALSE;
01154 }
01155 
01156 
01157 static gboolean mime_type_requested_cb(WebKitWebView             *web_view,
01158                                        WebKitWebFrame            *frame,
01159                                        WebKitNetworkRequest      *request,
01160                                        const gchar               *mime_type,
01161                                        WebKitWebPolicyDecision   *policy_decision,
01162                                        BrowserWindow             *window)
01163 {
01164     LOGPRINTF("entry");
01165     gboolean retval = FALSE;
01166     
01167     if (!webkit_web_view_can_show_mime_type (WEBKIT_WEB_VIEW (web_view), mime_type))
01168     {
01169         // can't show, so download
01170         
01171         webkit_web_policy_decision_download (policy_decision);
01172         window->open_download = FALSE;
01173 
01174 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800SW
01175         // override built-in Webkit defaults for Adobe DRM
01176         if (mime_type && strcmp(mime_type, "application/vnd.adobe.adept+xml") == 0)
01177         {
01178             LOGPRINTF("found Adobe Adept MIME type, download and open with Adobe Fullfilment");
01179             window->open_download = TRUE;
01180         }
01181         else if (g_browser->uri)
01182         {
01183             gchar *extension = g_strrstr(g_browser->uri,".");
01184             if (extension && (strncmp(extension, ".acsm", 5) == 0))
01185             {
01186                 LOGPRINTF("found .acsm file, download and open with Adobe Fullfilment");
01187                 window->open_download = TRUE;
01188             }
01189         }
01190 #endif
01191         
01192         // Webkit will continue loading which ends in an error
01193         // so stop here. This may be an error in Webkit. 
01194         webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(web_view));
01195 
01196         retval = TRUE;
01197     }
01198 
01199     return retval;
01200 }
01201 
01202 
01203 static void update_title(BrowserWindow *window, const gchar *title)
01204 {
01205     LOGPRINTF("entry");
01206     if (window && window->title)
01207     {
01208         LOGPRINTF("title [%s]", title);
01209         gtk_label_set_text(GTK_LABEL(window->title), title);
01210     }
01211 }
01212 
01213 
01214 static void notify_title_cb(WebKitWebView *web_view, GParamSpec *pspec, BrowserWindow *window)
01215 {
01216     LOGPRINTF("entry");
01217     const gchar *title;
01218     g_object_get(web_view, "title", &title, NULL);
01219     update_title(window, title);
01220 }
01221 
01222 
01223 static void notify_uri_cb(WebKitWebView *web_view, GParamSpec *pspec, BrowserWindow *window)
01224 {
01225     LOGPRINTF("entry");
01226     const gchar *uri;
01227     g_object_get(web_view, "uri", &uri, NULL);
01228 //    LOGPRINTF("uri [%s]\n", uri);
01229     
01230     if (window && window->toolbar)
01231     {
01232         GtkWidget *item = gtk_bin_get_child(GTK_BIN(gtk_toolbar_get_nth_item(GTK_TOOLBAR(window->toolbar), 2)));
01233         if (window->uri && g_str_has_prefix(window->uri, EBOOK_MALL_HOME))
01234         {
01235             gtk_widget_hide(item);
01236         }
01237         else
01238         {
01239             gtk_widget_show(item);
01240         }
01241     }
01242 }
01243 
01244 
01245 static gboolean key_event_cb(WebKitWebView *web_view, GdkEventKey *event, BrowserWindow *window)
01246 {
01247     gboolean retval = TRUE;
01248     guint new_keyval = 0;
01249     
01250     LOGPRINTF("entry: key %d, state %d", event->keyval, event->state);
01251     
01252     g_return_val_if_fail(g_browser, FALSE);
01253     
01254     if ((event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)) == 0) 
01255     {
01256         // scrolling 
01257         //
01258         switch (event->keyval) 
01259         {
01260 #if MACHINE_IS_DR800SG || MACHINE_IS_DR800S || MACHINE_IS_DR800SW
01261         case GDK_Up:
01262         case GDK_KP_Up:
01263             LOGPRINTF("select previous hyperlink in tab order");
01264             event->state = GDK_SHIFT_MASK;
01265             event->keyval = GDK_Tab;
01266             retval = FALSE;
01267             break;
01268         case GDK_Down:
01269         case GDK_KP_Down:
01270             LOGPRINTF("select next hyperlink in tab order");
01271             event->keyval = GDK_Tab;
01272             retval = FALSE;
01273             break;
01274         case GDK_Home:
01275         case GDK_KP_Home:
01276             LOGPRINTF("scroll left");
01277             go_to_page(g_browser, g_browser->hadjustment,
01278                        get_current_page(g_browser, g_browser->hadjustment) - 1);
01279             break;
01280         case GDK_Page_Up:
01281         case GDK_KP_Page_Up:
01282             LOGPRINTF("scroll up");
01283             go_to_page(g_browser, g_browser->vadjustment,
01284                        get_current_page(g_browser, g_browser->vadjustment) - 1);
01285             break;
01286         case GDK_End:
01287         case GDK_KP_End:
01288             LOGPRINTF("scroll right");
01289             go_to_page(g_browser, g_browser->hadjustment,
01290                        get_current_page(g_browser, g_browser->hadjustment) + 1);
01291             break;
01292         case GDK_Page_Down:
01293         case GDK_KP_Page_Down:
01294             LOGPRINTF("scroll down");
01295             go_to_page(g_browser, g_browser->vadjustment,
01296                        get_current_page(g_browser, g_browser->vadjustment) + 1);
01297             break;
01298 #elif MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
01299         case GDK_Left:
01300         case GDK_KP_Left:
01301             LOGPRINTF("scroll left");
01302             go_to_page(g_browser, g_browser->hadjustment, 
01303                        get_current_page(g_browser, g_browser->hadjustment) - 1);
01304             break;
01305         case GDK_Up:
01306         case GDK_KP_Up:
01307             LOGPRINTF("scroll up");
01308             go_to_page(g_browser, g_browser->vadjustment,
01309                        get_current_page(g_browser, g_browser->vadjustment) - 1);
01310             break;
01311         case GDK_Right:
01312         case GDK_KP_Right:
01313             LOGPRINTF("scroll right");
01314             go_to_page(g_browser, g_browser->hadjustment,
01315                        get_current_page(g_browser, g_browser->hadjustment) + 1);
01316             break;
01317         case GDK_Down:
01318         case GDK_KP_Down:
01319             LOGPRINTF("scroll down");
01320             go_to_page(g_browser, g_browser->vadjustment,
01321                        get_current_page(g_browser, g_browser->vadjustment) + 1);
01322             break;
01323         case GDK_Home:
01324         case GDK_KP_Home:
01325             LOGPRINTF("scroll 5 pages left");
01326             go_to_page(g_browser, g_browser->hadjustment,
01327                        get_current_page(g_browser, g_browser->hadjustment) - MULTIPLE_PAGES);
01328             break;
01329         case GDK_Page_Up:
01330         case GDK_KP_Page_Up:
01331             LOGPRINTF("scroll 5 pages up");
01332             go_to_page(g_browser, g_browser->vadjustment,
01333                        get_current_page(g_browser, g_browser->vadjustment) - MULTIPLE_PAGES);
01334             break;
01335         case GDK_End:
01336         case GDK_KP_End:
01337             LOGPRINTF("scroll 5 pages right");
01338             go_to_page(g_browser, g_browser->hadjustment,
01339                        get_current_page(g_browser, g_browser->hadjustment) + MULTIPLE_PAGES);
01340             break;
01341         case GDK_Page_Down:
01342         case GDK_KP_Page_Down:
01343             LOGPRINTF("scroll 5 pages down");
01344             go_to_page(g_browser, g_browser->vadjustment,
01345                        get_current_page(g_browser, g_browser->vadjustment) + MULTIPLE_PAGES);
01346             break;
01347 #else
01348 #error Unhandled machine type
01349 #endif
01350         default:
01351             LOGPRINTF("other key, propagate");
01352             // propagate event
01353             retval = FALSE;
01354             break;
01355         }
01356     }
01357     else if (event->state & GDK_SHIFT_MASK) 
01358     {
01359         
01360         // directional link navigation, key event handled by WebKit
01361         //
01362         switch (event->keyval) 
01363         {
01364 #if MACHINE_IS_DR1000S || MACHINE_IS_DR1000SW
01365         case GDK_Left:
01366         case GDK_KP_Left:
01367             LOGPRINTF("select previous/left hyperlink");
01368             new_keyval = GDK_Left;
01369             break;
01370         case GDK_Right:
01371         case GDK_KP_Right:
01372             LOGPRINTF("select next/right hyperlink");
01373             new_keyval = GDK_Right;
01374             break;
01375         case GDK_Up:
01376         case GDK_KP_Up:
01377             LOGPRINTF("select previous/up hyperlink");
01378             new_keyval = GDK_Up;
01379             break;
01380         case GDK_Down:
01381         case GDK_KP_Down:
01382             LOGPRINTF("select next/down hyperlink");
01383             new_keyval = GDK_Down;
01384             break;
01385 #endif
01386         default:
01387             new_keyval = 0;
01388             break;
01389         }
01390         
01391         if (new_keyval) 
01392         {
01393             event->state = GDK_CONTROL_MASK;
01394             event->keyval = new_keyval;
01395         }
01396 
01397         // propagate event
01398         retval = FALSE;
01399     }
01400 
01401     return retval;
01402 }
01403 
01404 
01405 static void notify_vadjustment_cb(BrowserWindow *window)
01406 {
01407     LOGPRINTF("entry");
01408     
01409     g_return_if_fail(window);
01410 
01411     if (window->scrolled_window)
01412     {
01413         if (window->vadjustment)
01414         {
01415             g_object_unref(window->vadjustment);
01416         }
01417         window->vadjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(window->scrolled_window));
01418         g_signal_connect(G_OBJECT(window->vadjustment), "value-changed", G_CALLBACK(vadjustment_changed_cb), window);
01419         g_object_ref(window->vadjustment);
01420     }
01421 }
01422 
01423 
01424 static void notify_hadjustment_cb(BrowserWindow *window)
01425 {
01426     LOGPRINTF("entry");
01427     
01428     g_return_if_fail(window);
01429 
01430     if (window->scrolled_window)
01431     {
01432         if (window->hadjustment)
01433         {
01434             g_object_unref(window->hadjustment);
01435         }
01436         window->hadjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(window->scrolled_window));
01437         g_signal_connect(G_OBJECT(window->hadjustment), "value-changed", G_CALLBACK(hadjustment_changed_cb), window);
01438         g_object_ref(window->hadjustment);
01439     }
01440 }
01441 
01442 
01443 static void hadjustment_changed_cb(GtkAdjustment *adjustment, BrowserWindow *window)
01444 {
01445     LOGPRINTF("entry");
01446     if (adjustment->value)
01447     {
01448         meta_set_h_position(adjustment->value);
01449     }
01450 }
01451 
01452 
01453 static void vadjustment_changed_cb(GtkAdjustment *adjustment, BrowserWindow *window)
01454 {
01455     LOGPRINTF("entry");
01456     if (adjustment->value)
01457     {
01458         meta_set_v_position(adjustment->value);
01459     }
01460 }
01461 
01462 
01463 static void destroy_cb(GtkWidget *widget, BrowserWindow *window)
01464 {
01465     LOGPRINTF("entry");
01466     meta_finalize();
01467     erkeyb_client_term();
01468     g_browser->window = NULL;
01469 }
01470 
01471 
01472 static gint get_total_pages(BrowserWindow *window, GtkAdjustment *adjustment)
01473 {
01474     LOGPRINTF("entry");
01475     
01476     gdouble upper;
01477     gdouble page_size;
01478     gint    total;
01479     
01480     g_object_get(G_OBJECT(adjustment),
01481                   "upper", &upper,
01482                   "page-size", &page_size,
01483                   NULL);
01484 
01485     if (page_size == upper)
01486     {
01487         /* upper >= page_size even if the effective size of the content is
01488          * smaller than page_size, so in this case we would return 2 because
01489          * of PAGE_OVERLAP. */
01490         total = 1;
01491     }
01492     else
01493     {
01494         total = MAX(ceil(upper / (page_size * (100-PAGE_OVERLAP) / 100)), 1);
01495     }
01496     
01497     LOGPRINTF("page-size %f, upper %f, total %d", page_size, upper, total);
01498     
01499     return total;
01500 }
01501 
01502 
01503 static gint get_current_page(BrowserWindow *window, GtkAdjustment *adjustment)
01504 {
01505     LOGPRINTF("entry");
01506     
01507     gdouble value;
01508     gdouble page_size;
01509     gdouble upper;
01510     gint current;
01511     gint total;
01512 
01513     g_object_get(G_OBJECT(adjustment),
01514                   "value", &value,
01515                   "page-size", &page_size,
01516                   "upper", &upper,
01517                   NULL);
01518 
01519     current = (int) (value / floor((page_size * (100-PAGE_OVERLAP) / 100)) + 1);
01520     
01521     total = get_total_pages(window, adjustment);
01522     
01523     LOGPRINTF("page-size %f, upper %f, value %f. total %d, current %d", page_size, upper, value, total, current);
01524     
01525     if (current != total && value + page_size >= upper)
01526     {
01527         /* If the last page is shorter than page_size than this function
01528          * would never return the number of the last page because the
01529          * beginning of the visualized content would be in the previous
01530          * page. So we return the last page if there is no more space
01531          * to scroll down. */
01532         current = total;
01533     }
01534     
01535     return current;
01536 }
01537 
01538 
01539 static void go_to_page(BrowserWindow *window, GtkAdjustment *adjustment, gint page)
01540 {
01541     LOGPRINTF("entry");
01542 
01543     gdouble page_size;
01544     gdouble upper;
01545     gdouble lower;
01546     gdouble value;
01547     
01548     g_object_get(G_OBJECT(adjustment),
01549                   "page-size", &page_size,
01550                   "lower", &lower,
01551                   "upper", &upper,
01552                   NULL);
01553     
01554     value = MAX(
01555                MIN(
01556                    floor((page - 1) * (page_size * (100-PAGE_OVERLAP) / 100)), 
01557                    upper - page_size), 
01558                 lower);
01559 
01560     LOGPRINTF("page-size %f, lower %f, upper %f, gotopage %d, check %f -- %f  >> %f", 
01561               page_size, lower, upper, page, 
01562               (page - 1) * (page_size * (100-PAGE_OVERLAP) / 100), 
01563               upper - page_size, 
01564               value);
01565     
01566     gtk_adjustment_set_value(adjustment, value);
01567 }
01568 
01569 
01570 static void show_busy_loading(gboolean show)
01571 {
01572     LOGPRINTF("entry");
01573     
01574     if (show)
01575     {
01576         gtk_widget_show_all(busy_dialog);
01577     }
01578     else
01579     {
01580         gtk_widget_hide_all(busy_dialog);
01581     }
01582 }
01583 
01584 
01585 static void show_busy(gboolean show)
01586 {
01587     static gint show_count = 0;
01588     
01589     LOGPRINTF("entry [%d] count [%d]", show, show_count);
01590     
01591     if (show)
01592     {
01593         show_count++;
01594         if (show_count==1)
01595         {
01596             show_busy_loading(TRUE);
01597             display_gain_control();
01598             ipc_sys_set_busy_nodialog(TRUE);
01599         }
01600     }
01601     else
01602     {
01603         if (show_count > 0)
01604         {
01605             show_count--;
01606         }
01607         if (show_count==0)
01608         {
01609             show_busy_loading(FALSE);
01610             display_return_control();
01611             ipc_sys_set_busy_nodialog(FALSE);
01612         }
01613     }
01614 }
01615 
01616 
01617 /*
01618   Inspired by sokoke_magic_uri Copyright (C) 2007-2008 Christian Dywan <christian@twotoasts.de>
01619 */
01620 
01621 static gchar *magic_uri(const gchar *uri)
01622 {
01623     LOGPRINTF("entry: %s", uri);
01624 
01625     gchar *result = NULL;
01626 
01627     g_return_val_if_fail(uri, NULL);
01628 
01629     // Just return if it's a javascript: uri 
01630     if (g_str_has_prefix(uri, "javascript:"))
01631     {
01632         return g_strdup(uri);
01633     }
01634     
01635     if (g_mountpoint)
01636     {
01637         // Add file://mountpoint if we have a local path on mountpoint
01638         gchar *path = g_strconcat(g_mountpoint, uri, NULL);
01639         if (g_file_test(path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
01640         {
01641             result = g_strconcat("file://", path, NULL);
01642             g_free(path);
01643             return result;
01644         }
01645         g_free(path);
01646     }
01647 
01648     // Add file:// if we have a local path
01649     if (g_path_is_absolute(uri))
01650     {
01651         return g_strconcat("file://", uri, NULL);
01652     }
01653 
01654     // Construct an absolute path if the file is relative
01655     if (g_file_test(uri, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
01656     {
01657       gchar *current_dir = g_get_current_dir();
01658         result = g_strconcat("file://", current_dir, G_DIR_SEPARATOR_S, uri, NULL);
01659         g_free(current_dir);
01660         return result;
01661     }
01662     
01663     // Do we need to add a protocol? 
01664     if (!strstr(uri, "://"))
01665     {
01666         // Do we have a domain, ip address or localhost? 
01667         gchar *search = strchr(uri, ':');
01668         if (search && search[0] && !g_ascii_isalpha(search[1]))
01669         {
01670             if (!strchr(search, '.'))
01671             {
01672                 return g_strconcat("http://", uri, NULL);
01673             }
01674         }
01675         
01676         if (!strcmp(uri, "localhost") || g_str_has_prefix(uri, "localhost/"))
01677         {
01678             return g_strconcat("http://", uri, NULL);
01679         }
01680         
01681         gchar** parts = g_strsplit(uri, ".", 0);
01682         if (!search && parts[0] && parts[1])
01683         {
01684             search = NULL;
01685             if (!(parts[1][1] == '\0' && !g_ascii_isalpha(parts[1][0])))
01686             {
01687                 if (!strchr(parts[0], ' ') && !strchr(parts[1], ' '))
01688                 {
01689                     search = g_strconcat("http://", uri, NULL);
01690                 }
01691             }
01692             g_free(parts);
01693             if (search)
01694             {
01695                 return search;
01696             }
01697         }
01698         return g_strdup(uri);
01699     }
01700     return g_strdup(uri);
01701 }
01702 
01703 
01704 static void set_browser_uri(const gchar *uri)
01705 {
01706     LOGPRINTF("entry");
01707     
01708     if (g_browser && uri)
01709     {
01710         LOGPRINTF("set uri [%s]", uri);
01711         g_free(g_browser->uri);
01712         g_browser->uri = g_strdup(uri);
01713     }
01714 }
01715 
01716 
01717 static void on_cancel(GtkWidget *widget, gpointer data)
01718 {
01719     LOGPRINTF("entry");
01720     webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(g_browser->web_view));
01721 }
01722 
01723 
01724 static void create_show_busy_loading()
01725 {
01726     busy_dialog = ergtk_busy_dialog_new(_("Loading page..."));
01727     cancel_button = gtk_button_new_with_label(_("Cancel"));
01728     gtk_dialog_add_action_widget(GTK_DIALOG(busy_dialog), cancel_button, GTK_RESPONSE_REJECT);
01729     g_signal_connect(G_OBJECT(cancel_button), "clicked", G_CALLBACK(on_cancel), NULL);
01730 }
01731 
01732 
01733 static gchar* get_file_content(const gchar* file_path)
01734 {
01735     gchar* contents = NULL;
01736     gsize  len      = 0;
01737 
01738     if (g_file_get_contents(file_path, &contents, &len, NULL) == FALSE)
01739     {
01740         return NULL;
01741     }
01742 
01743     // Remove trailing '\n' characters
01744     // End of string may have more than one \0 char
01745     while (len > 0 && (contents[len - 1] == '\n' || contents[len - 1] == '\0'))
01746     {
01747         contents[len - 1] = '\0';
01748         len--;
01749     }
01750     return contents;
01751 }
01752 
01753 
01754 static gchar* get_ebook_mall_home()
01755 {
01756     gchar* uri = NULL;
01757     gchar* serial = NULL;
01758     char hostname[100] = {0};
01759     int rc = gethostname(hostname, sizeof(hostname));
01760     if ((rc == 0) && (strcmp(hostname, "qemuarm") == 0))
01761     {
01762         // use bogus serial number when running emulator
01763         serial = g_strdup("DREMU-LATOR");
01764     }
01765     else
01766     {
01767         serial = get_file_content("/sys/devices/system/sysset/sysset0/fasm/serial");
01768     }
01769     
01770     uri = g_strconcat(EBOOK_MALL_HOME, serial, NULL);
01771     g_free(serial);
01772     return uri;
01773 }
Generated by  doxygen 1.6.2-20100208