]> git.decadent.org.uk Git - videolink.git/blobdiff - videolink.cpp
Release versions 1.2.11 and 1.2.11-1
[videolink.git] / videolink.cpp
index 3d88f4edb7c57a1fe7e26c8a0ff53f348b00f361..a15bbea1bfe125a2cf9c67e152935203a1e3e2a3 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2005-6 Ben Hutchings <ben@decadent.org.uk>.
+// Copyright 2005-8 Ben Hutchings <ben@decadent.org.uk>.
 // See the file "COPYING" for licence details.
 
 #include <cassert>
 
 #include <stdlib.h>
 
+#include <gdk/gdkkeysyms.h>
 #include <gdkmm/pixbuf.h>
 #include <glibmm/convert.h>
 #include <glibmm/spawn.h>
 #include <gtkmm/main.h>
 #include <gtkmm/window.h>
 
-#include <imglib2/ImageErrors.h>
+#include "videolink.hpp"
+#include "wchar_t_short.h"
+#include <ImageErrors.h>
+#if MOZ_VERSION_GE(1,9,0)
+#include <nsWeakPtr.h>
+/* For some reason <nsWeakPtr.h> no longer defines this */
+typedef nsCOMPtr<nsIWeakReference> nsWeakPtr;
+#endif
 #include <nsGUIEvent.h>
 #include <nsIBoxObject.h>
 #include <nsIContent.h>
 #include <nsIURI.h> // required before nsILink.h
 #include <nsILink.h>
 #include <nsIPrefBranch.h>
-#if MOZ_VERSION_MAJOR > 1 || (MOZ_VERSION_MAJOR == 1 && MOZ_VERSION_MINOR >= 8)
-#   include <nsPresContext.h>
-#else
-#   include <nsIPresContext.h>
-    typedef nsIPresContext nsPresContext; // ugh
-#endif
 #include <nsIPrefService.h>
 #include <nsIPresShell.h>
-#if MOZ_VERSION_MAJOR > 1 || (MOZ_VERSION_MAJOR == 1 && MOZ_VERSION_MINOR >= 8)
-#   include <nsServiceManagerUtils.h>
-#else
-#   include <nsIServiceManagerUtils.h>
-#endif
+#include <nsServiceManagerUtils.h>
 #include <nsIWebBrowser.h>
+#ifdef MOZILLA_INTERNAL_API
 #include <nsString.h>
+#else
+#include <nsStringAPI.h>
+#endif
+#include "wchar_t_default.h"
 
 #include "browser_widget.hpp"
 #include "child_iterator.hpp"
 #include "dvd.hpp"
+#include "event_state_manager.hpp"
 #include "generate_dvd.hpp"
 #include "geometry.hpp"
 #include "link_iterator.hpp"
@@ -77,14 +81,17 @@ using xpcom_support::check;
 
 namespace
 {
-    rectangle get_elem_rect(nsIDOMNSDocument * ns_doc,
-                           nsIDOMElement * elem)
+#if MOZ_VERSION_GE(2,0,-1)
+    rectangle get_elem_rect(nsIDocument * doc, nsIDOMElement * elem)
+#else
+    rectangle get_elem_rect(nsIDOMNSDocument * doc, nsIDOMElement * elem)
+#endif
     {
        rectangle result;
 
        // Start with this element's bounding box
        nsCOMPtr<nsIBoxObject> box;
-       check(ns_doc->GetBoxObjectFor(elem, getter_AddRefs(box)));
+       check(doc->GetBoxObjectFor(elem, getter_AddRefs(box)));
        int width, height;
        check(box->GetScreenX(&result.left));
        check(box->GetScreenY(&result.top));
@@ -103,7 +110,7 @@ namespace
            {
                nsCOMPtr<nsIDOMElement> child_elem(
                    do_QueryInterface(child_node));
-               result |= get_elem_rect(ns_doc, child_elem);
+               result |= get_elem_rect(doc, child_elem);
            }
        }
 
@@ -129,6 +136,7 @@ namespace
            {".vob",     video_format_mpeg2_ps},
            {".mpeg",    video_format_mpeg2_ps},
            {".mpeg2",   video_format_mpeg2_ps},
+           {".mpg",     video_format_mpeg2_ps},
            {".voblist", video_format_vob_list}
        };
        for (std::size_t i = 0;
@@ -144,15 +152,79 @@ namespace
        return video_format_none;
     }
 
-    
-    class videolink_window : public Gtk::Window
+
+    class base_window : public Gtk::Window
+    {
+    public:
+       base_window(const video::frame_params & frame_params);
+
+    protected:
+       video::frame_params frame_params_;
+       browser_widget browser_widget_;
+    };
+
+    base_window::base_window(const video::frame_params & frame_params)
+       : frame_params_(frame_params)
+    {
+       set_size_request(frame_params_.width, frame_params_.height);
+       set_resizable(false);
+
+       add(browser_widget_);
+       browser_widget_.show();
+    }
+
+    class preview_window : public base_window
+    {
+    public:
+       preview_window(const video::frame_params & frame_params,
+                      const std::string & main_page_uri);
+
+    private:
+       bool on_idle();
+       bool on_key_press(GdkEventKey *);
+
+       std::string main_page_uri_;
+    };
+
+    preview_window::preview_window(const video::frame_params & frame_params,
+                                  const std::string & main_page_uri)
+       : base_window(frame_params),
+         main_page_uri_(main_page_uri)
+    {
+       Glib::signal_idle().connect(
+           sigc::mem_fun(this, &preview_window::on_idle));
+       signal_key_press_event().connect(
+           sigc::mem_fun(this, &preview_window::on_key_press));
+    }
+
+    bool preview_window::on_idle()
+    {
+       browser_widget_.load_uri(main_page_uri_);
+       return false; // don't call again
+    }
+
+    bool preview_window::on_key_press(GdkEventKey * event)
+    {
+       switch (event->keyval)
+       {
+       case GDK_t: // = top menu
+           browser_widget_.load_uri(main_page_uri_);
+           return true;
+       case GDK_q: // = quit
+           Gtk::Main::quit();
+           return true;
+       default:
+           return false;
+       }
+    }
+
+    class conversion_window : public base_window
     {
     public:
-       videolink_window(
-           const video::frame_params & frame_params,
-           const std::string & main_page_uri,
-           const std::string & output_dir,
-           dvd_generator::mpeg_encoder encoder);
+       conversion_window(const video::frame_params & frame_params,
+                         const std::string & main_page_uri,
+                         const std::string & output_dir,
+                         dvd_generator::mpeg_encoder encoder);
 
        bool is_finished() const;
 
@@ -180,14 +252,16 @@ namespace
        bool process_links(
            page_state * state,
            nsIDOMDocument * basic_doc,
-           nsIPresShell * pres_shell,
-           nsPresContext * pres_context,
+           nsIDocShell * doc_shell,
            nsIDOMWindow * dom_window);
 
-       video::frame_params frame_params_;
        std::string output_dir_;
-       browser_widget browser_widget_;
-       agent_style_sheet_holder main_style_sheet_, frame_style_sheet_;
+
+       enum {
+           state_initial,
+           state_processing,
+           state_finished
+       } state_;
 
        dvd_generator generator_;
        typedef std::map<std::string, dvd_generator::pgc_ref>
@@ -197,53 +271,35 @@ namespace
        std::queue<std::string> page_queue_;
        bool pending_window_update_;
        int pending_req_count_;
-       bool have_tweaked_page_;
        std::auto_ptr<page_state> page_state_;
-
-       bool finished_;
     };
 
-    videolink_window::videolink_window(
+    conversion_window::conversion_window(
        const video::frame_params & frame_params,
        const std::string & main_page_uri,
        const std::string & output_dir,
        dvd_generator::mpeg_encoder encoder)
-           : frame_params_(frame_params),
-             output_dir_(output_dir),
-             main_style_sheet_(
-                 init_agent_style_sheet(
-                     "file://" VIDEOLINK_SHARE_DIR "/videolink.css")),
-             frame_style_sheet_(
-                 init_agent_style_sheet(
-                     std::string("file://" VIDEOLINK_SHARE_DIR "/")
-                     .append(frame_params.common_name)
-                     .append(".css")
-                     .c_str())),
-             generator_(frame_params, encoder),
-             pending_window_update_(false),
-             pending_req_count_(0),
-             have_tweaked_page_(false),
-             finished_(false)
+       : base_window(frame_params),
+         output_dir_(output_dir),
+         state_(state_initial),
+         generator_(frame_params, encoder),
+         pending_window_update_(false),
+         pending_req_count_(0)
     {
-       set_size_request(frame_params_.width, frame_params_.height);
-       set_resizable(false);
-
-       add(browser_widget_);
-       browser_widget_.show();
        Glib::signal_idle().connect(
-           SigC::slot(*this, &videolink_window::on_idle));
+           sigc::mem_fun(this, &conversion_window::on_idle));
        browser_widget_.signal_net_state().connect(
-           SigC::slot(*this, &videolink_window::on_net_state_change));
+           sigc::mem_fun(this, &conversion_window::on_net_state_change));
 
        add_menu(main_page_uri);
     }
 
-    bool videolink_window::is_finished() const
+    bool conversion_window::is_finished() const
     {
-       return finished_;
+       return state_ == state_finished;
     }
 
-    dvd_generator::pgc_ref videolink_window::add_menu(const std::string & uri)
+    dvd_generator::pgc_ref conversion_window::add_menu(const std::string & uri)
     {
        dvd_generator::pgc_ref & pgc_ref = resource_map_[uri];
        if (pgc_ref.type == dvd_generator::unknown_pgc)
@@ -254,7 +310,7 @@ namespace
        return pgc_ref;
     }
 
-    dvd_generator::pgc_ref videolink_window::add_title(const std::string & uri,
+    dvd_generator::pgc_ref conversion_window::add_title(const std::string & uri,
                                                      video_format format)
     {
        dvd_generator::pgc_ref & pgc_ref = resource_map_[uri];
@@ -293,34 +349,20 @@ namespace
        return pgc_ref;
     }
 
-    void videolink_window::load_next_page()
+    void conversion_window::load_next_page()
     {
        assert(!page_queue_.empty());
        const std::string & uri = page_queue_.front();
-       std::cout << "loading " << uri << std::endl;
+       std::cout << "INFO: Loading <" << uri << ">" << std::endl;
 
        browser_widget_.load_uri(uri);
     }
 
-    bool videolink_window::on_idle()
-    {
-       if (!output_dir_.empty())
-       {
-           // Put pointer in the top-left so that no links appear in
-           // the hover state when we take a screenshot.
-           warp_pointer(get_window(),
-                        -frame_params_.width, -frame_params_.height);
-       }
-       
-       load_next_page();
-       return false; // don't call again thankyou
-    }
-
-    void videolink_window::on_net_state_change(const char * uri,
-                                          gint flags, guint status)
+    void conversion_window::on_net_state_change(const char * uri,
+                                               gint flags, guint status)
     {
 #       ifdef DEBUG_ON_NET_STATE_CHANGE
-       std::cout << "videolink_window::on_net_state_change(";
+       std::cout << "conversion_window::on_net_state_change(";
        if (uri)
            std::cout << '"' << uri << '"';
        else
@@ -374,7 +416,6 @@ namespace
            && flags & GTK_MOZ_EMBED_FLAG_START)
        {
            pending_window_update_ = true;
-           have_tweaked_page_ = false;
        }
 
        if (flags & GTK_MOZ_EMBED_FLAG_IS_WINDOW
@@ -382,44 +423,16 @@ namespace
        {
            // Check whether the load was successful, ignoring this
            // pseudo-error.
+#ifdef NS_IMAGELIB_ERROR_LOAD_ABORTED
            if (status != NS_IMAGELIB_ERROR_LOAD_ABORTED)
+#endif
                check(status);
 
            pending_window_update_ = false;
        }
-
-       if (!browser_is_busy())
-       {
-           try
-           {
-               if (!process())
-               {
-                   finished_ = true;
-                   Gtk::Main::quit();
-               }
-           }
-           catch (std::exception & e)
-           {
-               std::cerr << "Fatal error";
-               if (!page_queue_.empty())
-                   std::cerr << " while processing <" << page_queue_.front()
-                             << ">";
-               std::cerr << ": " << e.what() << "\n";
-               Gtk::Main::quit();
-           }
-           catch (Glib::Exception & e)
-           {
-               std::cerr << "Fatal error";
-               if (!page_queue_.empty())
-                   std::cerr << " while processing <" << page_queue_.front()
-                             << ">";
-               std::cerr << ": " << e.what() << "\n";
-               Gtk::Main::quit();
-           }
-       }
     }
 
-    struct videolink_window::page_state
+    struct conversion_window::page_state
     {
        page_state(Glib::RefPtr<Gdk::Pixbuf> norm_pixbuf,
                   nsIDOMDocument * doc, int width, int height)
@@ -428,7 +441,6 @@ namespace
                                  Gdk::COLORSPACE_RGB,
                                  true, 8, // has_alpha, bits_per_sample
                                  width, height)),
-                 link_num(0),
                  links_it(doc),
                  link_changing(false)
            {
@@ -437,96 +449,122 @@ namespace
        Glib::RefPtr<Gdk::Pixbuf> norm_pixbuf;
        Glib::RefPtr<Gdk::Pixbuf> diff_pixbuf;
 
-       unsigned link_num;
        link_iterator links_it, links_end;
 
        rectangle link_rect;
+       std::string link_target;
        bool link_changing;
     };
 
-    bool videolink_window::process()
+    bool conversion_window::on_idle()
+    {
+       if (state_ == state_initial)
+       {
+           // Put pointer in the top-left so that no links appear in
+           // the hover state when we take a screenshot.
+           warp_pointer(get_window(),
+                        -frame_params_.width, -frame_params_.height);
+
+           load_next_page();
+
+           state_ = state_processing;
+       }
+       else if (state_ == state_processing && !browser_is_busy())
+       {
+           try
+           {
+               if (!process())
+               {
+                   state_ = state_finished;
+                   Gtk::Main::quit();
+               }
+           }
+           catch (...)
+           {
+               // Print context of exception.
+               if (!page_queue_.empty())
+               {
+                   std::cerr << "ERROR: While processing page <"
+                             << page_queue_.front() << ">:\n";
+                   if (page_state_.get() && !page_state_->link_target.empty())
+                       std::cerr << "ERROR: While processing link to <"
+                                 << page_state_->link_target << ">:\n";
+               }
+
+               // Print exception message.
+               try
+               {
+                   throw;
+               }
+               catch (std::exception & e)
+               {
+                   std::cerr << "ERROR: " << e.what() << "\n";
+               }
+               catch (Glib::Exception & e)
+               {
+                   std::cerr << "ERROR: " << e.what() << "\n";
+               }
+               catch (...)
+               {
+                   std::cerr << "ERROR: Unknown exception\n";
+               }
+
+               Gtk::Main::quit();
+           }
+       }
+
+       // Call again if we're not done.
+       return state_ != state_finished;
+    }
+
+    bool conversion_window::process()
     {
        assert(!page_queue_.empty());
 
        nsCOMPtr<nsIWebBrowser> browser(browser_widget_.get_browser());
        nsCOMPtr<nsIDocShell> doc_shell(do_GetInterface(browser));
        assert(doc_shell);
-       nsCOMPtr<nsIPresShell> pres_shell;
-       check(doc_shell->GetPresShell(getter_AddRefs(pres_shell)));
-       nsCOMPtr<nsPresContext> pres_context;
-       check(doc_shell->GetPresContext(getter_AddRefs(pres_context)));
        nsCOMPtr<nsIDOMWindow> dom_window;
        check(browser->GetContentDOMWindow(getter_AddRefs(dom_window)));
 
-       // If we haven't done so already, apply the stylesheet and
-       // disable scrollbars.
-       if (!have_tweaked_page_)
-       {
-           apply_agent_style_sheet(main_style_sheet_, pres_shell);
-           apply_agent_style_sheet(frame_style_sheet_, pres_shell);
-
-           // This actually only needs to be done once.
-           nsCOMPtr<nsIDOMBarProp> dom_bar_prop;
-           check(dom_window->GetScrollbars(getter_AddRefs(dom_bar_prop)));
-           check(dom_bar_prop->SetVisible(false));
-
-           have_tweaked_page_ = true;
-
-           // Might need to wait a while for things to load or more
-           // likely for a re-layout.
-           if (browser_is_busy())
-               return true;
-       }
+       nsCOMPtr<nsIDOMDocument> basic_doc;
+       check(dom_window->GetDocument(getter_AddRefs(basic_doc)));
 
-       // All further work should only be done if we're not in preview mode.
-       if (!output_dir_.empty())
+       // Start or continue processing links.
+       if (!page_state_.get())
+           page_state_.reset(
+               new page_state(
+                   get_screenshot(),
+                   basic_doc, frame_params_.width, frame_params_.height));
+       if (!process_links(page_state_.get(), basic_doc, doc_shell, dom_window))
        {
-           nsCOMPtr<nsIDOMDocument> basic_doc;
-           check(dom_window->GetDocument(getter_AddRefs(basic_doc)));
-
-           // Start or continue processing links.
-           std::auto_ptr<page_state> state(page_state_);
-           if (!state.get())
-               state.reset(
-                   new page_state(
-                       get_screenshot(),
-                       basic_doc, frame_params_.width, frame_params_.height));
-           if (process_links(
-                   state.get(),
-                   basic_doc, pres_shell, pres_context, dom_window))
+           // We've finished work on the links so generate the
+           // menu VOB.
+           quantise_rgba_pixbuf(page_state_->diff_pixbuf,
+                                dvd::button_n_colours);
+           generator_.generate_menu_vob(
+               resource_map_[page_queue_.front()].index,
+               page_state_->norm_pixbuf, page_state_->diff_pixbuf);
+
+           // Move on to the next page, if any, or else generate
+           // the DVD filesystem.
+           page_state_.reset();
+           page_queue_.pop();
+           if (!page_queue_.empty())
            {
-               // Save iteration state for later.
-               page_state_ = state;
+               load_next_page();
            }
            else
            {
-               // We've finished work on the links so generate the
-               // menu VOB.
-               quantise_rgba_pixbuf(state->diff_pixbuf,
-                                    dvd::button_n_colours);
-               generator_.generate_menu_vob(
-                   resource_map_[page_queue_.front()].index,
-                   state->norm_pixbuf, state->diff_pixbuf);
-
-               // Move on to the next page, if any, or else generate
-               // the DVD filesystem.
-               page_queue_.pop();
-               if (!page_queue_.empty())
-               {
-                   load_next_page();
-               }
-               else
-               {
-                   generator_.generate(output_dir_);
-                   return false;
-               }
+               generator_.generate(output_dir_);
+               return false;
            }
        }
 
        return true;
     }
 
-    Glib::RefPtr<Gdk::Pixbuf> videolink_window::get_screenshot()
+    Glib::RefPtr<Gdk::Pixbuf> conversion_window::get_screenshot()
     {
        Glib::RefPtr<Gdk::Window> window(get_window());
        assert(window);
@@ -538,11 +576,10 @@ namespace
                                   frame_params_.width, frame_params_.height);
     }
 
-    bool videolink_window::process_links(
+    bool conversion_window::process_links(
        page_state * state,
        nsIDOMDocument * basic_doc,
-       nsIPresShell * pres_shell,
-       nsPresContext * pres_context,
+       nsIDocShell * doc_shell,
        nsIDOMWindow * dom_window)
     {
        Glib::RefPtr<Gdk::Window> window(get_window());
@@ -550,8 +587,14 @@ namespace
 
        nsCOMPtr<nsIDOMNSDocument> ns_doc(do_QueryInterface(basic_doc));
        assert(ns_doc);
+#if MOZ_VERSION_GE(2,0,-1)
+       nsCOMPtr<nsIDocument> doc(do_QueryInterface(basic_doc));
+       assert(doc);
+#endif
+       nsCOMPtr<nsIPresShell> pres_shell;
+       check(doc_shell->GetPresShell(getter_AddRefs(pres_shell)));
        nsCOMPtr<nsIEventStateManager> event_state_man(
-           pres_context->EventStateManager()); // does not AddRef
+           get_event_state_manager(doc_shell));
        assert(event_state_man);
        nsCOMPtr<nsIDOMDocumentEvent> event_factory(
            do_QueryInterface(basic_doc));
@@ -574,21 +617,29 @@ namespace
            nsCOMPtr<nsIDOMNode> node(*state->links_it);
 
            // Find the link URI and separate any fragment from it.
+           nsCOMPtr<nsIURI> uri_iface;
+#if MOZ_VERSION_GE(2,0,-1)
+           nsCOMPtr<nsIContent> content(do_QueryInterface(node));
+           assert(content);
+           uri_iface = content->GetHrefURI();
+           assert(uri_iface);
+#else
            nsCOMPtr<nsILink> link(do_QueryInterface(node));
            assert(link);
-           nsCOMPtr<nsIURI> uri_iface;
            check(link->GetHrefURI(getter_AddRefs(uri_iface)));
-           std::string uri_and_fragment, uri, fragment;
+#endif
+           std::string uri, fragment;
            {
-               nsCString uri_and_fragment_ns;
-               check(uri_iface->GetSpec(uri_and_fragment_ns));
-               uri_and_fragment.assign(uri_and_fragment_ns.BeginReading(),
-                                       uri_and_fragment_ns.EndReading());
-
-               std::size_t hash_pos = uri_and_fragment.find('#');
-               uri.assign(uri_and_fragment, 0, hash_pos);
+               nsCString link_target_ns;
+               check(uri_iface->GetSpec(link_target_ns));
+               const char * str;
+               PRUint32 len = NS_CStringGetData(link_target_ns, &str);
+               state->link_target.assign(str, len);
+
+               std::size_t hash_pos = state->link_target.find('#');
+               uri.assign(state->link_target, 0, hash_pos);
                if (hash_pos != std::string::npos)
-                   fragment.assign(uri_and_fragment,
+                   fragment.assign(state->link_target,
                                    hash_pos + 1, std::string::npos);
            }
 
@@ -599,25 +650,17 @@ namespace
                // window.
                nsCOMPtr<nsIDOMElement> elem(do_QueryInterface(node));
                assert(elem);
+#if MOZ_VERSION_GE(2,0,-1)
+               state->link_rect = get_elem_rect(doc, elem);
+#else
                state->link_rect = get_elem_rect(ns_doc, elem);
+#endif
                state->link_rect &= window_rect;
 
                if (state->link_rect.empty())
                {
-                   std::cerr << "Ignoring invisible link to "
-                             << uri_and_fragment << "\n";
-                   continue;
-               }
-
-               ++state->link_num;
-
-               if (state->link_num >= unsigned(dvd::menu_buttons_max))
-               {
-                   if (state->link_num == unsigned(dvd::menu_buttons_max))
-                       std::cerr << "No more than " << dvd::menu_buttons_max
-                                 << " buttons can be placed on a menu\n";
-                   std::cerr << "Ignoring link to " << uri_and_fragment
-                             << "\n";
+                   std::cerr << "WARN: Ignoring invisible link to <"
+                             << state->link_target << ">\n";
                    continue;
                }
 
@@ -631,11 +674,8 @@ namespace
                    PRBool is_file;
                    check(uri_iface->SchemeIs("file", &is_file));
                    if (!is_file)
-                   {
-                       std::cerr << "Links to video must use the file:"
-                                 << " scheme\n";
-                       continue;
-                   }
+                       throw std::runtime_error(
+                           "Link to video does not use file: scheme");
                    target = add_title(uri, format);
                    target.sub_index =
                        std::strtoul(fragment.c_str(), NULL, 10);
@@ -682,12 +722,7 @@ namespace
                check(event_state_man->SetContentState(content,
                                                       NS_EVENT_STATE_HOVER));
 
-#              if MOZ_VERSION_MAJOR > 1                                   \
-                    || (MOZ_VERSION_MAJOR == 1 && MOZ_VERSION_MINOR >= 8)
-                   pres_shell->FlushPendingNotifications(Flush_Display);
-#              else
-                   pres_shell->FlushPendingNotifications(true);
-#              endif
+               pres_shell->FlushPendingNotifications(Flush_Display);
 
                // We may have to exit and wait for image loading
                // to complete, at which point we will be called
@@ -750,7 +785,7 @@ namespace
            "Usage: " << command_name << " [gtk-options] [--preview]\n"
            "           [--video-std {525|525/60|NTSC|ntsc"
            " | 625|625/50|PAL|pal}]\n"
-           "           [--encoder {mjpegtools|mjpegtools-old}]\n"
+           "           [--encoder {ffmpeg|mjpegtools}]\n"
            "           menu-url [output-dir]\n";
     }
     
@@ -763,15 +798,12 @@ namespace
        nsCOMPtr<nsIPrefBranch> pref_branch;
        check(pref_service->GetBranch("", getter_AddRefs(pref_branch)));
 
-#      if MOZ_VERSION_MAJOR > 1                                 \
-           || (MOZ_VERSION_MAJOR == 1 && MOZ_VERSION_MINOR >= 8)
-           // Disable IE-compatibility kluge that causes backgrounds to
-           // sometimes/usually be missing from snapshots.  This is only
-           // effective from Mozilla 1.8 onward.
-           check(pref_branch->SetBoolPref(
-                     "layout.fire_onload_after_image_background_loads",
-                     true));
-#      endif
+       // Disable IE-compatibility kluge that causes backgrounds to
+       // sometimes/usually be missing from snapshots.  This is only
+       // effective from Mozilla 1.8 onward.
+       check(pref_branch->SetBoolPref(
+                 "layout.fire_onload_after_image_background_loads",
+                 true));
 
        // Set display resolution.  With standard-definition video we
        // will be fitting ~600 pixels across a screen typically
@@ -792,7 +824,7 @@ namespace
        // separately, but don't know how yet.  Setting one to 40
        // but not the other is *bad*, so currently we set neither.
 
-#      if MOZ_VERSION_MAJOR == 1 && MOZ_VERSION_MINOR < 8
+#      if 0
            check(pref_branch->SetIntPref("browser.display.screen_resolution",
                                          40));
 #      endif
@@ -802,7 +834,7 @@ namespace
 
 void fatal_error(const std::string & message)
 {
-    std::cerr << "Fatal error: " << message << "\n";
+    std::cerr << "ERROR: " << message << "\n";
     Gtk::Main::quit();
 }
 
@@ -904,14 +936,9 @@ int main(int argc, char ** argv)
                {
                    encoder = dvd_generator::mpeg_encoder_ffmpeg;
                }
-               else if (std::strcmp(argv[argi + 1], "mjpegtools-old") == 0)
+               else if (std::strcmp(argv[argi + 1], "mjpegtools") == 0)
                {
-                   encoder = dvd_generator::mpeg_encoder_mjpegtools_old;
-               }
-               else if (std::strcmp(argv[argi + 1], "mjpegtools") == 0
-                        || std::strcmp(argv[argi + 1], "mjpegtools-new") == 0)
-               {
-                   encoder = dvd_generator::mpeg_encoder_mjpegtools_new;
+                   encoder = dvd_generator::mpeg_encoder_mjpegtools;
                }
                else
                {
@@ -959,22 +986,34 @@ int main(int argc, char ** argv)
        // Initialise Mozilla
        browser_widget::initialiser browser_init;
        set_browser_preferences();
+       init_agent_style_sheet("file://" VIDEOLINK_SHARE_DIR "/videolink.css");
+       init_agent_style_sheet(std::string("file://" VIDEOLINK_SHARE_DIR "/")
+                              .append(frame_params.common_name).append(".css")
+                              .c_str());
        if (!preview_mode)
            null_prompt_service::install();
 
        // Run the browser/converter
-       videolink_window window(frame_params, menu_url, output_dir, encoder);
-       window.show();
-       window.signal_hide().connect(SigC::slot(&Gtk::Main::quit));
-       Gtk::Main::run();
-
-       return ((preview_mode || window.is_finished())
-               ? EXIT_SUCCESS
-               : EXIT_FAILURE);
+       if (preview_mode)
+       {
+           preview_window window(frame_params, menu_url);
+           window.show();
+           window.signal_hide().connect(sigc::ptr_fun(Gtk::Main::quit));
+           Gtk::Main::run();
+           return EXIT_SUCCESS;
+       }
+       else
+       {
+           conversion_window window(frame_params, menu_url, output_dir, encoder);
+           window.show();
+           window.signal_hide().connect(sigc::ptr_fun(Gtk::Main::quit));
+           Gtk::Main::run();
+           return window.is_finished() ? EXIT_SUCCESS  : EXIT_FAILURE;
+       }
     }
     catch (std::exception & e)
     {
-       std::cerr << "Fatal error: " << e.what() << "\n";
+       std::cerr << "ERROR: " << e.what() << "\n";
        return EXIT_FAILURE;
     }
 }