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