diff options
| -rw-r--r-- | Makefile | 10 | ||||
| -rw-r--r-- | surf.c | 196 | 
2 files changed, 127 insertions, 79 deletions
| @@ -3,10 +3,10 @@  include config.mk -SRC = surf.c +SRC = surf.c tabbed.c  OBJ = ${SRC:.c=.o} -all: options surf +all: options surf tabbed  options:  	@echo surf build options: @@ -20,9 +20,11 @@ options:  ${OBJ}: config.mk -surf: ${OBJ} +surf: surf.o  	@echo CC -o $@ -	@${CC} -o $@ ${OBJ} ${LDFLAGS} +	@${CC} -o $@ surf.o ${LDFLAGS} + +tabbed: tabbed.o  clean:  	@echo cleaning @@ -1,3 +1,7 @@ +/* See LICENSE file for copyright and license details. + * + * To understand surf, start reading main(). + */  #include <X11/X.h>  #include <X11/Xatom.h>  #include <gtk/gtk.h> @@ -24,36 +28,48 @@  Display *dpy;  Atom urlprop; -GtkWidget *win; -GtkWidget *browser; -WebKitWebView *view; -gchar *title; -gint progress = 100; +typedef struct Client { +	GtkWidget *win; +	GtkWidget *browser; +	WebKitWebView *view; +	gchar *title; +	gint progress; +	struct Client *next; +} Client; +Client *clients = NULL;  gboolean embed = FALSE;  gboolean showxid = FALSE;  gboolean ignore_once = FALSE; +static Client *newclient(); +static void die(char *str);  static void setup(void);  static void cleanup(void); -static void updatetitle(void); +static void updatetitle(Client *c);  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 linkhover(WebKitWebView* page, const gchar* t, const gchar* l, gpointer d); +static void destroyclient(Client *c);  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 setupx(); +static void loaduri(const Client *c, const gchar *uri); +static void loadfile(const Client *c, const gchar *f);  GdkFilterReturn processx(GdkXEvent *xevent, GdkEvent *event, gpointer data); +void +cleanup(void) { + +} +  GdkFilterReturn -processx(GdkXEvent *e, GdkEvent *event, gpointer data) { +processx(GdkXEvent *e, GdkEvent *event, gpointer d) {  	XPropertyEvent *ev; +	Client *c = (Client *)d;  	Atom adummy;  	int idummy;  	unsigned long ldummy; @@ -62,8 +78,8 @@ processx(GdkXEvent *e, GdkEvent *event, gpointer data) {  		ev = &((XEvent *)e)->xproperty;  		if(ignore_once == FALSE && ev->atom == urlprop && ev->state == PropertyNewValue) {  			XGetWindowProperty(dpy, ev->window, urlprop, 0L, BUFSIZ, False, XA_STRING,  -			&adummy, &idummy, &ldummy, &ldummy, &buf); -			loaduri((gchar *)buf); +				&adummy, &idummy, &ldummy, &ldummy, &buf); +			loaduri(c, (gchar *)buf);  			XFree(buf);  			return GDK_FILTER_REMOVE;  		} @@ -73,45 +89,36 @@ processx(GdkXEvent *e, GdkEvent *event, gpointer data) {  }  void -setupx() { -	dpy = GDK_WINDOW_XDISPLAY(GTK_WIDGET(win)->window); -	urlprop = XInternAtom(dpy, "_SURF_URL", False); -	gdk_window_add_filter(GTK_WIDGET(win)->window, processx, NULL); -	gdk_window_set_events(GTK_WIDGET(win)->window, GDK_ALL_EVENTS_MASK); -} - -void -loadfile(gchar *f) { -	GIOChannel *c = NULL; +loadfile(const Client *c, const gchar *f) { +	GIOChannel *chan = NULL;  	GError *e = NULL;  	GString *code = g_string_new("");  	GString *uri = g_string_new(f);  	gchar *line;  	if(strcmp(f, "-") == 0) { -		c = g_io_channel_unix_new(STDIN_FILENO); -		if (c) { -			while(g_io_channel_read_line(c, &line, NULL, NULL, &e) == G_IO_STATUS_NORMAL) { +		chan = g_io_channel_unix_new(STDIN_FILENO); +		if (chan) { +			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(view, code->str, NULL); -			g_free(code); -			g_io_channel_shutdown(c, FALSE, NULL); +			webkit_web_view_load_html_string(c->view, code->str, NULL); +			g_io_channel_shutdown(chan, FALSE, NULL);  		}  	}  	else {  		g_string_prepend(uri, "file://"); -		loaduri(uri->str); +		loaduri(c, uri->str);  	}  } -static void loaduri(gchar *uri) { +static void loaduri(const Client *c, const gchar *uri) {  	GString* u = g_string_new(uri); -	if(g_strrstr(u->str, "://") == NULL) +	if(g_strrstr(u->str, ":") == NULL)  		g_string_prepend(u, "http://"); -	webkit_web_view_load_uri(view, u->str); +	webkit_web_view_load_uri(c->view, u->str);  	g_string_free(u, TRUE);  } @@ -125,8 +132,9 @@ gboolean  newwindow(WebKitWebView *view, WebKitWebFrame *f,  		WebKitNetworkRequest *r, WebKitWebNavigationAction *n,  		WebKitWebPolicyDecision *p, gpointer d) { -	/* TODO */ -	return FALSE; +	Client *c = newclient(); +	webkit_web_view_load_request(c->view, r); +	return TRUE;  }  void  linkhover(WebKitWebView* page, const gchar* t, const gchar* l, gpointer d) { @@ -135,43 +143,64 @@ linkhover(WebKitWebView* page, const gchar* t, const gchar* l, gpointer d) {  void  loadcommit(WebKitWebView *view, WebKitWebFrame *f, gpointer d) { +	Client *c = (Client *)d;  	gchar *uri;  	if(!(uri = (gchar *)webkit_web_view_get_uri(view)))  		uri = "(null)";  	ignore_once = TRUE; -	XChangeProperty(dpy, GDK_WINDOW_XID(GTK_WIDGET(win)->window), urlprop, +	XChangeProperty(dpy, GDK_WINDOW_XID(GTK_WIDGET(c->win)->window), urlprop,  			XA_STRING, 8, PropModeReplace, (unsigned char *)uri,  			strlen(uri) + 1);  }  void  progresschange(WebKitWebView* view, gint p, gpointer d) { -	progress = p; -	updatetitle(); +	Client *c = (Client *)d; + +	c->progress = p; +	updatetitle(c);  }  void -updatetitle() { +updatetitle(Client *c) {  	char t[512]; -	if(progress == 100) -		snprintf(t, LENGTH(t), "%s", title); +	if(c->progress == 100) +		snprintf(t, LENGTH(t), "%s", c->title);  	else -		snprintf(t, LENGTH(t), "%s [%i%%]", title, progress); -	gtk_window_set_title(GTK_WINDOW(win), t); +		snprintf(t, LENGTH(t), "%s [%i%%]", c->title, c->progress); +	gtk_window_set_title(GTK_WINDOW(c->win), t);  }  void  titlechange(WebKitWebView *v, WebKitWebFrame *f, const gchar *t, gpointer d) { -	if(title) -		g_free(title); -	title = g_strdup(t); -	updatetitle(); +	Client *c = (Client *)d; + +	if(c->title) +		g_free(c->title); +	c->title = g_strdup(t); +	updatetitle(c);  }  void  windestroy(GtkWidget* w, gpointer d) { -	gtk_main_quit(); +	Client *c = (Client *)d; + +	destroyclient(c); +} + +void +destroyclient(Client *c) { +	Client *p; +	gtk_widget_destroy(c->win); +	if(clients == c && c->next == NULL) +		gtk_main_quit(); +	for(p = clients; p && p->next != c; p = p->next); +	if(p) +		p->next = c->next; +	else +		clients = c->next; +	free(c);  }  gboolean @@ -181,43 +210,60 @@ keypress(GtkWidget* w, GdkEventKey *ev) {  }  void setup(void) { +	dpy = GDK_DISPLAY(); +	urlprop = XInternAtom(dpy, "_SURF_URL", False); +} + +void die(char *str) { +	fputs(str, stderr); +	exit(EXIT_FAILURE); +} + +Client * +newclient(void) { +	Client *c; +	if(!(c = calloc(1, sizeof(Client)))) +		die("Cannot malloc!\n");  	if(embed) { -		win = gtk_plug_new(0); +		c->win = gtk_plug_new(0);  	}  	else { -		win = gtk_window_new(GTK_WINDOW_TOPLEVEL); -		gtk_window_set_wmclass(GTK_WINDOW(win), "surf", "surf"); +		c->win = gtk_window_new(GTK_WINDOW_TOPLEVEL); +		gtk_window_set_wmclass(GTK_WINDOW(c->win), "surf", "surf");  	} -	gtk_window_set_default_size(GTK_WINDOW(win), 800, 600); -	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_window_set_default_size(GTK_WINDOW(c->win), 800, 600); +	c->browser = gtk_scrolled_window_new(NULL, NULL); +	g_signal_connect (G_OBJECT(c->win), "destroy", G_CALLBACK(windestroy), c); +	g_signal_connect (G_OBJECT(c->win), "key-press-event", G_CALLBACK(keypress), NULL); -	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(browser), +	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(c->browser),  			GTK_POLICY_NEVER, GTK_POLICY_NEVER); -	view = WEBKIT_WEB_VIEW(webkit_web_view_new()); -	gtk_container_add(GTK_CONTAINER(browser), GTK_WIDGET(view)); +	c->view = WEBKIT_WEB_VIEW(webkit_web_view_new()); +	gtk_container_add(GTK_CONTAINER(c->browser), GTK_WIDGET(c->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), "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); */ +	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-committed", G_CALLBACK(loadcommit), c); +	g_signal_connect(G_OBJECT(c->view), "hovering-over-link", G_CALLBACK(linkhover), c); +	g_signal_connect(G_OBJECT(c->view), "new-window-policy-decision-requested", G_CALLBACK(newwindow), c); +	g_signal_connect(G_OBJECT(c->view), "download-requested", G_CALLBACK(download), c); +	/* g_signal_connect(G_OBJECT(c->view), "create-web-view", G_CALLBACK(createwebview), c); */ -	gtk_container_add(GTK_CONTAINER(win), browser); -	gtk_widget_grab_focus(GTK_WIDGET(view)); -	gtk_widget_show_all(win); +	gtk_container_add(GTK_CONTAINER(c->win), c->browser); +	gtk_widget_grab_focus(GTK_WIDGET(c->view)); +	gtk_widget_show_all(c->win);  	if(showxid) -		printf("%u\n", (unsigned int)GDK_WINDOW_XID(GTK_WIDGET(win)->window)); -} - -void cleanup() { +		printf("%u\n", (unsigned int)GDK_WINDOW_XID(GTK_WIDGET(c->win)->window)); +	c->next = clients; +	clients = c; +	gdk_window_set_events(GTK_WIDGET(c->win)->window, GDK_ALL_EVENTS_MASK); +	gdk_window_add_filter(GTK_WIDGET(c->win)->window, processx, c); +	return c;  }  int main(int argc, char *argv[]) {  	gchar *uri = NULL, *file = NULL; +	Client *c;  	ARG {  	case 'x': @@ -247,12 +293,12 @@ int main(int argc, char *argv[]) {  	if (!g_thread_supported())  		g_thread_init(NULL);  	setup(); -	setupx(); +	c = newclient();  	if(uri) -		loaduri(uri); +		loaduri(c, uri);  	else if(file) -		loadfile(file); -	updatetitle(); +		loadfile(c, file); +	updatetitle(c);  	gtk_main();  	cleanup();  	return EXIT_SUCCESS; | 
