/* $Id: surfer.c,v 1.60 2010/04/20 18:51:35 khorben Exp $ */ /* Copyright (c) 2010 Pierre Pronchery */ /* This file is part of DeforaOS Desktop Surfer */ /* Surfer is free software; you can redistribute it and/or modify it under the * terms of the GNU General Public License version 2 as published by the Free * Software Foundation. * * Surfer is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * Surfer; if not, write to the Free Software Foundation, Inc., 59 Temple Place, * Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #include #include #include #include "callbacks.h" #include "ghtml.h" #include "surfer.h" #include "common.h" #define _(string) gettext(string) #define N_(string) (string) /* Surfer */ /* private */ /* types */ typedef struct _SurferIdle { Surfer * surfer; char * url; } SurferIdle; /* variables */ static DesktopAccel _surfer_accel[] = { #ifdef EMBEDDED /* FIXME implement the missing accelerators in embedded mode */ { G_CALLBACK(on_refresh), GDK_CONTROL_MASK, GDK_R }, { G_CALLBACK(on_close), GDK_CONTROL_MASK, GDK_W }, #endif { G_CALLBACK(on_fullscreen), 0, GDK_F11 }, { NULL, 0, 0 } }; #ifndef EMBEDDED static DesktopMenu _menu_file[] = { { N_("_New tab"), G_CALLBACK(on_file_new_tab), "tab-new", GDK_T }, { N_("_New window"), G_CALLBACK(on_file_new_window), "window-new", GDK_N }, { N_("_Open..."), G_CALLBACK(on_file_open), GTK_STOCK_OPEN, GDK_O }, { N_("_Open URL..."), G_CALLBACK(on_file_open_url), NULL, GDK_L }, { "", NULL, NULL, 0 }, { N_("Save _as..."), G_CALLBACK(on_file_save_as), GTK_STOCK_SAVE_AS, GDK_S }, { "", NULL, NULL, 0 }, { N_("_Print..."), G_CALLBACK(on_file_print), GTK_STOCK_PRINT, 0 }, { "", NULL, NULL, 0 }, { N_("Close _tab"), G_CALLBACK(on_file_close_tab), NULL, GDK_W }, { N_("_Close"), G_CALLBACK(on_file_close), GTK_STOCK_CLOSE, 0 }, { NULL, NULL, NULL, 0 } }; static DesktopMenu _menu_edit[] = { { N_("_Cut"), NULL, GTK_STOCK_CUT, GDK_X }, { N_("Cop_y"), NULL, GTK_STOCK_COPY, GDK_C }, { N_("_Paste"), NULL, GTK_STOCK_PASTE, GDK_V }, { "", NULL, NULL, 0 }, { N_("Select _all"), G_CALLBACK(on_edit_select_all), #if GTK_CHECK_VERSION(2, 10, 0) GTK_STOCK_SELECT_ALL, #else NULL, #endif GDK_A }, { N_("Unselect all"), G_CALLBACK(on_edit_unselect_all), NULL, 0 }, { "", NULL, NULL, 0 }, { N_("_Find"), G_CALLBACK(on_edit_find), GTK_STOCK_FIND, GDK_F }, { "", NULL, NULL, 0 }, { N_("_Preferences"), G_CALLBACK(on_edit_preferences), GTK_STOCK_PREFERENCES, GDK_P }, { NULL, NULL, NULL, 0 } }; static DesktopMenu _menu_view[] = { { N_("Zoom in"), G_CALLBACK(on_view_zoom_in), "zoom-in", GDK_plus }, { N_("Zoom out"), G_CALLBACK(on_view_zoom_out), "zoom-out", GDK_minus }, { N_("Normal size"), G_CALLBACK(on_view_normal_size), "zoom-1", GDK_0 }, { "", NULL, NULL, 0 }, { N_("_Refresh"), G_CALLBACK(on_view_refresh), GTK_STOCK_REFRESH, GDK_R }, { N_("_Force refresh"), G_CALLBACK(on_view_force_refresh), NULL, 0 }, { N_("_Stop"), G_CALLBACK(on_view_stop), GTK_STOCK_STOP, 0 }, { "", NULL, NULL, 0 }, { N_("Page so_urce"), G_CALLBACK(on_view_page_source), "stock_view-html-source", GDK_U }, { NULL, NULL, NULL, 0 } }; static DesktopMenu _menu_help[] = { { "_About", G_CALLBACK(on_help_about), #if GTK_CHECK_VERSION(2, 6, 0) GTK_STOCK_ABOUT, 0 }, #else NULL, 0 }, #endif { NULL, NULL, NULL, 0 } }; static DesktopMenubar _surfer_menubar[] = { { N_("_File"), _menu_file }, { N_("_Edit"), _menu_edit }, { N_("_View"), _menu_view }, { N_("_Help"), _menu_help }, { NULL, NULL } }; #endif /* !EMBEDDED */ static DesktopToolbar _surfer_toolbar[] = { { "Back", G_CALLBACK(on_back), GTK_STOCK_GO_BACK, 0, NULL }, { "Forward", G_CALLBACK(on_forward), GTK_STOCK_GO_FORWARD, 0, NULL }, { "Stop", G_CALLBACK(on_stop), GTK_STOCK_STOP, 0, NULL }, { "Refresh", G_CALLBACK(on_refresh), GTK_STOCK_REFRESH, 0, NULL }, { "", NULL, NULL, 0, NULL }, { "Home", G_CALLBACK(on_home), GTK_STOCK_HOME, 0, NULL }, { NULL, NULL, NULL, 0, NULL } }; unsigned int surfer_cnt = 0; /* prototypes */ static char * _config_get_filename(void); static int _config_load_string(Config * config, char const * variable, char ** value); static int _config_save_string(Config * config, char const * variable, char const * value); /* public */ /* functions */ /* surfer_new */ static Surfer * _new_do(char const * url); static gboolean _new_idle(gpointer data); Surfer * surfer_new(char const * url) { Surfer * surfer; SurferIdle * si; if((surfer = _new_do(url)) == NULL) return NULL; gtk_widget_show(surfer->window); /* load url as soon as we're idle */ if((si = malloc(sizeof(*si))) == NULL || (url != NULL && (si->url = strdup(url)) == NULL)) { free(si); surfer_delete(surfer); return NULL; } si->surfer = surfer; if(url == NULL) si->url = NULL; g_idle_add(_new_idle, si); return surfer; } Surfer * _new_do(char const * url) { Surfer * surfer; GtkAccelGroup * group; GtkWidget * vbox; GtkWidget * toolbar; GtkToolItem * toolitem; GtkWidget * widget; if((surfer = malloc(sizeof(*surfer))) == NULL) return NULL; surfer->homepage = NULL; if((surfer->config = config_new()) == NULL || surfer_config_load(surfer) != 0) { surfer_delete(surfer); return NULL; } /* widgets */ /* window */ group = gtk_accel_group_new(); surfer->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_add_accel_group(GTK_WINDOW(surfer->window), group); gtk_window_set_default_size(GTK_WINDOW(surfer->window), 800, 600); #if GTK_CHECK_VERSION(2, 6, 0) gtk_window_set_icon_name(GTK_WINDOW(surfer->window), "stock_internet"); #endif gtk_window_set_title(GTK_WINDOW(surfer->window), "Surfer"); g_signal_connect_swapped(G_OBJECT(surfer->window), "delete-event", G_CALLBACK(on_closex), surfer); vbox = gtk_vbox_new(FALSE, 0); #ifndef EMBEDDED /* menubar */ surfer->menubar = desktop_menubar_create(_surfer_menubar, surfer, group); gtk_box_pack_start(GTK_BOX(vbox), surfer->menubar, FALSE, FALSE, 0); #endif desktop_accel_create(_surfer_accel, surfer, group); /* toolbar */ toolbar = desktop_toolbar_create(_surfer_toolbar, surfer, group); surfer->toolbar = toolbar; surfer->tb_back = _surfer_toolbar[0].widget; surfer->tb_forward = _surfer_toolbar[1].widget; surfer->tb_stop = _surfer_toolbar[2].widget; gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_stop), FALSE); surfer->tb_refresh = _surfer_toolbar[3].widget; gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_refresh), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_back), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_forward), FALSE); #if GTK_CHECK_VERSION(2, 8, 0) toolitem = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_FULLSCREEN); #else toolitem = gtk_toggle_tool_button_new_from_stock(GTK_STOCK_ZOOM_FIT); #endif surfer->tb_fullscreen = toolitem; g_signal_connect_swapped(G_OBJECT(toolitem), "toggled", G_CALLBACK( on_fullscreen), surfer); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); #ifdef EMBEDDED toolitem = gtk_separator_tool_item_new(); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_PREFERENCES); g_signal_connect_swapped(G_OBJECT(toolitem), "clicked", G_CALLBACK( on_preferences), surfer); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); #endif /* EMBEDDED */ gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, TRUE, 0); /* toolbar */ toolbar = gtk_toolbar_new(); surfer->locationbar = toolbar; gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); #ifndef EMBEDDED toolitem = gtk_tool_item_new(); widget = gtk_label_new(_(" Location: ")); gtk_container_add(GTK_CONTAINER(toolitem), widget); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); #endif toolitem = gtk_tool_item_new(); surfer->lb_path = gtk_combo_box_entry_new_text(); widget = gtk_bin_get_child(GTK_BIN(surfer->lb_path)); g_signal_connect_swapped(G_OBJECT(widget), "activate", G_CALLBACK( on_path_activate), surfer); if(url != NULL) gtk_entry_set_text(GTK_ENTRY(widget), url); gtk_tool_item_set_expand(toolitem, TRUE); gtk_container_add(GTK_CONTAINER(toolitem), surfer->lb_path); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_JUMP_TO); g_signal_connect_swapped(G_OBJECT(toolitem), "clicked", G_CALLBACK( on_path_activate), surfer); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); /* notebook */ surfer->notebook = gtk_notebook_new(); gtk_notebook_set_show_border(GTK_NOTEBOOK(surfer->notebook), FALSE); gtk_notebook_set_show_tabs(GTK_NOTEBOOK(surfer->notebook), FALSE); g_signal_connect_swapped(G_OBJECT(surfer->notebook), "switch-page", G_CALLBACK(on_notebook_switch_page), surfer); gtk_box_pack_start(GTK_BOX(vbox), surfer->notebook, TRUE, TRUE, 0); /* statusbar */ surfer->statusbox = gtk_hbox_new(FALSE, 0); surfer->progress = gtk_progress_bar_new(); gtk_box_pack_start(GTK_BOX(surfer->statusbox), surfer->progress, FALSE, FALSE, 0); surfer->statusbar = gtk_statusbar_new(); surfer->statusbar_id = 0; gtk_box_pack_start(GTK_BOX(surfer->statusbox), surfer->statusbar, TRUE, TRUE, 0); gtk_widget_show_all(surfer->statusbox); gtk_container_add(GTK_CONTAINER(surfer->window), vbox); gtk_widget_grab_focus(GTK_WIDGET(surfer->lb_path)); gtk_widget_show_all(vbox); /* preferences window */ surfer->pr_window = NULL; /* find dialog */ surfer->fi_dialog = NULL; /* hack to display the statusbar only if necessary */ gtk_box_pack_start(GTK_BOX(vbox), surfer->statusbox, FALSE, FALSE, 0); surfer_set_status(surfer, NULL); surfer_cnt++; return surfer; } static gboolean _new_idle(gpointer data) { SurferIdle * si = data; surfer_open_tab(si->surfer, si->url); free(si->url); free(si); return FALSE; } /* surfer_new_copy */ Surfer * surfer_new_copy(Surfer * surfer) { Surfer * ret; GtkWidget * view; char const * url; if((view = surfer_get_view(surfer)) == NULL) url = NULL; else url = ghtml_get_location(view); if((ret = surfer_new(url)) == NULL) return NULL; /* FIXME also copy history */ return ret; } /* surfer_delete */ void surfer_delete(Surfer * surfer) { gtk_widget_destroy(surfer->window); config_delete(surfer->config); free(surfer->homepage); free(surfer); if(--surfer_cnt == 0) gtk_main_quit(); } /* accessors */ /* surfer_get_view */ GtkWidget * surfer_get_view(Surfer * surfer) { int cur; if((cur = gtk_notebook_get_current_page(GTK_NOTEBOOK(surfer->notebook))) < 0) return NULL; return gtk_notebook_get_nth_page(GTK_NOTEBOOK(surfer->notebook), cur); } /* surfer_set_fullscreen */ void surfer_set_fullscreen(Surfer * surfer, gboolean fullscreen) { if(fullscreen == TRUE) gtk_window_fullscreen(GTK_WINDOW(surfer->window)); else gtk_window_unfullscreen(GTK_WINDOW(surfer->window)); } /* surfer_set_location */ void surfer_set_location(Surfer * surfer, char const * url) { static int i = 0; /* XXX should be set per-window */ GtkWidget * widget; GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; /* consider the current tab only */ url = ghtml_get_location(view); if(url == NULL) url = ""; widget = gtk_bin_get_child(GTK_BIN(surfer->lb_path)); gtk_entry_set_text(GTK_ENTRY(widget), url); if(i == 8) gtk_combo_box_remove_text(GTK_COMBO_BOX(surfer->lb_path), 0); else i++; gtk_combo_box_append_text(GTK_COMBO_BOX(surfer->lb_path), url); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_back), ghtml_can_go_back( view)); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_forward), ghtml_can_go_forward(view)); } /* surfer_set_progress */ void surfer_set_progress(Surfer * surfer, gdouble fraction) { GtkWidget * view; char buf[10] = " "; if((view = surfer_get_view(surfer)) == NULL) return; /* consider the current tab only */ fraction = ghtml_get_progress(view); if(fraction >= 0.0 && fraction <= 1.0) snprintf(buf, sizeof(buf), "%.1f%%", fraction * 100); else fraction = 0.0; gtk_progress_bar_set_text(GTK_PROGRESS_BAR(surfer->progress), buf); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(surfer->progress), fraction); } /* surfer_set_status */ void surfer_set_status(Surfer * surfer, char const * status) { GtkWidget * view; GtkStatusbar * sb = GTK_STATUSBAR(surfer->statusbar); GtkProgressBar * pb = GTK_PROGRESS_BAR(surfer->progress); if((view = surfer_get_view(surfer)) == NULL) return; /* consider the current tab only */ status = ghtml_get_status(view); if(surfer->statusbar_id != 0) gtk_statusbar_remove(sb, gtk_statusbar_get_context_id(sb, ""), surfer->statusbar_id); surfer->statusbar_id = gtk_statusbar_push(sb, gtk_statusbar_get_context_id(sb, ""), (status != NULL) ? status : "Ready"); if(status == NULL) gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_stop), FALSE); if(status == NULL) { gtk_progress_bar_set_text(pb, " "); gtk_progress_bar_set_fraction(pb, 0.0); #ifdef EMBEDDED gtk_widget_hide(surfer->statusbox); } else { gtk_widget_show(surfer->statusbox); #endif } } /* surfer_set_title */ void surfer_set_title(Surfer * surfer, char const * title) { GtkWidget * view; char buf[256]; if((view = surfer_get_view(surfer)) == NULL) return; /* consider the current tab only */ title = ghtml_get_title(view); snprintf(buf, sizeof(buf), "%s%s%s", "Web surfer", (title != NULL) ? " - " : "", (title != NULL) ? title : ""); gtk_window_set_title(GTK_WINDOW(surfer->window), buf); } /* useful */ /* surfer_close_tab */ void surfer_close_tab(Surfer * surfer) { gint n; GtkWidget * view; if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(surfer->notebook)) == 1) { surfer_delete(surfer); return; } n = gtk_notebook_get_current_page(GTK_NOTEBOOK(surfer->notebook)); view = gtk_notebook_get_nth_page(GTK_NOTEBOOK(surfer->notebook), n); ghtml_delete(view); gtk_notebook_remove_page(GTK_NOTEBOOK(surfer->notebook), n); if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(surfer->notebook)) == 1) gtk_notebook_set_show_tabs(GTK_NOTEBOOK(surfer->notebook), FALSE); } /* surfer_config_load */ int surfer_config_load(Surfer * surfer) { char * filename; if((filename = _config_get_filename()) == NULL) return 1; config_load(surfer->config, filename); /* XXX ignore errors */ free(filename); _config_load_string(surfer->config, "homepage", &surfer->homepage); return 0; } /* surfer_config_save */ int surfer_config_save(Surfer * surfer) { int ret = 0; char * filename; if((filename = _config_get_filename()) == NULL) return 1; ret |= _config_save_string(surfer->config, "homepage", surfer->homepage); if(ret == 0) ret |= config_save(surfer->config, filename); free(filename); return ret; } /* surfer_confirm */ int surfer_confirm(Surfer * surfer, char const * message) { int ret; GtkWidget * dialog; dialog = gtk_message_dialog_new((surfer != NULL) ? GTK_WINDOW(surfer->window) : NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO, "%s", _("Question")); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", message); gtk_window_set_title(GTK_WINDOW(dialog), _("Question")); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK( gtk_widget_destroy), NULL); ret = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return (ret == GTK_RESPONSE_YES) ? 1 : 0; } /* surfer_download */ void surfer_download(Surfer * surfer, char const * url, char const * suggested) { GtkWidget * dialog; char * filename = NULL; char * argv[] = { "download", "-O", NULL, NULL, NULL }; GError * error = NULL; dialog = gtk_file_chooser_dialog_new(_("Save file as..."), GTK_WINDOW(surfer->window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); if(suggested != NULL) /* XXX also suggest a name otherwise */ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), suggested); if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER( dialog)); gtk_widget_destroy(dialog); if(filename == NULL) return; argv[2] = filename; argv[3] = strdup(url); /* XXX may fail */ g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); free(argv[3]); g_free(filename); } /* surfer_error */ int surfer_error(Surfer * surfer, char const * message, int ret) { GtkWidget * dialog; dialog = gtk_message_dialog_new((surfer != NULL) ? GTK_WINDOW(surfer->window) : NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", _("Error")); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", (message != NULL) ? message : _("Unknown error")); gtk_window_set_title(GTK_WINDOW(dialog), _("Error")); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK( gtk_widget_destroy), NULL); gtk_widget_show(dialog); return ret; } /* surfer_find */ static void _find_dialog(Surfer * surfer); static void _on_find_activate(GtkWidget * widget, gpointer data); static void _on_find_response(GtkWidget * widget, gint response, gpointer data); void surfer_find(Surfer * surfer, char const * text) { if(surfer->fi_dialog == NULL) _find_dialog(surfer); gtk_entry_set_text(GTK_ENTRY(surfer->fi_text), (text != NULL) ? text : ""); gtk_widget_show(surfer->fi_dialog); } static void _find_dialog(Surfer * surfer) { GtkWidget * vbox; GtkWidget * hbox; GtkWidget * widget; surfer->fi_dialog = gtk_dialog_new_with_buttons(_("Find text"), GTK_WINDOW(surfer->window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, GTK_STOCK_FIND, GTK_RESPONSE_ACCEPT, NULL); vbox = GTK_DIALOG(surfer->fi_dialog)->vbox; hbox = gtk_hbox_new(FALSE, 0); widget = gtk_label_new(_("Text:")); gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); surfer->fi_text = gtk_entry_new(); g_signal_connect(G_OBJECT(surfer->fi_text), "activate", G_CALLBACK( _on_find_activate), surfer); gtk_box_pack_start(GTK_BOX(hbox), surfer->fi_text, TRUE, TRUE, 4); gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 4); surfer->fi_case = gtk_check_button_new_with_label(_("Case-sensitive")); gtk_box_pack_start(GTK_BOX(vbox), surfer->fi_case, TRUE, TRUE, 4); surfer->fi_wrap = gtk_check_button_new_with_label(_("Wrap")); gtk_box_pack_start(GTK_BOX(vbox), surfer->fi_wrap, TRUE, TRUE, 4); gtk_widget_show_all(vbox); g_signal_connect(G_OBJECT(surfer->fi_dialog), "response", G_CALLBACK( _on_find_response), surfer); } static void _on_find_activate(GtkWidget * widget, gpointer data) { Surfer * surfer = data; GtkWidget * view; char const * text; gboolean sensitive; gboolean wrap; if((view = surfer_get_view(surfer)) == NULL) return; if((text = gtk_entry_get_text(GTK_ENTRY(widget))) == NULL || strlen(text) == 0) return; sensitive = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( surfer->fi_case)); wrap = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( surfer->fi_wrap)); if(ghtml_find(view, text, sensitive, wrap) == TRUE) return; surfer_error(surfer, _("Text not found"), 0); } static void _on_find_response(GtkWidget * widget, gint response, gpointer data) { Surfer * surfer = data; if(response != GTK_RESPONSE_ACCEPT) { gtk_widget_hide(widget); if(response == GTK_RESPONSE_DELETE_EVENT) surfer->fi_dialog = NULL; return; } _on_find_activate(surfer->fi_text, surfer); } /* surfer_go_back */ gboolean surfer_go_back(Surfer * surfer) { gboolean ret; GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return FALSE; gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_stop), TRUE); ret = ghtml_go_back(view); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_back), ret); return ret; } /* surfer_go_forward */ gboolean surfer_go_forward(Surfer * surfer) { gboolean ret; GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return FALSE; gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_stop), TRUE); ret = ghtml_go_forward(view); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_forward), ret); return ret; } /* surfer_go_home */ void surfer_go_home(Surfer * surfer) { char const * homepage; if((homepage = config_get(surfer->config, "", "homepage")) == NULL) homepage = SURFER_DEFAULT_HOME; surfer_open(surfer, homepage); } /* surfer_open */ void surfer_open(Surfer * surfer, char const * url) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) { surfer_open_tab(surfer, url); return; } if(url != NULL) { view = surfer_get_view(surfer); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_refresh), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_stop), TRUE); ghtml_stop(view); ghtml_load_url(view, url); } else gtk_widget_grab_focus(surfer->lb_path); } /* surfer_open_dialog */ void surfer_open_dialog(Surfer * surfer) { GtkWidget * dialog; char * filename = NULL; dialog = gtk_file_chooser_dialog_new(_("Open file..."), GTK_WINDOW(surfer->window), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER( dialog)); gtk_widget_destroy(dialog); if(filename == NULL) return; surfer_open(surfer, filename); g_free(filename); } /* surfer_open_tab */ static GtkWidget * _tab_button(Surfer * surfer, char const * label); void surfer_open_tab(Surfer * surfer, char const * url) { GtkWidget * widget; if((widget = ghtml_new(surfer)) == NULL) { surfer_error(NULL, _("Could not initialize HTML renderer"), 0); return; } if(url != NULL) ghtml_load_url(widget, url); gtk_notebook_append_page(GTK_NOTEBOOK(surfer->notebook), widget, _tab_button(surfer, _("Untitled"))); if(gtk_notebook_get_n_pages(GTK_NOTEBOOK(surfer->notebook)) > 1) gtk_notebook_set_show_tabs(GTK_NOTEBOOK(surfer->notebook), TRUE); gtk_widget_show_all(widget); } static GtkWidget * _tab_button(Surfer * surfer, char const * label) { GtkWidget * hbox; GtkWidget * button; hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(label), TRUE, TRUE, 4); button = gtk_button_new(); gtk_button_set_image(GTK_BUTTON(button), gtk_image_new_from_stock( GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU)); gtk_button_set_relief(GTK_BUTTON(button), GTK_RELIEF_NONE); g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK( on_notebook_close_tab), surfer); gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, TRUE, 0); gtk_widget_show_all(hbox); return hbox; } /* surfer_print */ void surfer_print(Surfer * surfer) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; ghtml_print(view); } /* surfer_refresh */ void surfer_refresh(Surfer * surfer) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_stop), TRUE); ghtml_refresh(view); } /* surfer_reload */ void surfer_reload(Surfer * surfer) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_stop), TRUE); ghtml_reload(view); } /* surfer_resize */ void surfer_resize(Surfer * surfer, gint width, gint height) { gtk_window_resize(GTK_WINDOW(surfer->window), width, height); } /* surfer_save */ void surfer_save(Surfer * surfer, char const * filename) { GtkWidget * view; char const * source; GtkWidget * dialog; size_t len; FILE * fp; char buf[256]; if((view = surfer_get_view(surfer)) == NULL) return; if((source = ghtml_get_source(view)) == NULL) return; /* XXX report error */ if(filename == NULL) { dialog = gtk_file_chooser_dialog_new(_("Save file as..."), GTK_WINDOW(surfer->window), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) filename = gtk_file_chooser_get_filename( GTK_FILE_CHOOSER(dialog)); gtk_widget_destroy(dialog); if(filename == NULL) return; } if((fp = fopen(filename, "w")) == NULL) /* XXX use GIOChannel instead */ { snprintf(buf, sizeof(buf), "%s: %s", filename, strerror(errno)); surfer_error(surfer, buf, 0); return; } len = strlen(source); if(fwrite(source, sizeof(*source), len, fp) != len) { snprintf(buf, sizeof(buf), "%s: %s", filename, strerror(errno)); surfer_error(surfer, buf, 0); } fclose(fp); } /* surfer_select_all */ void surfer_select_all(Surfer * surfer) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; ghtml_select_all(view); } /* surfer_show_menubar */ void surfer_show_menubar(Surfer * surfer, gboolean show) { #ifndef EMBEDDED if(show == TRUE) gtk_widget_show(surfer->menubar); else gtk_widget_hide(surfer->menubar); #endif } /* surfer_show_statusbar */ void surfer_show_statusbar(Surfer * surfer, gboolean show) { if(show == TRUE) gtk_widget_show(surfer->statusbar); else gtk_widget_hide(surfer->statusbar); } /* surfer_show_toolbar */ void surfer_show_toolbar(Surfer * surfer, gboolean show) { if(show == TRUE) { gtk_widget_show(surfer->toolbar); gtk_widget_show(surfer->locationbar); } else { gtk_widget_hide(surfer->toolbar); gtk_widget_hide(surfer->locationbar); } } /* surfer_show_window */ void surfer_show_window(Surfer * surfer, gboolean show) { if(show == TRUE) gtk_widget_show(surfer->window); else gtk_widget_hide(surfer->window); } /* surfer_stop */ void surfer_stop(Surfer * surfer) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; ghtml_stop(view); } /* surfer_unselect_all */ void surfer_unselect_all(Surfer * surfer) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; ghtml_unselect_all(view); } /* surfer_view_source */ static void _on_source_close(GtkWidget * widget); static gboolean _on_source_closex(void); void surfer_view_source(Surfer * surfer) { GtkAccelGroup * group; GClosure * cc; GtkWidget * window; GtkWidget * scrolled; GtkWidget * widget; GtkTextBuffer * tbuf; PangoFontDescription * desc; char buf[256]; char const * url; char const * source; if((widget = surfer_get_view(surfer)) == NULL) return; if((url = ghtml_get_location(widget)) == NULL) return; if((source = ghtml_get_source(widget)) == NULL) return; /* FIXME download to a temporary file and open */ window = gtk_window_new(GTK_WINDOW_TOPLEVEL); group = gtk_accel_group_new(); cc = g_cclosure_new_swap(G_CALLBACK(_on_source_close), window, NULL); gtk_accel_group_connect(group, GDK_W, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE, cc); gtk_window_add_accel_group(GTK_WINDOW(window), group); gtk_window_set_default_size(GTK_WINDOW(window), 640, 480); snprintf(buf, sizeof(buf), "%s%s", _("Web surfer - Source of "), url); gtk_window_set_title(GTK_WINDOW(window), buf); g_signal_connect(G_OBJECT(window), "delete-event", G_CALLBACK( _on_source_closex), NULL); scrolled = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); widget = gtk_text_view_new(); desc = pango_font_description_new(); pango_font_description_set_family(desc, "monospace"); gtk_widget_modify_font(widget, desc); pango_font_description_free(desc); gtk_text_view_set_editable(GTK_TEXT_VIEW(widget), FALSE); tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); /* FIXME probably should convert to UTF-8 when not already */ gtk_text_buffer_set_text(tbuf, source, strlen(source)); gtk_container_add(GTK_CONTAINER(scrolled), widget); gtk_container_add(GTK_CONTAINER(window), scrolled); gtk_widget_show_all(window); } static void _on_source_close(GtkWidget * widget) { gtk_widget_destroy(widget); } static gboolean _on_source_closex(void) { return FALSE; } /* surfer_warning */ void surfer_warning(Surfer * surfer, char const * message) { GtkWidget * dialog; dialog = gtk_message_dialog_new((surfer != NULL) ? GTK_WINDOW(surfer->window) : NULL, GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", _("Warning")); gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", message); gtk_window_set_title(GTK_WINDOW(dialog), _("Warning")); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK( gtk_widget_destroy), NULL); gtk_widget_show(dialog); } /* surfer_zoom_in */ void surfer_zoom_in(Surfer * surfer) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; ghtml_zoom_in(view); } /* surfer_zoom_out */ void surfer_zoom_out(Surfer * surfer) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; ghtml_zoom_out(view); } /* surfer_zoom_reset */ void surfer_zoom_reset(Surfer * surfer) { GtkWidget * view; if((view = surfer_get_view(surfer)) == NULL) return; ghtml_zoom_reset(view); } /* private */ /* functions */ static char * _config_get_filename(void) { char const * homedir; size_t len; char * filename; if((homedir = getenv("HOME")) == NULL) homedir = g_get_home_dir(); len = strlen(homedir) + 1 + sizeof(SURFER_CONFIG_FILE); if((filename = malloc(len)) == NULL) return NULL; snprintf(filename, len, "%s/%s", homedir, SURFER_CONFIG_FILE); return filename; } static int _config_load_string(Config * config, char const * variable, char ** value) { char const * str; char * p; if((str = config_get(config, "", variable)) == NULL) return 0; if((p = strdup(str)) == NULL) return 1; free(*value); *value = p; return 0; } static int _config_save_string(Config * config, char const * variable, char const * value) { return config_set(config, "", variable, value); }