/* $Id: xfce_aboutdialog.c 21555 2006-05-06 22:56:19Z benny $ */
/*-
 * Copyright (c) 2002-2006 Benedikt Meurer <benny@xfce.org>
 * All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif 

#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif

#include <libxfcegui4/libxfcegui4.h>
#include <libxfcegui4/xfce-internals.h>



/**
 ** XfceAboutPerson
 **/

typedef struct _XfceAboutPerson XfceAboutPerson;
struct _XfceAboutPerson
{
  gchar *name;
  gchar *mail;
  gchar *task;
};



static XfceAboutPerson*
xfce_about_person_new (const gchar *name,
                       const gchar *mail,
                       const gchar *task)
{
  XfceAboutPerson *person;

  g_return_val_if_fail (name != NULL, NULL);

  person = g_new (XfceAboutPerson, 1);
  person->name = g_strdup (name);
  person->mail = g_strdup (mail);
  person->task = g_strdup (task);

  return person;
}



static XfceAboutPerson*
xfce_about_person_copy (const XfceAboutPerson *person)
{
  XfceAboutPerson *person_copy = NULL;

  if (G_LIKELY (person != NULL))
    {
      person_copy = g_new (XfceAboutPerson, 1);
      person_copy->name = g_strdup (person->name);
      person_copy->mail = g_strdup (person->mail);
      person_copy->task = g_strdup (person->task);
    }

  return person_copy;
}



static void
xfce_about_person_free (XfceAboutPerson *person)
{
  if (G_LIKELY (person != NULL))
    {
      g_free (person->name);
      g_free (person->mail);
      g_free (person->task);
      g_free (person);
    }
}




/**
 ** XfceAboutInfo
 **/

struct _XfceAboutInfo
{
  gchar *program;
  gchar *version;
  gchar *description;
  gchar *copyright;
  GList *credits;
  gchar *license;
  gchar *homepage;
};



/**
 * xfce_about_info_get_type:
 *
 * Returns the boxed #GType for #XfceAboutInfo.
 *
 * Return value: the boxed #GType for #XfceAboutInfo.
 **/
GType
xfce_about_info_get_type (void)
{
  static GType type = G_TYPE_INVALID;

  if (G_UNLIKELY (type == G_TYPE_INVALID))
    {
      type = g_boxed_type_register_static ("XfceAboutInfo",
                                           (GBoxedCopyFunc) xfce_about_info_copy,
                                           (GBoxedFreeFunc) xfce_about_info_free);
    }

  return type;
}



/**
 * xfce_about_info_new:
 * @program     : program name (e.g. "xfce4-session")
 * @version     : application version.
 * @description : short descriptive text (e.g. "Xfce session manager").
 * @copyright   : copyright text, use the #XFCE_COPYRIGHT_TEXT macro. This
 *                parameter is optional. If set to NULL, a default copyright
 *                text will be choosen.
 * @license     : optional license text, can either be the text of a license
 *                or can be one of the builtin license constants, which are
 *                limited to XFCE_LICENSE_BSD, XFCE_LICENSE_GPL and
 *                XFCE_LICENSE_LGPL currently. If NULL, no license text will
 *                be displayed.
 *
 * Return value:  the new #XfceAboutInfo object or NULL on error. The result
 *                needs to be freed using xfce_about_info_free().
 **/
XfceAboutInfo*
xfce_about_info_new (const gchar *program,
                     const gchar *version,
                     const gchar *description,
                     const gchar *copyright,
                     const gchar *license)
{
  XfceAboutInfo *info;

  g_return_val_if_fail (program != NULL, NULL);
  g_return_val_if_fail (version != NULL, NULL);
  g_return_val_if_fail (description != NULL, NULL);

  /* put in place default values for optional parameters */
  if (G_UNLIKELY (copyright == NULL))
    copyright = XFCE_COPYRIGHT_TEXT ("2002-2006", "The Xfce development team");

  /* allocate the about info */
  info = g_new0 (XfceAboutInfo, 1);
  info->program = g_strdup (program);
  info->version = g_strdup (version);
  info->description = g_strdup (description);
  info->copyright = g_strdup (copyright);
  info->license = g_strdup (license);

  return info;
}



/**
 * xfce_about_info_copy:
 * @info : an #XfceAboutInfo, which should be duplicated.
 *
 * Takes a deep copy of the @info and returns the copy. The
 * caller is responsible to free the returned object using
 * xfce_about_info_free() when no longer needed.
 *
 * Return value: a copy of @info.
 **/
XfceAboutInfo*
xfce_about_info_copy (const XfceAboutInfo *info)
{
  XfceAboutInfo *info_copy;
  GList         *lp;

  /* copying NULL gives NULL :-) */
  if (G_UNLIKELY (info == NULL))
    return NULL;

  /* allocate the new copy for info */
  info_copy = g_new0 (XfceAboutInfo, 1);
  info_copy->program = g_strdup (info->program);
  info_copy->version = g_strdup (info->version);
  info_copy->description = g_strdup (info->description);
  info_copy->copyright = g_strdup (info->copyright);
  info_copy->license = g_strdup (info->license);
  info_copy->homepage = g_strdup (info->homepage);

  /* also duplicate the credits */
  for (lp = info->credits; lp != NULL; lp = lp->next)
    info_copy->credits = g_list_append (info_copy->credits, xfce_about_person_copy (lp->data));

  return info_copy;
}



/**
 * xfce_about_info_free:
 * @info : an #XfceAboutInfo.
 *
 * Frees the @info object and all resources covered by it.
 **/
void
xfce_about_info_free (XfceAboutInfo *info)
{
  if (G_LIKELY (info != NULL))
    {
      /* free attributes */
      g_free (info->description);
      g_free (info->copyright);
      g_free (info->homepage);
      g_free (info->license);
      g_free (info->program);
      g_free (info->version);

      /* free credits */
      g_list_foreach (info->credits, (GFunc) xfce_about_person_free, NULL);
      g_list_free (info->credits);

      /* free info itself */
      g_free (info);
    }
}



/**
 * xfce_about_info_get_program:
 * @info : an #XfceAboutInfo.
 *
 * Returns the program for @info.
 *
 * Return value: the program for @info.
 **/
const gchar*
xfce_about_info_get_program (const XfceAboutInfo *info)
{
  g_return_val_if_fail (info != NULL, NULL);
  return info->program;
}



/**
 * xfce_about_info_set_program:
 * @info    : an #XfceAboutInfo.
 * @program : the new program for @info.
 *
 * Sets the program for @info to @program.
 **/
void
xfce_about_info_set_program (XfceAboutInfo *info,
                             const gchar   *program)
{
  g_return_if_fail (info != NULL);
  g_return_if_fail (g_utf8_validate (program, -1, NULL));

  g_free (info->program);
  info->program = g_strdup (program);
}



/**
 * xfce_about_info_get_version:
 * @info : an #XfceAboutInfo.
 *
 * Returns the version for @info.
 *
 * Return value: the version for @info.
 **/
const gchar*
xfce_about_info_get_version (const XfceAboutInfo *info)
{
  g_return_val_if_fail (info != NULL, NULL);
  return info->version;
}



/**
 * xfce_about_info_set_version:
 * @info    : an #XfceAboutInfo.
 * @version : the new version for @info.
 *
 * Sets the version for @info to @version.
 **/
void
xfce_about_info_set_version (XfceAboutInfo *info,
                             const gchar   *version)
{
  g_return_if_fail (info != NULL);
  g_return_if_fail (g_utf8_validate (version, -1, NULL));

  g_free (info->version);
  info->version = g_strdup (version);
}



/**
 * xfce_about_info_get_description:
 * @info : an #XfceAboutInfo.
 *
 * Returns the description for @info.
 *
 * Return value: the description for @info.
 **/
const gchar*
xfce_about_info_get_description (const XfceAboutInfo *info)
{
  g_return_val_if_fail (info != NULL, NULL);
  return info->description;
}



/**
 * xfce_about_info_set_description:
 * @info        : an #XfceAboutInfo.
 * @description : the new description for @info.
 *
 * Sets the description for @info to @description.
 **/
void
xfce_about_info_set_description (XfceAboutInfo *info,
                                 const gchar   *description)
{
  g_return_if_fail (info != NULL);
  g_return_if_fail (g_utf8_validate (description, -1, NULL));

  g_free (info->description);
  info->description = g_strdup (description);
}



/**
 * xfce_about_info_get_copyright:
 * @info : an #XfceAboutInfo.
 *
 * Returns the copyright for @info.
 *
 * Return value: the copyright for @info.
 **/
const gchar*
xfce_about_info_get_copyright (const XfceAboutInfo *info)
{
  g_return_val_if_fail (info != NULL, NULL);
  return info->copyright;
}



/**
 * xfce_about_info_set_copyright:
 * @info      : an #XfceAboutInfo.
 * @copyright : the new copyright for @info.
 *
 * Sets the copyright for @info to @copyright.
 **/
void
xfce_about_info_set_copyright (XfceAboutInfo *info,
                               const gchar   *copyright)
{
  g_return_if_fail (info != NULL);
  g_return_if_fail (g_utf8_validate (copyright, -1, NULL));

  g_free (info->copyright);
  info->copyright = g_strdup (copyright);
}



/**
 * xfce_about_info_get_license:
 * @info : an #XfceAboutInfo.
 *
 * Returns the license for @info.
 *
 * Return value: the license for @info.
 **/
const gchar*
xfce_about_info_get_license (const XfceAboutInfo *info)
{
  g_return_val_if_fail (info != NULL, NULL);
  return info->license;
}



/**
 * xfce_about_info_set_license:
 * @info    : an #XfceAboutInfo.
 * @license : the new license for @info.
 *
 * Sets the license for @info to @license.
 **/
void
xfce_about_info_set_license (XfceAboutInfo *info,
                             const gchar   *license)
{
  g_return_if_fail (info != NULL);
  g_return_if_fail (g_utf8_validate (license, -1, NULL));
  
  g_free (info->license);
  info->license = g_strdup (license);
}



/**
 * xfce_about_info_get_homepage:
 * @info : an #XfceAboutInfo.
 *
 * Returns the homepage for @info.
 *
 * Return value: the homepage for @info.
 **/
const char*
xfce_about_info_get_homepage (const XfceAboutInfo *info)
{
  g_return_val_if_fail (info != NULL, NULL);
  return info->homepage;
}



/**
 * xfce_about_info_set_homepage:
 * @info      : an #XfceAboutInfo.
 * @homepage  : the URL of the projects website, has to be a valid URL, that
 *              can be loaded by a webbrowser.
 *
 * Associates a @homepage with the @info object.
 **/
void
xfce_about_info_set_homepage (XfceAboutInfo *info,
                              const gchar   *homepage)
{
  g_return_if_fail (info != NULL);
  g_return_if_fail (g_utf8_validate (homepage, -1, NULL));

  g_free (info->homepage);
  info->homepage = g_strdup (homepage);
}



/**
 * xfce_about_info_add_credit:
 * @info  : an #XfceAboutInfo.
 * @name  : the full name of the person.
 * @mail  : the persons email address.
 * @task  : the persons task in the project.
 *
 * Adds a credit to the @info object.
 **/
void
xfce_about_info_add_credit (XfceAboutInfo *info,
                            const gchar   *name,
                            const gchar   *mail,
                            const gchar   *task)
{
  g_return_if_fail (info != NULL);
  g_return_if_fail (name != NULL);

  /* add person to credits list */
  info->credits = g_list_append (info->credits, xfce_about_person_new (name, mail, task));
}




/**
 ** XfceAboutDialog
 **/

struct _XfceAboutDialogPrivate
{
	XfceAboutInfo	*info;
	
  /* icon if any */
  GdkPixbuf *pixbuf;

  /* tooltips help */
  GtkTooltips *tooltips;

  /* header widgets */
  GtkWidget *heading;

  /* widgets in the "Info" tab */
  GtkWidget *info_des_label;
  GtkWidget *info_url_button;
  GtkWidget *info_url_label;
  GtkWidget *info_cop_label;

  /* widgets in the "Credits" tab */
  GtkWidget *credits_scrollwin;
  GtkWidget *credits_label;

  /* widgets in the "License" tab */
  GtkWidget *license_scrollwin;
  GtkWidget *license_textview;
};

static void xfce_about_dialog_class_init(XfceAboutDialogClass *klass);
static void xfce_about_dialog_init(XfceAboutDialog *dialog);
static void xfce_about_dialog_finalize(GObject *object);



G_DEFINE_TYPE (XfceAboutDialog, xfce_about_dialog, GTK_TYPE_DIALOG);



enum {
	PROGRAM_PROP = 1,
	VERSION_PROP,
	DESCRIPTION_PROP,
	COPYRIGHT_PROP,
	LICENSE_PROP,
	HOMEPAGE_PROP,
	ICON_PROP,
	/* credit? */
};

static void
xfce_about_dialog_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec)
{
	XfceAboutDialog*	dialog;
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	dialog = (XfceAboutDialog*) object;
	priv = dialog->priv;
	info = priv->info;
	switch (param_id) {
	case PROGRAM_PROP:
		g_value_set_string (value, info->program);
		break;
		
	case VERSION_PROP:
		g_value_set_string (value, info->version);
		break;
		
	case DESCRIPTION_PROP:
		g_value_set_string (value, info->description);
		break;
		
	case COPYRIGHT_PROP:
		g_value_set_string (value, info->copyright);
		break;
		
	case LICENSE_PROP:
		g_value_set_string (value, info->license);
		break;
		
	case HOMEPAGE_PROP:
		g_value_set_string (value, info->homepage);
		break;
		
	case ICON_PROP:
		g_value_set_object (value, priv->pixbuf);
		break;
		
	/* credits */
	                                                
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
		break;
	}
}

static void
xfce_about_dialog_update_info_pvd(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	gchar*	s;
	
	priv = dialog->priv;
	info = priv->info;
	
	/* set header title */
	s = g_strdup_printf ("%s %s", info->program, info->version/*, xfce_version_string ()*/);
  xfce_heading_set_title (XFCE_HEADING (priv->heading), s);
	g_free (s);

  /* set header subtitle */
  s = g_strdup_printf ("Xfce %s", xfce_version_string ());
  xfce_heading_set_subtitle (XFCE_HEADING (priv->heading), s);
  g_free (s);

	/* set "Info" description text */
	s = g_strdup_printf ("<span size=\"larger\" weight=\"bold\">%s</span>", info->description);
	gtk_label_set_markup (GTK_LABEL (priv->info_des_label), s);
	g_free (s);
}

static void
xfce_about_dialog_update_info_program(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	gchar	buffer[1024];

	priv = dialog->priv;
	info = priv->info;
	
	/* set window title */
	g_snprintf (buffer, sizeof (buffer), _("About %s..."), info->program);
	gtk_window_set_title (GTK_WINDOW (dialog), buffer);
	xfce_about_dialog_update_info_pvd (dialog);
}

static void
xfce_about_dialog_update_info_version(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	xfce_about_dialog_update_info_pvd (dialog);
}

static void
xfce_about_dialog_update_info_description(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	xfce_about_dialog_update_info_pvd (dialog);
}


static void
xfce_about_dialog_update_info_copyright(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	/* set "Info" copyright text */
	gtk_label_set_text (GTK_LABEL (priv->info_cop_label), info->copyright);
}


static void
xfce_about_dialog_update_info_license(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	GtkTextBuffer*	tb;

	priv = dialog->priv;
	info = priv->info;

	/* display "License" */
	if (info->license != NULL) {
		tb = gtk_text_view_get_buffer(GTK_TEXT_VIEW(priv->license_textview));
		gtk_text_buffer_set_text(tb, info->license, strlen(info->license));
		gtk_widget_show(priv->license_scrollwin);
	}
}


static void
xfce_about_dialog_update_info_homepage(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	gchar	buffer[1024];

	priv = dialog->priv;
	info = priv->info;

	/* set "Info" homepage if given */
	if (info->homepage != NULL) {
		g_snprintf(buffer, sizeof(buffer), "<tt>%s</tt>", info->homepage);
		gtk_label_set_use_markup (GTK_LABEL(priv->info_url_label), TRUE);
		gtk_label_set_markup (GTK_LABEL(priv->info_url_label), buffer);
		gtk_widget_show (priv->info_url_button);
	} else {
		gtk_widget_hide (priv->info_url_button);
	}
}

static void
xfce_about_dialog_update_info_icon(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	GdkPixbuf*	icon;
	priv = dialog->priv;
	icon = priv->pixbuf;

  gtk_window_set_icon (GTK_WINDOW (dialog), icon);
  xfce_heading_set_icon (XFCE_HEADING (priv->heading), icon);
}

static void
xfce_about_dialog_update_info_credits(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	gchar*	text;
	gchar*	p;
	GList *credit;
	gchar	buffer[1024];
  
	priv = dialog->priv;
	info = priv->info;

	/* display "Credits" */
	if (info->credits != NULL) {
		text = g_strdup("");
		for (credit = info->credits; credit != NULL; credit = credit->next) {
			const XfceAboutPerson *person = (const XfceAboutPerson *)credit->data;

			g_snprintf(buffer, sizeof(buffer), "<big><i>%s</i></big>", person->name);

			if (person->mail != NULL) {
				g_strlcat(buffer, "\n\t", sizeof(buffer));
				g_strlcat(buffer, person->mail, sizeof(buffer));
			}

			if (person->task != NULL) {
				g_strlcat(buffer, "\n\t", sizeof(buffer));
				g_strlcat(buffer, person->task, sizeof(buffer));
			}

			p = g_strconcat(text, buffer, "\n\n", NULL);
			g_free(text);
			text = p;
		}
		gtk_label_set_markup(GTK_LABEL(priv->credits_label), text);
		gtk_widget_show(priv->credits_scrollwin);
		g_free(text);
	}
}

static void
xfce_about_dialog_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec)
{
	XfceAboutDialog*	dialog;
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	const gchar*	s_value;
	GdkPixbuf*	pix;
	
	
	dialog = (XfceAboutDialog*) object;
	priv = dialog->priv;
	info = priv->info;
	s_value = g_value_get_string (value);
	
	switch (param_id) {
	case PROGRAM_PROP:
		xfce_about_info_set_program(info, s_value);
		xfce_about_dialog_update_info_program (dialog);
		break;
		
	case VERSION_PROP:
		xfce_about_info_set_version(info, s_value);
		xfce_about_dialog_update_info_version (dialog);
		break;
		
	case DESCRIPTION_PROP:
		xfce_about_info_set_description(info, s_value);
		xfce_about_dialog_update_info_description (dialog);
		break;
		
	case COPYRIGHT_PROP:
		xfce_about_info_set_copyright(info, s_value);
		xfce_about_dialog_update_info_copyright (dialog);
		break;
		
	case LICENSE_PROP:
		xfce_about_info_set_license(info, s_value);
		xfce_about_dialog_update_info_license (dialog);
		break;
		
	case HOMEPAGE_PROP:
		xfce_about_info_set_homepage(info, s_value);
		xfce_about_dialog_update_info_homepage (dialog);
		break;

	case ICON_PROP:
		pix = (GdkPixbuf *) g_value_get_object (value);
		if (pix)
			g_object_ref (pix);
		
		if (priv->pixbuf) {
			g_object_unref (G_OBJECT (priv->pixbuf));
			priv->pixbuf = NULL;
		}
			
		xfce_about_dialog_set_icon(dialog, pix);		
		break;
		
	/* credits ? */
	                                                
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec);
		break;
	}
}

static void
xfce_about_dialog_class_init(XfceAboutDialogClass *klass)
{
  GObjectClass *gobject_class;
  GtkWidgetClass *widget_class;

  /* be sure to initialize the libraries i18n support first */
  _xfce_i18n_init ();

  gobject_class = G_OBJECT_CLASS(klass);
  widget_class = GTK_WIDGET_CLASS(klass);

  gobject_class->finalize = xfce_about_dialog_finalize;
  gobject_class->set_property = xfce_about_dialog_set_property;
  gobject_class->get_property = xfce_about_dialog_get_property;
  
  g_object_class_install_property (gobject_class, PROGRAM_PROP,
  	g_param_spec_string ("program", "Program Name", "Program Name", NULL/*dfl*/, (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
  g_object_class_install_property (gobject_class, VERSION_PROP,
  	g_param_spec_string ("version", "Program Version", "Program Version", NULL/*dfl*/, (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
  g_object_class_install_property (gobject_class, DESCRIPTION_PROP,
  	g_param_spec_string ("description", "Program Description", "Program Description", NULL/*dfl*/, (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
  g_object_class_install_property (gobject_class, COPYRIGHT_PROP,
  	g_param_spec_string ("copyright", "Program Copyright", "Program Copyright", NULL/*dfl*/, (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
  g_object_class_install_property (gobject_class, LICENSE_PROP,
  	g_param_spec_string ("license", "Program License", "Program License", NULL/*dfl*/, (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
  g_object_class_install_property (gobject_class, HOMEPAGE_PROP,
  	g_param_spec_string ("homepage", "Program Homepage", "Program Homepage", NULL/*dfl*/, (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
  g_object_class_install_property (gobject_class, ICON_PROP,
  	g_param_spec_object ("icon", "icon to use", "icon to use, if any", GDK_TYPE_PIXBUF,  (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
  /* credits? */
}


static void
homepage_clicked(GtkButton *button, XfceAboutDialogPrivate *priv)
{
  const gchar *browser;
  gchar        command[2048];

  /* verify that we have a valid info */
  if (G_UNLIKELY (priv->info == NULL))
    return;

  browser = g_find_program_in_path ("exo-open");
  if (G_UNLIKELY (browser == NULL))
    {
      browser = g_find_program_in_path ("xfbrowser4");
      if (G_UNLIKELY (browser == NULL))
        browser = g_getenv ("BROWSER");
    }
  
  if (G_LIKELY (browser != NULL))
    {
      /* use user selected browser */
      g_snprintf (command, sizeof (command), "%s \"%s\"", browser, xfce_about_info_get_homepage (priv->info));
    }
  else
    {
      /* fallback */
      g_snprintf (command, sizeof (command), "ns-remote -remote \"openURL(%s)\"", xfce_about_info_get_homepage (priv->info));
    }

  xfce_exec (command, FALSE, FALSE, NULL);
}

static void
xfce_about_dialog_init(XfceAboutDialog *dialog)
{
  XfceAboutDialogPrivate* priv;
  GtkWidget *info_box;
  GtkWidget *notebook;
  GtkWidget *label;
  GtkWidget *align;
  GtkWidget *box;
  GtkWidget *button;
  GtkWidget *vbox;
  GtkWidget *line;

  /* allocate private data storage */
  priv = g_new0 (XfceAboutDialogPrivate, 1);
  priv->info = g_new0 (XfceAboutInfo, 1);
  dialog->priv = priv;

  /* remove the main dialog box from the window */
  g_object_ref (G_OBJECT (GTK_DIALOG (dialog)->vbox));
  gtk_container_remove (GTK_CONTAINER (dialog), GTK_DIALOG (dialog)->vbox);

  /* add a new vbox w/o border to the main window */
  vbox = gtk_vbox_new (FALSE, 0);
  gtk_container_add (GTK_CONTAINER (dialog), vbox);
  gtk_widget_show (vbox);

  /* add the heading to the window */
  priv->heading = xfce_heading_new ();
  gtk_box_pack_start (GTK_BOX (vbox), priv->heading, FALSE, FALSE, 0);
  gtk_widget_show (priv->heading);

  /* add the separator between header and content */
  line = gtk_hseparator_new ();
  gtk_box_pack_start (GTK_BOX (vbox), line, FALSE, FALSE, 0);
  gtk_widget_show (line);

  /* add the main dialog box to the new vbox */
  gtk_box_pack_start (GTK_BOX (vbox), GTK_DIALOG (dialog)->vbox, TRUE, TRUE, 0);
  g_object_unref (G_OBJECT (GTK_DIALOG (dialog)->vbox));

  /*
   * configure dialog
   */
  button = gtk_dialog_add_button (GTK_DIALOG (dialog),
				  GTK_STOCK_CLOSE,
				  GTK_RESPONSE_CLOSE);
  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);

  gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);

  /*
   * allocate tooltips
   */
  priv->tooltips = gtk_tooltips_new();
  g_object_ref(G_OBJECT(priv->tooltips));
  gtk_object_sink(GTK_OBJECT(priv->tooltips));

  /*
   * create notebook
   */
  box = gtk_event_box_new ();
  gtk_container_set_border_width (GTK_CONTAINER (box), 6);
  gtk_widget_show (box);
  notebook = gtk_notebook_new ();
  gtk_widget_show (notebook);
  gtk_container_add (GTK_CONTAINER (box), notebook);
  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), box, TRUE, TRUE, 0);

  /*
   * create "Info" tab
   */
  align = gtk_alignment_new(0.5, 0.5, 0.0, 0.0);
  gtk_widget_show(align);
  info_box = gtk_vbox_new(FALSE, 0);
  gtk_container_set_border_width(GTK_CONTAINER(info_box), 6);
  gtk_widget_show(info_box);
  priv->info_des_label = gtk_label_new(NULL);
  gtk_label_set_justify(GTK_LABEL(priv->info_des_label), GTK_JUSTIFY_CENTER);
  gtk_label_set_selectable(GTK_LABEL(priv->info_des_label), TRUE);
  gtk_label_set_use_markup(GTK_LABEL(priv->info_des_label), TRUE);
  gtk_misc_set_padding(GTK_MISC(priv->info_des_label), 2, 10);
  gtk_widget_show(priv->info_des_label);
  gtk_box_pack_start(GTK_BOX(info_box), priv->info_des_label, FALSE, FALSE, 0);

  box = gtk_hbutton_box_new();
  priv->info_url_button = gtk_button_new();
  gtk_button_set_relief(GTK_BUTTON(priv->info_url_button), GTK_RELIEF_NONE);
  g_signal_connect(G_OBJECT(priv->info_url_button), "clicked",
      G_CALLBACK(homepage_clicked), priv);
  gtk_box_pack_start(GTK_BOX(box), priv->info_url_button, FALSE, FALSE, 0);
  gtk_tooltips_set_tip(priv->tooltips, priv->info_url_button,
      _("Visit homepage"), NULL);
  gtk_widget_show(box);
  gtk_box_pack_start(GTK_BOX(info_box), box, FALSE, FALSE, 0);

  priv->info_cop_label = gtk_label_new(NULL);
  gtk_label_set_justify(GTK_LABEL(priv->info_cop_label), GTK_JUSTIFY_CENTER);
  gtk_label_set_selectable(GTK_LABEL(priv->info_cop_label), TRUE);
  gtk_label_set_use_markup(GTK_LABEL(priv->info_cop_label), TRUE);
  gtk_misc_set_padding(GTK_MISC(priv->info_cop_label), 2, 10);
  gtk_widget_show(priv->info_cop_label);
  gtk_box_pack_start(GTK_BOX(info_box), priv->info_cop_label, FALSE, FALSE, 0);

  label = gtk_label_new(_("Info"));
  gtk_widget_show(label);
  gtk_container_add(GTK_CONTAINER(align), info_box);
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), align, label);

  /*
   * create "Credits" tab
   */
  priv->credits_scrollwin = gtk_scrolled_window_new(NULL, NULL);
  gtk_container_set_border_width(GTK_CONTAINER(priv->credits_scrollwin), 6);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(priv->credits_scrollwin),
      GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
  priv->credits_label = gtk_label_new(NULL);
  gtk_label_set_selectable(GTK_LABEL(priv->credits_label), TRUE);
  gtk_label_set_use_markup(GTK_LABEL(priv->credits_label), TRUE);
  gtk_misc_set_alignment(GTK_MISC(priv->credits_label), 0.0, 0.0);
  gtk_misc_set_padding(GTK_MISC(priv->credits_label), 5, 0);
  gtk_widget_show(priv->credits_label);
  gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(
        priv->credits_scrollwin), priv->credits_label);
  gtk_viewport_set_shadow_type(GTK_VIEWPORT(gtk_widget_get_parent(
          priv->credits_label)), GTK_SHADOW_NONE);
  label = gtk_label_new(_("Credits"));
  gtk_widget_show(label);
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), priv->credits_scrollwin,
      label);

  /*
   * create "License" tab
   */
  priv->license_scrollwin = gtk_scrolled_window_new(NULL, NULL);
  gtk_container_set_border_width(GTK_CONTAINER(priv->license_scrollwin), 6);
  gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(priv->license_scrollwin), GTK_SHADOW_IN);
  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(priv->license_scrollwin),
      GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
  priv->license_textview = gtk_text_view_new();
  gtk_text_view_set_editable(GTK_TEXT_VIEW(priv->license_textview), FALSE);
  gtk_text_view_set_left_margin(GTK_TEXT_VIEW(priv->license_textview), 6);
  gtk_text_view_set_right_margin(GTK_TEXT_VIEW(priv->license_textview), 6);
  gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(priv->license_textview),
      FALSE);
  gtk_widget_show(priv->license_textview);
  gtk_container_add(GTK_CONTAINER(priv->license_scrollwin),
      priv->license_textview);
  label = gtk_label_new(_("License"));
  gtk_widget_show(label);
  gtk_notebook_append_page(GTK_NOTEBOOK(notebook), priv->license_scrollwin,
      label);

    priv->info_url_label = gtk_label_new (NULL);
    gtk_widget_show (priv->info_url_label);
    gtk_container_add (GTK_CONTAINER(priv->info_url_button), priv->info_url_label);

      gtk_window_set_position (GTK_WINDOW (dialog),
                               GTK_WIN_POS_CENTER_ALWAYS);

}

static void
xfce_about_dialog_finalize(GObject *object)
{
  XfceAboutDialog *about_dialog = XFCE_ABOUT_DIALOG (object);

 
  if (G_LIKELY (about_dialog->priv->pixbuf != NULL))
  	g_object_unref (G_OBJECT (about_dialog->priv->pixbuf));

  if (G_LIKELY (about_dialog->priv->info != NULL))
  	xfce_about_info_free (about_dialog->priv->info);

  g_object_unref (G_OBJECT (about_dialog->priv->tooltips));
  g_free (about_dialog->priv);

  (*G_OBJECT_CLASS (xfce_about_dialog_parent_class)->finalize) (object);
}

/**
 * xfce_about_dialog_new:
 * @parent  : parent window or NULL.
 * @info    : an #XfceAboutInfo object with the about info.
 * @icon    : an optional icon, if NULL, no icon will be displayed.
 *
 * Return value:  the newly allocated dialog widget.
 *
 * @Deprecated: Use xfce_about_dialog_new_with_values instead.   
 *
 **/
GtkWidget*
xfce_about_dialog_new (GtkWindow            *parent,
                       const XfceAboutInfo  *info,
                       GdkPixbuf            *icon)
{
	return xfce_about_dialog_new_with_values (parent, info, icon);
}

/**
 * xfce_about_dialog_new_with_values:
 * @parent  : parent window or NULL.
 * @info    : an #XfceAboutInfo object with the about info.
 * @icon    : an optional icon, if NULL, no icon will be displayed.
 *
 * Return value:  the newly allocated dialog widget.
 **/
GtkWidget*
xfce_about_dialog_new_with_values (GtkWindow            *parent,
                       const XfceAboutInfo  *info,
                       GdkPixbuf            *icon)
{
  XfceAboutDialogPrivate *priv;
  XfceAboutDialog *dialog;
  XfceAboutInfo*	xinfo;
 
  /* validate parameters */
  g_return_val_if_fail(info != NULL, NULL);

  /* allocate dialog */
  dialog = XFCE_ABOUT_DIALOG(g_object_new(XFCE_TYPE_ABOUT_DIALOG, NULL));
  priv = dialog->priv;
  
  xfce_about_info_free (priv->info);
  xinfo = priv->info = xfce_about_info_copy (info);

  /* make transient for parent */
  if (parent != NULL)
    {
      gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
      gtk_window_set_position (GTK_WINDOW (dialog),
                               GTK_WIN_POS_CENTER_ON_PARENT);
    }
  else
    {
      gtk_window_set_position (GTK_WINDOW (dialog),
                               GTK_WIN_POS_CENTER_ALWAYS);
    }

    
  xfce_about_dialog_update_info_program (dialog);
  xfce_about_dialog_update_info_version (dialog);
  xfce_about_dialog_update_info_description (dialog);
  xfce_about_dialog_update_info_copyright (dialog);
  xfce_about_dialog_update_info_license (dialog);
  xfce_about_dialog_update_info_homepage (dialog);
  xfce_about_dialog_set_icon (dialog, icon);		
		
  /*xinfo, */
  xfce_about_dialog_update_info_credits (dialog);

  return GTK_WIDGET (dialog);
}


/**
 * xfce_about_dialog_new_empty:
 *
 * Return value:  the newly allocated dialog widget.
 * 
 * (the weird name - instead of xfce_about_dialog_new - is to keep source and binary compat with previous about dialog)
 *
 **/
GtkWidget*
xfce_about_dialog_new_empty (void)
{
	return g_object_new(XFCE_TYPE_ABOUT_DIALOG, NULL);
}

void xfce_about_dialog_set_program(XfceAboutDialog* dialog, const gchar *value)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	xfce_about_info_set_program(info, value);
	xfce_about_dialog_update_info_program (dialog);
}

void xfce_about_dialog_set_version(XfceAboutDialog* dialog, const gchar *value)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	xfce_about_info_set_version(info, value);
	xfce_about_dialog_update_info_version (dialog);
}

void xfce_about_dialog_set_description(XfceAboutDialog* dialog, const gchar *value)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	xfce_about_info_set_description(info, value);
	xfce_about_dialog_update_info_description (dialog);
}

void xfce_about_dialog_set_copyright(XfceAboutDialog* dialog, const gchar *value)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	xfce_about_info_set_copyright(info, value);
	xfce_about_dialog_update_info_copyright (dialog);
}

void xfce_about_dialog_set_license(XfceAboutDialog* dialog, const gchar *value)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	xfce_about_info_set_license(info, value);
	xfce_about_dialog_update_info_license (dialog);
}

void xfce_about_dialog_set_homepage(XfceAboutDialog* dialog, const gchar *value)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	xfce_about_info_set_homepage(info, value);
	xfce_about_dialog_update_info_homepage (dialog);
}

void xfce_about_dialog_set_icon(XfceAboutDialog* dialog, GdkPixbuf *icon)
{
  if (G_UNLIKELY (dialog->priv->pixbuf != NULL))
    g_object_unref (G_OBJECT (dialog->priv->pixbuf));
  if (G_LIKELY (icon != NULL))
    dialog->priv->pixbuf = g_object_ref (G_OBJECT (icon));
  xfce_about_dialog_update_info_icon (dialog);
}

void xfce_about_dialog_add_credit(XfceAboutDialog* dialog, 
	const gchar   *name,
	const gchar   *mail,
	const gchar   *task)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	xfce_about_info_add_credit(info, name, mail, task);
	xfce_about_dialog_update_info_credits (dialog);
}

const gchar *xfce_about_dialog_get_program(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	return info->program;
}

const gchar *xfce_about_dialog_get_version(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	return info->version;
}

const gchar *xfce_about_dialog_get_description(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	return info->description;
}

const gchar *xfce_about_dialog_get_copyright(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	return info->copyright;
}

const gchar *xfce_about_dialog_get_license(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	return info->license;
}

const gchar *xfce_about_dialog_get_homepage(XfceAboutDialog* dialog)
{
	XfceAboutDialogPrivate* priv;
	XfceAboutInfo*	info;
	priv = dialog->priv;
	info = priv->info;
	return info->homepage;
}

GdkPixbuf *xfce_about_dialog_get_icon(XfceAboutDialog* dialog)
{
	return dialog->priv->pixbuf;
}

