// 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);
}

void BrowserWidget::init()
{
    gtk_moz_embed_set_comp_path(MOZ_LIB_DIR);
    wrap_register(gtk_moz_embed_get_type(), wrap_new);
}

namespace Glib
{
    BrowserWidget * wrap(GtkMozEmbed * object, bool take_copy)
    {
	return dynamic_cast<BrowserWidget *>(
	    Glib::wrap_auto((GObject*)(object), take_copy));
    }
}
