Merge branch 'master' of git://github.com/Dieterbe/uzbl into dieter/master
authorBarrucadu <mike@barrucadu.co.uk>
Sat, 25 Apr 2009 11:40:19 +0000 (12:40 +0100)
committerBarrucadu <mike@barrucadu.co.uk>
Sat, 25 Apr 2009 11:40:19 +0000 (12:40 +0100)
1  2 
AUTHORS
README
TODO
sampleconfig
uzbl.c

diff --cc AUTHORS
+++ b/AUTHORS
@@@ -1,8 -1,2 +1,8 @@@
  Original code taken from webkit example application whis is copyrighted 2006, 2007 Apple Inc and 2007 Alp Toker <alp@atoker.com>
  enhancements to form uzbl made by Dieter Plaetinck.
 +
 +Michael Walker (Barrucadu) <mike@barrucadu.co.uk> - Original threaded FIFO interface. Command adding methods.
 +
 +Zane Ashby (HashBox) <http://demonastery.org> - Rewrote FIFO interface. Fixed various bugs.
 +
- (sentientswitch) - Cleaned up code. Added some commands.
++(sentientswitch) - Cleaned up code. Added some commands.
diff --cc README
--- 1/README
--- 2/README
+++ b/README
@@@ -65,10 -63,3 +66,10 @@@ CONTROL
  NOTE:
  - My c skills are very rusty, it will take me a while to get back up to speed
  - For more thoughts & ideas see http://bbs.archlinux.org/viewtopic.php?id=67463
 +- I push the code most times I save any changes, regardless of whether it actually compiles or not. Thus, the code here should be regarded as highly experimental.
 +
 +KNOWN BUGS
 +- Segfault occurs on shutdown, almost definitely FIFO related (I'm not seeing this bug now, but the warning was here when I forked the code and I haven't touched the FIFO bit)
 +- Segfaults when using zoom commands (happens when max zoom already reached?).
 +- Something in the FIFO code causes CPU usage to jump.
- - Segfaults when loading aliases from confgi file (currently aliases are defined in the code as a 'work-around').
++- Segfaults when loading aliases from confgi file (currently aliases are defined in the code as a 'work-around').
diff --cc TODO
--- 1/TODO
--- 2/TODO
+++ b/TODO
@@@ -1,6 -1,10 +1,12 @@@
  * implement all the ideas from README
++* Support for arguments to commands (argc/argv-like structure?).
++* Support for binding keyboard shortcuts in config file.
+ * where to put proxy config? webkit support?
  * do not store the 'http://' part in the history file
  * improve commandline arguments
+ * have a better look at /merge the fifo code from barrucadu and friends
  
- * Support for arguments to commands (argc/argv-like structure?).
- * Support for binding keyboard shortcuts in config file.
+ SOMEDAY:
+ figure out caching with webkit and in general how we can speed everything
+ figure out how webkit intercepts key input
diff --cc sampleconfig
index 0000000,c1dac2b..4d25674
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,31 +1,38 @@@
+ # example uzbl config. in a real config, we should obey the xdg spec
+ # all keys in the behavior group are optional.  if not set, the corresponding behavior is disabed.
+ # bindings_internal denote keys to trigger actions internally in uzbl
+ # bindings_external denote keys to trigger scripts outside uzbl
+ # keyboard behavior is vimstyle by default (all actions -> 1 key). set
+ # always_insert_mode to always be in insert mode and disable going out of it.
+ # if you do this, make sure you've set a modkey so you can reach the actions
+ # from insert mode by combining them with the modkey
+ [behavior]
+ history_file = /tmp/uzbl.history
+ download_handler = ./extra/download.sh
+ fifo_dir = /tmp
+ always_insert_mode = 0
+ modkey = Mod4
+ [bindings_internal]
+ next = n
+ follow_link_here = f
+ follow_link_new_tab = F
+ follow_link_new_window = w
+ [bindings_external]
+ ./extra/insert_bookmark.sh = b
+ ./extra/load_url_from_history.sh = u
+ ./extra/load_url_from_bookmarks.sh = U
++[alias]
++b  = back
++f  = forward
++z+ = zoom in
++z- = zoom out
++r  = refresh
++s  = stop
+ [network]
diff --cc uzbl.c
--- 1/uzbl.c
--- 2/uzbl.c
+++ b/uzbl.c
   */
  
  #include <gtk/gtk.h>
 +#include <gdk/gdk.h>
  #include <gdk/gdkx.h>
 +#include <gdk/gdkkeys.h>
 +#include <gdk/gdkkeysyms.h>
  #include <webkit/webkit.h>
  
 -static GtkWidget* main_window;
 -static GtkWidget* uri_entry;
 -static GtkWidget* mainbar;
 +#include <pthread.h>
 +#include <stdio.h>
 +#include <string.h>
 +#include <sys/stat.h>
 +#include <sys/types.h>
 +#include <unistd.h>
 +#include <stdlib.h>
 +
 +static GtkWidget*     main_window;
 +static GtkWidget*     modeline;
  static WebKitWebView* web_view;
 -static gchar* main_title;
 -static gchar* history_file;
 -static gint load_progress;
 -static guint status_context_id;
  
- static gchar* history_file;
- static gchar* home_page;
- static gchar* uri       = NULL;
- static gchar* fifodir   = NULL;
- static char   fifopath[64];
- static bool   modevis = FALSE;
 -Window xwin = NULL;
 -gchar* uri = NULL;
++static gchar*   history_file;
++static gchar*   home_page;
++static gchar*   uri       = NULL;
++static gchar*   fifodir   = NULL;
++static char     fifopath[64];
++static bool     modevis = FALSE;
+ static gboolean verbose = FALSE;
++static Window   xwin    = NULL;
  
  static GOptionEntry entries[] =
  {
    { NULL }
  };
  
 +struct command
 +{
 +  char command[256];
 +  void (*func)(WebKitWebView*);
 +};
  
 +static struct command commands[256];
 +static int            numcmds = 0;
  
 -static void
 -log_history_cb () {
 -    FILE * output_file = fopen(history_file, "a");
 -    if (output_file == NULL) {
 -       fprintf(stderr, "Cannot open %s for logging\n", history_file);
 -    } else {
 -        time_t rawtime;
 -        struct tm * timeinfo;
 -        char buffer [80];
 -        time ( &rawtime );
 -        timeinfo = localtime ( &rawtime );
 -        strftime (buffer,80,"%Y-%m-%d %H:%M:%S",timeinfo);
 +struct alias
 +{
 +  char alias[256];
 +  char command[256];
 +};
  
 -        fprintf(output_file, "%s %s\n",buffer, uri);
 -        fclose(output_file);
 -    }
 -}
 +static struct alias aliases[256];
 +static int          numalias = 0;
  
 +static void parse_command(char*);
  
 -static void
 -activate_uri_entry_cb (GtkWidget* entry, gpointer data)
 +static bool parse_modeline (GtkWidget* mode, GdkEventKey* event)
  {
 -    uri = gtk_entry_get_text (GTK_ENTRY (entry));
 -    g_assert (uri);
 -    webkit_web_view_load_uri (web_view, uri);
 +  if ((event->type==GDK_KEY_PRESS) && (event->keyval==GDK_Return))
 +    parse_command (gtk_entry_get_text (modeline));
++ 
 +  return false;
  }
  
 -static void
 -update_title (GtkWindow* window)
 +static void log_history_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data)
  {
 -    GString* string = g_string_new (main_title);
 -    g_string_append (string, " - Uzbl browser");
 -    if (load_progress < 100)
 -        g_string_append_printf (string, " (%d%%)", load_progress);
 -    gchar* title = g_string_free (string, FALSE);
 -    gtk_window_set_title (window, title);
 -    g_free (title);
 +  strncpy (uri, webkit_web_frame_get_uri (frame), strlen (webkit_web_frame_get_uri (frame)));
 +  
-   FILE * output_file = fopen (history_file, "a");
++  FILE * output_file = fopen(history_file, "a");
 +  if (output_file == NULL)
 +    {
-       fprintf (stderr, "Cannot open %s for logging\n", history_file);
++      fprintf(stderr, "Cannot open %s for logging\n", history_file);
 +    }
 +  else
 +    {
 +      time_t rawtime;
 +      struct tm * timeinfo;
 +      char buffer [80];
-       time (&rawtime);
-       timeinfo = localtime (&rawtime);
++      time ( &rawtime );
++      timeinfo = localtime ( &rawtime );
 +      strftime (buffer,80,"%Y-%m-%d %H:%M:%S",timeinfo);
 +      
-       fprintf (output_file, "%s %s\n",buffer, uri);
-       fclose (output_file);
++      fprintf(output_file, "%s %s\n",buffer, uri);
++      fclose(output_file);
 +    }
  }
  
 -static void
 -link_hover_cb (WebKitWebView* page, const gchar* title, const gchar* link, gpointer data)
 +static void toggle_command_mode ()
  {
 -    /* underflow is allowed */
 -    //gtk_statusbar_pop (main_statusbar, status_context_id);
 -    //if (link)
 -    //    gtk_statusbar_push (main_statusbar, status_context_id, link);
 -    //TODO implementation roadmap pending..
 +  if (modevis)
 +    {
 +      gtk_widget_hide (modeline);
-       gtk_widget_grab_default (modeline);
++      gtk_widget_grab_focus (web_view);
 +    }
 +  else
 +    {
 +      gtk_widget_show (modeline);
 +      gtk_widget_grab_focus (modeline);
 +    }
 +  modevis = ! modevis;
  }
  
 -static void
 -title_change_cb (WebKitWebView* web_view, WebKitWebFrame* web_frame, const gchar* title, gpointer data)
 +static gboolean key_press_cb (WebKitWebView* page, GdkEventKey* event)
  {
 -    if (main_title)
 -        g_free (main_title);
 -    main_title = g_strdup (title);
 -    update_title (GTK_WINDOW (main_window));
 +  gboolean result=FALSE; //TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.
 +  if ((event->type==GDK_KEY_PRESS) && (event->keyval==GDK_Escape))
 +    {
 +      toggle_command_mode ();
 +      result=TRUE;
 +    }
 + 
 +  return(result);
  }
  
 -static void
 -progress_change_cb (WebKitWebView* page, gint progress, gpointer data)
 +static GtkWidget* create_browser ()
  {
 -    load_progress = progress;
 -    update_title (GTK_WINDOW (main_window));
 -}
 +  GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 +  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_NEVER, GTK_POLICY_NEVER);
  
 -static void
 -load_commit_cb (WebKitWebView* page, WebKitWebFrame* frame, gpointer data)
 -{
 -    const gchar* uri = webkit_web_frame_get_uri(frame);
 -    if (uri)
 -        gtk_entry_set_text (GTK_ENTRY (uri_entry), uri);
 +  web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
 +  gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (web_view));
 +
 +  g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (log_history_cb), web_view);
 +
 +  return scrolled_window;
  }
  
 -static void
 -destroy_cb (GtkWidget* widget, gpointer data)
 +static GtkWidget* create_window ()
  {
 -    gtk_main_quit ();
 +  GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 +  gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
 +  gtk_widget_set_name (window, "Uzbl Browser");
 +  g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (gtk_main_quit), NULL);
 +  g_signal_connect (G_OBJECT (window), "key-press-event", G_CALLBACK(key_press_cb), NULL);
 +
 +  return window;
  }
  
 -static void
 -go_back_cb (GtkWidget* widget, gpointer data)
 +static GtkWidget* create_modeline ()
  {
 -    webkit_web_view_go_back (web_view);
 +  GtkWidget* modeline = gtk_entry_new ();
 +  g_signal_connect (G_OBJECT (modeline), "key-press-event", G_CALLBACK(parse_modeline), modeline);
 +
 +  return modeline;
  }
  
 -static void
 -go_forward_cb (GtkWidget* widget, gpointer data)
 +static void parse_command(char *command)
  {
 -    webkit_web_view_go_forward (web_view);
 +  int  i    = 0;
 +  bool done = false;
 +  char *cmdstr = command;
 +  void (*func)(WebKitWebView*);
 +
 +  printf("Checking aliases\n");
 +  for (i = 0; i < numalias && ! done; i++)
 +    {
 +      if (!strncmp (cmdstr, aliases[i].alias, strlen (aliases[i].alias)))
 +        {
 +          strcpy(cmdstr, aliases[i].command);
 +          done = true;
 +        }
 +    }
 +
 +  done = false;
 +  printf("Checking commands\n");
 +  for (i = 0; i < numcmds && ! done; i++)
 +    {
 +      if (!strncmp (cmdstr, commands[i].command, strlen (commands[i].command)))
 +        {
 +          func = commands[i].func;
 +          done = true;
 +        }
 +    }
 +
 +  printf("Command identified as \"%s\"\n", cmdstr);
 +
 +  if (done)
 +    {
 +      func (web_view);
 +    }
 +  else
 +    {
 +      if (!strncmp ("http://", command, 7))
 +        {
 +          printf ("Loading URI \"%s\"\n", command);
 +          uri = command;
 +          webkit_web_view_load_uri (web_view, uri);
 +        }
 +    }
  }
  
 -static GtkWidget*
 -create_browser ()
 +static void *control_fifo()
  {
 -    GtkWidget* scrolled_window = gtk_scrolled_window_new (NULL, NULL);
 -    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
 +  if (fifodir)
 +    {
 +      sprintf (fifopath, "%s/uzbl_%d", fifodir, getpid ());
 +    }
 +  else
 +    {
 +      sprintf (fifopath, "/tmp/uzbl_%d", getpid ());
 +    }
 +
 +  if (mkfifo (fifopath, 0666) == -1)
 +    {
 +      printf ("Possible error creating fifo\n");
 +    }
  
 -    web_view = WEBKIT_WEB_VIEW (webkit_web_view_new ());
 -    gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (web_view));
 +    printf ("Opened control fifo in %s\n", fifopath);
 +
 +    while (true)
 +      {
 +        FILE *fifo = fopen(fifopath, "r");
 +        if (!fifo)
 +          {
 +            printf("Could not open %s for reading\n", fifopath);
 +            return NULL;
 +          }
 +        
 +        char buffer[256];
 +        memset (buffer, 0, sizeof (buffer));
 +        while (!feof (fifo) && fgets (buffer, sizeof (buffer), fifo))
 +          {
 +            if (strcmp (buffer, "\n"))
 +              {
 +                buffer[strlen (buffer) - 1] = '\0'; // Remove newline
 +                parse_command (buffer);
 +              }
 +          }
 +      }
 +    
 +    return NULL;
 +}
  
 -    g_signal_connect (G_OBJECT (web_view), "title-changed", G_CALLBACK (title_change_cb), web_view);
 -    g_signal_connect (G_OBJECT (web_view), "load-progress-changed", G_CALLBACK (progress_change_cb), web_view);
 -    g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (load_commit_cb), web_view);
 -    g_signal_connect (G_OBJECT (web_view), "load-committed", G_CALLBACK (log_history_cb), web_view);
 -    g_signal_connect (G_OBJECT (web_view), "hovering-over-link", G_CALLBACK (link_hover_cb), web_view);
 +static void add_command (char* cmdstr, void* function)
 +{
 +  strncpy (commands[numcmds].command, cmdstr, strlen (cmdstr));
 +  commands[numcmds].func = function;
 +  numcmds++;
 +}
  
 -    return scrolled_window;
 +static void add_command_alias (char* alias, char* command)
 +{
 +  strncpy (aliases[numalias].alias,   alias,   strlen (alias));
 +  strncpy (aliases[numalias].command, command, strlen (command));
 +  numalias++;
  }
  
- static bool setup_gtk (int argc, char* argv[])
 -static GtkWidget*
 -create_mainbar ()
++static void setup_gtk (int argc, char* argv[])
  {
 -    mainbar = gtk_hbox_new(FALSE, 0);
 -    uri_entry = gtk_entry_new();
 -    gtk_entry_set_width_chars(GTK_ENTRY(uri_entry), 40);
 -    gtk_entry_set_text(GTK_ENTRY(uri_entry), "http://");
 -    gtk_box_pack_start (GTK_BOX (mainbar), uri_entry, FALSE,TRUE , 0);
 -    gtk_signal_connect_object (GTK_OBJECT (uri_entry), "activate", GTK_SIGNAL_FUNC (activate_uri_entry_cb), GTK_OBJECT (uri_entry));
 +  gtk_init (&argc, &argv);
  
 -    //status_context_id = gtk_statusbar_get_context_id (main_statusbar, "Link Hover");
 +  GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
 +  gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
 +  modeline = create_modeline ();
 +  gtk_box_pack_start (GTK_BOX (vbox), modeline, FALSE, FALSE, 0);
  
 -    return mainbar;
 +  main_window = create_window ();
 +  gtk_container_add (GTK_CONTAINER (main_window), vbox);
 +  GError *error = NULL;
 +
 +  GOptionContext* context = g_option_context_new ("- The Usable Browser, controlled entirely through a FIFO");
 +  g_option_context_add_main_entries (context, entries, NULL);
 +  g_option_context_add_group (context, gtk_get_option_group (TRUE));
 +  g_option_context_parse (context, &argc, &argv, &error);
 +
 +  if (uri)
 +    {
 +      webkit_web_view_load_uri (web_view, uri);
 +    }
 +
 +  gtk_widget_grab_focus (GTK_WIDGET (web_view));
 +  gtk_widget_show_all (main_window);
 +  gtk_widget_hide(modeline);
-   return true;
++  gtk_widget_grab_focus (GTK_WIDGET (web_view));
  }
  
 -static
 -GtkWidget* create_window ()
 +static void setup_commands ()
  {
 -    GtkWidget* window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 -    gtk_window_set_default_size (GTK_WINDOW (window), 800, 600);
 -    gtk_widget_set_name (window, "Uzbl browser");
 -    g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy_cb), NULL);
 +  //This func. is nice but currently it cannot be used for functions that require arguments or return data. --sentientswitch
 +
 +  add_command("back",     &webkit_web_view_go_back);
 +  add_command("forward",  &webkit_web_view_go_forward);
 +  add_command("refresh",  &webkit_web_view_reload); //Buggy
 +  add_command("stop",     &webkit_web_view_stop_loading);
 +  add_command("zoom in",  &webkit_web_view_zoom_in); //Can crash (when max zoom reached?).
 +  add_command("zoom out", &webkit_web_view_zoom_out); //Crashes as zoom +
 +  //add_command("get uri", &webkit_web_view_get_uri);
 +}
  
 -    return window;
 +static void setup_threading ()
 +{
 +  pthread_t control_thread;
 +  pthread_create(&control_thread, NULL, control_fifo, NULL);
  }
  
 -int main (int argc, char* argv[])
 +static void setup_settings ()
  {
 -    gtk_init (&argc, &argv);
 -    if (!g_thread_supported ())
 -        g_thread_init (NULL);
 +  GKeyFile* config = g_key_file_new ();
-   gboolean  res    = g_key_file_load_from_file (config, "./config", G_KEY_FILE_NONE, NULL); //TODO: pass config file as argument
++  gboolean  res    = g_key_file_load_from_file (config, "./sampleconfig", G_KEY_FILE_NONE, NULL); //TODO: pass config file as argument
  
 -    GKeyFile* config = g_key_file_new ();
 -    gboolean res = g_key_file_load_from_file (config, "./sampleconfig", G_KEY_FILE_NONE, NULL); //TODO: pass config file as argument
 -    if(res) {
 -        printf("config loaded\n");
 -    } else {
 -        fprintf(stderr,"config loading failed\n"); //TODO: exit codes with gtk? 
 +  if (res)
 +    {
 +      printf ("Config loaded\n");
      }
 -    history_file = g_key_file_get_value (config, "behavior", "history_file", NULL);
 -    if(history_file) {
 -        printf("setting history file to: %s\n",history_file);
 -    } else {
 -        printf("history logging disabled\n");
 +  else
 +    {
 +      fprintf (stderr, "config loading failed\n"); //TODO: exit codes with gtk? 
      }
  
 -    GtkWidget* vbox = gtk_vbox_new (FALSE, 0);
 -    gtk_box_pack_start (GTK_BOX (vbox), create_mainbar (), FALSE, TRUE, 0);
 -    gtk_box_pack_start (GTK_BOX (vbox), create_browser (), TRUE, TRUE, 0);
 +  history_file = g_key_file_get_value (config, "behavior", "history_file", NULL);
 +  if (history_file)
 +    {
 +      printf ("Setting history file to: %s\n", history_file);
 +    }
 +  else
 +    {
 +      printf ("History logging disabled\n");
 +    }
  
 +  home_page = g_key_file_get_value (config, "behavior", "home_page", NULL);
 +  if (home_page)
 +    {
 +      printf ("Setting home page to: %s\n", home_page);
 +    }
 +  else
 +    {
 +      printf ("Home page disabled\n");
 +    }
  
 +  /*GError *error = 0;
 +  char   *keys  = g_key_file_get_keys (config, "alias", NULL, &error);
  
 -    main_window = create_window ();
 -    gtk_container_add (GTK_CONTAINER (main_window), vbox);
 -  GError *error = NULL;
 +  if (error) 
 +    {
 +      printf("Error: %n\n", error);
 +    }
 +  else
 +    {
 +      printf("Loading aliases\n");
 +      while (keys != NULL &&  (*keys) != NULL)
 +        {
 +          char* value = g_key_file_get_value (config, (gchar *)"alias", (*keys), NULL);
 +          add_command_alias((*keys), value);
 +          ++keys;
 +        }
 +    }
  
 -  GOptionContext* context = g_option_context_new ("- some stuff here maybe someday");
 -  g_option_context_add_main_entries (context, entries, NULL);
 -  g_option_context_add_group (context, gtk_get_option_group (TRUE));
 -  g_option_context_parse (context, &argc, &argv, &error);
 +    Until segfaults is fixed, manually add aliases to test the rest of it. */
 +  add_command_alias("b",  "back");
 +  add_command_alias("f",  "forward");
 +  add_command_alias("z+", "zoom in");
 +  add_command_alias("z-", "zoom out");
 +  add_command_alias("r",  "refresh");
 +  add_command_alias("s",  "stop");
 +}
 +
 +int main (int argc, char* argv[])
 +{
 +  if (!g_thread_supported ())
 +    g_thread_init (NULL);
  
++  xwin = GDK_WINDOW_XID (GTK_WIDGET (main_window)->window);
++  printf("My X window id is %i\n",(int) xwin);
 -    webkit_web_view_load_uri (web_view, uri);
 +  setup_settings ();
 +  setup_gtk (argc, argv);
 +  setup_commands ();
 +  setup_threading ();
 +  gtk_main ();
  
 -    gtk_widget_grab_focus (GTK_WIDGET (web_view));
 -    gtk_widget_show_all (main_window);
 -    xwin = GDK_WINDOW_XID (GTK_WIDGET (main_window)->window);
 -    printf("My X window id is %i\n",(int) xwin);
 +  printf ("Shutting down...\n");
  
 -    gtk_main ();
 +  unlink (fifopath);
  
 -    return 0;
 +  return 0;
  }