]> git.armaanb.net Git - chorizo.git/blob - zea.c
b590da78791370d2a847afbea022da116e941f4e
[chorizo.git] / zea.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #include <gtk/gtk.h>
5 #include <gdk/gdkx.h>
6 #include <gdk/gdkkeysyms.h>
7 #include <webkit/webkit.h>
8
9
10 #define DOWNLOAD_DIR "/tmp/tmp"
11
12
13 static void zea_destroy_client(GtkWidget *, gpointer);
14 static gboolean zea_do_download(WebKitWebView *, WebKitDownload *, gpointer);
15 static gboolean zea_download_request(WebKitWebView *, WebKitWebFrame *,
16                                      WebKitNetworkRequest *, gchar *,
17                                      WebKitWebPolicyDecision *, gpointer);
18 static gboolean zea_location_key(GtkWidget *, GdkEvent *, gpointer);
19 static void zea_new_client(const gchar *uri);
20 static gboolean zea_new_client_request(WebKitWebView *, WebKitWebFrame *,
21                                        WebKitNetworkRequest *,
22                                        WebKitWebNavigationAction *,
23                                        WebKitWebPolicyDecision *, gpointer);
24 static void zea_title_changed(GObject *, GParamSpec *, gpointer);
25 static void zea_uri_changed(GObject *, GParamSpec *, gpointer);
26 static gboolean zea_web_view_key(GtkWidget *, GdkEvent *, gpointer);
27
28
29 static Window embed = 0;
30 static int clients = 0;
31 static double global_zoom = 1.0;
32
33
34 struct Client
35 {
36         GtkWidget *win;
37         GtkWidget *vbox;
38         GtkWidget *location;
39         GtkWidget *scroll;
40         GtkWidget *web_view;
41 };
42
43
44 void
45 zea_destroy_client(GtkWidget *obj, gpointer data)
46 {
47         struct Client *c = (struct Client *)data;
48
49         (void)obj;
50
51         webkit_web_view_stop_loading(WEBKIT_WEB_VIEW(c->web_view));
52         gtk_widget_destroy(c->web_view);
53         gtk_widget_destroy(c->scroll);
54         gtk_widget_destroy(c->win);
55         free(c);
56
57         clients--;
58         if (clients == 0)
59                 gtk_main_quit();
60 }
61
62 gboolean
63 zea_do_download(WebKitWebView *web_view, WebKitDownload *download, gpointer data)
64 {
65         const gchar *uri;
66         char id[16] = "";
67         int ret;
68
69         (void)web_view;
70         (void)data;
71
72         uri = webkit_download_get_uri(download);
73         if (fork() == 0)
74         {
75                 chdir(DOWNLOAD_DIR);
76                 if (embed == 0)
77                         ret = execlp("xterm", "xterm", "-hold", "-e", "wget", uri, NULL);
78                 else
79                 {
80                         if (snprintf(id, 16, "%ld", embed) >= 16)
81                         {
82                                 fprintf(stderr, "zea: id for xterm embed truncated!\n");
83                                 exit(EXIT_FAILURE);
84                         }
85                         ret = execlp("xterm", "xterm", "-hold", "-into", id, "-e", "wget",
86                                      uri, NULL);
87                 }
88
89                 if (ret == -1)
90                 {
91                         fprintf(stderr, "zea: exec'ing xterm for download");
92                         perror(" failed");
93                         exit(EXIT_FAILURE);
94                 }
95         }
96
97         return FALSE;
98 }
99
100 gboolean
101 zea_download_request(WebKitWebView *web_view, WebKitWebFrame *frame,
102                      WebKitNetworkRequest *request, gchar *mime_type,
103                      WebKitWebPolicyDecision *policy_decision,
104                      gpointer data)
105 {
106         (void)frame;
107         (void)request;
108         (void)data;
109
110         if (!webkit_web_view_can_show_mime_type(web_view, mime_type))
111         {
112                 webkit_web_policy_decision_download(policy_decision);
113                 return TRUE;
114         }
115         return FALSE;
116 }
117
118 gboolean
119 zea_location_key(GtkWidget *widget, GdkEvent *event, gpointer data)
120 {
121         struct Client *c = (struct Client *)data;
122
123         (void)widget;
124
125         if (event->type == GDK_KEY_PRESS)
126         {
127                 if (((GdkEventKey *)event)->keyval == GDK_KEY_Return)
128                 {
129                         gtk_widget_grab_focus(c->web_view);
130                         webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view),
131                                                  gtk_entry_get_text(GTK_ENTRY(c->location)));
132                         return TRUE;
133                 }
134         }
135
136         return FALSE;
137 }
138
139 void
140 zea_new_client(const gchar *uri)
141 {
142         struct Client *c = malloc(sizeof(struct Client));
143         if (!c)
144         {
145                 fprintf(stderr, "zea: fatal: malloc failed\n");
146                 exit(EXIT_FAILURE);
147         }
148
149         if (embed == 0)
150         {
151                 c->win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
152         }
153         else
154         {
155                 c->win = gtk_plug_new(embed);
156         }
157
158         /* When using Gtk2, zea only shows a white area when run in
159          * suckless' tabbed. It appears we need to set a default window size
160          * for this to work. This is not needed when using Gtk3. */
161         gtk_window_set_default_size(GTK_WINDOW(c->win), 1024, 768);
162
163         g_signal_connect(G_OBJECT(c->win), "destroy",
164                          G_CALLBACK(zea_destroy_client), c);
165         gtk_window_set_title(GTK_WINDOW(c->win), "zea");
166
167         c->web_view = webkit_web_view_new();
168         webkit_web_view_set_full_content_zoom(WEBKIT_WEB_VIEW(c->web_view), TRUE);
169         webkit_web_view_set_zoom_level(WEBKIT_WEB_VIEW(c->web_view), global_zoom);
170         g_signal_connect(G_OBJECT(c->web_view), "notify::title",
171                          G_CALLBACK(zea_title_changed), c);
172         g_signal_connect(G_OBJECT(c->web_view), "notify::uri",
173                          G_CALLBACK(zea_uri_changed), c);
174         g_signal_connect(G_OBJECT(c->web_view),
175                          "new-window-policy-decision-requested",
176                          G_CALLBACK(zea_new_client_request), NULL);
177         g_signal_connect(G_OBJECT(c->web_view),
178                          "mime-type-policy-decision-requested",
179                          G_CALLBACK(zea_download_request), NULL);
180         g_signal_connect(G_OBJECT(c->web_view), "download-requested",
181                          G_CALLBACK(zea_do_download), NULL);
182         g_signal_connect(G_OBJECT(c->web_view), "key-press-event",
183                          G_CALLBACK(zea_web_view_key), c);
184
185         c->scroll = gtk_scrolled_window_new(NULL, NULL);
186
187         gtk_container_add(GTK_CONTAINER(c->scroll), c->web_view);
188
189         c->location = gtk_entry_new();
190         g_signal_connect(G_OBJECT(c->location), "key-press-event",
191                          G_CALLBACK(zea_location_key), c);
192
193         c->vbox = gtk_vbox_new(FALSE, 0);
194         gtk_box_pack_start(GTK_BOX(c->vbox), c->location, FALSE, FALSE, 0);
195         gtk_container_add(GTK_CONTAINER(c->vbox), c->scroll);
196
197         gtk_container_add(GTK_CONTAINER(c->win), c->vbox);
198
199         gtk_widget_grab_focus(c->web_view);
200         gtk_widget_show_all(c->win);
201
202         webkit_web_view_load_uri(WEBKIT_WEB_VIEW(c->web_view), uri);
203
204         clients++;
205 }
206
207 gboolean
208 zea_new_client_request(WebKitWebView *web_view, WebKitWebFrame *frame,
209                        WebKitNetworkRequest *request,
210                        WebKitWebNavigationAction *navigation_action,
211                        WebKitWebPolicyDecision *policy_decision,
212                        gpointer user_data)
213 {
214         (void)web_view;
215         (void)frame;
216         (void)navigation_action;
217         (void)user_data;
218
219         webkit_web_policy_decision_ignore(policy_decision);
220         zea_new_client(webkit_network_request_get_uri(request));
221
222         return TRUE;
223 }
224
225 void
226 zea_title_changed(GObject *obj, GParamSpec *pspec, gpointer data)
227 {
228         const gchar *t;
229         struct Client *c = (struct Client *)data;
230
231         (void)obj;
232         (void)pspec;
233
234         t = webkit_web_view_get_title(WEBKIT_WEB_VIEW(c->web_view));
235         gtk_window_set_title(GTK_WINDOW(c->win), (t == NULL ? "zea" : t));
236 }
237
238 void
239 zea_uri_changed(GObject *obj, GParamSpec *pspec, gpointer data)
240 {
241         const gchar *t;
242         struct Client *c = (struct Client *)data;
243
244         (void)obj;
245         (void)pspec;
246
247         t = webkit_web_view_get_uri(WEBKIT_WEB_VIEW(c->web_view));
248         gtk_entry_set_text(GTK_ENTRY(c->location), (t == NULL ? "zea" : t));
249 }
250
251 gboolean
252 zea_web_view_key(GtkWidget *widget, GdkEvent *event, gpointer data)
253 {
254         struct Client *c = (struct Client *)data;
255
256         (void)widget;
257
258         if (event->type == GDK_KEY_PRESS)
259         {
260                 if (((GdkEventKey *)event)->state & GDK_MOD1_MASK)
261                 {
262                         if (((GdkEventKey *)event)->keyval == GDK_KEY_l)
263                         {
264                                 gtk_widget_grab_focus(c->location);
265                                 return TRUE;
266                         }
267                 }
268         }
269
270         return FALSE;
271 }
272
273 int
274 main(int argc, char **argv)
275 {
276         int opt;
277
278         gtk_init(&argc, &argv);
279
280         while ((opt = getopt(argc, argv, "z:e:")) != -1)
281         {
282                 switch (opt)
283                 {
284                         case 'z':
285                                 global_zoom = atof(optarg);
286                                 break;
287                         case 'e':
288                                 embed = atol(optarg);
289                                 break;
290                 }
291         }
292
293         if (optind >= argc)
294         {
295                 fprintf(stderr, "Usage: zea [OPTIONS] <URI>\n");
296                 exit(EXIT_FAILURE);
297         }
298
299         zea_new_client(argv[optind]);
300         gtk_main();
301         exit(EXIT_SUCCESS);
302 }