/* $Id: surfer.c,v 1.18 2009/03/29 01:06:56 khorben Exp $ */ /* Copyright (c) 2009 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 */ /* FIXME: * - disabling the menubar with FOR_EMBEDDED also disables accelerators */ #include #include #include #include "callbacks.h" #include "ghtml.h" #include "surfer.h" /* Surfer */ /* types */ #ifndef FOR_EMBEDDED struct _menu { char * name; GtkSignalFunc callback; char * stock; unsigned int accel; /* FIXME doesn't work */ }; struct _menubar { char * name; struct _menu * menu; }; /* variables */ static struct _menu _menu_file[] = { { "_New window", G_CALLBACK(on_file_new_window), "window-new", GDK_N }, { "_Open...", G_CALLBACK(on_file_open), GTK_STOCK_OPEN, GDK_O }, { "_Open URL...", G_CALLBACK(on_file_open_url), NULL, GDK_L }, { "", NULL, NULL, 0 }, { "_Close", G_CALLBACK(on_file_close), GTK_STOCK_CLOSE, GDK_W }, { NULL, NULL, NULL, 0 } }; static struct _menu _menu_edit[] = { { "_Cut", NULL, GTK_STOCK_CUT, GDK_X }, { "Cop_y", NULL, GTK_STOCK_COPY, GDK_C }, { "_Paste", NULL, GTK_STOCK_PASTE, GDK_V }, { "", NULL, NULL, 0 }, { "Select _all", G_CALLBACK(on_edit_select_all), GTK_STOCK_SELECT_ALL, GDK_A }, { "Unselect all", G_CALLBACK(on_edit_unselect_all), NULL, 0 }, { "", NULL, NULL, 0 }, { "_Preferences", G_CALLBACK(on_edit_preferences), GTK_STOCK_PREFERENCES, GDK_P }, { NULL, NULL, NULL, 0 } }; static struct _menu _menu_view[] = { { "Zoom in", G_CALLBACK(on_view_zoom_in), "zoom-in", GDK_plus }, { "Zoom out", G_CALLBACK(on_view_zoom_out), "zoom-out", GDK_minus }, { "Normal size", G_CALLBACK(on_view_normal_size), "zoom-1", GDK_0 }, { "", NULL, NULL, 0 }, { "_Refresh", G_CALLBACK(on_view_refresh), GTK_STOCK_REFRESH, GDK_R }, { "_Force refresh", G_CALLBACK(on_view_force_refresh), NULL, 0 }, { "_Stop", G_CALLBACK(on_view_stop), GTK_STOCK_STOP, 0 }, { "", NULL, NULL, 0 }, { "Page so_urce", G_CALLBACK(on_view_page_source), "stock_view-html-source", GDK_U }, { NULL, NULL, NULL, 0 } }; static struct _menu _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 struct _menubar _menubar[] = { { "_File", _menu_file }, { "_Edit", _menu_edit }, { "_View", _menu_view }, { "_Help", _menu_help }, { NULL, NULL } }; #endif /* !FOR_EMBEDDED */ unsigned int surfer_cnt = 0; /* functions */ /* surfer_new */ #ifndef FOR_EMBEDDED static GtkWidget * _new_menubar(Surfer * surfer); #endif static gboolean _new_idle(gpointer data); Surfer * surfer_new(char const * url) { Surfer * surfer; GtkWidget * vbox; GtkWidget * toolbar; GtkToolItem * toolitem; GtkWidget * widget; if((surfer = malloc(sizeof(*surfer))) == NULL) return NULL; /* window */ surfer->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(surfer->window), 800, 600); surfer_set_title(surfer, NULL); g_signal_connect(G_OBJECT(surfer->window), "delete_event", G_CALLBACK( on_closex), surfer); vbox = gtk_vbox_new(FALSE, 0); #ifndef FOR_EMBEDDED /* menubar */ surfer->menubar = _new_menubar(surfer); gtk_box_pack_start(GTK_BOX(vbox), surfer->menubar, FALSE, FALSE, 0); #endif /* toolbar */ toolbar = gtk_toolbar_new(); surfer->tb_back = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK); g_signal_connect(G_OBJECT(surfer->tb_back), "clicked", G_CALLBACK( on_back), surfer); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_back), FALSE); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), surfer->tb_back, -1); surfer->tb_forward = gtk_tool_button_new_from_stock( GTK_STOCK_GO_FORWARD); g_signal_connect(G_OBJECT(surfer->tb_forward), "clicked", G_CALLBACK( on_forward), surfer); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_forward), FALSE); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), surfer->tb_forward, -1); surfer->tb_stop = gtk_tool_button_new_from_stock(GTK_STOCK_STOP); g_signal_connect(G_OBJECT(surfer->tb_stop), "clicked", G_CALLBACK( on_stop), surfer); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), surfer->tb_stop, -1); surfer->tb_refresh = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH); g_signal_connect(G_OBJECT(surfer->tb_refresh), "clicked", G_CALLBACK( on_refresh), surfer); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), surfer->tb_refresh, -1); toolitem = gtk_separator_tool_item_new(); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_HOME); g_signal_connect(G_OBJECT(toolitem), "clicked", G_CALLBACK(on_home), surfer); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); #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 g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK( on_fullscreen), surfer); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); /* toolbar */ toolbar = gtk_toolbar_new(); gtk_toolbar_set_icon_size(GTK_TOOLBAR(toolbar), GTK_ICON_SIZE_SMALL_TOOLBAR); gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS); #ifndef FOR_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->tb_path = gtk_combo_box_entry_new_text(); widget = gtk_bin_get_child(GTK_BIN(surfer->tb_path)); g_signal_connect(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->tb_path); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_JUMP_TO); g_signal_connect(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); /* view */ if((surfer->view = ghtml_new(surfer)) == NULL) { surfer_error(NULL, "Could not initialize HTML renderer", 0); surfer_delete(surfer); return NULL; } gtk_box_pack_start(GTK_BOX(vbox), surfer->view, 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->tb_path)); gtk_widget_show_all(surfer->window); /* 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++; /* load url as soon as we're idle */ if(url != NULL) { g_object_set_data(G_OBJECT(surfer->window), "url", g_strdup(url)); /* XXX a bit ugly */ g_idle_add(_new_idle, surfer); } return surfer; } #ifndef FOR_EMBEDDED static GtkWidget * _new_menubar(Surfer * surfer) { GtkWidget * tb_menubar; GtkAccelGroup * group; GtkWidget * menu; GtkWidget * menubar; GtkWidget * menuitem; GtkWidget * image; unsigned int i; unsigned int j; struct _menu * p; tb_menubar = gtk_menu_bar_new(); group = gtk_accel_group_new(); for(i = 0; _menubar[i].name != NULL; i++) { menubar = gtk_menu_item_new_with_mnemonic(_menubar[i].name); menu = gtk_menu_new(); for(j = 0; _menubar[i].menu[j].name != NULL; j++) { p = &_menubar[i].menu[j]; if(p->name[0] == '\0') menuitem = gtk_separator_menu_item_new(); else if(p->stock == 0) menuitem = gtk_menu_item_new_with_mnemonic( p->name); else if(strncmp(p->stock, "gtk-", 4) == 0) menuitem = gtk_image_menu_item_new_from_stock( p->stock, NULL); else { image = gtk_image_new_from_icon_name(p->stock, GTK_ICON_SIZE_MENU); menuitem = gtk_image_menu_item_new_with_mnemonic( p->name); gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(menuitem), image); } if(p->callback != NULL) g_signal_connect(G_OBJECT(menuitem), "activate", G_CALLBACK(p->callback), surfer); else gtk_widget_set_sensitive(menuitem, FALSE); if(p->accel != 0) gtk_widget_add_accelerator(menuitem, "activate", group, p->accel, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE); gtk_menu_shell_append(GTK_MENU_SHELL(menu), menuitem); } gtk_menu_item_set_submenu(GTK_MENU_ITEM(menubar), menu); gtk_menu_bar_append(GTK_MENU_BAR(tb_menubar), menubar); } gtk_window_add_accel_group(GTK_WINDOW(surfer->window), group); return tb_menubar; } #endif /* !FOR_EMBEDDED */ static gboolean _new_idle(gpointer data) { Surfer * surfer = data; gchar * url; url = g_object_get_data(G_OBJECT(surfer->window), "url"); ghtml_load_url(surfer->view, url); g_free(url); return FALSE; } /* surfer_delete */ void surfer_delete(Surfer * surfer) { /* config_delete(surfer->config); */ free(surfer); surfer_cnt--; } /* accessors */ /* surfer_set_location */ void surfer_set_location(Surfer * surfer, char const * url) { static int i = 0; /* XXX should be set per-window */ GtkWidget * widget; widget = gtk_bin_get_child(GTK_BIN(surfer->tb_path)); gtk_entry_set_text(GTK_ENTRY(widget), url); if(i == 8) gtk_combo_box_remove_text(GTK_COMBO_BOX(surfer->tb_path), 0); else i++; gtk_combo_box_append_text(GTK_COMBO_BOX(surfer->tb_path), url); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_back), ghtml_can_go_back(surfer->view)); gtk_widget_set_sensitive(GTK_WIDGET(surfer->tb_forward), ghtml_can_go_forward(surfer->view)); } /* surfer_set_progress */ void surfer_set_progress(Surfer * surfer, gdouble fraction) { char buf[10] = ""; 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) { GtkStatusbar * sb; sb = GTK_STATUSBAR(surfer->statusbar); 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_progress_bar_set_text(GTK_PROGRESS_BAR(surfer->progress), ""); gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR( surfer->progress), 0.0); #ifdef FOR_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) { char buf[256]; 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_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", message); 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_open */ void surfer_open(Surfer * surfer, char const * url) { if(url != NULL) { ghtml_stop(surfer->view); ghtml_load_url(surfer->view, url); } else gtk_widget_grab_focus(surfer->tb_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_refresh */ void surfer_refresh(Surfer * surfer) { ghtml_refresh(surfer->view); } /* surfer_reload */ void surfer_reload(Surfer * surfer) { ghtml_reload(surfer->view); } /* surfer_select_all */ void surfer_select_all(Surfer * surfer) { ghtml_select_all(surfer->view); } /* surfer_stop */ void surfer_stop(Surfer * surfer) { ghtml_stop(surfer->view); } /* surfer_unselect_all */ void surfer_unselect_all(Surfer * surfer) { ghtml_unselect_all(surfer->view); } /* surfer_zoom_in */ void surfer_zoom_in(Surfer * surfer) { ghtml_zoom_in(surfer->view); } /* surfer_zoom_out */ void surfer_zoom_out(Surfer * surfer) { ghtml_zoom_out(surfer->view); } /* surfer_zoom_reset */ void surfer_zoom_reset(Surfer * surfer) { ghtml_zoom_reset(surfer->view); }