40 Commits

Author SHA1 Message Date
Enno Boland (tox) bdfa30bf33 fixing double calling functions from contextmenu. 2009-10-17 08:57:23 +02:00
Enno Boland (tox) 5ac31995a3 implementing cookie persistance with multiple processes. 2009-10-17 08:38:46 +02:00
Enno Boland (tox) 3657813fec removed builtin unfinished cookie handling. 2009-10-17 07:50:10 +02:00
Enno Boland (tox) 7ffdcd756c small typo 2009-10-16 16:34:05 +02:00
Enno Boland (tox) 2eafff0e8b using char instead of gchar. 2009-10-16 16:33:18 +02:00
Enno Boland (tox) b298d889de implementing user defined context menu 2009-10-16 15:35:11 +02:00
Enno Boland (tox) e3690dffed renaming newproc to newwindow; make it usable within keys; begin implementing contextmenu 2009-10-16 14:19:25 +02:00
Enno Boland (tox) f62505a47a changing char to gchar where possible; unifing WebKitWebView variable naming 2009-10-16 14:03:39 +02:00
Enno Boland (tox) 7e86ea553f improving urlbar hiding. 2009-10-16 10:55:05 +02:00
Enno Boland (tox) 17bbc1a3cc creating new process when opening new window if possible. 2009-10-15 16:31:49 +02:00
Enno Boland (tox) 533c8e5b35 better useragent string (for google-* and stuff) 2009-10-14 19:05:01 +02:00
Enno Boland (tox) d97b8adfde changing useragent. 2009-10-14 16:28:00 +02:00
Enno Boland (tox) 24bbd6be02 uncommenting source() 2009-10-14 15:19:00 +02:00
Enno Boland (tox) fe87a88954 removing loadfile. readding later in a simpler way. 2009-10-13 23:22:25 +02:00
Enno Boland (tox) 95a6bfcc03 removing debug output 2009-10-13 22:02:06 +02:00
Enno Boland (tox) 499a497b4e fixing stupidy bug. 2009-10-13 22:01:19 +02:00
Enno Boland (tox) 029dac1504 fixing memoryleak. 2009-10-13 21:58:35 +02:00
Enno Boland (tox) 0d28cf7458 making config-files configurable in config.h 2009-10-13 21:52:43 +02:00
Enno Boland (tox) 92cb8792e1 small whitespacefix. 2009-10-13 20:10:43 +02:00
Enno Boland (tox) 04173f6661 hooking onloadfunctions should be done by script.js. 2009-10-07 15:00:20 +02:00
Enno Boland (tox) d3d32fd6c7 commenting. 2009-09-21 19:28:39 +02:00
Enno Boland (tox) a3e1e27762 typo 2009-09-21 03:27:20 +02:00
Enno Boland (tox) 2e9af54363 reformating 2009-09-17 13:03:58 +02:00
Enno Boland (tox) 25b9ae3ce4 applied patch from arg. thanks :) 2009-09-17 01:09:00 +02:00
Enno Boland (tox) d2a4436123 next version is 0.2 2009-09-16 10:18:08 +02:00
Enno Boland (tox) 65e09f7b03 auto creation of script.js 2009-09-16 10:12:27 +02:00
Enno Boland (tox) e9d4da3030 adding user.js support. 2009-09-16 10:06:21 +02:00
Enno Boland (tox) 0e3ac7f3b0 usercss works again. 2009-09-13 16:15:28 +02:00
Enno Boland (tox) a2da3b7eef Added tag 0.1.2 for changeset bffb0c3c2341 2009-09-11 09:39:43 +02:00
Enno Boland (tox) 0ece786d3f next will be 0.1.2 2009-09-11 09:39:36 +02:00
Enno Boland (tox) 2f639aede5 Makefile fixing 2009-09-11 09:38:53 +02:00
Enno Boland (tox) f400f0d56f Adding README file. 2009-09-11 08:18:09 +02:00
Enno Boland (tox) 44511e2549 unfocus should return false; renaming cookie-file. 2009-09-11 08:12:08 +02:00
Enno Boland (tox) 38a098c81d surf embeds now itself into another window. 2009-09-11 07:21:18 +02:00
Enno Boland (tox) c023780eda Added tag 0.1.1 for changeset 3ef997607115 2009-09-10 23:36:54 +02:00
Enno Boland (tox) 9d213cec97 bugfix release 2009-09-10 23:36:39 +02:00
Enno Boland (tox) 2d83c719a2 removing unneeded background color. 2009-09-10 23:32:39 +02:00
Enno Boland (tox) 159022e4ef rearranging some source. 2009-09-10 17:51:16 +02:00
Enno Boland (tox) 2fd67f61e7 adding user stylesheets. 2009-09-10 17:41:56 +02:00
Enno Boland (tox) f5ac8546ea Added tag 0.1 for changeset 9c8ebcf54061 2009-09-10 09:49:21 +02:00
6 changed files with 416 additions and 255 deletions
+4
View File
@@ -1 +1,5 @@
d8628fc93353faa411c9fc7eef82d11a84d26ae2 0.1
d8628fc93353faa411c9fc7eef82d11a84d26ae2 0.1
9c8ebcf54061112b5979742b403de26fc94007ff 0.1
3ef997607115303fe93873b592d152f0ec186f77 0.1.1
bffb0c3c23410ac7f260d167f4b9771497fc1127 0.1.2
+1 -1
View File
@@ -35,7 +35,7 @@ clean:
dist: clean
@echo creating dist tarball
@mkdir -p surf-${VERSION}
@cp -R LICENSE Makefile config.mk \
@cp -R LICENSE Makefile config.mk config.def.h README \
surf.1 ${SRC} surf-${VERSION}
@tar -cf surf-${VERSION}.tar surf-${VERSION}
@gzip surf-${VERSION}.tar
+25
View File
@@ -0,0 +1,25 @@
surf - simple webkit-based browser
==================================
surf is a simple Web browser based on WebKit/GTK+.
Requirements
------------
In order to build surf you need GTK+ and Webkit/GTK+ header files.
Installation
------------
Edit config.mk to match your local setup (surf is installed into
the /usr/local namespace by default).
Afterwards enter the following command to build and install surf (if
necessary as root):
make clean install
Running surf
------------
run
surf [URL]
+38 -27
View File
@@ -1,33 +1,44 @@
/* modifier 0 means no modifier */
static gchar *progress = "#FF0000";
static gchar *progress_trust = "#00FF00";
static gchar *background = "#000000";
static char *useragent = "Mozilla/5.0 (X11; U; Linux; en-us) AppleWebKit/531.2+ (KHTML, like Gecko, surf-"VERSION") Safari/531.2+";
static char *progress = "#FF0000";
static char *progress_trust = "#00FF00";
static char *stylefile = ".surf/style.css";
static char *scriptfile = ".surf/script.js";
static char *cookiefile = ".surf/cookie.txt";
static char *dldir = ".surf/dl";
#define MODKEY GDK_CONTROL_MASK
static Key keys[] = {
/* modifier keyval function arg Focus */
{ MODKEY|GDK_SHIFT_MASK,GDK_r, reload, { .b = TRUE }, ALWAYS },
{ MODKEY, GDK_r, reload, { .b = FALSE }, ALWAYS },
{ MODKEY, GDK_g, showurl, { 0 }, ALWAYS },
{ MODKEY, GDK_slash, showsearch, { 0 }, ALWAYS },
{ 0, GDK_Escape, hidesearch, { 0 }, ALWAYS },
{ 0, GDK_Escape, hideurl, { 0 }, ALWAYS },
{ MODKEY|GDK_SHIFT_MASK,GDK_p, print, { 0 }, ALWAYS },
{ MODKEY, GDK_p, clipboard, { .b = TRUE }, BROWSER },
{ MODKEY, GDK_y, clipboard, { .b = FALSE }, BROWSER },
{ MODKEY|GDK_SHIFT_MASK,GDK_j, zoom, { .i = -1 }, BROWSER },
{ MODKEY|GDK_SHIFT_MASK,GDK_k, zoom, { .i = +1 }, BROWSER },
{ MODKEY|GDK_SHIFT_MASK,GDK_i, zoom, { .i = 0 }, BROWSER },
{ MODKEY, GDK_l, navigate, { .i = +1 }, BROWSER },
{ MODKEY, GDK_h, navigate, { .i = -1 }, BROWSER },
{ MODKEY, GDK_j, scroll, { .i = +1 }, BROWSER },
{ MODKEY, GDK_k, scroll, { .i = -1 }, BROWSER },
{ 0, GDK_Escape, stop, { 0 }, BROWSER },
{ MODKEY, GDK_o, source, { 0 }, BROWSER },
{ MODKEY, GDK_n, searchtext, { .b = TRUE }, BROWSER|SEARCHBAR },
{ MODKEY|GDK_SHIFT_MASK,GDK_n, searchtext, { .b = FALSE }, BROWSER|SEARCHBAR },
{ 0, GDK_Return, searchtext, { .b = TRUE }, SEARCHBAR },
{ GDK_SHIFT_MASK, GDK_Return, searchtext, { .b = FALSE }, SEARCHBAR },
{ 0, GDK_Return, loaduri, { .v = NULL }, URLBAR },
{ 0, GDK_Return, hideurl, { 0 }, URLBAR },
{ MODKEY|GDK_SHIFT_MASK,GDK_r, reload, { .b = TRUE }, Any },
{ MODKEY, GDK_r, reload, { .b = FALSE }, Any },
{ MODKEY, GDK_g, showuri, { 0 }, Any },
{ MODKEY, GDK_slash, showsearch, { 0 }, Any },
{ 0, GDK_Escape, hidesearch, { 0 }, Any },
{ 0, GDK_Escape, hideuri, { 0 }, Any },
{ MODKEY|GDK_SHIFT_MASK,GDK_p, print, { 0 }, Any },
{ MODKEY, GDK_p, clipboard, { .b = TRUE }, Browser },
{ MODKEY, GDK_y, clipboard, { .b = FALSE }, Browser },
{ MODKEY|GDK_SHIFT_MASK,GDK_j, zoom, { .i = -1 }, Browser },
{ MODKEY|GDK_SHIFT_MASK,GDK_k, zoom, { .i = +1 }, Browser },
{ MODKEY|GDK_SHIFT_MASK,GDK_i, zoom, { .i = 0 }, Browser },
{ MODKEY, GDK_l, navigate, { .i = +1 }, Browser },
{ MODKEY, GDK_h, navigate, { .i = -1 }, Browser },
{ MODKEY, GDK_j, scroll, { .i = +1 }, Browser },
{ MODKEY, GDK_k, scroll, { .i = -1 }, Browser },
{ 0, GDK_Escape, stop, { 0 }, Browser },
{ MODKEY, GDK_o, source, { 0 }, Browser },
{ MODKEY, GDK_n, searchtext, { .b = TRUE }, Browser|SearchBar },
{ MODKEY|GDK_SHIFT_MASK,GDK_n, searchtext, { .b = FALSE }, Browser|SearchBar },
{ 0, GDK_Return, searchtext, { .b = TRUE }, SearchBar },
{ GDK_SHIFT_MASK, GDK_Return, searchtext, { .b = FALSE }, SearchBar },
{ 0, GDK_Return, loaduri, { .v = NULL }, UriBar },
{ 0, GDK_Return, hideuri, { 0 }, UriBar },
};
static Item items[] = {
{ "New Window", newwindow, { .v = NULL } },
{ "Reload", reload, { .b = FALSE } },
{ "Stop", stop, { 0 } },
{ "<===", navigate, { .i = -1 } },
{ "===>", navigate, { .i = +1 } },
};
+1 -1
View File
@@ -1,5 +1,5 @@
# surf version
VERSION = 0.1
VERSION = 0.2
# Customize below to fit your system
+347 -226
View File
@@ -2,6 +2,7 @@
*
* To understand surf, start reading main().
*/
#include <signal.h>
#include <X11/X.h>
#include <X11/Xatom.h>
#include <gtk/gtk.h>
@@ -9,47 +10,46 @@
#include <gdk/gdk.h>
#include <gdk/gdkkeysyms.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <getopt.h>
#include <stdlib.h>
#include <stdio.h>
#include <webkit/webkit.h>
#include <glib/gstdio.h>
#include <JavaScriptCore/JavaScript.h>
#define LENGTH(x) (sizeof x / sizeof x[0])
#define LENGTH(x) (sizeof x / sizeof x[0])
#define CLEANMASK(mask) (mask & ~(GDK_MOD2_MASK))
Display *dpy;
Atom urlprop;
typedef union Arg Arg;
union Arg {
const gboolean b;
const gint i;
const void *v;
} ;
};
typedef struct Client {
GtkWidget *win, *scroll, *vbox, *urlbar, *searchbar, *indicator;
GtkWidget *win, *scroll, *vbox, *uribar, *searchbar, *indicator;
GtkWidget **items;
WebKitWebView *view;
WebKitDownload *download;
gchar *title;
char *title, *linkhover;
gint progress;
struct Client *next;
} Client;
typedef struct Cookie {
char *name;
char *value;
char *domain;
char *path;
struct Cookie *next;
} Cookie;
typedef struct {
char *label;
void (*func)(Client *c, const Arg *arg);
const Arg arg;
} Item;
typedef enum {
BROWSER = 0x0001,
SEARCHBAR = 0x0010,
URLBAR = 0x0100,
ALWAYS = ~0,
Browser = 0x0001,
SearchBar = 0x0010,
UriBar = 0x0100,
Any = ~0,
} KeyFocus;
typedef struct {
@@ -60,68 +60,109 @@ typedef struct {
KeyFocus focus;
} Key;
SoupCookieJar *cookiejar;
SoupSession *session;
Client *clients = NULL;
Cookie *cookies = NULL;
gboolean embed = FALSE;
gboolean showxid = FALSE;
gboolean ignore_once = FALSE;
extern char *optarg;
extern gint optind;
static Display *dpy;
static Atom uriprop;
static SoupCookieJar *cookiejar;
static SoupSession *session;
static Client *clients = NULL;
static GdkNativeWindow embed = 0;
static gboolean showxid = FALSE;
static gboolean ignore_once = FALSE;
static char winid[64];
static char *progname;
static const char *autouri(Client *c);
static char *buildpath(const char *path);
static void cleanup(void);
static void clipboard(Client *c, const Arg *arg);
static gchar *copystr(gchar **str, const gchar *src);
static void context(WebKitWebView *v, GtkMenu *m, Client *c);
static char *copystr(char **str, const char *src);
static gboolean decidewindow(WebKitWebView *v, WebKitWebFrame *f, WebKitNetworkRequest *r, WebKitWebNavigationAction *n, WebKitWebPolicyDecision *p, Client *c);
static void destroyclient(Client *c);
static void destroywin(GtkWidget* w, Client *c);
static void die(char *str);
static void download(WebKitDownload *o, GParamSpec *pspec, Client *c);
static void drawindicator(Client *c);
static gboolean exposeindicator(GtkWidget *w, GdkEventExpose *e, Client *c);
static gboolean initdownload(WebKitWebView *view, WebKitDownload *o, Client *c);
static gchar *geturi(Client *c);
static gboolean initdownload(WebKitWebView *v, WebKitDownload *o, Client *c);
static char *geturi(Client *c);
static void hidesearch(Client *c, const Arg *arg);
static void hideurl(Client *c, const Arg *arg);
static gboolean keypress(GtkWidget* w, GdkEventKey *ev, Client *c);
static void linkhover(WebKitWebView* page, const gchar* t, const gchar* l, Client *c);
static void loadcommit(WebKitWebView *view, WebKitWebFrame *f, Client *c);
static void loadstart(WebKitWebView *view, WebKitWebFrame *f, Client *c);
static void loadfile(Client *c, const gchar *f);
static void hideuri(Client *c, const Arg *arg);
static void itemclick(GtkMenuItem *mi, Client *c);
static gboolean keypress(GtkWidget *w, GdkEventKey *ev, Client *c);
static void linkhover(WebKitWebView *v, const char* t, const char* l, Client *c);
static void loadcommit(WebKitWebView *v, WebKitWebFrame *f, Client *c);
static void loadfinished(WebKitWebView *v, WebKitWebFrame *f, Client *c);
static void loadstart(WebKitWebView *v, WebKitWebFrame *f, Client *c);
static void loaduri(Client *c, const Arg *arg);
static void navigate(Client *c, const Arg *arg);
static Client *newclient(void);
static WebKitWebView *newwindow(WebKitWebView *v, WebKitWebFrame *f, Client *c);
static void pasteurl(GtkClipboard *clipboard, const gchar *text, gpointer d);
static void newwindow(Client *c, const Arg *arg);
static WebKitWebView *createwindow(WebKitWebView *v, WebKitWebFrame *f, Client *c);
static void pasteuri(GtkClipboard *clipboard, const char *text, gpointer d);
static GdkFilterReturn processx(GdkXEvent *xevent, GdkEvent *event, gpointer d);
static void print(Client *c, const Arg *arg);
static void proccookies(SoupMessage *m, Client *c);
static void progresschange(WebKitWebView *view, gint p, Client *c);
static void request(SoupSession *s, SoupMessage *m, Client *c);
static void progresschange(WebKitWebView *v, gint p, Client *c);
static void reload(Client *c, const Arg *arg);
static void rereadcookies(void);
static void setcookie(char *name, char *val, char *dom, char *path, long exp);
static void reloadcookie();
static void sigchld(int unused);
static void setup(void);
static void titlechange(WebKitWebView* view, WebKitWebFrame* frame,
const gchar* title, Client *c);
static void spawn(Client *c, const Arg *arg);
static void scroll(Client *c, const Arg *arg);
static void searchtext(Client *c, const Arg *arg);
static void source(Client *c, const Arg *arg);
static void showsearch(Client *c, const Arg *arg);
static void showurl(Client *c, const Arg *arg);
static void showuri(Client *c, const Arg *arg);
static void stop(Client *c, const Arg *arg);
static void titlechange(WebKitWebView* view, WebKitWebFrame* frame, const gchar* title, Client *c);
static gboolean unfocusbar(GtkWidget *w, GdkEventFocus *e, Client *c);
static void titlechange(WebKitWebView *v, WebKitWebFrame* frame, const char* title, Client *c);
static gboolean focusview(GtkWidget *w, GdkEventFocus *e, Client *c);
static void usage(void);
static void update(Client *c);
static void updatewinid(Client *c);
static void windowobjectcleared(GtkWidget *w, WebKitWebFrame *frame, JSContextRef js, JSObjectRef win, Client *c);
static void zoom(Client *c, const Arg *arg);
/* configuration, allows nested code to access above variables */
#include "config.h"
const char *
autouri(Client *c) {
if(GTK_WIDGET_HAS_FOCUS(c->uribar))
return gtk_entry_get_text(GTK_ENTRY(c->uribar));
else if(c->linkhover)
return c->linkhover;
return NULL;
}
char *
buildpath(const char *path) {
char *apath, *p;
FILE *f;
/* creating directory */
if(path[0] == '/')
apath = g_strdup(path);
else
apath = g_strconcat(g_get_home_dir(), "/", path, NULL);
if((p = strrchr(apath, '/'))) {
*p = '\0';
g_mkdir_with_parents(apath, 0755);
*p = '/';
}
/* creating file (gives error when apath ends with "/") */
if((f = g_fopen(apath, "a")))
fclose(f);
return apath;
}
void
cleanup(void) {
while(clients)
destroyclient(clients);
g_free(cookiefile);
g_free(dldir);
g_free(scriptfile);
g_free(stylefile);
}
void
@@ -129,14 +170,30 @@ clipboard(Client *c, const Arg *arg) {
gboolean paste = *(gboolean *)arg;
if(paste)
gtk_clipboard_request_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), pasteurl, c);
gtk_clipboard_request_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), pasteuri, c);
else
gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_PRIMARY), webkit_web_view_get_uri(c->view), -1);
}
gchar *
copystr(gchar **str, const gchar *src) {
gchar *tmp;
void
context(WebKitWebView *v, GtkMenu *m, Client *c) {
int i;
GtkContainer *parent;
gtk_widget_hide_all(GTK_WIDGET(m));
gtk_widget_show(GTK_WIDGET(m));
for(i = 0; i < LENGTH(items); i++) {
parent = GTK_CONTAINER(gtk_widget_get_parent(c->items[i]));
if(parent)
gtk_container_remove(parent, c->items[i]);
gtk_menu_shell_append(GTK_MENU_SHELL(m), c->items[i]);
gtk_widget_show(c->items[i]);
}
}
char *
copystr(char **str, const char *src) {
char *tmp;
tmp = g_strdup(src);
if(str && *str) {
@@ -148,14 +205,19 @@ copystr(gchar **str, const gchar *src) {
void
destroyclient(Client *c) {
int i;
Client *p;
gtk_widget_destroy(GTK_WIDGET(webkit_web_view_new()));
gtk_widget_destroy(GTK_WIDGET(c->view));
gtk_widget_destroy(c->scroll);
gtk_widget_destroy(c->urlbar);
gtk_widget_destroy(c->uribar);
gtk_widget_destroy(c->searchbar);
gtk_widget_destroy(c->vbox);
gtk_widget_destroy(c->win);
for(i = 0; i < LENGTH(items); i++)
gtk_widget_destroy(c->items[i]);
free(c->items);
for(p = clients; p && p->next != c; p = p->next);
if(p)
p->next = c->next;
@@ -166,6 +228,18 @@ destroyclient(Client *c) {
gtk_main_quit();
}
gboolean
decidewindow(WebKitWebView *view, WebKitWebFrame *f, WebKitNetworkRequest *r, WebKitWebNavigationAction *n, WebKitWebPolicyDecision *p, Client *c) {
Arg arg;
if(webkit_web_navigation_action_get_reason(n) == WEBKIT_WEB_NAVIGATION_REASON_LINK_CLICKED) {
webkit_web_policy_decision_ignore(p);
arg.v = (void *)webkit_network_request_get_uri(r);
newwindow(NULL, &arg);
return TRUE;
}
return FALSE;
}
void
destroywin(GtkWidget* w, Client *c) {
destroyclient(c);
@@ -180,7 +254,7 @@ die(char *str) {
void
drawindicator(Client *c) {
gint width;
gchar *uri;
char *uri;
GtkWidget *w;
GdkGC *gc;
GdkColor fg;
@@ -219,16 +293,13 @@ download(WebKitDownload *o, GParamSpec *pspec, Client *c) {
gboolean
initdownload(WebKitWebView *view, WebKitDownload *o, Client *c) {
const gchar *home, *filename;
gchar *uri, *path, *html;
const char *filename;
char *uri, *html;
stop(c, NULL);
c->download = o;
home = g_get_home_dir();
filename = webkit_download_get_suggested_filename(o);
path = g_build_filename(home, ".surf", "dl",
filename, NULL);
uri = g_strconcat("file://", path, NULL);
uri = g_strconcat("file://", dldir, "/", filename, NULL);
webkit_download_set_destination_uri(c->download, uri);
c->progress = 0;
g_free(uri);
@@ -245,11 +316,11 @@ initdownload(WebKitWebView *view, WebKitDownload *o, Client *c) {
return TRUE;
}
gchar *
char *
geturi(Client *c) {
gchar *uri;
char *uri;
if(!(uri = (gchar *)webkit_web_view_get_uri(c->view)))
if(!(uri = (char *)webkit_web_view_get_uri(c->view)))
uri = copystr(NULL, "about:blank");
return uri;
}
@@ -261,11 +332,22 @@ hidesearch(Client *c, const Arg *arg) {
}
void
hideurl(Client *c, const Arg *arg) {
gtk_widget_hide(c->urlbar);
hideuri(Client *c, const Arg *arg) {
gtk_widget_hide(c->uribar);
gtk_widget_grab_focus(GTK_WIDGET(c->view));
}
void
itemclick(GtkMenuItem *mi, Client *c) {
int i;
const char *label;
label = gtk_menu_item_get_label(mi);
for(i = 0; i < LENGTH(items); i++)
if(!strcmp(items[i].label, label))
items[i].func(c, &(items[i].arg));
}
gboolean
keypress(GtkWidget* w, GdkEventKey *ev, Client *c) {
guint i, focus;
@@ -274,11 +356,12 @@ keypress(GtkWidget* w, GdkEventKey *ev, Client *c) {
if(ev->type != GDK_KEY_PRESS)
return FALSE;
if(GTK_WIDGET_HAS_FOCUS(c->searchbar))
focus = SEARCHBAR;
else if(GTK_WIDGET_HAS_FOCUS(c->urlbar))
focus = URLBAR;
focus = SearchBar;
else if(GTK_WIDGET_HAS_FOCUS(c->uribar))
focus = UriBar;
else
focus = BROWSER;
focus = Browser;
updatewinid(c);
for(i = 0; i < LENGTH(keys); i++) {
if(focus & keys[i].focus
&& gdk_keyval_to_lower(ev->keyval) == keys[i].keyval
@@ -292,69 +375,48 @@ keypress(GtkWidget* w, GdkEventKey *ev, Client *c) {
}
void
linkhover(WebKitWebView* page, const gchar* t, const gchar* l, Client *c) {
linkhover(WebKitWebView *v, const char* t, const char* l, Client *c) {
if(l)
gtk_window_set_title(GTK_WINDOW(c->win), l);
else
update(c);
c->linkhover = copystr(&c->linkhover, l);
else if(c->linkhover) {
free(c->linkhover);
c->linkhover = NULL;
}
update(c);
}
void
loadcommit(WebKitWebView *view, WebKitWebFrame *f, Client *c) {
gchar *uri;
char *uri;
ignore_once = TRUE;
uri = geturi(c);
XChangeProperty(dpy, GDK_WINDOW_XID(GTK_WIDGET(c->win)->window), urlprop,
XChangeProperty(dpy, GDK_WINDOW_XID(GTK_WIDGET(c->win)->window), uriprop,
XA_STRING, 8, PropModeReplace, (unsigned char *)uri,
strlen(uri) + 1);
}
void
loadfinished(WebKitWebView *v, WebKitWebFrame *f, Client *c) {
reloadcookie();
}
void
loadstart(WebKitWebView *view, WebKitWebFrame *f, Client *c) {
reloadcookie();
c->progress = 0;
update(c);
}
void
loadfile(Client *c, const gchar *f) {
GIOChannel *chan = NULL;
GError *e = NULL;
GString *code;
gchar *line, *uri;
Arg arg;
if(strcmp(f, "-") == 0) {
chan = g_io_channel_unix_new(STDIN_FILENO);
if (chan) {
code = g_string_new("");
while(g_io_channel_read_line(chan, &line, NULL, NULL,
&e) == G_IO_STATUS_NORMAL) {
g_string_append(code, line);
g_free(line);
}
webkit_web_view_load_html_string(c->view, code->str,
"file://.");
g_io_channel_shutdown(chan, FALSE, NULL);
g_string_free(code, TRUE);
}
arg.v = uri = g_strdup("stdin");
}
else {
arg.v = uri = g_strdup_printf("file://%s", f);
loaduri(c, &arg);
}
c->title = copystr(&c->title, uri);
update(c);
g_free(uri);
}
void
loaduri(Client *c, const Arg *arg) {
gchar *u;
const gchar *uri = (gchar *)arg->v;
char *u;
const char *uri = (char *)arg->v;
if(!uri)
uri = gtk_entry_get_text(GTK_ENTRY(c->urlbar));
uri = autouri(c);
if(!uri)
return;
u = g_strrstr(uri, "://") ? g_strdup(uri)
: g_strdup_printf("http://%s", uri);
webkit_web_view_load_uri(c->view, u);
@@ -372,12 +434,16 @@ navigate(Client *c, const Arg *arg) {
Client *
newclient(void) {
int i;
Client *c;
WebKitWebSettings *settings;
char *uri;
if(!(c = calloc(1, sizeof(Client))))
die("Cannot malloc!\n");
/* Window */
if(embed) {
c->win = gtk_plug_new(0);
c->win = gtk_plug_new(embed);
}
else {
c->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
@@ -387,6 +453,17 @@ newclient(void) {
g_signal_connect(G_OBJECT(c->win), "destroy", G_CALLBACK(destroywin), c);
g_signal_connect(G_OBJECT(c->win), "key-press-event", G_CALLBACK(keypress), c);
if(!(c->items = calloc(1, sizeof(GtkWidget *) * LENGTH(items))))
die("Cannot malloc!\n");
/* contextmenu */
for(i = 0; i < LENGTH(items); i++) {
c->items[i] = gtk_menu_item_new_with_label(items[i].label);
g_signal_connect(G_OBJECT(c->items[i]), "activate",
G_CALLBACK(itemclick), c);
}
/* VBox */
c->vbox = gtk_vbox_new(FALSE, 0);
@@ -399,22 +476,24 @@ newclient(void) {
c->view = WEBKIT_WEB_VIEW(webkit_web_view_new());
g_signal_connect(G_OBJECT(c->view), "title-changed", G_CALLBACK(titlechange), c);
g_signal_connect(G_OBJECT(c->view), "load-progress-changed", G_CALLBACK(progresschange), c);
g_signal_connect(G_OBJECT(c->view), "load-finished", G_CALLBACK(loadfinished), c);
g_signal_connect(G_OBJECT(c->view), "load-committed", G_CALLBACK(loadcommit), c);
g_signal_connect(G_OBJECT(c->view), "load-started", G_CALLBACK(loadstart), c);
g_signal_connect(G_OBJECT(c->view), "hovering-over-link", G_CALLBACK(linkhover), c);
g_signal_connect(G_OBJECT(c->view), "create-web-view", G_CALLBACK(newwindow), c);
g_signal_connect(G_OBJECT(c->view), "create-web-view", G_CALLBACK(createwindow), c);
g_signal_connect(G_OBJECT(c->view), "new-window-policy-decision-requested", G_CALLBACK(decidewindow), c);
g_signal_connect(G_OBJECT(c->view), "download-requested", G_CALLBACK(initdownload), c);
g_signal_connect_after(session, "request-started", G_CALLBACK(request), c);
g_signal_connect(G_OBJECT(c->view), "window-object-cleared", G_CALLBACK(windowobjectcleared), c);
g_signal_connect(G_OBJECT(c->view), "focus-in-event", G_CALLBACK(focusview), c);
g_signal_connect(G_OBJECT(c->view), "populate-popup", G_CALLBACK(context), c);
/* urlbar */
c->urlbar = gtk_entry_new();
gtk_entry_set_has_frame(GTK_ENTRY(c->urlbar), FALSE);
g_signal_connect(G_OBJECT(c->urlbar), "focus-out-event", G_CALLBACK(unfocusbar), c);
/* uribar */
c->uribar = gtk_entry_new();
gtk_entry_set_has_frame(GTK_ENTRY(c->uribar), FALSE);
/* searchbar */
c->searchbar = gtk_entry_new();
gtk_entry_set_has_frame(GTK_ENTRY(c->searchbar), FALSE);
g_signal_connect(G_OBJECT(c->searchbar), "focus-out-event", G_CALLBACK(unfocusbar), c);
/* indicator */
c->indicator = gtk_drawing_area_new();
@@ -422,24 +501,22 @@ newclient(void) {
g_signal_connect (G_OBJECT (c->indicator), "expose_event",
G_CALLBACK (exposeindicator), c);
/* downloadbar */
/* Arranging */
gtk_container_add(GTK_CONTAINER(c->scroll), GTK_WIDGET(c->view));
gtk_container_add(GTK_CONTAINER(c->win), c->vbox);
gtk_container_add(GTK_CONTAINER(c->vbox), c->scroll);
gtk_container_add(GTK_CONTAINER(c->vbox), c->searchbar);
gtk_container_add(GTK_CONTAINER(c->vbox), c->urlbar);
gtk_container_add(GTK_CONTAINER(c->vbox), c->uribar);
gtk_container_add(GTK_CONTAINER(c->vbox), c->indicator);
/* Setup */
gtk_box_set_child_packing(GTK_BOX(c->vbox), c->urlbar, FALSE, FALSE, 0, GTK_PACK_START);
gtk_box_set_child_packing(GTK_BOX(c->vbox), c->uribar, FALSE, FALSE, 0, GTK_PACK_START);
gtk_box_set_child_packing(GTK_BOX(c->vbox), c->searchbar, FALSE, FALSE, 0, GTK_PACK_START);
gtk_box_set_child_packing(GTK_BOX(c->vbox), c->indicator, FALSE, FALSE, 0, GTK_PACK_START);
gtk_box_set_child_packing(GTK_BOX(c->vbox), c->scroll, TRUE, TRUE, 0, GTK_PACK_START);
gtk_widget_grab_focus(GTK_WIDGET(c->view));
gtk_widget_hide_all(c->searchbar);
gtk_widget_hide_all(c->urlbar);
gtk_widget_hide_all(c->uribar);
gtk_widget_show(c->vbox);
gtk_widget_show(c->indicator);
gtk_widget_show(c->scroll);
@@ -448,6 +525,12 @@ newclient(void) {
gdk_window_set_events(GTK_WIDGET(c->win)->window, GDK_ALL_EVENTS_MASK);
gdk_window_add_filter(GTK_WIDGET(c->win)->window, processx, c);
webkit_web_view_set_full_content_zoom(c->view, TRUE);
settings = webkit_web_view_get_settings(c->view);
g_object_set(G_OBJECT(settings), "user-agent", useragent, NULL);
uri = g_strconcat("file://", stylefile, NULL);
g_object_set(G_OBJECT(settings), "user-stylesheet-uri", uri, NULL);
g_free(uri);
c->download = NULL;
c->title = NULL;
c->next = clients;
@@ -460,15 +543,38 @@ newclient(void) {
return c;
}
void
newwindow(Client *c, const Arg *arg) {
guint i = 0;
const char *cmd[7], *uri;
const Arg a = { .v = (void *)cmd };
char tmp[64];
cmd[i++] = progname;
if(embed) {
cmd[i++] = "-e";
snprintf(tmp, LENGTH(tmp), "%u\n", (int)embed);
cmd[i++] = tmp;
}
if(showxid) {
cmd[i++] = "-x";
}
cmd[i++] = "--";
uri = arg->v ? (char *)arg->v : autouri(c);
if(uri)
cmd[i++] = uri;
cmd[i++] = NULL;
spawn(NULL, &a);
}
WebKitWebView *
newwindow(WebKitWebView *v, WebKitWebFrame *f, Client *c) {
createwindow(WebKitWebView *v, WebKitWebFrame *f, Client *c) {
Client *n = newclient();
return n->view;
}
void
pasteurl(GtkClipboard *clipboard, const gchar *text, gpointer d) {
pasteuri(GtkClipboard *clipboard, const char *text, gpointer d) {
Arg arg = {.v = text };
if(text != NULL)
loaduri((Client *) d, &arg);
@@ -486,11 +592,11 @@ processx(GdkXEvent *e, GdkEvent *event, gpointer d) {
if(((XEvent *)e)->type == PropertyNotify) {
ev = &((XEvent *)e)->xproperty;
if(ev->atom == urlprop && ev->state == PropertyNewValue) {
if(ev->atom == uriprop && ev->state == PropertyNewValue) {
if(ignore_once)
ignore_once = FALSE;
else {
XGetWindowProperty(dpy, ev->window, urlprop, 0L, BUFSIZ, False, XA_STRING,
XGetWindowProperty(dpy, ev->window, uriprop, 0L, BUFSIZ, False, XA_STRING,
&adummy, &idummy, &ldummy, &ldummy, &buf);
arg.v = buf;
loaduri(c, &arg);
@@ -508,32 +614,11 @@ print(Client *c, const Arg *arg) {
}
void
proccookies(SoupMessage *m, Client *c) {
GSList *l;
SoupCookie *co;
long t;
rereadcookies();
for (l = soup_cookies_from_response(m); l; l = l->next){
co = (SoupCookie *)l->data;
t = co->expires ? soup_date_to_time_t(co->expires) : 0;
setcookie(co->name, co->value, co->domain, co->value, t);
}
g_slist_free(l);
}
void
progresschange(WebKitWebView* view, gint p, Client *c) {
progresschange(WebKitWebView *v, gint p, Client *c) {
c->progress = p;
update(c);
}
void
request(SoupSession *s, SoupMessage *m, Client *c) {
soup_message_add_header_handler(m, "got-headers", "Set-Cookie",
G_CALLBACK(proccookies), c);
}
void
reload(Client *c, const Arg *arg) {
gboolean nocache = *(gboolean *)arg;
@@ -544,12 +629,14 @@ reload(Client *c, const Arg *arg) {
}
void
rereadcookies(void) {
const gchar *filename, *home;
reloadcookie(void) {
SoupSession *s;
home = g_get_home_dir();
filename = g_build_filename(home, ".surf", "cookies", NULL);
}
/* This forces the cookie to be written to hdd */
s = webkit_get_default_session();
soup_session_remove_feature(s, SOUP_SESSION_FEATURE(cookiejar));
soup_session_add_feature(s, SOUP_SESSION_FEATURE(cookiejar));
}
void
scroll(Client *c, const Arg *arg) {
@@ -565,20 +652,41 @@ scroll(Client *c, const Arg *arg) {
}
void
setcookie(char *name, char *val, char *dom, char *path, long exp) {
sigchld(int unused) {
if(signal(SIGCHLD, sigchld) == SIG_ERR)
die("Can't install SIGCHLD handler");
while(0 < waitpid(-1, NULL, WNOHANG));
}
void
setup(void) {
SoupSession *s;
/* clean up any zombies immediately */
sigchld(0);
gtk_init(NULL, NULL);
if (!g_thread_supported())
g_thread_init(NULL);
dpy = GDK_DISPLAY();
session = webkit_get_default_session();
urlprop = XInternAtom(dpy, "_SURF_URL", False);
uriprop = XInternAtom(dpy, "_SURF_uri", False);
/* create dirs and files */
cookiefile = buildpath(cookiefile);
dldir = buildpath(dldir);
scriptfile = buildpath(scriptfile);
stylefile = buildpath(stylefile);
/* cookie persistance */
s = webkit_get_default_session();
cookiejar = soup_cookie_jar_text_new(cookiefile, FALSE);
soup_session_add_feature(s, SOUP_SESSION_FEATURE(cookiejar));
}
void
showsearch(Client *c, const Arg *arg) {
hideurl(c, NULL);
hideuri(c, NULL);
gtk_widget_show(c->searchbar);
gtk_widget_grab_focus(c->searchbar);
}
@@ -586,32 +694,31 @@ showsearch(Client *c, const Arg *arg) {
void
source(Client *c, const Arg *arg) {
Arg a = { .b = FALSE };
/*gboolean s;
gboolean s;
s = webkit_web_view_get_view_source_mode(c->view);
webkit_web_view_set_view_source_mode(c->view, c->source);*/
webkit_web_view_set_view_source_mode(c->view, !s);
reload(c, &a);
}
void
searchtext(Client *c, const Arg *arg) {
const char *text;
gboolean forward = *(gboolean *)arg;
webkit_web_view_search_text(c->view,
gtk_entry_get_text(GTK_ENTRY(c->searchbar)),
FALSE,
forward,
TRUE);
text = gtk_entry_get_text(GTK_ENTRY(c->searchbar));
webkit_web_view_search_text(c->view, text, FALSE, forward, TRUE);
webkit_web_view_mark_text_matches(c->view, text, FALSE, 0);
}
void
showurl(Client *c, const Arg *arg) {
gchar *uri;
showuri(Client *c, const Arg *arg) {
char *uri;
hidesearch(c, NULL);
uri = geturi(c);
gtk_entry_set_text(GTK_ENTRY(c->urlbar), uri);
gtk_widget_show(c->urlbar);
gtk_widget_grab_focus(c->urlbar);
gtk_entry_set_text(GTK_ENTRY(c->uribar), uri);
gtk_widget_show(c->uribar);
gtk_widget_grab_focus(c->uribar);
}
void
@@ -624,38 +731,72 @@ stop(Client *c, const Arg *arg) {
}
void
titlechange(WebKitWebView *v, WebKitWebFrame *f, const gchar *t, Client *c) {
spawn(Client *c, const Arg *arg) {
if(fork() == 0) {
if(dpy)
close(ConnectionNumber(dpy));
setsid();
execvp(((char **)arg->v)[0], (char **)arg->v);
fprintf(stderr, "tabbed: execvp %s", ((char **)arg->v)[0]);
perror(" failed");
exit(0);
}
}
void
titlechange(WebKitWebView *v, WebKitWebFrame *f, const char *t, Client *c) {
c->title = copystr(&c->title, t);
update(c);
}
gboolean
unfocusbar(GtkWidget *w, GdkEventFocus *e, Client *c) {
focusview(GtkWidget *w, GdkEventFocus *e, Client *c) {
hidesearch(c, NULL);
hideurl(c, NULL);
return TRUE;
hideuri(c, NULL);
return FALSE;
}
void
usage(void) {
fputs("surf - simple browser\n", stderr);
die("usage: surf [-e] [-x] [uri]\n");
die("usage: surf [-e Window] [-x] [uri]\n");
}
void
update(Client *c) {
gchar *t;
char *t;
if(c->progress == 100)
t = g_strdup(c->title);
else
if(c->progress != 100)
t = g_strdup_printf("%s [%i%%]", c->title, c->progress);
else if(c->linkhover)
t = g_strdup(c->linkhover);
else
t = g_strdup(c->title);
drawindicator(c);
gtk_window_set_title(GTK_WINDOW(c->win), t);
g_free(t);
}
void
updatewinid(Client *c) {
snprintf(winid, LENGTH(winid), "%u",
(int)GDK_WINDOW_XID(GTK_WIDGET(c->win)->window));
}
void
windowobjectcleared(GtkWidget *w, WebKitWebFrame *frame, JSContextRef js, JSObjectRef win, Client *c) {
JSStringRef jsscript;
char *script;
JSValueRef exception = NULL;
GError *error;
if(g_file_get_contents(scriptfile, &script, NULL, &error)) {
jsscript = JSStringCreateWithUTF8CString(script);
JSEvaluateScript(js, jsscript, JSContextGetGlobalObject(js), NULL, 0, &exception);
}
}
void
zoom(Client *c, const Arg *arg) {
if(arg->i < 0) /* zoom out */
@@ -667,56 +808,36 @@ zoom(Client *c, const Arg *arg) {
}
int main(int argc, char *argv[]) {
SoupSession *s;
Client *c;
gint o;
const gchar *home, *filename;
int i;
Arg arg;
gtk_init(NULL, NULL);
if (!g_thread_supported())
g_thread_init(NULL);
setup();
while((o = getopt(argc, argv, "vhxeu:f:")) != -1)
switch(o) {
case 'x':
progname = argv[0];
/* command line args */
for(i = 1, arg.v = NULL; i < argc && argv[i][0] == '-'; i++) {
if(!strcmp(argv[i], "-x"))
showxid = TRUE;
break;
case 'e':
showxid = TRUE;
embed = TRUE;
break;
case 'v':
die("surf-"VERSION", © 2009 surf engineers, see LICENSE for details\n");
break;
default:
usage();
else if(!strcmp(argv[i], "-e")) {
if(++i < argc)
embed = atoi(argv[i]);
else
usage();
}
if(optind + 1 == argc) {
c = newclient();
arg.v = argv[optind];
if(strchr("./", argv[optind][0]) || strcmp("-", argv[optind]) == 0)
loadfile(c, argv[optind]);
else if(!strcmp(argv[i], "--")) {
i++;
break;
}
else if(!strcmp(argv[i], "-v"))
die("surf-"VERSION", © 2009 surf engineers, see LICENSE for details\n");
else
loaduri(c, &arg);
usage();
}
if(i < argc)
arg.v = argv[i];
setup();
newclient();
if(arg.v) {
loaduri(clients, &arg);
}
else if(optind != argc)
usage();
if(!clients)
newclient();
/* make dirs */
home = g_get_home_dir();
filename = g_build_filename(home, ".surf", "dl", NULL);
g_mkdir_with_parents(filename, 0755);
/* cookie persistance */
s = webkit_get_default_session();
filename = g_build_filename(home, ".surf", "cookies.jar", NULL);
cookiejar = soup_cookie_jar_text_new(filename, FALSE);
soup_session_add_feature(s, SOUP_SESSION_FEATURE(cookiejar));
gtk_main();
cleanup();
return EXIT_SUCCESS;