surf

Simple Web browser based on WebKit/GTK+
git clone git://git.janpasierb.com/surf.git
Log | Files | Refs | README | LICENSE

commit efdd0dd584829a9db969511e487010bf2107b503
Author: Enno Boland (Gottox) <gottox@s01.de>
Date:   Fri,  5 Jun 2009 13:22:40 +0200

Initial Commit.
Diffstat:
ALICENSE | 21+++++++++++++++++++++
AMakefile | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aconfig.mk | 30++++++++++++++++++++++++++++++
Asurf.c | 234+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 341 insertions(+), 0 deletions(-)

diff --git a/LICENSE b/LICENSE @@ -0,0 +1,21 @@ +MIT/X Consortium License + +© 2009 Enno Boland <g s01 de> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile @@ -0,0 +1,56 @@ +# surf - simple browser +# See LICENSE file for copyright and license details. + +include config.mk + +SRC = surf.c +OBJ = ${SRC:.c=.o} + +all: options surf + +options: + @echo surf build options: + @echo "CFLAGS = ${CFLAGS}" + @echo "LDFLAGS = ${LDFLAGS}" + @echo "CC = ${CC}" + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +${OBJ}: config.mk + +surf: ${OBJ} + @echo CC -o $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} + +clean: + @echo cleaning + @rm -f surf ${OBJ} surf-${VERSION}.tar.gz + +dist: clean + @echo creating dist tarball + @mkdir -p surf-${VERSION} + @cp -R LICENSE Makefile README config.def.h config.mk \ + surf.1 ${SRC} surf-${VERSION} + @tar -cf surf-${VERSION}.tar surf-${VERSION} + @gzip surf-${VERSION}.tar + @rm -rf surf-${VERSION} + +install: all + @echo installing executable file to ${DESTDIR}${PREFIX}/bin + @mkdir -p ${DESTDIR}${PREFIX}/bin + @cp -f surf ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/surf + @echo installing manual page to ${DESTDIR}${MANPREFIX}/man1 + @mkdir -p ${DESTDIR}${MANPREFIX}/man1 + @sed "s/VERSION/${VERSION}/g" < surf.1 > ${DESTDIR}${MANPREFIX}/man1/surf.1 + @chmod 644 ${DESTDIR}${MANPREFIX}/man1/surf.1 + +uninstall: + @echo removing executable file from ${DESTDIR}${PREFIX}/bin + @rm -f ${DESTDIR}${PREFIX}/bin/surf + @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 + @rm -f ${DESTDIR}${MANPREFIX}/man1/surf.1 + +.PHONY: all options clean dist install uninstall diff --git a/config.mk b/config.mk @@ -0,0 +1,30 @@ +# surf version +VERSION = 0.0 + +# Customize below to fit your system + +# paths +PREFIX = /usr/local +MANPREFIX = ${PREFIX}/share/man + +GTKINC=$(shell pkg-config --cflags gtk+-2.0 webkit-1.0) +GTKLIB=$(shell pkg-config --libs gtk+-2.0 webkit-1.0) + + +# includes and libs +INCS = -I. -I/usr/include ${GTKINC} +LIBS = -L/usr/lib -lc ${GTKLIB} + +# flags +CPPFLAGS = -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS} +#CFLAGS = -std=c99 -pedantic -Wall -Os ${INCS} ${CPPFLAGS} +CFLAGS = -std=c99 -pedantic -Wall -O0 ${INCS} ${CPPFLAGS} +#LDFLAGS = -s ${LIBS} +LDFLAGS = ${LIBS} + +# Solaris +#CFLAGS = -fast ${INCS} -DVERSION=\"${VERSION}\" +#LDFLAGS = ${LIBS} + +# compiler and linker +CC = cc diff --git a/surf.c b/surf.c @@ -0,0 +1,234 @@ +#include <gtk/gtk.h> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <webkit/webkit.h> + +#define LENGTH(x) (sizeof x / sizeof x[0]) +/* Plan9-style Argument parsing */ +/* Vars: _c -> count; _b -> break; _a -> argument */ +#define ARG int _c, _b; char *_a; \ + for(_c = 1; _c < argc && argv[_c][0] == '-' && argv[_c][1] && \ + (strcmp(argv[_c], "--") != 0); _c++) \ + for(_a = &argv[_c][1], _b = 0; !_b && *_a; _a++ ) \ + switch(*_a) +#define ARGVAL() (!_b && _a[1] && (_b = 1) ? &_a[1] : _c + 1 == argc ? \ + 0 : argv[++_c]) +#define ARGCHR() (*_a) +#define ARGC() _c + +GtkWidget *win; +GtkWidget *browser; +WebKitWebView *view; +gchar *title; +gint progress = 100; +gboolean embed = FALSE; + +static void setup(void); +static void cleanup(void); +static void updatetitle(void); +static void windestroy(GtkWidget* w, gpointer d); +static gboolean keypress(GtkWidget* w, GdkEventKey *ev); +static void titlechange(WebKitWebView* view, WebKitWebFrame* frame, const gchar* title, gpointer d); +static void progresschange(WebKitWebView *view, gint p, gpointer d); +static void loadcommit(WebKitWebView *view, WebKitWebFrame *f, gpointer d); +static void loadstart(WebKitWebView *view, WebKitWebFrame *f, gpointer d); +static void loadfinish(WebKitWebView *view, WebKitWebFrame *f, gpointer d); +static void linkhover(WebKitWebView* page, const gchar* t, const gchar* l, gpointer d); +static gboolean newwindow(WebKitWebView *view, WebKitWebFrame *f, + WebKitNetworkRequest *r, WebKitWebNavigationAction *n, + WebKitWebPolicyDecision *p, gpointer d); +static gboolean download(WebKitWebView *view, GObject *o, gpointer d); +static void loaduri(gchar *uri); +static void loadfile(gchar *f); +static void setupstdin(); +static gboolean readstdin(GIOChannel *c, GIOCondition con); + +gboolean +readstdin(GIOChannel *c, GIOCondition con) { + gchar *line, *p; + GIOStatus ret; + + ret = g_io_channel_read_line(c, &line, NULL, NULL, NULL); + if(ret == G_IO_STATUS_ERROR || ret == G_IO_STATUS_EOF) + return FALSE; + for(p = line; *p && *p != '\n'; p++); + *p = '\0'; + loaduri(line); + g_free(line); + return TRUE; +} + +void +setupstdin() { + GIOChannel *c = NULL; + + c = g_io_channel_unix_new(STDIN_FILENO); + if(c && !g_io_add_watch(c, G_IO_IN|G_IO_HUP, (GIOFunc) readstdin, NULL)) + g_error("Stdin: could not add watch\n"); +} + +void +loadfile(gchar *f) { + GIOChannel *c = NULL; + GError *e = NULL; + GString *code = g_string_new(""); + gchar *line; + + /* cannot use fileno in c99 - workaround*/ + if(strcmp(f, "-") == 0) + c = g_io_channel_unix_new(STDIN_FILENO); + else + c = g_io_channel_new_file(f, "r", NULL); + if (c) { + while(g_io_channel_read_line(c, &line, NULL, NULL, &e) == G_IO_STATUS_NORMAL) { + g_string_append(code, line); + g_free(line); + } + webkit_web_view_load_html_string(view, code->str, NULL); + g_io_channel_shutdown(c, FALSE, NULL); + } +} + +static void loaduri(gchar *uri) { + GString* u = g_string_new(uri); + if(g_strrstr(u->str, "://") == NULL) + g_string_prepend(u, "http://"); + webkit_web_view_load_uri(view, u->str); + g_string_free(u, TRUE); +} + +gboolean +download(WebKitWebView *view, GObject *o, gpointer d) { + /* TODO */ + return FALSE; +} + +gboolean +newwindow(WebKitWebView *view, WebKitWebFrame *f, + WebKitNetworkRequest *r, WebKitWebNavigationAction *n, + WebKitWebPolicyDecision *p, gpointer d) { + /* TODO */ + return FALSE; +} +void +linkhover(WebKitWebView* page, const gchar* t, const gchar* l, gpointer d) { + /* TODO */ +} + +void +loadstart(WebKitWebView *view, WebKitWebFrame *f, gpointer d) { + /* ??? TODO */ +} + +void +loadcommit(WebKitWebView *view, WebKitWebFrame *f, gpointer d) { + /* ??? TODO */ +} + +void +loadfinish(WebKitWebView *view, WebKitWebFrame *f, gpointer d) { + /* ??? TODO */ +} + +void +progresschange(WebKitWebView* view, gint p, gpointer d) { + progress = p; + updatetitle(); +} + +void +updatetitle() { + char t[512]; + snprintf(t, LENGTH(t), "%s [%i%%]", title, progress); + gtk_window_set_title(GTK_WINDOW(win), t); +} + +void +titlechange(WebKitWebView *v, WebKitWebFrame *f, const gchar *t, gpointer d) { + if(title) + g_free(title); + title = g_strdup(t); + updatetitle(); +} + +void +windestroy(GtkWidget* w, gpointer d) { + gtk_main_quit(); +} + +gboolean +keypress(GtkWidget* w, GdkEventKey *ev) { + /* TODO */ + return FALSE; +} + +void setup(void) { + win = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(win), 800, 600); + gtk_widget_set_name(win, "surf window"); + browser = gtk_scrolled_window_new(NULL, NULL); + g_signal_connect (G_OBJECT(win), "destroy", G_CALLBACK(windestroy), NULL); + g_signal_connect (G_OBJECT(win), "key-press-event", G_CALLBACK(keypress), NULL); + + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(browser), + GTK_POLICY_NEVER, GTK_POLICY_NEVER); + view = WEBKIT_WEB_VIEW(webkit_web_view_new()); + gtk_container_add(GTK_CONTAINER(browser), GTK_WIDGET(view)); + + g_signal_connect(G_OBJECT(view), "title-changed", G_CALLBACK(titlechange), view); + g_signal_connect(G_OBJECT(view), "load-progress-changed", G_CALLBACK(progresschange), view); + g_signal_connect(G_OBJECT(view), "load-committed", G_CALLBACK(loadcommit), view); + g_signal_connect(G_OBJECT(view), "load-started", G_CALLBACK(loadstart), view); + g_signal_connect(G_OBJECT(view), "load-finished", G_CALLBACK(loadfinish), view); + g_signal_connect(G_OBJECT(view), "hovering-over-link", G_CALLBACK(linkhover), view); + g_signal_connect(G_OBJECT(view), "new-window-policy-decision-requested", G_CALLBACK(newwindow), view); + g_signal_connect(G_OBJECT(view), "download-requested", G_CALLBACK(download), view); + /* g_signal_connect(G_OBJECT(view), "create-web-view", G_CALLBACK(createwebview), view); */ + + gtk_container_add(GTK_CONTAINER(win), browser); + gtk_widget_grab_focus(GTK_WIDGET(view)); + gtk_widget_show_all(win); +} + +void cleanup() { +} + +int main(int argc, char *argv[]) { + gchar *uri = NULL, *file = NULL; + + ARG { + case 'e': + embed = TRUE; + break; + case 'u': + if(!(uri = ARGVAL())) + goto argerr; + break; + case 'f': + if(!(file = ARGVAL())) + goto argerr; + break; + argerr: + default: + puts("surf - simple browser"); + printf("usage: %s [-e] [-u uri] [-f file]", argv[0]); + return EXIT_FAILURE; + } + if(argc != ARGC()) + goto argerr; + gtk_init(NULL, NULL); + if (!g_thread_supported()) + g_thread_init(NULL); + setup(); + if(uri) + loaduri(uri); + else if(file) + loadfile(file); + setupstdin(); + updatetitle(); + gtk_main(); + cleanup(); + return EXIT_SUCCESS; +}