tsupporting multiple windows per instance - surf - customized build of surf, th… | |
git clone git://src.adamsgaard.dk/surf | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit ad005db13f571dabb72fce448eb0d93f79acf97d | |
parent d1cfea4e86d517177ced89eb96f7f51aa9200298 | |
Author: Enno Boland (Gottox) <[email protected]> | |
Date: Fri, 5 Jun 2009 20:16:10 +0200 | |
supporting multiple windows per instance | |
Diffstat: | |
M Makefile | 10 ++++++---- | |
M surf.c | 196 +++++++++++++++++++----------… | |
2 files changed, 127 insertions(+), 79 deletions(-) | |
--- | |
diff --git a/Makefile b/Makefile | |
t@@ -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: | |
t@@ -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 | |
diff --git a/surf.c b/surf.c | |
t@@ -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> | |
t@@ -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 gcha… | |
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, gpo… | |
+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; | |
t@@ -62,8 +78,8 @@ processx(GdkXEvent *e, GdkEvent *event, gpointer data) { | |
ev = &((XEvent *)e)->xproperty; | |
if(ignore_once == FALSE && ev->atom == urlprop && ev->state ==… | |
XGetWindowProperty(dpy, ev->window, urlprop, 0L, BUFSI… | |
- &adummy, &idummy, &ldummy, &ldummy, &buf); | |
- loaduri((gchar *)buf); | |
+ &adummy, &idummy, &ldummy, &ldummy, &buf); | |
+ loaduri(c, (gchar *)buf); | |
XFree(buf); | |
return GDK_FILTER_REMOVE; | |
} | |
t@@ -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)… | |
+ chan = g_io_channel_unix_new(STDIN_FILENO); | |
+ if (chan) { | |
+ while(g_io_channel_read_line(chan, &line, NULL, NULL, … | |
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, N… | |
+ 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); | |
} | |
t@@ -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) { | |
t@@ -135,43 +143,64 @@ linkhover(WebKitWebView* page, const gchar* t, const gch… | |
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), urlpr… | |
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 | |
t@@ -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), NU… | |
- g_signal_connect (G_OBJECT(win), "key-press-event", G_CALLBACK(keypres… | |
+ 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),… | |
+ g_signal_connect (G_OBJECT(c->win), "key-press-event", G_CALLBACK(keyp… | |
- 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(titlechan… | |
- g_signal_connect(G_OBJECT(view), "load-progress-changed", G_CALLBACK(p… | |
- g_signal_connect(G_OBJECT(view), "load-committed", G_CALLBACK(loadcomm… | |
- g_signal_connect(G_OBJECT(view), "hovering-over-link", G_CALLBACK(link… | |
- g_signal_connect(G_OBJECT(view), "new-window-policy-decision-requested… | |
- g_signal_connect(G_OBJECT(view), "download-requested", G_CALLBACK(down… | |
- /* g_signal_connect(G_OBJECT(view), "create-web-view", G_CALLBACK(crea… | |
+ g_signal_connect(G_OBJECT(c->view), "title-changed", G_CALLBACK(titlec… | |
+ g_signal_connect(G_OBJECT(c->view), "load-progress-changed", G_CALLBAC… | |
+ g_signal_connect(G_OBJECT(c->view), "load-committed", G_CALLBACK(loadc… | |
+ g_signal_connect(G_OBJECT(c->view), "hovering-over-link", G_CALLBACK(l… | |
+ g_signal_connect(G_OBJECT(c->view), "new-window-policy-decision-reques… | |
+ g_signal_connect(G_OBJECT(c->view), "download-requested", G_CALLBACK(d… | |
+ /* g_signal_connect(G_OBJECT(c->view), "create-web-view", G_CALLBACK(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)->w… | |
-} | |
- | |
-void cleanup() { | |
+ printf("%u\n", (unsigned int)GDK_WINDOW_XID(GTK_WIDGET(c->win)… | |
+ 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': | |
t@@ -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; |