Renamed FrameBuffer to the more specific x_frame_buffer and removed "x_" from its accessor function names.
Renamed files to match function/class names.
endif
cxxsources := \
- auto_proc.cpp browserwidget.cpp childiterator.cpp framebuffer.cpp \
- linkiterator.cpp pixbufs.cpp stylesheets.cpp temp_file.cpp video.cpp \
- webdvd.cpp xpcom_support.cpp
+ auto_proc.cpp browser_widget.cpp child_iterator.cpp \
+ link_iterator.cpp pixbufs.cpp style_sheets.cpp temp_file.cpp video.cpp \
+ webdvd.cpp x_frame_buffer.cpp xpcom_support.cpp
csources := jquant2.c
webdvd : $(cxxsources:.cpp=.o) $(csources:.c=.o)
.PHONY : clean distclean install
-browserwidget.% : CPPFLAGS += -DMOZ_LIB_DIR='"$(moz_lib_dir)"'
+browser_widget.% : CPPFLAGS += -DMOZ_LIB_DIR='"$(moz_lib_dir)"'
webdvd.% \
: CPPFLAGS += -DWEBDVD_LIB_DIR='"$(webdvd_lib_dir)"' \
-DMOZ_VERSION_MINOR=$(moz_version_minor) \
-DMOZ_VERSION_PATCHLEVEL=$(moz_version_patchlevel)
-browserwidget.% pixbufs.% temp_file.% webdvd.% \
+browser_widget.% pixbufs.% temp_file.% webdvd.% \
: CPPFLAGS += $(shell pkg-config --cflags gtkmm-2.0)
-browserwidget.% childiterator.o linkiterator.% stylesheets.% webdvd.% \
-xpcom_support.% \
+browser_widget.% child_iterator.o link_iterator.% style_sheets.% webdvd.% \
+xpcom_support.% \
: CPPFLAGS += $(shell pkg-config --cflags mozilla-gtkmozembed)
# These dig a bit deeper into Mozilla
-linkiterator.% stylesheets.% webdvd.% \
- : CPPFLAGS += $(addprefix -I$(moz_include_dir)/, \
+link_iterator.% style_sheets.% webdvd.% \
+ : CPPFLAGS += $(addprefix -I$(moz_include_dir)/, \
content docshell dom gfx layout necko webshell widget)
%.d : %.cpp
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#include "browser_widget.hpp"
+
+#include <cassert>
+
+#include <gtkmozembed_internal.h>
+
+browser_widget::browser_widget()
+ : Gtk::Bin(GTK_BIN(gtk_moz_embed_new()))
+{
+}
+browser_widget::~browser_widget()
+{
+}
+
+GtkMozEmbed * browser_widget::gobj()
+{
+ return GTK_MOZ_EMBED(gobject_);
+}
+const GtkMozEmbed * browser_widget::gobj() const
+{
+ return GTK_MOZ_EMBED(gobject_);
+}
+
+void browser_widget::load_uri(const char * uri)
+{
+ gtk_moz_embed_load_url(gobj(), uri);
+}
+void browser_widget::load_uri(const std::string & uri)
+{
+ return load_uri(uri.c_str());
+}
+void browser_widget::stop_load()
+{
+ gtk_moz_embed_stop_load(gobj());
+}
+void browser_widget::go_back()
+{
+ gtk_moz_embed_go_back(gobj());
+}
+void browser_widget::go_forward()
+{
+ gtk_moz_embed_go_forward(gobj());
+}
+void browser_widget::reload(gint32 flags)
+{
+ gtk_moz_embed_reload(gobj(), flags);
+}
+
+bool browser_widget::can_go_back() const
+{
+ return gtk_moz_embed_can_go_back(const_cast<GtkMozEmbed *>(gobj()));
+}
+bool browser_widget::can_go_forward() const
+{
+ return gtk_moz_embed_can_go_forward(const_cast<GtkMozEmbed *>(gobj()));
+}
+
+namespace
+{
+ template<typename T>
+ class c_scoped_ptr
+ {
+ public:
+ explicit c_scoped_ptr(T * p = 0) : p_(p) {}
+ ~c_scoped_ptr() { free(p_); }
+ T * get() const { return p_; }
+ T * release()
+ {
+ T * p = p_;
+ p_ = NULL;
+ return p;
+ }
+ void reset(T * p = 0)
+ {
+ free(p_);
+ p_ = p;
+ }
+ private:
+ T * p_;
+ };
+}
+
+std::string browser_widget::get_link_message() const
+{
+ c_scoped_ptr<char> str(
+ gtk_moz_embed_get_link_message(const_cast<GtkMozEmbed *>(gobj())));
+ return std::string(str.get());
+}
+std::string browser_widget::get_js_status() const
+{
+ c_scoped_ptr<char> str(
+ gtk_moz_embed_get_js_status(const_cast<GtkMozEmbed *>(gobj())));
+ return std::string(str.get());
+}
+std::string browser_widget::get_title() const
+{
+ c_scoped_ptr<char> str(
+ gtk_moz_embed_get_title(const_cast<GtkMozEmbed *>(gobj())));
+ return std::string(str.get());
+}
+std::string browser_widget::get_location() const
+{
+ c_scoped_ptr<char> str(
+ gtk_moz_embed_get_location(const_cast<GtkMozEmbed *>(gobj())));
+ return std::string(str.get());
+}
+already_AddRefed<nsIWebBrowser> browser_widget::get_browser()
+{
+ nsIWebBrowser * result = 0;
+ gtk_moz_embed_get_nsIWebBrowser(gobj(), &result);
+ assert(result);
+ return dont_AddRef(result);
+}
+
+namespace
+{
+ void browser_widget_signal_link_message_callback(GtkMozEmbed * self, void * data)
+ {
+ typedef SigC::Slot0<void> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_link_message_info =
+ {
+ "link_message",
+ (GCallback) &browser_widget_signal_link_message_callback,
+ (GCallback) &browser_widget_signal_link_message_callback
+ };
+
+ void browser_widget_signal_js_status_callback(GtkMozEmbed * self, void * data)
+ {
+ typedef SigC::Slot0<void> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_js_status_info =
+ {
+ "js_status",
+ (GCallback) &browser_widget_signal_js_status_callback,
+ (GCallback) &browser_widget_signal_js_status_callback
+ };
+
+ void browser_widget_signal_location_callback(GtkMozEmbed * self, void * data)
+ {
+ typedef SigC::Slot0<void> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_location_info =
+ {
+ "location",
+ (GCallback) &browser_widget_signal_location_callback,
+ (GCallback) &browser_widget_signal_location_callback
+ };
+
+ void browser_widget_signal_title_callback(GtkMozEmbed * self, void * data)
+ {
+ typedef SigC::Slot0<void> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_title_info =
+ {
+ "title",
+ (GCallback) &browser_widget_signal_title_callback,
+ (GCallback) &browser_widget_signal_title_callback
+ };
+
+ void browser_widget_signal_progress_callback(
+ GtkMozEmbed * self, gint p0, gint p1, void * data)
+ {
+ typedef SigC::Slot2<void, gint, gint> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(p0, p1, slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_progress_info =
+ {
+ "progress",
+ (GCallback) &browser_widget_signal_progress_callback,
+ (GCallback) &browser_widget_signal_progress_callback
+ };
+
+ void browser_widget_signal_net_state_callback(
+ GtkMozEmbed * self, const char * p0, gint p1, guint p2, void * data)
+ {
+ typedef SigC::Slot3<void, const char *, gint, guint> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(p0, p1, p2, slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_net_state_info =
+ {
+ "net_state_all",
+ (GCallback) &browser_widget_signal_net_state_callback,
+ (GCallback) &browser_widget_signal_net_state_callback
+ };
+
+ void browser_widget_signal_net_start_callback(GtkMozEmbed * self, void * data)
+ {
+ typedef SigC::Slot0<void> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_net_start_info =
+ {
+ "net_start",
+ (GCallback) &browser_widget_signal_net_start_callback,
+ (GCallback) &browser_widget_signal_net_start_callback
+ };
+
+ void browser_widget_signal_net_stop_callback(GtkMozEmbed * self, void * data)
+ {
+ typedef SigC::Slot0<void> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_net_stop_info =
+ {
+ "net_stop",
+ (GCallback) &browser_widget_signal_net_stop_callback,
+ (GCallback) &browser_widget_signal_net_stop_callback
+ };
+
+ void browser_widget_signal_new_window_callback(
+ GtkMozEmbed * self, GtkMozEmbed ** p0, guint p1, void * data)
+ {
+ typedef SigC::Slot1<browser_widget *, guint> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ {
+ if (browser_widget * result =
+ (*(SlotType::Proxy)(slot->proxy_))(p1, slot))
+ {
+ *p0 = result->gobj();
+ return;
+ }
+ }
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+
+ *p0 = NULL;
+ return;
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_new_window_info =
+ {
+ "new_window",
+ (GCallback) &browser_widget_signal_new_window_callback,
+ (GCallback) &browser_widget_signal_new_window_callback
+ };
+
+ void browser_widget_signal_visibility_callback(
+ GtkMozEmbed * self, gboolean p0, void * data)
+ {
+ typedef SigC::Slot1<void, bool> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(p0, slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_visibility_info =
+ {
+ "visibility",
+ (GCallback) &browser_widget_signal_visibility_callback,
+ (GCallback) &browser_widget_signal_visibility_callback
+ };
+
+ void browser_widget_signal_destroy_browser_callback(
+ GtkMozEmbed * self, void * data)
+ {
+ typedef SigC::Slot0<void> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ (*(SlotType::Proxy)(slot->proxy_))(slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_destroy_info =
+ {
+ "destroy_browser",
+ (GCallback) &browser_widget_signal_destroy_browser_callback,
+ (GCallback) &browser_widget_signal_destroy_browser_callback
+ };
+
+ gint browser_widget_signal_open_uri_callback(
+ GtkMozEmbed * self, const char * p0, void * data)
+ {
+ typedef SigC::Slot1<bool, const char *> SlotType;
+
+ if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
+ {
+ try
+ {
+ if (SigC::SlotNode * const slot =
+ Glib::SignalProxyNormal::data_to_slot(data))
+ return (*(SlotType::Proxy)(slot->proxy_))(p0, slot);
+ }
+ catch(...)
+ {
+ Glib::exception_handlers_invoke();
+ }
+ }
+
+ return 0;
+ }
+
+ const Glib::SignalProxyInfo browser_widget_signal_open_uri_info =
+ {
+ "open_uri",
+ (GCallback) &browser_widget_signal_open_uri_callback,
+ (GCallback) &browser_widget_signal_open_uri_callback
+ };
+
+} // namespace
+
+Glib::SignalProxy0<void> browser_widget::signal_link_message()
+{
+ return Glib::SignalProxy0<void>(this, &browser_widget_signal_link_message_info);
+}
+Glib::SignalProxy0<void> browser_widget::signal_js_status()
+{
+ return Glib::SignalProxy0<void>(this, &browser_widget_signal_js_status_info);
+}
+Glib::SignalProxy0<void> browser_widget::signal_location()
+{
+ return Glib::SignalProxy0<void>(this, &browser_widget_signal_location_info);
+}
+Glib::SignalProxy0<void> browser_widget::signal_title()
+{
+ return Glib::SignalProxy0<void>(this, &browser_widget_signal_title_info);
+}
+Glib::SignalProxy2<void, gint /*cur*/, gint /*max*/> browser_widget::signal_progress()
+{
+ return Glib::SignalProxy2<void, gint, gint>(
+ this, &browser_widget_signal_progress_info);
+}
+Glib::SignalProxy3<void, const char *, gint /*flags*/, guint /*status*/>
+browser_widget::signal_net_state()
+{
+ return Glib::SignalProxy3<void, const char *, gint, guint>(
+ this, &browser_widget_signal_net_state_info);
+}
+Glib::SignalProxy0<void> browser_widget::signal_net_start()
+{
+ return Glib::SignalProxy0<void>(this, &browser_widget_signal_net_start_info);
+}
+Glib::SignalProxy0<void> browser_widget::signal_net_stop()
+{
+ return Glib::SignalProxy0<void>(this, &browser_widget_signal_net_stop_info);
+}
+Glib::SignalProxy1<browser_widget *, guint /*chromemask*/> browser_widget::signal_new_window()
+{
+ return Glib::SignalProxy1<browser_widget *, guint>(
+ this, &browser_widget_signal_new_window_info);
+}
+Glib::SignalProxy1<void, bool /*visibility*/> browser_widget::signal_visibility()
+{
+ return Glib::SignalProxy1<void, bool>(
+ this, &browser_widget_signal_visibility_info);
+}
+Glib::SignalProxy0<void> browser_widget::signal_destroy()
+{
+ return Glib::SignalProxy0<void>(this, &browser_widget_signal_destroy_info);
+}
+Glib::SignalProxy1<bool, const char * /*uri*/> browser_widget::signal_open_uri()
+{
+ return Glib::SignalProxy1<bool, const char *>(
+ this, &browser_widget_signal_open_uri_info);
+}
+
+browser_widget::browser_widget(GObject * gobject, bool take_copy)
+{
+ assert(GTK_MOZ_EMBED(gobject));
+ gobject_ = gobject;
+ if (take_copy)
+ reference();
+}
+Glib::ObjectBase * browser_widget::wrap_new(GObject * gobject)
+{
+ return new browser_widget(gobject, false);
+}
+
+browser_widget::initialiser::initialiser()
+{
+ gtk_moz_embed_set_comp_path(MOZ_LIB_DIR);
+ gtk_moz_embed_push_startup();
+
+ wrap_register(gtk_moz_embed_get_type(), wrap_new);
+}
+
+browser_widget::initialiser::~initialiser()
+{
+ gtk_moz_embed_pop_startup();
+}
+
+namespace Glib
+{
+ browser_widget * wrap(GtkMozEmbed * object, bool take_copy)
+ {
+ return dynamic_cast<browser_widget *>(
+ Glib::wrap_auto((GObject*)(object), take_copy));
+ }
+}
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#ifndef INC_BROWSER_WIDGET_HPP
+#define INC_BROWSER_WIDGET_HPP
+
+#include <glibmm/signalproxy.h>
+#include <gtkmm/bin.h>
+
+#include <gtkmozembed.h>
+#include <nsCOMPtr.h>
+
+class browser_widget;
+class nsIWebBrowser;
+
+namespace Glib
+{
+ browser_widget * wrap(GtkMozEmbed * object, bool take_copy = false);
+}
+
+class browser_widget : public Gtk::Bin
+{
+public:
+ browser_widget();
+ virtual ~browser_widget();
+ GtkMozEmbed * gobj();
+ const GtkMozEmbed * gobj() const;
+
+ void load_uri(const char * uri);
+ void load_uri(const std::string & uri);
+ void stop_load();
+ void go_back();
+ void go_forward();
+ void reload(gint32 flags = GTK_MOZ_EMBED_FLAG_RELOADNORMAL);
+
+ bool can_go_back() const;
+ bool can_go_forward() const;
+
+ std::string get_link_message() const;
+ std::string get_js_status() const;
+ std::string get_title() const;
+ std::string get_location() const;
+ already_AddRefed<nsIWebBrowser> get_browser();
+
+ Glib::SignalProxy0<void> signal_link_message();
+ Glib::SignalProxy0<void> signal_js_status();
+ Glib::SignalProxy0<void> signal_location();
+ Glib::SignalProxy0<void> signal_title();
+ Glib::SignalProxy2<void, gint /*cur*/, gint /*max*/> signal_progress();
+ Glib::SignalProxy3<void, const char *, gint /*flags*/, guint /*status*/>
+ signal_net_state();
+ Glib::SignalProxy0<void> signal_net_start();
+ Glib::SignalProxy0<void> signal_net_stop();
+ Glib::SignalProxy1<browser_widget *, guint /*chromemask*/> signal_new_window();
+ Glib::SignalProxy1<void, bool /*visibility*/> signal_visibility();
+ Glib::SignalProxy0<void> signal_destroy();
+ Glib::SignalProxy1<bool, const char * /*uri*/> signal_open_uri();
+
+ // This must be instantiated after Gtk initialisation and before
+ // instantiation of browser_widget.
+ struct initialiser
+ {
+ initialiser();
+ ~initialiser();
+ };
+
+private:
+ browser_widget(GObject * gobject, bool take_copy);
+ static Glib::ObjectBase * wrap_new(GObject * gobject);
+ friend browser_widget * Glib::wrap(GtkMozEmbed * object, bool take_copy);
+};
+
+#endif // !INC_BROWSER_WIDGET_HPP
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#include "browserwidget.hpp"
-
-#include <cassert>
-
-#include <gtkmozembed_internal.h>
-
-BrowserWidget::BrowserWidget()
- : Gtk::Bin(GTK_BIN(gtk_moz_embed_new()))
-{
-}
-BrowserWidget::~BrowserWidget()
-{
-}
-
-GtkMozEmbed * BrowserWidget::gobj()
-{
- return GTK_MOZ_EMBED(gobject_);
-}
-const GtkMozEmbed * BrowserWidget::gobj() const
-{
- return GTK_MOZ_EMBED(gobject_);
-}
-
-void BrowserWidget::load_uri(const char * uri)
-{
- gtk_moz_embed_load_url(gobj(), uri);
-}
-void BrowserWidget::load_uri(const std::string & uri)
-{
- return load_uri(uri.c_str());
-}
-void BrowserWidget::stop_load()
-{
- gtk_moz_embed_stop_load(gobj());
-}
-void BrowserWidget::go_back()
-{
- gtk_moz_embed_go_back(gobj());
-}
-void BrowserWidget::go_forward()
-{
- gtk_moz_embed_go_forward(gobj());
-}
-void BrowserWidget::reload(gint32 flags)
-{
- gtk_moz_embed_reload(gobj(), flags);
-}
-
-bool BrowserWidget::can_go_back() const
-{
- return gtk_moz_embed_can_go_back(const_cast<GtkMozEmbed *>(gobj()));
-}
-bool BrowserWidget::can_go_forward() const
-{
- return gtk_moz_embed_can_go_forward(const_cast<GtkMozEmbed *>(gobj()));
-}
-
-namespace
-{
- template<typename T>
- class c_scoped_ptr
- {
- public:
- explicit c_scoped_ptr(T * p = 0) : p_(p) {}
- ~c_scoped_ptr() { free(p_); }
- T * get() const { return p_; }
- T * release()
- {
- T * p = p_;
- p_ = NULL;
- return p;
- }
- void reset(T * p = 0)
- {
- free(p_);
- p_ = p;
- }
- private:
- T * p_;
- };
-}
-
-std::string BrowserWidget::get_link_message() const
-{
- c_scoped_ptr<char> str(
- gtk_moz_embed_get_link_message(const_cast<GtkMozEmbed *>(gobj())));
- return std::string(str.get());
-}
-std::string BrowserWidget::get_js_status() const
-{
- c_scoped_ptr<char> str(
- gtk_moz_embed_get_js_status(const_cast<GtkMozEmbed *>(gobj())));
- return std::string(str.get());
-}
-std::string BrowserWidget::get_title() const
-{
- c_scoped_ptr<char> str(
- gtk_moz_embed_get_title(const_cast<GtkMozEmbed *>(gobj())));
- return std::string(str.get());
-}
-std::string BrowserWidget::get_location() const
-{
- c_scoped_ptr<char> str(
- gtk_moz_embed_get_location(const_cast<GtkMozEmbed *>(gobj())));
- return std::string(str.get());
-}
-already_AddRefed<nsIWebBrowser> BrowserWidget::get_browser()
-{
- nsIWebBrowser * result = 0;
- gtk_moz_embed_get_nsIWebBrowser(gobj(), &result);
- assert(result);
- return dont_AddRef(result);
-}
-
-namespace
-{
- void BrowserWidget_signal_link_message_callback(GtkMozEmbed * self, void * data)
- {
- typedef SigC::Slot0<void> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_link_message_info =
- {
- "link_message",
- (GCallback) &BrowserWidget_signal_link_message_callback,
- (GCallback) &BrowserWidget_signal_link_message_callback
- };
-
- void BrowserWidget_signal_js_status_callback(GtkMozEmbed * self, void * data)
- {
- typedef SigC::Slot0<void> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_js_status_info =
- {
- "js_status",
- (GCallback) &BrowserWidget_signal_js_status_callback,
- (GCallback) &BrowserWidget_signal_js_status_callback
- };
-
- void BrowserWidget_signal_location_callback(GtkMozEmbed * self, void * data)
- {
- typedef SigC::Slot0<void> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_location_info =
- {
- "location",
- (GCallback) &BrowserWidget_signal_location_callback,
- (GCallback) &BrowserWidget_signal_location_callback
- };
-
- void BrowserWidget_signal_title_callback(GtkMozEmbed * self, void * data)
- {
- typedef SigC::Slot0<void> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_title_info =
- {
- "title",
- (GCallback) &BrowserWidget_signal_title_callback,
- (GCallback) &BrowserWidget_signal_title_callback
- };
-
- void BrowserWidget_signal_progress_callback(
- GtkMozEmbed * self, gint p0, gint p1, void * data)
- {
- typedef SigC::Slot2<void, gint, gint> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(p0, p1, slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_progress_info =
- {
- "progress",
- (GCallback) &BrowserWidget_signal_progress_callback,
- (GCallback) &BrowserWidget_signal_progress_callback
- };
-
- void BrowserWidget_signal_net_state_callback(
- GtkMozEmbed * self, const char * p0, gint p1, guint p2, void * data)
- {
- typedef SigC::Slot3<void, const char *, gint, guint> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(p0, p1, p2, slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_net_state_info =
- {
- "net_state_all",
- (GCallback) &BrowserWidget_signal_net_state_callback,
- (GCallback) &BrowserWidget_signal_net_state_callback
- };
-
- void BrowserWidget_signal_net_start_callback(GtkMozEmbed * self, void * data)
- {
- typedef SigC::Slot0<void> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_net_start_info =
- {
- "net_start",
- (GCallback) &BrowserWidget_signal_net_start_callback,
- (GCallback) &BrowserWidget_signal_net_start_callback
- };
-
- void BrowserWidget_signal_net_stop_callback(GtkMozEmbed * self, void * data)
- {
- typedef SigC::Slot0<void> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_net_stop_info =
- {
- "net_stop",
- (GCallback) &BrowserWidget_signal_net_stop_callback,
- (GCallback) &BrowserWidget_signal_net_stop_callback
- };
-
- void BrowserWidget_signal_new_window_callback(
- GtkMozEmbed * self, GtkMozEmbed ** p0, guint p1, void * data)
- {
- typedef SigC::Slot1<BrowserWidget *, guint> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- {
- if (BrowserWidget * result =
- (*(SlotType::Proxy)(slot->proxy_))(p1, slot))
- {
- *p0 = result->gobj();
- return;
- }
- }
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
-
- *p0 = NULL;
- return;
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_new_window_info =
- {
- "new_window",
- (GCallback) &BrowserWidget_signal_new_window_callback,
- (GCallback) &BrowserWidget_signal_new_window_callback
- };
-
- void BrowserWidget_signal_visibility_callback(
- GtkMozEmbed * self, gboolean p0, void * data)
- {
- typedef SigC::Slot1<void, bool> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(p0, slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_visibility_info =
- {
- "visibility",
- (GCallback) &BrowserWidget_signal_visibility_callback,
- (GCallback) &BrowserWidget_signal_visibility_callback
- };
-
- void BrowserWidget_signal_destroy_browser_callback(
- GtkMozEmbed * self, void * data)
- {
- typedef SigC::Slot0<void> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- (*(SlotType::Proxy)(slot->proxy_))(slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_destroy_info =
- {
- "destroy_browser",
- (GCallback) &BrowserWidget_signal_destroy_browser_callback,
- (GCallback) &BrowserWidget_signal_destroy_browser_callback
- };
-
- gint BrowserWidget_signal_open_uri_callback(
- GtkMozEmbed * self, const char * p0, void * data)
- {
- typedef SigC::Slot1<bool, const char *> SlotType;
-
- if (Glib::ObjectBase::_get_current_wrapper((GObject *)self))
- {
- try
- {
- if (SigC::SlotNode * const slot =
- Glib::SignalProxyNormal::data_to_slot(data))
- return (*(SlotType::Proxy)(slot->proxy_))(p0, slot);
- }
- catch(...)
- {
- Glib::exception_handlers_invoke();
- }
- }
-
- return 0;
- }
-
- const Glib::SignalProxyInfo BrowserWidget_signal_open_uri_info =
- {
- "open_uri",
- (GCallback) &BrowserWidget_signal_open_uri_callback,
- (GCallback) &BrowserWidget_signal_open_uri_callback
- };
-
-} // namespace
-
-Glib::SignalProxy0<void> BrowserWidget::signal_link_message()
-{
- return Glib::SignalProxy0<void>(this, &BrowserWidget_signal_link_message_info);
-}
-Glib::SignalProxy0<void> BrowserWidget::signal_js_status()
-{
- return Glib::SignalProxy0<void>(this, &BrowserWidget_signal_js_status_info);
-}
-Glib::SignalProxy0<void> BrowserWidget::signal_location()
-{
- return Glib::SignalProxy0<void>(this, &BrowserWidget_signal_location_info);
-}
-Glib::SignalProxy0<void> BrowserWidget::signal_title()
-{
- return Glib::SignalProxy0<void>(this, &BrowserWidget_signal_title_info);
-}
-Glib::SignalProxy2<void, gint /*cur*/, gint /*max*/> BrowserWidget::signal_progress()
-{
- return Glib::SignalProxy2<void, gint, gint>(
- this, &BrowserWidget_signal_progress_info);
-}
-Glib::SignalProxy3<void, const char *, gint /*flags*/, guint /*status*/>
-BrowserWidget::signal_net_state()
-{
- return Glib::SignalProxy3<void, const char *, gint, guint>(
- this, &BrowserWidget_signal_net_state_info);
-}
-Glib::SignalProxy0<void> BrowserWidget::signal_net_start()
-{
- return Glib::SignalProxy0<void>(this, &BrowserWidget_signal_net_start_info);
-}
-Glib::SignalProxy0<void> BrowserWidget::signal_net_stop()
-{
- return Glib::SignalProxy0<void>(this, &BrowserWidget_signal_net_stop_info);
-}
-Glib::SignalProxy1<BrowserWidget *, guint /*chromemask*/> BrowserWidget::signal_new_window()
-{
- return Glib::SignalProxy1<BrowserWidget *, guint>(
- this, &BrowserWidget_signal_new_window_info);
-}
-Glib::SignalProxy1<void, bool /*visibility*/> BrowserWidget::signal_visibility()
-{
- return Glib::SignalProxy1<void, bool>(
- this, &BrowserWidget_signal_visibility_info);
-}
-Glib::SignalProxy0<void> BrowserWidget::signal_destroy()
-{
- return Glib::SignalProxy0<void>(this, &BrowserWidget_signal_destroy_info);
-}
-Glib::SignalProxy1<bool, const char * /*uri*/> BrowserWidget::signal_open_uri()
-{
- return Glib::SignalProxy1<bool, const char *>(
- this, &BrowserWidget_signal_open_uri_info);
-}
-
-BrowserWidget::BrowserWidget(GObject * gobject, bool take_copy)
-{
- assert(GTK_MOZ_EMBED(gobject));
- gobject_ = gobject;
- if (take_copy)
- reference();
-}
-Glib::ObjectBase * BrowserWidget::wrap_new(GObject * gobject)
-{
- return new BrowserWidget(gobject, false);
-}
-
-BrowserWidget::Initialiser::Initialiser()
-{
- gtk_moz_embed_set_comp_path(MOZ_LIB_DIR);
- gtk_moz_embed_push_startup();
-
- wrap_register(gtk_moz_embed_get_type(), wrap_new);
-}
-
-BrowserWidget::Initialiser::~Initialiser()
-{
- gtk_moz_embed_pop_startup();
-}
-
-namespace Glib
-{
- BrowserWidget * wrap(GtkMozEmbed * object, bool take_copy)
- {
- return dynamic_cast<BrowserWidget *>(
- Glib::wrap_auto((GObject*)(object), take_copy));
- }
-}
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#ifndef INC_BROWSERWIDGET_HPP
-#define INC_BROWSERWIDGET_HPP
-
-#include <glibmm/signalproxy.h>
-#include <gtkmm/bin.h>
-
-#include <gtkmozembed.h>
-#include <nsCOMPtr.h>
-
-class BrowserWidget;
-class nsIWebBrowser;
-
-namespace Glib
-{
- BrowserWidget * wrap(GtkMozEmbed * object, bool take_copy = false);
-}
-
-class BrowserWidget : public Gtk::Bin
-{
-public:
- BrowserWidget();
- virtual ~BrowserWidget();
- GtkMozEmbed * gobj();
- const GtkMozEmbed * gobj() const;
-
- void load_uri(const char * uri);
- void load_uri(const std::string & uri);
- void stop_load();
- void go_back();
- void go_forward();
- void reload(gint32 flags = GTK_MOZ_EMBED_FLAG_RELOADNORMAL);
-
- bool can_go_back() const;
- bool can_go_forward() const;
-
- std::string get_link_message() const;
- std::string get_js_status() const;
- std::string get_title() const;
- std::string get_location() const;
- already_AddRefed<nsIWebBrowser> get_browser();
-
- Glib::SignalProxy0<void> signal_link_message();
- Glib::SignalProxy0<void> signal_js_status();
- Glib::SignalProxy0<void> signal_location();
- Glib::SignalProxy0<void> signal_title();
- Glib::SignalProxy2<void, gint /*cur*/, gint /*max*/> signal_progress();
- Glib::SignalProxy3<void, const char *, gint /*flags*/, guint /*status*/>
- signal_net_state();
- Glib::SignalProxy0<void> signal_net_start();
- Glib::SignalProxy0<void> signal_net_stop();
- Glib::SignalProxy1<BrowserWidget *, guint /*chromemask*/> signal_new_window();
- Glib::SignalProxy1<void, bool /*visibility*/> signal_visibility();
- Glib::SignalProxy0<void> signal_destroy();
- Glib::SignalProxy1<bool, const char * /*uri*/> signal_open_uri();
-
- // This must be instantiated after Gtk initialisation and before
- // instantiation of BrowserWidget.
- struct Initialiser
- {
- Initialiser();
- ~Initialiser();
- };
-
-private:
- BrowserWidget(GObject * gobject, bool take_copy);
- static Glib::ObjectBase * wrap_new(GObject * gobject);
- friend BrowserWidget * Glib::wrap(GtkMozEmbed * object, bool take_copy);
-};
-
-#endif // !INC_BROWSERWIDGET_HPP
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#include "child_iterator.hpp"
+
+#include <cassert>
+
+#include "xpcom_support.hpp"
+
+using xpcom_support::check;
+
+child_iterator::child_iterator()
+ : node_(0)
+{}
+
+child_iterator::child_iterator(nsIDOMNode * node)
+{
+ check(node->GetFirstChild(&node_));
+}
+
+child_iterator::~child_iterator()
+{
+ if (node_)
+ node_->Release();
+}
+
+already_AddRefed<nsIDOMNode> child_iterator::operator*() const
+{
+ assert(node_);
+ node_->AddRef();
+ return node_;
+}
+
+child_iterator & child_iterator::operator++()
+{
+ nsIDOMNode * next;
+ check(node_->GetNextSibling(&next));
+ node_->Release();
+ node_ = next;
+ return *this;
+}
+
+bool child_iterator::operator==(const child_iterator & other) const
+{
+ return node_ == other.node_;
+}
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#ifndef INC_CHILD_ITERATOR_HPP
+#define INC_CHILD_ITERATOR_HPP
+
+#include <iterator>
+
+#include <nsCOMPtr.h>
+#include <nsIDOMNode.h>
+
+class child_iterator
+ : public std::iterator<std::input_iterator_tag, nsCOMPtr<nsIDOMNode>,
+ void, void, void>
+{
+public:
+ child_iterator();
+ explicit child_iterator(nsIDOMNode * node);
+ ~child_iterator();
+
+ already_AddRefed<nsIDOMNode> operator*() const;
+ child_iterator & operator++();
+ bool operator==(const child_iterator &) const;
+ bool operator!=(const child_iterator & other) const
+ {
+ return !(*this == other);
+ }
+
+private:
+ nsIDOMNode * node_;
+};
+
+#endif // !INC_CHILD_ITERATOR_HPP
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#include "childiterator.hpp"
-
-#include <cassert>
-
-#include "xpcom_support.hpp"
-
-using xpcom_support::check;
-
-ChildIterator::ChildIterator()
- : node_(0)
-{}
-
-ChildIterator::ChildIterator(nsIDOMNode * node)
-{
- check(node->GetFirstChild(&node_));
-}
-
-ChildIterator::~ChildIterator()
-{
- if (node_)
- node_->Release();
-}
-
-already_AddRefed<nsIDOMNode> ChildIterator::operator*() const
-{
- assert(node_);
- node_->AddRef();
- return node_;
-}
-
-ChildIterator & ChildIterator::operator++()
-{
- nsIDOMNode * next;
- check(node_->GetNextSibling(&next));
- node_->Release();
- node_ = next;
- return *this;
-}
-
-bool ChildIterator::operator==(const ChildIterator & other) const
-{
- return node_ == other.node_;
-}
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#ifndef INC_CHILDITERATOR_HPP
-#define INC_CHILDITERATOR_HPP
-
-#include <iterator>
-
-#include <nsCOMPtr.h>
-#include <nsIDOMNode.h>
-
-class ChildIterator
- : public std::iterator<std::input_iterator_tag, nsCOMPtr<nsIDOMNode>,
- void, void, void>
-{
-public:
- ChildIterator();
- explicit ChildIterator(nsIDOMNode * node);
- ~ChildIterator();
-
- already_AddRefed<nsIDOMNode> operator*() const;
- ChildIterator & operator++();
- bool operator==(const ChildIterator &) const;
- bool operator!=(const ChildIterator & other) const
- {
- return !(*this == other);
- }
-
-private:
- nsIDOMNode * node_;
-};
-
-#endif // !INC_CHILDITERATOR_HPP
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#include "framebuffer.hpp"
-
-#include <cassert>
-#include <cstdio>
-#include <cstring>
-#include <stdexcept>
-
-#include <sys/types.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/utsname.h>
-#include <unistd.h>
-#include <wait.h>
-
-#include "auto_fd.hpp"
-#include "auto_handle.hpp"
-#include "temp_file.hpp"
-
-namespace
-{
- struct addrinfo_factory
- {
- addrinfo * operator()() const { return NULL; }
- };
- struct addrinfo_closer
- {
- void operator()(addrinfo * addr_list) const
- {
- if (addr_list)
- freeaddrinfo(addr_list);
- }
- };
- typedef auto_handle<addrinfo *, addrinfo_closer, addrinfo_factory>
- auto_addrinfo;
-
- int select_display_num(auto_fd & tcp4_socket, auto_fd & tcp6_socket)
- {
- // Minimum and maximum display numbers to use. Xvnc and ssh's
- // proxies start at 10, so we'll follow that convention. We
- // have to put a limit on iteration somewhere, and 100
- // displays seems rather excessive so we'll stop there.
- const int min_display_num = 10;
- const int max_display_num = 99;
-
- for (int display_num = min_display_num;
- display_num <= max_display_num;
- ++display_num)
- {
- // Check that there's no lock file for the local socket
- // for this display. We could also check for stale locks,
- // but this will probably do.
- char lock_file_name[20];
- std::sprintf(lock_file_name, "/tmp/.X%d-lock", display_num);
- if (!(access(lock_file_name, 0) == -1 && errno == ENOENT))
- continue;
-
- // Attempt to create TCP socket(s) and bind them to the
- // appropriate port number. We won't set the X server to
- // listen on a TCP socket but this does ensure that ssh
- // isn't using and won't use this display number. This is
- // roughly based on the x11_create_display_inet function
- // in OpenSSH.
-
- auto_addrinfo addr_list;
-
- {
- addrinfo hints = {};
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- char port_str[5 + 1];
- std::sprintf(port_str, "%d", 6000 + display_num);
- addrinfo * addr_list_temp;
- int error = getaddrinfo(NULL, port_str, &hints,
- &addr_list_temp);
- if (error != 0)
- throw std::runtime_error(
- std::string("getaddrinfo: ")
- .append(gai_strerror(error)));
- addr_list.reset(addr_list_temp);
- }
-
- const addrinfo * addr;
-
- for (addr = addr_list.get(); addr != NULL; addr = addr->ai_next)
- {
- // We're only interested in TCPv4 and TCPv6.
- if (addr->ai_family != AF_INET && addr->ai_family != AF_INET6)
- continue;
- auto_fd & tcp_socket =
- (addr->ai_family == AF_INET) ? tcp4_socket : tcp6_socket;
-
- tcp_socket.reset(socket(addr->ai_family,
- SOCK_STREAM,
- addr->ai_protocol));
- if (tcp_socket.get() < 0)
- {
- // If the family is unsupported, no-one can bind
- // to this address, so this is not a problem.
- if (errno == EAFNOSUPPORT
-# ifdef EPFNOSUPPORT
- || errno == EPFNOSUPPORT
-# endif
- )
- continue;
- throw std::runtime_error(
- std::string("socket: ").append(strerror(errno)));
- }
-
- // Don't let TCPv6 sockets interfere with TCPv4 sockets.
-# ifdef IPV6_V6ONLY
- if (addr->ai_family == AF_INET6)
- {
- int on = 1;
- if (setsockopt(tcp_socket.get(), IPPROTO_IPV6, IPV6_V6ONLY,
- &on, sizeof(on)) != 0)
- {
- throw std::runtime_error(
- std::string("setsockopt IPV6_V6ONLY: ")
- .append(strerror(errno)));
- }
- }
-# endif
-
- if (bind(tcp_socket.get(), addr->ai_addr, addr->ai_addrlen)
- != 0)
- break;
- }
-
- // If we reached the end of the address list, we've
- // successfully bound to all appropriate addresses for
- // this display number, so we can use it.
- if (addr == NULL)
- return display_num;
- }
-
- throw std::runtime_error("did not find a free X display");
- }
-
- void get_random_bytes(unsigned char * buf, int len)
- {
- assert(len > 0);
- auto_fd random_fd(open("/dev/urandom", O_RDONLY));
- if (random_fd.get() == -1 || read(random_fd.get(), buf, len) != len)
- throw std::runtime_error(std::strerror(errno));
- }
-
- std::auto_ptr<temp_file> create_temp_auth_file(int display_num)
- {
- std::auto_ptr<temp_file> auth_file(new temp_file("Xvfb-auth-"));
-
- // An xauth entry consists of the following fields. All u16 fields
- // are big-endian and unaligned. Character arrays are not null-
- // terminated.
- // u16 address family (= 256 for local socket)
- // u16 length of address
- // char[] address (= hostname)
- // u16 length of display number
- // char[] display number
- // u16 auth type name length
- // char[] auth type name (= "MIT-MAGIC-COOKIE-1")
- // u16 length of auth data (= 16)
- // char[] auth data (= random bytes)
- uint16_t family = htons(0x100);
- write(auth_file->get_fd(), &family, sizeof(family));
- utsname my_uname;
- uname(&my_uname);
- uint16_t len = htons(strlen(my_uname.nodename));
- write(auth_file->get_fd(), &len, sizeof(len));
- write(auth_file->get_fd(),
- my_uname.nodename, strlen(my_uname.nodename));
- char display[15];
- std::sprintf(display, "%d", display_num);
- len = htons(strlen(display));
- write(auth_file->get_fd(), &len, sizeof(len));
- write(auth_file->get_fd(), display, strlen(display));
- static const char auth_type[] = "MIT-MAGIC-COOKIE-1";
- len = htons(sizeof(auth_type) - 1);
- write(auth_file->get_fd(), &len, sizeof(len));
- write(auth_file->get_fd(), auth_type, sizeof(auth_type) - 1);
- unsigned char auth_key[16];
- get_random_bytes(auth_key, sizeof(auth_key));
- len = htons(sizeof(auth_key));
- write(auth_file->get_fd(), &len, sizeof(len));
- write(auth_file->get_fd(), auth_key, sizeof(auth_key));
-
- return auth_file;
- }
-
- // Run the X server with the specified auth file, dimensions and
- // assigned display number.
- auto_kill_proc spawn_x_server(int display_num,
- const std::string & auth_file_name,
- int width, int height, int depth)
- {
- char display[15];
- std::sprintf(display, ":%d", display_num);
- const char * auth_file_c_str = auth_file_name.c_str();
- std::fflush(NULL);
- auto_kill_proc server_proc(fork());
- if (server_proc.get() == -1)
- throw std::runtime_error(std::strerror(errno));
-
- if (server_proc.get() == 0)
- {
- char dimensions[40];
- std::sprintf(dimensions, "%dx%dx%d", width, height, depth);
- execlp("Xvfb",
- "Xvfb",
- "-auth", auth_file_c_str,
- "-nolisten", "tcp",
- "-screen", "0", dimensions,
- "-terminate",
- display,
- NULL);
- _exit(128 + errno);
- }
-
- // Wait for the lock file to appear or the server to exit. We can't
- // really wait on both of these, so poll at 1-second intervals.
- char lock_file_name[20];
- std::sprintf(lock_file_name, "/tmp/.X%d-lock", display_num);
- for (;;)
- {
- if (access(lock_file_name, 0) == 0)
- break;
- if (errno != ENOENT) // huh?
- throw std::runtime_error(std::strerror(errno));
- if (waitpid(server_proc.get(), NULL, WNOHANG) == server_proc.get())
- {
- server_proc.release(); // pid is now invalid
- // TODO: Get the exit status and decode it properly.
- throw std::runtime_error("X server failed to create display");
- }
- sleep(1);
- }
-
- return server_proc;
- }
-}
-
-FrameBuffer::FrameBuffer(int width, int height, int depth)
- : display_num_(select_display_num(tcp4_socket_, tcp6_socket_)),
- auth_file_(create_temp_auth_file(display_num_)),
- server_proc_(spawn_x_server(display_num_,
- get_x_authority(),
- width, height, depth))
-{}
-
-std::string FrameBuffer::get_x_authority() const
-{
- return auth_file_->get_name();
-}
-
-std::string FrameBuffer::get_x_display() const
-{
- char display[15];
- std::sprintf(display, ":%d", display_num_);
- return display;
-}
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#ifndef INC_FRAMEBUFFER_HPP
-#define INC_FRAMEBUFFER_HPP
-
-#include <memory>
-#include <string>
-
-#include "auto_fd.hpp"
-#include "auto_proc.hpp"
-#include "temp_file.hpp"
-
-// Run Xvfb with a frame buffer of the given dimensions.
-class FrameBuffer
-{
-public:
- FrameBuffer(int width, int height, int depth);
- std::string get_x_authority() const;
- std::string get_x_display() const;
-
-private:
- auto_fd tcp4_socket_, tcp6_socket_;
- int display_num_;
- std::auto_ptr<temp_file> auth_file_;
- auto_kill_proc server_proc_;
-};
-
-#endif // !INC_FRAMEBUFFER_HPP
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#include "link_iterator.hpp"
+
+#include <cassert>
+
+#include <nsIDOMHTMLCollection.h>
+#include <nsIDOMHTMLDocument.h>
+
+link_iterator::link_iterator()
+{}
+
+link_iterator::link_iterator(nsIDOMDocument * document)
+{
+ nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(document));
+ if (!htmlDoc)
+ return;
+
+ htmlDoc->GetLinks(getter_AddRefs(collection_));
+ assert(collection_);
+
+ index_ = 0;
+ length_ = 0;
+ collection_->GetLength(&length_);
+ if (length_ == 0)
+ collection_ = 0;
+}
+
+already_AddRefed<nsIDOMNode> link_iterator::operator*() const
+{
+ assert(collection_);
+ nsIDOMNode * result = 0;
+ collection_->Item(index_, &result);
+ assert(result);
+ return dont_AddRef(result);
+}
+
+link_iterator & link_iterator::operator++()
+{
+ assert(collection_);
+ ++index_;
+ if (index_ == length_)
+ collection_ = 0;
+ return *this;
+}
+
+bool link_iterator::operator==(const link_iterator & other) const
+{
+ return (collection_ == other.collection_
+ && (!collection_ || index_ == other.index_));
+}
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#ifndef INC_LINK_ITERATOR_HPP
+#define INC_LINK_ITERATOR_HPP
+
+#include <iterator>
+
+#include <nsCOMPtr.h>
+#include <nsIDOMHTMLCollection.h>
+#include <nsIDOMNode.h>
+
+class nsIDOMDocument;
+
+class link_iterator
+ : public std::iterator<std::input_iterator_tag, nsCOMPtr<nsIDOMNode>,
+ void, void, void>
+{
+public:
+ link_iterator();
+ explicit link_iterator(nsIDOMDocument * document);
+
+ already_AddRefed<nsIDOMNode> operator*() const;
+ link_iterator & operator++();
+ bool operator==(const link_iterator &) const;
+ bool operator!=(const link_iterator & other) const
+ {
+ return !(*this == other);
+ }
+
+private:
+ nsCOMPtr<nsIDOMHTMLCollection> collection_;
+ unsigned int index_, length_;
+};
+
+#endif // !INC_LINK_ITERATOR_HPP
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#include "linkiterator.hpp"
-
-#include <cassert>
-
-#include <nsIDOMHTMLCollection.h>
-#include <nsIDOMHTMLDocument.h>
-
-LinkIterator::LinkIterator()
-{}
-
-LinkIterator::LinkIterator(nsIDOMDocument * document)
-{
- nsCOMPtr<nsIDOMHTMLDocument> htmlDoc(do_QueryInterface(document));
- if (!htmlDoc)
- return;
-
- htmlDoc->GetLinks(getter_AddRefs(collection_));
- assert(collection_);
-
- index_ = 0;
- length_ = 0;
- collection_->GetLength(&length_);
- if (length_ == 0)
- collection_ = 0;
-}
-
-already_AddRefed<nsIDOMNode> LinkIterator::operator*() const
-{
- assert(collection_);
- nsIDOMNode * result = 0;
- collection_->Item(index_, &result);
- assert(result);
- return dont_AddRef(result);
-}
-
-LinkIterator & LinkIterator::operator++()
-{
- assert(collection_);
- ++index_;
- if (index_ == length_)
- collection_ = 0;
- return *this;
-}
-
-bool LinkIterator::operator==(const LinkIterator & other) const
-{
- return (collection_ == other.collection_
- && (!collection_ || index_ == other.index_));
-}
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#ifndef INC_LINKITERATOR_HPP
-#define INC_LINKITERATOR_HPP
-
-#include <iterator>
-
-#include <nsCOMPtr.h>
-#include <nsIDOMHTMLCollection.h>
-#include <nsIDOMNode.h>
-
-class nsIDOMDocument;
-
-class LinkIterator
- : public std::iterator<std::input_iterator_tag, nsCOMPtr<nsIDOMNode>,
- void, void, void>
-{
-public:
- LinkIterator();
- explicit LinkIterator(nsIDOMDocument * document);
-
- already_AddRefed<nsIDOMNode> operator*() const;
- LinkIterator & operator++();
- bool operator==(const LinkIterator &) const;
- bool operator!=(const LinkIterator & other) const
- {
- return !(*this == other);
- }
-
-private:
- nsCOMPtr<nsIDOMHTMLCollection> collection_;
- unsigned int index_, length_;
-};
-
-#endif // !INC_LINKITERATOR_HPP
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#include "style_sheets.hpp"
+
+#include <nsContentCID.h>
+#include <nsICSSLoader.h>
+#include <nsICSSStyleSheet.h>
+#include <nsIPresShell.h>
+#include <nsIServiceManagerUtils.h>
+#include <nsIURI.h>
+#include <nsNetUtil.h>
+
+#include "xpcom_support.hpp"
+
+using xpcom_support::check;
+
+// Load a CSS from an (absolute) URI.
+// TODO: Support loading from an absolute, or better, relative filename.
+already_AddRefed<nsIStyleSheet> load_css(const char * uri)
+{
+ nsCOMPtr<nsICSSLoader> css_loader;
+ static const nsCID css_loader_cid = NS_CSS_LOADER_CID;
+ check(CallGetService<nsICSSLoader>(css_loader_cid,
+ getter_AddRefs(css_loader)));
+
+ nsCOMPtr<nsIURI> style_sheet_uri;
+ check(NS_NewURI(getter_AddRefs(style_sheet_uri), nsCString(uri)));
+
+ nsICSSStyleSheet * style_sheet;
+ check(css_loader->LoadAgentSheet(style_sheet_uri, &style_sheet));
+ return style_sheet;
+}
+
+// Apply a style-sheet to a given presentation shell as the top-priority
+// agent style-sheet and disable the preferences-derived style rules.
+void apply_style_sheet(nsIStyleSheet * style_sheet, nsIPresShell * pres_shell)
+{
+ nsCOMArray<nsIStyleSheet> style_sheets;
+ check(pres_shell->GetAgentStyleSheets(style_sheets));
+ check(style_sheets.InsertObjectAt(style_sheet, 0));
+ check(pres_shell->SetAgentStyleSheets(style_sheets));
+
+ check(pres_shell->EnablePrefStyleRules(false));
+
+ // Update the display
+ check(pres_shell->ReconstructStyleData());
+ check(pres_shell->FlushPendingNotifications(true));
+}
+
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#ifndef INC_STYLESHEETS_HPP
+#define INC_STYLESHEETS_HPP
+
+#include <nsCOMPtr.h>
+#include <nsIStyleSheet.h>
+
+class nsIPresShell;
+
+// Load a CSS from an (absolute) URI.
+// TODO: Support loading from an absolute, or better, relative filename.
+already_AddRefed<nsIStyleSheet> load_css(const char * uri);
+
+// Apply a style-sheet to a given presentation shell as the top-priority
+// agent style-sheet and disable the preferences-derived style rules.
+void apply_style_sheet(nsIStyleSheet *, nsIPresShell *);
+
+#endif // !INC_STYLESHEETS_HPP
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#include "stylesheets.hpp"
-
-#include <nsContentCID.h>
-#include <nsICSSLoader.h>
-#include <nsICSSStyleSheet.h>
-#include <nsIPresShell.h>
-#include <nsIServiceManagerUtils.h>
-#include <nsIURI.h>
-#include <nsNetUtil.h>
-
-#include "xpcom_support.hpp"
-
-using xpcom_support::check;
-
-// Load a CSS from an (absolute) URI.
-// TODO: Support loading from an absolute, or better, relative filename.
-already_AddRefed<nsIStyleSheet> load_css(const char * uri)
-{
- nsCOMPtr<nsICSSLoader> css_loader;
- static const nsCID css_loader_cid = NS_CSS_LOADER_CID;
- check(CallGetService<nsICSSLoader>(css_loader_cid,
- getter_AddRefs(css_loader)));
-
- nsCOMPtr<nsIURI> style_sheet_uri;
- check(NS_NewURI(getter_AddRefs(style_sheet_uri), nsCString(uri)));
-
- nsICSSStyleSheet * style_sheet;
- check(css_loader->LoadAgentSheet(style_sheet_uri, &style_sheet));
- return style_sheet;
-}
-
-// Apply a style-sheet to a given presentation shell as the top-priority
-// agent style-sheet and disable the preferences-derived style rules.
-void apply_style_sheet(nsIStyleSheet * style_sheet, nsIPresShell * pres_shell)
-{
- nsCOMArray<nsIStyleSheet> style_sheets;
- check(pres_shell->GetAgentStyleSheets(style_sheets));
- check(style_sheets.InsertObjectAt(style_sheet, 0));
- check(pres_shell->SetAgentStyleSheets(style_sheets));
-
- check(pres_shell->EnablePrefStyleRules(false));
-
- // Update the display
- check(pres_shell->ReconstructStyleData());
- check(pres_shell->FlushPendingNotifications(true));
-}
-
+++ /dev/null
-// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
-// See the file "COPYING" for licence details.
-
-#ifndef INC_STYLESHEETS_HPP
-#define INC_STYLESHEETS_HPP
-
-#include <nsCOMPtr.h>
-#include <nsIStyleSheet.h>
-
-class nsIPresShell;
-
-// Load a CSS from an (absolute) URI.
-// TODO: Support loading from an absolute, or better, relative filename.
-already_AddRefed<nsIStyleSheet> load_css(const char * uri);
-
-// Apply a style-sheet to a given presentation shell as the top-priority
-// agent style-sheet and disable the preferences-derived style rules.
-void apply_style_sheet(nsIStyleSheet *, nsIPresShell *);
-
-#endif // !INC_STYLESHEETS_HPP
#include <nsIWebBrowser.h>
#include <nsString.h>
-#include "browserwidget.hpp"
-#include "childiterator.hpp"
+#include "browser_widget.hpp"
+#include "child_iterator.hpp"
#include "dvd.hpp"
-#include "framebuffer.hpp"
-#include "linkiterator.hpp"
+#include "link_iterator.hpp"
#include "pixbufs.hpp"
-#include "stylesheets.hpp"
+#include "style_sheets.hpp"
#include "temp_file.hpp"
#include "video.hpp"
+#include "x_frame_buffer.hpp"
#include "xpcom_support.hpp"
using xpcom_support::check;
result.bottom = result.top + height;
// Merge bounding boxes of all child elements
- for (ChildIterator it = ChildIterator(elem), end; it != end; ++it)
+ for (child_iterator it = child_iterator(elem), end; it != end; ++it)
{
nsCOMPtr<nsIDOMNode> child_node(*it);
PRUint16 child_type;
return result;
}
- class WebDvdWindow : public Gtk::Window
+ class webdvd_window : public Gtk::Window
{
public:
- WebDvdWindow(
+ webdvd_window(
const video::frame_params & frame_params,
const std::string & main_page_uri,
const std::string & output_dir);
nsIDOMWindow * dom_window);
void generate_dvd();
- enum ResourceType { page_resource, video_resource };
- typedef std::pair<ResourceType, int> ResourceEntry;
+ enum resource_type { page_resource, video_resource };
+ typedef std::pair<resource_type, int> resource_entry;
video::frame_params frame_params_;
std::string output_dir_;
- BrowserWidget browser_widget_;
+ browser_widget browser_widget_;
nsCOMPtr<nsIStyleSheet> stylesheet_;
std::queue<std::string> page_queue_;
- std::map<std::string, ResourceEntry> resource_map_;
+ std::map<std::string, resource_entry> resource_map_;
std::vector<std::vector<std::string> > page_links_;
std::vector<std::string> video_paths_;
bool pending_window_update_;
std::vector<boost::shared_ptr<temp_file> > page_temp_files_;
};
- WebDvdWindow::WebDvdWindow(
+ webdvd_window::webdvd_window(
const video::frame_params & frame_params,
const std::string & main_page_uri,
const std::string & output_dir)
add(browser_widget_);
browser_widget_.show();
browser_widget_.signal_net_state().connect(
- SigC::slot(*this, &WebDvdWindow::on_net_state_change));
+ SigC::slot(*this, &webdvd_window::on_net_state_change));
add_page(main_page_uri);
load_next_page();
}
- void WebDvdWindow::add_page(const std::string & uri)
+ void webdvd_window::add_page(const std::string & uri)
{
if (resource_map_.insert(
- std::make_pair(uri, ResourceEntry(page_resource, 0)))
+ std::make_pair(uri, resource_entry(page_resource, 0)))
.second)
{
page_queue_.push(uri);
}
}
- void WebDvdWindow::add_video(const std::string & uri)
+ void webdvd_window::add_video(const std::string & uri)
{
if (resource_map_.insert(
- std::make_pair(uri, ResourceEntry(video_resource,
- video_paths_.size() + 1)))
+ std::make_pair(uri, resource_entry(video_resource,
+ video_paths_.size() + 1)))
.second)
{
Glib::ustring hostname;
}
}
- void WebDvdWindow::load_next_page()
+ void webdvd_window::load_next_page()
{
assert(!page_queue_.empty());
const std::string & uri = page_queue_.front();
browser_widget_.load_uri(uri);
}
- void WebDvdWindow::on_net_state_change(const char * uri,
+ void webdvd_window::on_net_state_change(const char * uri,
gint flags, guint status)
{
# ifdef DEBUG_ON_NET_STATE_CHANGE
- std::cout << "WebDvdWindow::on_net_state_change(";
+ std::cout << "webdvd_window::on_net_state_change(";
if (uri)
std::cout << '"' << uri << '"';
else
}
}
- bool WebDvdWindow::process_page()
+ bool webdvd_window::process_page()
{
assert(!page_queue_.empty());
return true;
}
- void WebDvdWindow::save_screenshot()
+ void webdvd_window::save_screenshot()
{
Glib::RefPtr<Gdk::Window> window(get_window());
assert(window);
->save(background_temp_->get_name(), "png");
}
- struct WebDvdWindow::page_state
+ struct webdvd_window::page_state
{
page_state(nsIDOMDocument * doc, int width, int height)
: diff_pixbuf(Gdk::Pixbuf::create(
temp_file links_temp;
int link_num;
- LinkIterator links_it, links_end;
+ link_iterator links_it, links_end;
rectangle link_rect;
bool link_changing;
Glib::RefPtr<Gdk::Pixbuf> norm_pixbuf;
};
- void WebDvdWindow::process_links(nsIPresShell * pres_shell,
+ void webdvd_window::process_links(nsIPresShell * pres_shell,
nsIPresContext * pres_context,
nsIDOMWindow * dom_window)
{
void generate_page_dispatch(std::ostream &, int indent,
int first_page, int last_page);
- void WebDvdWindow::generate_dvd()
+ void webdvd_window::generate_dvd()
{
temp_file temp("webdvd-dvdauthor-");
temp.close();
" g1 = " << link_num * link_mult + page_num << ";";
// Jump to appropriate resource.
- const ResourceEntry & resource_loc =
+ const resource_entry & resource_loc =
resource_map_[page_links[link_num - 1]];
if (resource_loc.first == page_resource)
file <<
}
}
- std::auto_ptr<FrameBuffer> fb;
+ std::auto_ptr<x_frame_buffer> fb;
if (!preview_mode)
{
// Spawn Xvfb and set env variables so that Xlib will use it
// Use 8 bits each for RGB components, which should translate into
// "enough" bits for YUV components.
- fb.reset(new FrameBuffer(frame_params.width, frame_params.height,
- 3 * 8));
- setenv("XAUTHORITY", fb->get_x_authority().c_str(), true);
- setenv("DISPLAY", fb->get_x_display().c_str(), true);
+ fb.reset(new x_frame_buffer(frame_params.width,
+ frame_params.height,
+ 3 * 8));
+ setenv("XAUTHORITY", fb->get_authority().c_str(), true);
+ setenv("DISPLAY", fb->get_display().c_str(), true);
}
// Initialise Gtk
output_dir = argv[argi + 1];
// Initialise Mozilla
- BrowserWidget::Initialiser browser_init;
+ browser_widget::initialiser browser_init;
set_browser_preferences();
// Run the browser/converter
- WebDvdWindow window(frame_params, menu_url, output_dir);
+ webdvd_window window(frame_params, menu_url, output_dir);
Gtk::Main::run(window);
}
catch (std::exception & e)
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#include "x_frame_buffer.hpp"
+
+#include <cassert>
+#include <cstdio>
+#include <cstring>
+#include <stdexcept>
+
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+#include <wait.h>
+
+#include "auto_fd.hpp"
+#include "auto_handle.hpp"
+#include "temp_file.hpp"
+
+namespace
+{
+ struct addrinfo_factory
+ {
+ addrinfo * operator()() const { return NULL; }
+ };
+ struct addrinfo_closer
+ {
+ void operator()(addrinfo * addr_list) const
+ {
+ if (addr_list)
+ freeaddrinfo(addr_list);
+ }
+ };
+ typedef auto_handle<addrinfo *, addrinfo_closer, addrinfo_factory>
+ auto_addrinfo;
+
+ int select_display_num(auto_fd & tcp4_socket, auto_fd & tcp6_socket)
+ {
+ // Minimum and maximum display numbers to use. Xvnc and ssh's
+ // proxies start at 10, so we'll follow that convention. We
+ // have to put a limit on iteration somewhere, and 100
+ // displays seems rather excessive so we'll stop there.
+ const int min_display_num = 10;
+ const int max_display_num = 99;
+
+ for (int display_num = min_display_num;
+ display_num <= max_display_num;
+ ++display_num)
+ {
+ // Check that there's no lock file for the local socket
+ // for this display. We could also check for stale locks,
+ // but this will probably do.
+ char lock_file_name[20];
+ std::sprintf(lock_file_name, "/tmp/.X%d-lock", display_num);
+ if (!(access(lock_file_name, 0) == -1 && errno == ENOENT))
+ continue;
+
+ // Attempt to create TCP socket(s) and bind them to the
+ // appropriate port number. We won't set the X server to
+ // listen on a TCP socket but this does ensure that ssh
+ // isn't using and won't use this display number. This is
+ // roughly based on the x11_create_display_inet function
+ // in OpenSSH.
+
+ auto_addrinfo addr_list;
+
+ {
+ addrinfo hints = {};
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ char port_str[5 + 1];
+ std::sprintf(port_str, "%d", 6000 + display_num);
+ addrinfo * addr_list_temp;
+ int error = getaddrinfo(NULL, port_str, &hints,
+ &addr_list_temp);
+ if (error != 0)
+ throw std::runtime_error(
+ std::string("getaddrinfo: ")
+ .append(gai_strerror(error)));
+ addr_list.reset(addr_list_temp);
+ }
+
+ const addrinfo * addr;
+
+ for (addr = addr_list.get(); addr != NULL; addr = addr->ai_next)
+ {
+ // We're only interested in TCPv4 and TCPv6.
+ if (addr->ai_family != AF_INET && addr->ai_family != AF_INET6)
+ continue;
+ auto_fd & tcp_socket =
+ (addr->ai_family == AF_INET) ? tcp4_socket : tcp6_socket;
+
+ tcp_socket.reset(socket(addr->ai_family,
+ SOCK_STREAM,
+ addr->ai_protocol));
+ if (tcp_socket.get() < 0)
+ {
+ // If the family is unsupported, no-one can bind
+ // to this address, so this is not a problem.
+ if (errno == EAFNOSUPPORT
+# ifdef EPFNOSUPPORT
+ || errno == EPFNOSUPPORT
+# endif
+ )
+ continue;
+ throw std::runtime_error(
+ std::string("socket: ").append(strerror(errno)));
+ }
+
+ // Don't let TCPv6 sockets interfere with TCPv4 sockets.
+# ifdef IPV6_V6ONLY
+ if (addr->ai_family == AF_INET6)
+ {
+ int on = 1;
+ if (setsockopt(tcp_socket.get(), IPPROTO_IPV6, IPV6_V6ONLY,
+ &on, sizeof(on)) != 0)
+ {
+ throw std::runtime_error(
+ std::string("setsockopt IPV6_V6ONLY: ")
+ .append(strerror(errno)));
+ }
+ }
+# endif
+
+ if (bind(tcp_socket.get(), addr->ai_addr, addr->ai_addrlen)
+ != 0)
+ break;
+ }
+
+ // If we reached the end of the address list, we've
+ // successfully bound to all appropriate addresses for
+ // this display number, so we can use it.
+ if (addr == NULL)
+ return display_num;
+ }
+
+ throw std::runtime_error("did not find a free X display");
+ }
+
+ void get_random_bytes(unsigned char * buf, int len)
+ {
+ assert(len > 0);
+ auto_fd random_fd(open("/dev/urandom", O_RDONLY));
+ if (random_fd.get() == -1 || read(random_fd.get(), buf, len) != len)
+ throw std::runtime_error(std::strerror(errno));
+ }
+
+ std::auto_ptr<temp_file> create_temp_auth_file(int display_num)
+ {
+ std::auto_ptr<temp_file> auth_file(new temp_file("Xvfb-auth-"));
+
+ // An xauth entry consists of the following fields. All u16 fields
+ // are big-endian and unaligned. Character arrays are not null-
+ // terminated.
+ // u16 address family (= 256 for local socket)
+ // u16 length of address
+ // char[] address (= hostname)
+ // u16 length of display number
+ // char[] display number
+ // u16 auth type name length
+ // char[] auth type name (= "MIT-MAGIC-COOKIE-1")
+ // u16 length of auth data (= 16)
+ // char[] auth data (= random bytes)
+ uint16_t family = htons(0x100);
+ write(auth_file->get_fd(), &family, sizeof(family));
+ utsname my_uname;
+ uname(&my_uname);
+ uint16_t len = htons(strlen(my_uname.nodename));
+ write(auth_file->get_fd(), &len, sizeof(len));
+ write(auth_file->get_fd(),
+ my_uname.nodename, strlen(my_uname.nodename));
+ char display[15];
+ std::sprintf(display, "%d", display_num);
+ len = htons(strlen(display));
+ write(auth_file->get_fd(), &len, sizeof(len));
+ write(auth_file->get_fd(), display, strlen(display));
+ static const char auth_type[] = "MIT-MAGIC-COOKIE-1";
+ len = htons(sizeof(auth_type) - 1);
+ write(auth_file->get_fd(), &len, sizeof(len));
+ write(auth_file->get_fd(), auth_type, sizeof(auth_type) - 1);
+ unsigned char auth_key[16];
+ get_random_bytes(auth_key, sizeof(auth_key));
+ len = htons(sizeof(auth_key));
+ write(auth_file->get_fd(), &len, sizeof(len));
+ write(auth_file->get_fd(), auth_key, sizeof(auth_key));
+
+ return auth_file;
+ }
+
+ // Run the X server with the specified auth file, dimensions and
+ // assigned display number.
+ auto_kill_proc spawn_x_server(int display_num,
+ const std::string & auth_file_name,
+ int width, int height, int depth)
+ {
+ char display[15];
+ std::sprintf(display, ":%d", display_num);
+ const char * auth_file_c_str = auth_file_name.c_str();
+ std::fflush(NULL);
+ auto_kill_proc server_proc(fork());
+ if (server_proc.get() == -1)
+ throw std::runtime_error(std::strerror(errno));
+
+ if (server_proc.get() == 0)
+ {
+ char dimensions[40];
+ std::sprintf(dimensions, "%dx%dx%d", width, height, depth);
+ execlp("Xvfb",
+ "Xvfb",
+ "-auth", auth_file_c_str,
+ "-nolisten", "tcp",
+ "-screen", "0", dimensions,
+ "-terminate",
+ display,
+ NULL);
+ _exit(128 + errno);
+ }
+
+ // Wait for the lock file to appear or the server to exit. We can't
+ // really wait on both of these, so poll at 1-second intervals.
+ char lock_file_name[20];
+ std::sprintf(lock_file_name, "/tmp/.X%d-lock", display_num);
+ for (;;)
+ {
+ if (access(lock_file_name, 0) == 0)
+ break;
+ if (errno != ENOENT) // huh?
+ throw std::runtime_error(std::strerror(errno));
+ if (waitpid(server_proc.get(), NULL, WNOHANG) == server_proc.get())
+ {
+ server_proc.release(); // pid is now invalid
+ // TODO: Get the exit status and decode it properly.
+ throw std::runtime_error("X server failed to create display");
+ }
+ sleep(1);
+ }
+
+ return server_proc;
+ }
+}
+
+x_frame_buffer::x_frame_buffer(int width, int height, int depth)
+ : display_num_(select_display_num(tcp4_socket_, tcp6_socket_)),
+ auth_file_(create_temp_auth_file(display_num_)),
+ server_proc_(spawn_x_server(display_num_,
+ get_authority(),
+ width, height, depth))
+{}
+
+std::string x_frame_buffer::get_authority() const
+{
+ return auth_file_->get_name();
+}
+
+std::string x_frame_buffer::get_display() const
+{
+ char display[15];
+ std::sprintf(display, ":%d", display_num_);
+ return display;
+}
--- /dev/null
+// Copyright 2005 Ben Hutchings <ben@decadentplace.org.uk>.
+// See the file "COPYING" for licence details.
+
+#ifndef INC_X_FRAME_BUFFER_HPP
+#define INC_X_FRAME_BUFFER_HPP
+
+#include <memory>
+#include <string>
+
+#include "auto_fd.hpp"
+#include "auto_proc.hpp"
+#include "temp_file.hpp"
+
+// Run Xvfb with a frame buffer of the given dimensions.
+class x_frame_buffer
+{
+public:
+ x_frame_buffer(int width, int height, int depth);
+ std::string get_authority() const;
+ std::string get_display() const;
+
+private:
+ auto_fd tcp4_socket_, tcp6_socket_;
+ int display_num_;
+ std::auto_ptr<temp_file> auth_file_;
+ auto_kill_proc server_proc_;
+};
+
+#endif // !INC_X_FRAME_BUFFER_HPP