remove the aliases concept. commands is all we need + synchronize command names with...
[uzbl-mobile] / uzbl.c
1 // Original code taken from the example webkit-gtk+ application. see notice below.
2 // Modified code is licensed under the GPL 3.  See LICENSE file.
3
4
5 /*
6  * Copyright (C) 2006, 2007 Apple Inc.
7  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <gtk/gtk.h>
32 #include <gdk/gdkx.h>
33 #include <webkit/webkit.h>
34 #include <pthread.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <sys/stat.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41
42 static GtkWidget* main_window;
43 static GtkWidget* uri_entry;
44 static GtkWidget* mainbar;
45 static WebKitWebView* web_view;
46 static gchar* main_title;
47 static gchar* history_file;
48 static gchar* fifodir   = NULL;
49 static char fifopath[64];
50 static gint load_progress;
51 static guint status_context_id;
52 static Window xwin = NULL;
53 static gchar* uri = NULL;
54
55 static gboolean verbose = FALSE;
56
57
58 static GOptionEntry entries[] =
59 {
60   { "uri",     'u', 0, G_OPTION_ARG_STRING, &uri,     "Uri to load", NULL },
61   { "verbose", 'v', 0, G_OPTION_ARG_NONE,   &verbose, "Be verbose",  NULL },
62   { NULL }
63 };
64
65 struct command
66 {
67   char command[256];
68   void (*func)(WebKitWebView*);
69 };
70
71 static struct command commands[256];
72 static int            numcmds = 0;
73
74 static void
75 parse_command(const char*);
76
77
78 static void
79 parse_command(const char *command)
80 {
81   int  i    = 0;
82   bool done = false;
83   char *cmdstr;
84   void (*func)(WebKitWebView*);
85
86   strcpy(cmdstr, command);
87
88   done = false;
89   printf("Checking commands\n");
90   for (i = 0; i < numcmds && ! done; i++)
91     {
92       if (!strncmp (cmdstr, commands[i].command, strlen (commands[i].command)))
93         {
94           func = commands[i].func;
95           done = true;
96         }
97     }
98
99   printf("Command identified as \"%s\"\n", cmdstr);
100
101   if (done)
102     {
103       func (web_view);
104     }
105   else
106     {
107       if (!strncmp ("http://", command, 7))
108         {
109           printf ("Loading URI \"%s\"\n", command);
110           strcpy(uri, command);
111           webkit_web_view_load_uri (web_view, uri);
112         }
113     }
114 }
115
116 static void
117 *control_fifo()
118 {
119   if (fifodir)
120     {
121       sprintf (fifopath, "%s/uzbl_%d", fifodir, getpid ());
122     }
123   else
124     {
125       sprintf (fifopath, "/tmp/uzbl_%d", getpid ());
126     }
127
128   if (mkfifo (fifopath, 0666) == -1)
129     {
130       printf ("Possible error creating fifo\n");
131     }
132
133     printf ("Opened control fifo in %s\n", fifopath);
134
135     while (true)
136       {
137         FILE *fifo = fopen(fifopath, "r");
138         if (!fifo)
139           {
140             printf("Could not open %s for reading\n", fifopath);
141             return NULL;
142           }
143         
144         char buffer[256];
145         memset (buffer, 0, sizeof (buffer));
146         while (!feof (fifo) && fgets (buffer, sizeof (buffer), fifo))
147           {
148             if (strcmp (buffer, "\n"))
149               {
150                 buffer[strlen (buffer) - 1] = '\0'; // Remove newline
151                 parse_command (buffer);
152               }
153           }
154       }
155     
156     return NULL;
157 }
158
159 static void
160 add_command (char* cmdstr, void* function)
161 {
162   strncpy (commands[numcmds].command, cmdstr, strlen (cmdstr));
163   commands[numcmds].func = function;
164   numcmds++;
165 }
166
167 static void
168 setup_commands ()
169 {
170   // This func. is nice but currently it cannot be used for functions that require arguments or return data. --sentientswitch
171   // TODO: reload, home
172   add_command("back",     &webkit_web_view_go_back);
173   add_command("forward",  &webkit_web_view_go_forward);
174   add_command("refresh",  &webkit_web_view_reload); //Buggy
175   add_command("stop",     &webkit_web_view_stop_loading);
176   add_command("zoom_in",  &webkit_web_view_zoom_in); //Can crash (when max zoom reached?).
177   add_command("zoom_out", &webkit_web_view_zoom_out); //Crashes as zoom +
178   //add_command("get uri", &webkit_web_view_get_uri);
179 }
180
181 static void
182 setup_threading ()
183 {
184   pthread_t control_thread;
185   pthread_create(&control_thread, NULL, control_fifo, NULL);
186 }
187
188
189 static void
190 log_history_cb () {
191     FILE * output_file = fopen(history_file, "a");
192     if (output_file == NULL) {
193        fprintf(stderr, "Cannot open %s for logging\n", history_file);
194     } else {
195         time_t rawtime;
196         struct tm * timeinfo;
197         char buffer [80];
198         time ( &rawtime );
199         timeinfo = localtime ( &rawtime );
200         strftime (buffer,80,"%Y-%m-%d %H:%M:%S",timeinfo);
201
202         fprintf(output_file, "%s %s\n",buffer, uri);
203         fclose(output_file);
204     }
205 }
206
207
208 static void
209 activate_uri_entry_cb (GtkWidget* entry, gpointer data)
210 {
211     uri = gtk_entry_get_text (GTK_ENTRY (entry));
212     g_assert (uri);
213     webkit_web_view_load_uri (web_view, uri);
214 }
215
216 static void
217 update_title (GtkWindow* window)
218 {
219     GString* string = g_string_new (main_title);
220     g_string_append (string, " - Uzbl browser");
221     if (load_progress < 100)
222         g_string_append_printf (string, " (%d%%)", load_progress);
223     gchar* title = g_string_free (string, FALSE);
224     gtk_window_set_title (window, title);
225     g_free (title);
226 }
227
228 static void
229 link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data)
230 {
231     /* underflow is allowed */
232     //gtk_statusbar_pop (main_statusbar, status_context_id);
233     //if (link)
234     //    gtk_statusbar_push (main_statusbar, status_context_id, link);
235     //TODO implementation roadmap pending..
236 }
237
238 static void
239 title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data)
240 {
241     if (main_title)
242         g_free (main_title);
243     main_title = g_strdup (title);
244     update_title (GTK_WINDOW (main_window));
245 }
246
247 static void
248 progress_change_cb (WebKitWebView* page, gint progress, gpointer data)
249 {
250     load_progress = progress;
251     update_title (GTK_WINDOW (main_window));
252 }
253
254 static void
255 load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data)
256 {
257     const gchar* uri = webkit_web_frame_get_uri(frame);
258     if (uri)
259         gtk_entry_set_text (GTK_ENTRY (uri_entry), uri);
260 }
261
262 static void
263 destroy_cb (GtkWidget* widget, gpointer data)
264 {
265     gtk_main_quit ();
266 }
267
268 static void
269 go_back_cb (GtkWidget* widget, gpointer data)
270 {
271     webkit_web_view_go_back (web_view);
272 }
273
274 static void
275 go_forward_cb (GtkWidget* widget, gpointer data)
276 {
277     webkit_web_view_go_forward (web_view);
278 }
279
280 static GtkWidget*
281 create_browser ()
282 {
283     GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
284     gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_NEVER); //todo: some sort of display of position/total length. like what emacs does
285
286     web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
287     gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (web_view));
288
289     g_signal_connect (G_OBJECT (web_view), "title-changed", G_CALLBACK (title_change_cb), web_view);
290     g_signal_connect (G_OBJECT (web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), web_view);
291     g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (load_commit_cb), web_view);
292     g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (log_history_cb), web_view);
293     g_signal_connect (G_OBJECT (web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), web_view);
294
295     return scrolled_window;
296 }
297
298 static GtkWidget*
299 create_mainbar ()
300 {
301     mainbar = gtk_hbox_new(FALSE, 0);
302     uri_entry = gtk_entry_new();
303     gtk_entry_set_width_chars(GTK_ENTRY(uri_entry), 40);
304     gtk_entry_set_text(GTK_ENTRY(uri_entry), "http://");
305     gtk_box_pack_start (GTK_BOX (mainbar), uri_entry, FALSE,TRUE , 0);
306     gtk_signal_connect_object (GTK_OBJECT (uri_entry), "activate", GTK_SIGNAL_FUNC (activate_uri_entry_cb), GTK_OBJECT (uri_entry));
307
308     //status_context_id = gtk_statusbar_get_context_id (main_statusbar, "Link Hover");
309
310     return mainbar;
311 }
312
313 static
314 GtkWidget* create_window ()
315 {
316     GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
317     gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
318     gtk_widget_set_name (window, "Uzbl browser");
319     g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
320
321     return window;
322 }
323
324 int main (int argc, char* argv[])
325 {
326     gtk_init (&argc, &argv);
327     if (!g_thread_supported ())
328         g_thread_init (NULL);
329
330     GKeyFile* config = g_key_file_new ();
331     gboolean res = g_key_file_load_from_file (config, "./sampleconfig", G_KEY_FILE_NONE, NULL); //TODO: pass config file as argument
332     if(res) {
333         printf("config loaded\n");
334     } else {
335         fprintf(stderr,"config loading failed\n"); //TODO: exit codes with gtk? 
336     }
337     history_file = g_key_file_get_value (config, "behavior", "history_file", NULL);
338     if(history_file) {
339         printf("setting history file to: %s\n",history_file);
340     } else {
341         printf("history logging disabled\n");
342     }
343
344     GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
345     gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
346     gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
347
348
349
350     main_window = create_window ();
351     gtk_container_add (GTK_CONTAINER (main_window), vbox);
352   GError *error = NULL;
353
354   GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
355   g_option_context_add_main_entries (context, entries, NULL);
356   g_option_context_add_group (context, gtk_get_option_group (TRUE));
357   g_option_context_parse (context, &argc, &argv, &error);
358
359
360     webkit_web_view_load_uri (web_view, uri);
361
362     gtk_widget_grab_focus (GTK_WIDGET (web_view));
363     gtk_widget_show_all (main_window);
364     xwin = GDK_WINDOW_XID (GTK_WIDGET (main_window)->window);
365     printf("My X window id is %i\n",(int) xwin);
366
367
368     setup_commands ();
369     setup_threading ();
370
371     gtk_main ();
372
373     unlink (fifopath);
374     return 0;
375 }