]> git.armaanb.net Git - chorizo.git/blobdiff - browser.c
draft 4
[chorizo.git] / browser.c
index 020ce9f5926fede7b2d8dc5c1009b9295c916466..385f1671d2741eeb24f5e4ded80d5662aa85b4fe 100644 (file)
--- a/browser.c
+++ b/browser.c
@@ -31,8 +31,10 @@ void show_web_view(WebKitWebView *, gpointer);
 void trust_user_certs(WebKitWebContext *);
 
 struct Client {
-       GtkWidget *jsbutton;
        GtkWidget *location;
+       GtkWidget *search;
+       GtkWidget *search_switch;
+       GtkWidget *isearch;
        GtkWidget *tabicon;
        GtkWidget *tablabel;
        GtkWidget *vbox;
@@ -63,15 +65,13 @@ int cooperative_pipe_fp = 0;
 gchar *search_text;
 gchar *fifopath;
 char **closed_tabs;
+size_t num_closed = 0;
 
 void
-togglejs(GtkButton *jsbutton, gpointer data)
+allocfail(void)
 {
-       struct Client *c = (struct Client *)data;
-       webkit_settings_set_enable_javascript(
-               c->settings,
-               !webkit_settings_get_enable_javascript(c->settings));
-       webkit_web_view_set_settings(WEBKIT_WEB_VIEW(c->web_view), c->settings);
+       fprintf(stderr, "chorizo: fatal: alloc failed\n");
+       exit(EXIT_FAILURE);
 }
 
 void
@@ -84,17 +84,27 @@ client_destroy(GtkWidget *widget, gpointer data)
 
        idx = gtk_notebook_page_num(GTK_NOTEBOOK(mw.notebook), c->vbox);
        if (idx == -1)
-               fprintf(stderr, "chorizo: Tab index was -1, bamboozled\n");
+               fprintf(stderr, "chorizo: warning: tab index was -1\n");
        else
                gtk_notebook_remove_page(GTK_NOTEBOOK(mw.notebook), idx);
 
        if (!cfg.private && WEBKIT_IS_WEB_VIEW(c->web_view)) {
-               int len = sizeof(closed_tabs) / sizeof(char *);
                const char *uri =
                        webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
-               closed_tabs = (char **)realloc(closed_tabs,
-                                              len * sizeof(closed_tabs[0]));
-               closed_tabs[len] = strdup(uri);
+
+               // TODO: Shift everything left if over certain amount
+               num_closed++;
+               if (num_closed > cfg_max_tabs_closed) {
+                       memmove(closed_tabs, closed_tabs,
+                               cfg_max_tabs_closed - 1);
+                       num_closed = cfg_max_tabs_closed;
+               } else {
+                       closed_tabs =
+                               realloc(closed_tabs,
+                                       num_closed * sizeof(closed_tabs[0]));
+                       if (!closed_tabs) allocfail();
+               }
+               closed_tabs[num_closed - 1] = strdup(uri);
        }
 
        free(c);
@@ -127,10 +137,7 @@ client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
                return NULL;
        }
        c = calloc(1, sizeof(struct Client));
-       if (!c) {
-               fprintf(stderr, "chorizo: fatal: calloc failed\n");
-               exit(EXIT_FAILURE);
-       }
+       if (!c) allocfail();
        c->focus_new_tab = focus_tab;
 
        if (related_wv == NULL) {
@@ -160,8 +167,7 @@ client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
                                        webkit_user_script_unref(wkscript);
                                }
                                g_free(path);
-                               if (source)
-                                       g_free(source);
+                               if (source) g_free(source);
                        }
                        g_dir_close(dir);
                }
@@ -198,11 +204,9 @@ client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
 
        c->settings =
                webkit_web_view_get_settings(WEBKIT_WEB_VIEW(c->web_view));
-       webkit_settings_set_enable_javascript(c->settings, cfg_js_default);
-       if (cfg.verbose) {
+       if (cfg.verbose)
                webkit_settings_set_enable_write_console_messages_to_stdout(
                        c->settings, true);
-       }
        webkit_settings_set_enable_developer_extras(c->settings, TRUE);
 
        g_signal_connect(G_OBJECT(c->web_view), "notify::favicon",
@@ -222,8 +226,6 @@ client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
                         G_CALLBACK(decide_policy), NULL);
        g_signal_connect(G_OBJECT(c->web_view), "key-press-event",
                         G_CALLBACK(key_web_view), c);
-       g_signal_connect(G_OBJECT(c->web_view), "button-release-event",
-                        G_CALLBACK(key_web_view), c);
        g_signal_connect(G_OBJECT(c->web_view), "scroll-event",
                         G_CALLBACK(key_web_view), c);
        g_signal_connect(G_OBJECT(c->web_view), "mouse-target-changed",
@@ -232,16 +234,15 @@ client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
                         G_CALLBACK(crashed_web_view), c);
 
        GtkWidget *locbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
-       c->jsbutton = gtk_toggle_button_new_with_label("JS");
-       gtk_widget_set_tooltip_text(c->jsbutton, "Toggle JavaScript execution");
-       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(c->jsbutton),
-                                    cfg_js_default);
-       g_signal_connect(G_OBJECT(c->jsbutton), "toggled", G_CALLBACK(togglejs),
-                        c);
 
        c->location = gtk_entry_new();
+       gtk_entry_set_placeholder_text(GTK_ENTRY(c->location), "Web address");
        gtk_box_pack_start(GTK_BOX(locbox), c->location, TRUE, TRUE, 0);
 
+       c->search = gtk_entry_new();
+       gtk_entry_set_placeholder_text(GTK_ENTRY(c->search), "Search");
+       gtk_box_pack_start(GTK_BOX(locbox), c->search, FALSE, TRUE, 0);
+
        if (cfg.private) {
                GtkWidget *privindicator = gtk_label_new("Private mode");
                gtk_widget_set_tooltip_text(
@@ -251,7 +252,6 @@ client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
                gtk_box_pack_end(GTK_BOX(locbox), privindicator, FALSE, FALSE,
                                 5);
        }
-       gtk_box_pack_start(GTK_BOX(locbox), c->jsbutton, FALSE, FALSE, 5);
 
        g_signal_connect(G_OBJECT(c->location), "key-press-event",
                         G_CALLBACK(key_location), c);
@@ -271,6 +271,15 @@ client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
        c->vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
        gtk_box_pack_start(GTK_BOX(c->vbox), locbox, FALSE, FALSE, 0);
        gtk_box_pack_start(GTK_BOX(c->vbox), c->web_view, TRUE, TRUE, 0);
+
+       GtkWidget *overlay = gtk_overlay_new();
+       c->isearch = gtk_entry_new();
+       gtk_container_add(GTK_CONTAINER(c->vbox), overlay);
+       gtk_container_add(GTK_CONTAINER(overlay), c->isearch);
+      gtk_widget_set_halign (overlay, GTK_ALIGN_CENTER);
+           gtk_widget_set_valign (overlay, GTK_ALIGN_CENTER);
+       gtk_widget_show_all(overlay);
+
        gtk_container_set_focus_child(GTK_CONTAINER(c->vbox), c->web_view);
 
        c->tabicon = gtk_image_new_from_icon_name("text-html",
@@ -278,7 +287,7 @@ client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
 
        c->tablabel = gtk_label_new("chorizo");
        gtk_label_set_ellipsize(GTK_LABEL(c->tablabel), PANGO_ELLIPSIZE_END);
-       gtk_label_set_width_chars(GTK_LABEL(c->tablabel), 20);
+       gtk_label_set_width_chars(GTK_LABEL(c->tablabel), cfg_tab_width);
        gtk_widget_set_has_tooltip(c->tablabel, TRUE);
 
        /*
@@ -330,10 +339,11 @@ client_new(const gchar *uri, WebKitWebView *related_wv, gboolean show,
 
        clients++;
        client_arr = realloc(client_arr, (clients + 1) * sizeof(client_arr[0]));
+       if (!client_arr) allocfail();
+
        client_arr[clients] = c;
 
-       if (clients == 1 || uri == NULL)
-               gtk_widget_grab_focus(c->location);
+       if (clients == 1 || uri == NULL) gtk_widget_grab_focus(c->location);
 
        return WEBKIT_WEB_VIEW(c->web_view);
 }
@@ -353,8 +363,7 @@ mkdirp(const char *dir, mode_t mode)
        size_t len;
        snprintf(tmp, sizeof(tmp), "%s", dir);
        len = strlen(tmp);
-       if (tmp[len - 1] == '/')
-               tmp[len - 1] = 0;
+       if (tmp[len - 1] == '/') tmp[len - 1] = 0;
        for (p = tmp + 1; *p; p++)
                if (*p == '/') {
                        *p = 0;
@@ -380,12 +389,11 @@ cooperation_setup(void)
        mkdirp(dirname(fifopath), 0600);
        g_free(fifofilename);
 
-       if (!g_file_test(fifopath, G_FILE_TEST_EXISTS))
-               mkfifo(fifopath, 0600);
+       if (!g_file_test(fifopath, G_FILE_TEST_EXISTS)) mkfifo(fifopath, 0600);
 
        cooperative_pipe_fp = open(fifopath, O_WRONLY | O_NONBLOCK);
        if (!cooperative_pipe_fp) {
-               fprintf(stderr, "chorizo: Can't open FIFO at all.\n");
+               fprintf(stderr, "chorizo: error: can't open FIFO\n");
        } else {
                if (write(cooperative_pipe_fp, "", 0) == -1) {
                        /*
@@ -491,6 +499,8 @@ changed_title(GObject *obj, GParamSpec *pspec, gpointer data)
        t = t[0] == 0 ? u : t;
 
        gchar *name = malloc(strlen(t) + 4);
+       if (!name) allocfail();
+
        gboolean mute =
                webkit_web_view_get_is_muted(WEBKIT_WEB_VIEW(c->web_view));
        gchar *muted = (mute) ? "[m] " : "";
@@ -511,12 +521,6 @@ changed_uri(GObject *obj, GParamSpec *pspec, gpointer data)
        FILE *fp;
        t = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
 
-       /*
-       * When a web process crashes, we get a "notify::uri" signal, but we
-       * can no longer read a meaningful URI. It's just an empty string
-       * now. Not updating the location bar in this scenario is important,
-       * because we would override the "WEB PROCESS CRASHED" message.
-       */
        if (t != NULL && strlen(t) > 0) {
                set_uri(t, c);
 
@@ -537,22 +541,26 @@ changed_uri(GObject *obj, GParamSpec *pspec, gpointer data)
                                fprintf(fp, "%s\n", t);
                                fclose(fp);
                        } else {
-                               perror("chorizo: Error opening history file");
+                               perror("chorizo: error: could not open history file");
                        }
                }
                g_free(history_file);
                g_free(state_dir);
        }
 }
+
 gboolean
 crashed_web_view(WebKitWebView *web_view, gpointer data)
 {
-       gchar *t;
        struct Client *c = (struct Client *)data;
-       t = g_strdup_printf("WEB PROCESS CRASHED: %s",
-                           webkit_web_view_get_uri(WEBKIT_WEB_VIEW(web_view)));
-       gtk_entry_set_text(GTK_ENTRY(c->location), t);
-       g_free(t);
+       GtkDialogFlags flags = GTK_DIALOG_DESTROY_WITH_PARENT;
+       GtkWidget *dialog = gtk_message_dialog_new(
+               GTK_WINDOW(c->vbox), flags, GTK_MESSAGE_ERROR,
+               GTK_BUTTONS_CLOSE, "ERROR: Web process %s crashed.",
+               webkit_web_view_get_uri(WEBKIT_WEB_VIEW(web_view)),
+               g_strerror(errno));
+       gtk_dialog_run(GTK_DIALOG(dialog));
+       gtk_widget_destroy(dialog);
 
        return TRUE;
 }
@@ -619,7 +627,8 @@ grab_feeds_finished(GObject *object, GAsyncResult *result, gpointer data)
        js_result = webkit_web_view_run_javascript_finish(
                WEBKIT_WEB_VIEW(object), result, &err);
        if (!js_result) {
-               fprintf(stderr, "chorizo: Error running javascript: %s\n",
+               fprintf(stderr,
+                       "chorizo: error: error running javascript: %s\n",
                        err->message);
                g_error_free(err);
                return;
@@ -631,7 +640,7 @@ grab_feeds_finished(GObject *object, GAsyncResult *result, gpointer data)
                        jsc_context_get_exception(jsc_value_get_context(value));
                if (exception != NULL) {
                        fprintf(stderr,
-                               "chorizo: Error running javascript: %s\n",
+                               "chorizo: warning: error running javascript: %s\n",
                                jsc_exception_get_message(exception));
                } else {
                        c->feed_html = str_value;
@@ -666,8 +675,7 @@ hover_web_view(WebKitWebView *web_view, WebKitHitTestResult *ht,
                c->hover_uri = NULL;
        }
 
-       if (!gtk_widget_is_focus(c->location))
-               set_uri(to_show, c);
+       if (!gtk_widget_is_focus(c->location)) set_uri(to_show, c);
 }
 
 void
@@ -768,8 +776,7 @@ search(gpointer data, gint direction)
        WebKitWebView *web_view = WEBKIT_WEB_VIEW(c->web_view);
        WebKitFindController *fc =
                webkit_web_view_get_find_controller(web_view);
-       if (search_text == NULL)
-               return;
+       if (search_text == NULL) return;
 
        switch (direction) {
        case 0:
@@ -805,6 +812,7 @@ search_init(struct Client *c, int direction)
                search(c, direction);
        }
 }
+
 gboolean
 key_common(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
@@ -852,7 +860,7 @@ key_common(GtkWidget *widget, GdkEvent *event, gpointer data)
                                        "document.activeElement.blur();",
                                        NULL, NULL, c);
                                return TRUE;
-                       } else if (GDK_KEY_r == key) {
+                       } else if (GDK_KEY_semicolon == key) {
                                webkit_web_view_reload_bypass_cache(
                                        WEBKIT_WEB_VIEW(c->web_view));
                                return TRUE;
@@ -938,32 +946,19 @@ key_common(GtkWidget *widget, GdkEvent *event, gpointer data)
                                client_new(cfg_home_uri, NULL, TRUE, TRUE);
                                return TRUE;
                        } else if (GDK_KEY_bracketleft == key) {
-                               if (!closed_tabs)
-                                       return TRUE;
-                               int len = sizeof(closed_tabs) / sizeof(char *);
-                               if (len < 1)
-                                       return TRUE;
-                               client_new(closed_tabs[len], NULL, TRUE, TRUE);
-                               free(closed_tabs[len]);
-                               closed_tabs = (char **)realloc(
+                               if (num_closed == 0) return TRUE;
+                               client_new(closed_tabs[num_closed - 1], NULL,
+                                          TRUE, TRUE);
+                               num_closed--;
+                               closed_tabs = realloc(
                                        closed_tabs,
-                                       (len - 1) * sizeof(closed_tabs[0]));
+                                       num_closed * sizeof(closed_tabs[0]));
+                               if (!closed_tabs) allocfail();
                                return TRUE;
                        } else if (GDK_KEY_i == key) {
                                gtk_notebook_next_page(
                                        GTK_NOTEBOOK(mw.notebook));
                                return TRUE;
-                       } else if (GDK_KEY_p == key) {
-                               gboolean on =
-                                       webkit_settings_get_enable_javascript(
-                                               c->settings);
-                               webkit_settings_set_enable_javascript(
-                                       c->settings, !on);
-                               webkit_web_view_set_settings(
-                                       WEBKIT_WEB_VIEW(c->web_view),
-                                       c->settings);
-                               gtk_toggle_button_set_active(
-                                       GTK_TOGGLE_BUTTON(c->jsbutton), !on);
                        } else if (GDK_KEY_d == key) {
                                gtk_widget_grab_focus(c->location);
                                gtk_entry_set_text(GTK_ENTRY(c->location),
@@ -999,8 +994,7 @@ key_location(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
        struct Client *c = (struct Client *)data;
        const gchar *t;
-       if (key_common(widget, event, data))
-               return TRUE;
+       if (key_common(widget, event, data)) return TRUE;
 
        if (event->type == GDK_KEY_PRESS) {
                int key = ((GdkEventKey *)event)->keyval;
@@ -1008,14 +1002,14 @@ key_location(GtkWidget *widget, GdkEvent *event, gpointer data)
                        gtk_widget_grab_focus(c->web_view);
                        t = gtk_entry_get_text(GTK_ENTRY(c->location));
                        if (t != NULL && t[0] == 's' && t[1] == '/') {
-                               if (search_text != NULL)
-                                       g_free(search_text);
+                               if (search_text != NULL) g_free(search_text);
                                search_text = g_strdup(t + 2);
                                search(c, 0);
                        } else if (t != NULL && t[0] == 'w' && t[1] == '/') {
                                int len = strlen(cfg_search_engine) +
                                          strlen(t) - 2;
                                gchar *f = malloc(len + 1);
+                               if (!f) allocfail();
                                snprintf(f, len + 1, "%s%s", cfg_search_engine,
                                         t + 2);
                                webkit_web_view_load_uri(
@@ -1063,14 +1057,14 @@ key_tablabel(GtkWidget *widget, GdkEvent *event, gpointer data)
        }
        return FALSE;
 }
+
 gboolean
 key_web_view(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
        struct Client *c = (struct Client *)data;
        gdouble dx, dy;
        gfloat z;
-       if (key_common(widget, event, data))
-               return TRUE;
+       if (key_common(widget, event, data)) return TRUE;
 
        if (event->type == GDK_KEY_PRESS) {
                if (((GdkEventKey *)event)->keyval == GDK_KEY_Escape) {
@@ -1079,26 +1073,6 @@ key_web_view(GtkWidget *widget, GdkEvent *event, gpointer data)
                        gtk_entry_set_progress_fraction(GTK_ENTRY(c->location),
                                                        0);
                }
-       } else if (event->type == GDK_BUTTON_RELEASE) {
-               GdkModifierType modifiers =
-                       gtk_accelerator_get_default_mod_mask();
-               switch (((GdkEventButton *)event)->button) {
-               case 1:
-                       if ((((GdkEventButton *)event)->state & modifiers) ==
-                                   GDK_CONTROL_MASK &&
-                           c->hover_uri != NULL) {
-                               client_new(c->hover_uri, NULL, TRUE, FALSE);
-                               return TRUE;
-                       }
-                       break;
-               case 8:
-                       webkit_web_view_go_back(WEBKIT_WEB_VIEW(c->web_view));
-                       return TRUE;
-               case 9:
-                       webkit_web_view_go_forward(
-                               WEBKIT_WEB_VIEW(c->web_view));
-                       return TRUE;
-               }
        } else if (event->type == GDK_SCROLL) {
                event->scroll.delta_y *= cfg_scroll_lines;
                if (((GdkEventScroll *)event)->state & GDK_CONTROL_MASK) {
@@ -1124,15 +1098,28 @@ mainwindow_setup(void)
 
        gchar *priv = (cfg.private) ? "-private" : "";
        gchar *title = malloc(strlen(priv) + 7);
+       if (!title) allocfail();
        sprintf(title, "%s%s", "chorizo", priv);
        gtk_window_set_title(GTK_WINDOW(mw.win), title);
        g_free(title);
 
        mw.notebook = gtk_notebook_new();
        gtk_notebook_set_scrollable(GTK_NOTEBOOK(mw.notebook), TRUE);
+       gtk_notebook_set_tab_pos(GTK_NOTEBOOK(mw.notebook), GTK_POS_LEFT);
        gtk_container_add(GTK_CONTAINER(mw.win), mw.notebook);
        g_signal_connect(G_OBJECT(mw.notebook), "switch-page",
                         G_CALLBACK(notebook_switch_page), NULL);
+
+       GtkCssProvider *css = gtk_css_provider_new();
+       const char *css_data = "notebook header.left * { \
+                                       margin: 0; \
+                                       padding-top: 0; \
+                                       padding-bottom: 0; \
+                               }";
+       gtk_css_provider_load_from_data(css, css_data, strlen(css_data), NULL);
+       gtk_style_context_add_provider_for_screen(
+               gdk_screen_get_default(), GTK_STYLE_PROVIDER(css),
+               GTK_STYLE_PROVIDER_PRIORITY_USER);
 }
 
 void
@@ -1141,8 +1128,7 @@ mainwindow_title(gint idx)
        GtkWidget *child, *widg, *tablabel;
        const gchar *text;
        child = gtk_notebook_get_nth_page(GTK_NOTEBOOK(mw.notebook), idx);
-       if (child == NULL)
-               return;
+       if (child == NULL) return;
 
        widg = gtk_notebook_get_tab_label(GTK_NOTEBOOK(mw.notebook), child);
        tablabel = (GtkWidget *)g_object_get_data(G_OBJECT(widg),
@@ -1156,6 +1142,7 @@ notebook_switch_page(GtkNotebook *nb, GtkWidget *p, guint idx, gpointer data)
 {
        mainwindow_title(idx);
 }
+
 gboolean
 quit_if_nothing_active(void)
 {
@@ -1222,7 +1209,7 @@ trust_user_certs(WebKitWebContext *wc)
                        g_free(absfile);
                        if (cert == NULL)
                                fprintf(stderr,
-                                       "chorizo: Could not load trusted cert '%s'\n",
+                                       "chorizo: warning: could not load trusted cert: %s\n",
                                        file);
                        else
                                webkit_web_context_allow_tls_certificate_for_host(
@@ -1233,6 +1220,12 @@ trust_user_certs(WebKitWebContext *wc)
        }
 }
 
+void
+version(void)
+{
+       printf("%s %s\n", "chorizo", VERSION);
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1241,6 +1234,8 @@ main(int argc, char **argv)
        //TODO:pretty this
        cfg.noncooperative_instances = FALSE;
        cfg.cooperative_alone = TRUE;
+       closed_tabs = malloc(0);
+       if (!closed_tabs) allocfail();
 
        while ((opt = getopt(argc, argv, "cpvV")) != -1) {
                switch (opt) {
@@ -1254,23 +1249,24 @@ main(int argc, char **argv)
                        cfg.verbose = TRUE;
                        break;
                case 'V':
-                       printf("%s %s\n", "chorizo", VERSION);
+                       version();
                        exit(0);
                default:
                        fprintf(stderr,
-                               "Usage: chorizo [OPTION]... [URI]...\n");
+                               "usage: chorizo [OPTION]... [URI]...\n");
                        exit(EXIT_FAILURE);
                }
        }
 
+       if (cfg.verbose) version();
+
        gtk_init(&argc, &argv);
 
-       //Keep clipboard contents after program closes
+       // Keep clipboard contents after program closes
        gtk_clipboard_store(gtk_clipboard_get_for_display(
                gdk_display_get_default(), GDK_SELECTION_CLIPBOARD));
 
-       if (!cfg.noncooperative_instances)
-               cooperation_setup();
+       if (!cfg.noncooperative_instances) cooperation_setup();
 
        if (cfg.noncooperative_instances || cfg.cooperative_alone)
                init_default_web_context();
@@ -1279,6 +1275,8 @@ main(int argc, char **argv)
        mainwindow_setup();
 
        client_arr = malloc(sizeof(struct Client *));
+       if (!client_arr) allocfail();
+
        if (optind >= argc) {
                client_new(cfg_home_uri, NULL, TRUE, TRUE);
        } else {
@@ -1290,9 +1288,6 @@ main(int argc, char **argv)
                gtk_main();
                remove(fifopath);
        }
-       for (int i = 0; i < clients; i++) {
-               free(&(client_arr[i]));
-       }
 
        exit(EXIT_SUCCESS);
 }