/*
 * clock plugin for the xfce4 panel
 *
 * Copyright (c) 2005 Brian Tarricone <bjt23@cornell.edu>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License ONLY.
 * 
 * This program 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 General Public License
 * along with this program; 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_TIME_H
#include <time.h>
#endif

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

#include <libxfce4util/libxfce4util.h>
#include <libxfcegui4/libxfcegui4.h>
#include <libxfce4panel/xfce-panel-plugin.h>

typedef enum
{
    CLOCK_LAYOUT_DATE_ONLY = 0,
    CLOCK_LAYOUT_TIME_ONLY,
    CLOCK_LAYOUT_DATE_TIME,
    CLOCK_LAYOUT_TIME_DATE,
    CLOCK_LAYOUT_DATE_ABOVE_TIME,
    CLOCK_LAYOUT_TIME_ABOVE_DATE,
    N_CLOCK_LAYOUTS,
} XfceClockLayout;

static const gchar *clock_layout_strs[] = {
    N_("Date only"),
    N_("Time only"),
    N_("Date, then time"),
    N_("Time, then date"),
    N_("Date above time"),
    N_("Time above date"),
};

typedef struct
{
    XfcePanelPlugin *plugin;
    
    GtkWidget *evtbox;
    GtkWidget *frame;
    GtkWidget *label;
    GtkTooltips *tooltip;
    
    guint clock_timeout;
    gchar *overall_format;
    gint max_width;
    
    gboolean show_frame;
    
    guint builtin_time_format;
    gboolean use_custom_time_format;
    gchar *custom_time_format;
    gboolean use_custom_time_font;
    PangoFontDescription *time_font;
    GdkColor time_color;
    
    guint builtin_date_format;
    gboolean use_custom_date_format;
    gchar *custom_date_format;
    gboolean use_custom_date_font;
    PangoFontDescription *date_font;
    GdkColor date_color;
    
    XfceClockLayout layout;
} XfceClockPlugin;

typedef struct
{
    XfceClockPlugin *clock_plugin;
    
    GtkWidget *dlg;
    
    GtkWidget *date_frame;
    GtkWidget *date_custom_box;
    GtkWidget *date_fontbtn;
    GtkWidget *date_colorbtn;
    
    GtkWidget *time_frame;
    GtkWidget *time_custom_box;
    GtkWidget *time_fontbtn;
    GtkWidget *time_colorbtn;
} XfceClockConfig;

static const gchar *builtin_time_formats[] = {
    "%H:%M",
    "%H:%M:%S",
    "%l:%M %P",
    "%l:%M:%S %P",
};
#define N_TIME_FORMATS       4
#define DEFAULT_TIME_FORMAT  1

static const gchar *builtin_date_formats[] = {
    "%Y/%m/%d",
    "%m/%d/%Y",
    "%B %d, %Y",
    "%b %d, %Y",
    "%A, %B %d, %Y",
    "%a, %b %d, %Y",
    "%d/%m/%Y",
    "%d %B %Y",
    "%d %b %Y",
    "%A, %d %B %Y",
    "%a, %d %b %Y",
};
#define N_DATE_FORMATS       11
#define DEFAULT_DATE_FORMAT  0

#define BORDER 8

static inline gchar *
xfclock_do_strftime(const gchar *fmt)
{
    gchar buf[2048], *buf_utf8 = NULL;
    time_t now = time(NULL);
#ifdef HAVE_LOCALTIME_R
    struct tm real_tm;
    struct tm *tm_now = &real_tm;
    
    localtime_r(&now, tm_now);
#else
    struct *tm tm_now = localtime(&now);
#endif
    
    if(strftime(buf, 2048, fmt, tm_now) == 0)
        return g_strdup(_("(Invalid format)"));
    
    if(!g_utf8_validate(buf, -1, NULL)) {
        gsize read, written;
        GError *err = NULL;
        
       buf_utf8 = g_locale_to_utf8(buf, -1, &read, &written, &err);
        if(!buf_utf8) {
            g_critical("System strftime() returned string in strange locale (%d): %s",
                       err->code, err->message);
            g_error_free(err);
            buf_utf8 = g_strdup(_("(UTF-8 conversion failed)"));
        }
    }
    
    return buf_utf8 ? buf_utf8 : g_strdup(buf);
}

static inline gchar *
xfclock_gdkcolor_to_htmlstr(const GdkColor *color)
{
    return g_strdup_printf("#%02x%02x%02x",
                           color->red / 256,
                           color->green / 256,
                           color->blue / 256);
}

static void
xfclock_set_tooltip(XfceClockPlugin *clock_plugin)
{
    gchar *str = NULL;
    
    if(clock_plugin->layout == CLOCK_LAYOUT_DATE_ONLY) {
        if(clock_plugin->use_custom_time_format)
            str = xfclock_do_strftime(clock_plugin->custom_time_format);
        else
            str = xfclock_do_strftime(builtin_time_formats[clock_plugin->builtin_time_format]);
    } else if(clock_plugin->layout == CLOCK_LAYOUT_TIME_ONLY) {
        if(clock_plugin->use_custom_date_format)
            str = xfclock_do_strftime(clock_plugin->custom_date_format);
        else
            str = xfclock_do_strftime(builtin_date_formats[clock_plugin->builtin_date_format]);
    } else {
        gtk_tooltips_set_tip(clock_plugin->tooltip, clock_plugin->evtbox, NULL, NULL);
        return;
    }
    
    gtk_tooltips_set_tip(clock_plugin->tooltip, clock_plugin->evtbox, str, NULL);
    g_free(str);
}

static gchar *
xfclock_get_overall_format(XfceClockPlugin *clock_plugin)
{
    gchar *overall_format = NULL;
    const gchar *date_str, *time_str;
    gchar *date_str_head = NULL, *date_str_foot = "", *time_str_head = NULL,
          *time_str_foot = "";
    
    if(clock_plugin->use_custom_date_format)
        date_str = clock_plugin->custom_date_format;
    else
        date_str = builtin_date_formats[clock_plugin->builtin_date_format];
    if(!date_str)
        date_str = " ";
    
    if(clock_plugin->use_custom_time_format)
        time_str = clock_plugin->custom_time_format;
    else
        time_str = builtin_time_formats[clock_plugin->builtin_time_format];
    if(!time_str)
        time_str = " ";
    
    if(clock_plugin->use_custom_date_font && clock_plugin->date_font) {
        gchar *str = pango_font_description_to_string(clock_plugin->date_font);
        gchar *color_str = xfclock_gdkcolor_to_htmlstr(&clock_plugin->date_color);
        date_str_head = g_strconcat("<span font_desc='", str, "' foreground='",
                                    color_str, "'>", NULL);
        date_str_foot = "</span>";
        g_free(str);
        g_free(color_str);
    }
    
    if(clock_plugin->use_custom_time_font && clock_plugin->time_font) {
        gchar *str = pango_font_description_to_string(clock_plugin->time_font);
        gchar *color_str = xfclock_gdkcolor_to_htmlstr(&clock_plugin->time_color);
        time_str_head = g_strconcat("<span font_desc='", str, "' foreground='",
                                    color_str, "'>", NULL);
        time_str_foot = "</span>";
        g_free(str);
        g_free(color_str);
    }
    
    switch(clock_plugin->layout) {
        case CLOCK_LAYOUT_DATE_ONLY:
            overall_format = g_strconcat(date_str_head?date_str_head:"",
                                         date_str, date_str_foot, NULL);
            break;
        
        case CLOCK_LAYOUT_TIME_ONLY:
            overall_format = g_strconcat(time_str_head?time_str_head:"",
                                         time_str, time_str_foot, NULL);
            break;
        
        case CLOCK_LAYOUT_DATE_TIME:
            overall_format = g_strconcat(date_str_head?date_str_head:"",
                                         date_str, date_str_foot, " ",
                                         time_str_head?time_str_head:"",
                                         time_str, time_str_foot, NULL);
            break;
        
        case CLOCK_LAYOUT_TIME_DATE:
            overall_format = g_strconcat(time_str_head?time_str_head:"",
                                         time_str, time_str_foot, " ",
                                         date_str_head?date_str_head:"",
                                         date_str, date_str_foot, NULL);
            break;
        
        case CLOCK_LAYOUT_DATE_ABOVE_TIME:
            overall_format = g_strconcat(date_str_head?date_str_head:"",
                                         date_str, date_str_foot, "\n",
                                         time_str_head?time_str_head:"",
                                         time_str, time_str_foot, NULL);
            break;
        
        case CLOCK_LAYOUT_TIME_ABOVE_DATE:
            overall_format = g_strconcat(time_str_head?time_str_head:"",
                                         time_str, time_str_foot, "\n",
                                         date_str_head?date_str_head:"",
                                         date_str, date_str_foot, NULL);
            break;
        
        default:
            g_critical("Invalid XfceClockLayout: %d", clock_plugin->layout);
            overall_format = g_strdup(builtin_time_formats[DEFAULT_TIME_FORMAT]);
            break;
    }
    
    g_free(date_str_head);
    g_free(time_str_head);
    
    return overall_format;
}

static gboolean
xfclock_timeout(XfceClockPlugin *clock_plugin)
{
    gchar *timestr;
    GtkRequisition req;
    gint w, h;
    
    timestr = xfclock_do_strftime(clock_plugin->overall_format);
    gtk_label_set_markup(GTK_LABEL(clock_plugin->label), timestr);
    g_free(timestr);
    
    xfclock_set_tooltip(clock_plugin);
    
    /* the idea here is to force the plugin to allocate as much width as it
     * will ever need, and always keep that width.  that way, we will never
     * resize second-to-second if the text takes up more or less space due to
     * a changing value */
    gtk_widget_get_size_request(clock_plugin->label, &w, &h);
    gtk_widget_set_size_request(clock_plugin->label, -1, -1);
    gtk_widget_size_request(clock_plugin->label, &req);
    if(req.width > clock_plugin->max_width)
        clock_plugin->max_width = req.width;
    else {
        gtk_widget_set_size_request(clock_plugin->label,
                                    clock_plugin->max_width, h);
    }
    
    return TRUE;
}

static void
xfclock_config_changed(XfceClockPlugin *clock_plugin)
{
    g_free(clock_plugin->overall_format);
    clock_plugin->overall_format = xfclock_get_overall_format(clock_plugin);
    
    clock_plugin->max_width = -1;
    
    xfclock_timeout(clock_plugin);
}

static gboolean
xfclock_read_config(XfceClockPlugin *clock_plugin)
{
    XfceRc *rcfile;
    char *filename;
    const gchar *str;
    GdkColor *default_color;
    
    filename = xfce_panel_plugin_save_location(clock_plugin->plugin, FALSE);
    if(!filename)
        return FALSE;
    
    rcfile = xfce_rc_simple_open(filename, TRUE);
    if(!rcfile) {
        g_free(filename);
        return FALSE;
    }
    
    default_color = &(GTK_WIDGET(clock_plugin->plugin)->style->text[GTK_STATE_NORMAL]);
    
    xfce_rc_set_group(rcfile, "plugin");
    clock_plugin->show_frame = xfce_rc_read_bool_entry(rcfile, "show_frame",
                                                       TRUE);
    clock_plugin->layout = xfce_rc_read_int_entry(rcfile, "layout",
                                                  CLOCK_LAYOUT_TIME_ONLY);
    if(clock_plugin->layout >= N_CLOCK_LAYOUTS)
        clock_plugin->layout = CLOCK_LAYOUT_TIME_ONLY;
    
    xfce_rc_set_group(rcfile, "date");
    clock_plugin->builtin_date_format = xfce_rc_read_int_entry(rcfile,
                                                               "builtin_format",
                                                               DEFAULT_DATE_FORMAT);
    if(clock_plugin->builtin_date_format >= N_DATE_FORMATS)
        clock_plugin->builtin_date_format = DEFAULT_DATE_FORMAT;
    clock_plugin->use_custom_date_format = xfce_rc_read_bool_entry(rcfile,
                                                                   "use_custom_format",
                                                                   FALSE);
    str = xfce_rc_read_entry(rcfile, "custom_format", NULL);
    if(str)
        clock_plugin->custom_date_format = g_strdup(str);
    clock_plugin->use_custom_date_font = xfce_rc_read_bool_entry(rcfile,
                                                                 "use_custom_font",
                                                                 FALSE);
    str = xfce_rc_read_entry(rcfile, "font", NULL);
    if(str)
        clock_plugin->date_font = pango_font_description_from_string(str);
    clock_plugin->date_color.red = xfce_rc_read_int_entry(rcfile, "color_r",
                                                          default_color->red);
    clock_plugin->date_color.green = xfce_rc_read_int_entry(rcfile, "color_g",
                                                            default_color->green);
    clock_plugin->date_color.blue = xfce_rc_read_int_entry(rcfile, "color_b",
                                                           default_color->blue);
    
    xfce_rc_set_group(rcfile, "time");
    clock_plugin->builtin_time_format = xfce_rc_read_int_entry(rcfile,
                                                               "builtin_format",
                                                               DEFAULT_TIME_FORMAT);
    if(clock_plugin->builtin_time_format >= N_TIME_FORMATS)
        clock_plugin->builtin_time_format = DEFAULT_TIME_FORMAT;
    clock_plugin->use_custom_time_format = xfce_rc_read_bool_entry(rcfile,
                                                                   "use_custom_format",
                                                                   FALSE);
    str = xfce_rc_read_entry(rcfile, "custom_format", NULL);
    if(str)
        clock_plugin->custom_time_format = g_strdup(str);
    clock_plugin->use_custom_time_font = xfce_rc_read_bool_entry(rcfile,
                                                                 "use_custom_font",
                                                                 FALSE);
    str = xfce_rc_read_entry(rcfile, "font", NULL);
    if(str)
        clock_plugin->time_font = pango_font_description_from_string(str);
    clock_plugin->time_color.red = xfce_rc_read_int_entry(rcfile, "color_r",
                                                          default_color->red);
    clock_plugin->time_color.green = xfce_rc_read_int_entry(rcfile, "color_g",
                                                            default_color->green);
    clock_plugin->time_color.blue = xfce_rc_read_int_entry(rcfile, "color_b",
                                                           default_color->blue);
    
    xfce_rc_close(rcfile);
    g_free(filename);
    
    clock_plugin->overall_format = xfclock_get_overall_format(clock_plugin);
    
    return TRUE;
}

static XfceClockPlugin *
xfclock_plugin_new(XfcePanelPlugin *plugin)
{
    XfceClockPlugin *clock_plugin = g_new0(XfceClockPlugin, 1);
    
    clock_plugin->plugin = plugin;
    clock_plugin->tooltip = gtk_tooltips_new();
    
    if(!xfclock_read_config(clock_plugin)) {
        clock_plugin->show_frame = TRUE;
        clock_plugin->layout = CLOCK_LAYOUT_TIME_ONLY;
        clock_plugin->builtin_date_format = DEFAULT_DATE_FORMAT;
        clock_plugin->builtin_time_format = DEFAULT_TIME_FORMAT;
        clock_plugin->overall_format = g_strdup(builtin_time_formats[DEFAULT_TIME_FORMAT]);
    }
    
    clock_plugin->evtbox = gtk_event_box_new();
    gtk_widget_show(clock_plugin->evtbox);
    
    clock_plugin->frame = gtk_frame_new(NULL);
    gtk_container_set_border_width(GTK_CONTAINER(clock_plugin->frame), BORDER/2);
    gtk_frame_set_shadow_type(GTK_FRAME(clock_plugin->frame),
                              clock_plugin->show_frame
                                  ? GTK_SHADOW_IN : GTK_SHADOW_NONE);
    gtk_widget_show(clock_plugin->frame);
    gtk_container_add(GTK_CONTAINER(clock_plugin->evtbox), clock_plugin->frame);
    
    clock_plugin->label = gtk_label_new("");
    gtk_label_set_justify(GTK_LABEL(clock_plugin->label), GTK_JUSTIFY_CENTER);
    gtk_misc_set_alignment(GTK_MISC(clock_plugin->label), 0.5, 0.5);
    gtk_widget_show(clock_plugin->label);
    gtk_container_add(GTK_CONTAINER(clock_plugin->frame), clock_plugin->label);
    
    return clock_plugin;
}

static void
xfclock_config_layout_changed_cb(GtkComboBox *combo,
                                 XfceClockConfig *clock_config)
{
    clock_config->clock_plugin->layout = gtk_combo_box_get_active(combo);
    
    if(clock_config->clock_plugin->layout == CLOCK_LAYOUT_DATE_ONLY) {
        gtk_widget_set_sensitive(clock_config->date_frame, TRUE);
        gtk_widget_set_sensitive(clock_config->time_frame, FALSE);
        if(!clock_config->clock_plugin->use_custom_date_format)
            gtk_widget_set_sensitive(clock_config->date_custom_box, FALSE);
    } else if(clock_config->clock_plugin->layout == CLOCK_LAYOUT_TIME_ONLY) {
        gtk_widget_set_sensitive(clock_config->date_frame, FALSE);
        gtk_widget_set_sensitive(clock_config->time_frame, TRUE);
        if(!clock_config->clock_plugin->use_custom_time_format)
            gtk_widget_set_sensitive(clock_config->time_custom_box, FALSE);
    } else {
        gtk_widget_set_sensitive(clock_config->date_frame, TRUE);
        gtk_widget_set_sensitive(clock_config->time_frame, TRUE);
        if(!clock_config->clock_plugin->use_custom_date_format)
            gtk_widget_set_sensitive(clock_config->date_custom_box, FALSE);
        if(!clock_config->clock_plugin->use_custom_time_format)
            gtk_widget_set_sensitive(clock_config->time_custom_box, FALSE);
    }
    
    xfclock_config_changed(clock_config->clock_plugin);
}

static void
xfclock_config_frame_toggled_cb(GtkToggleButton *tb,
                                XfceClockConfig *clock_config)
{
    clock_config->clock_plugin->show_frame = gtk_toggle_button_get_active(tb);
    gtk_frame_set_shadow_type(GTK_FRAME(clock_config->clock_plugin->frame),
                              clock_config->clock_plugin->show_frame
                                  ? GTK_SHADOW_IN : GTK_SHADOW_NONE);
}

static void
xfclock_config_time_fmt_changed_cb(GtkComboBox *combo,
                                   XfceClockConfig *clock_config)
{
    gint setting = gtk_combo_box_get_active(combo);
    
    if(setting == N_TIME_FORMATS) {
        clock_config->clock_plugin->use_custom_time_format = TRUE;
        gtk_widget_set_sensitive(clock_config->time_custom_box, TRUE);
    } else {
        clock_config->clock_plugin->builtin_time_format = setting;
        clock_config->clock_plugin->use_custom_time_format = FALSE;
        gtk_widget_set_sensitive(clock_config->time_custom_box, FALSE);
    }
    
    xfclock_config_changed(clock_config->clock_plugin);
}

static void
xfclock_config_date_fmt_changed_cb(GtkComboBox *combo,
                                   XfceClockConfig *clock_config)
{
    gint setting = gtk_combo_box_get_active(combo);
    
    if(setting == N_DATE_FORMATS) {
        clock_config->clock_plugin->use_custom_date_format = TRUE;
        gtk_widget_set_sensitive(clock_config->date_custom_box, TRUE);
    } else {
        clock_config->clock_plugin->builtin_date_format = setting;
        clock_config->clock_plugin->use_custom_date_format = FALSE;
        gtk_widget_set_sensitive(clock_config->date_custom_box, FALSE);
    }
    
    xfclock_config_changed(clock_config->clock_plugin);
}

static gboolean
xfclock_config_custom_time_focus_out_cb(GtkWidget *w,
                                        GdkEventFocus *evt,
                                        XfceClockConfig *clock_config)
{
    gchar *str = gtk_editable_get_chars(GTK_EDITABLE(w), 0, -1);
    
    if(str && clock_config->clock_plugin->custom_time_format
                && strcmp(str, clock_config->clock_plugin->custom_time_format))
    {
        /* hasn't changed */
        g_free(str);
        return FALSE;
    }
    
    g_free(clock_config->clock_plugin->custom_time_format);
    clock_config->clock_plugin->custom_time_format = str;
    
    xfclock_config_changed(clock_config->clock_plugin);
    
    return FALSE;
}

static gboolean
xfclock_config_custom_date_focus_out_cb(GtkWidget *w,
                                        GdkEventFocus *evt,
                                        XfceClockConfig *clock_config)
{
    gchar *str = gtk_editable_get_chars(GTK_EDITABLE(w), 0, -1);
    
    if(str && clock_config->clock_plugin->custom_date_format
                && strcmp(str, clock_config->clock_plugin->custom_date_format))
    {
        /* hasn't changed */
        g_free(str);
        return FALSE;
    }
    
    g_free(clock_config->clock_plugin->custom_date_format);
    clock_config->clock_plugin->custom_date_format = str;
    
    xfclock_config_changed(clock_config->clock_plugin);
    
    return FALSE;
}

static void
xfclock_config_custom_time_font_cb(GtkToggleButton *tb,
                                   XfceClockConfig *clock_config)
{
    gboolean setting = gtk_toggle_button_get_active(tb);
    
    clock_config->clock_plugin->use_custom_time_font = setting;
    
    if(setting) {
        gtk_widget_set_sensitive(clock_config->time_fontbtn, TRUE);
        gtk_widget_set_sensitive(clock_config->time_colorbtn, TRUE);
    } else {
        gtk_widget_set_sensitive(clock_config->time_fontbtn, FALSE);
        gtk_widget_set_sensitive(clock_config->time_colorbtn, FALSE);
    }
    
    xfclock_config_changed(clock_config->clock_plugin);
}

static void
xfclock_config_time_font_set_cb(GtkFontButton *btn,
                                XfceClockConfig *clock_config)
{
    const gchar *fontname = gtk_font_button_get_font_name(btn);
    
    if(clock_config->clock_plugin->time_font)
        pango_font_description_free(clock_config->clock_plugin->time_font);
    clock_config->clock_plugin->time_font = pango_font_description_from_string(fontname);
    
    xfclock_config_changed(clock_config->clock_plugin);
}

static void
xfclock_config_time_color_set_cb(GtkColorButton *btn,
                                 XfceClockConfig *clock_config)
{
    GdkColor color;
    
    gtk_color_button_get_color(btn, &color);
    memcpy(&clock_config->clock_plugin->time_color, &color, sizeof(color));
    
    xfclock_config_changed(clock_config->clock_plugin);
}

static void
xfclock_config_custom_date_font_cb(GtkToggleButton *tb,
                                   XfceClockConfig *clock_config)
{
    gboolean setting = gtk_toggle_button_get_active(tb);
    
    clock_config->clock_plugin->use_custom_date_font = setting;
    
    if(setting) {
        gtk_widget_set_sensitive(clock_config->date_fontbtn, TRUE);
        gtk_widget_set_sensitive(clock_config->date_colorbtn, TRUE);
    } else {
        gtk_widget_set_sensitive(clock_config->date_fontbtn, FALSE);
        gtk_widget_set_sensitive(clock_config->date_colorbtn, FALSE);
    }
    
    xfclock_config_changed(clock_config->clock_plugin);
}

static void
xfclock_config_date_font_set_cb(GtkFontButton *btn,
                                XfceClockConfig *clock_config)
{
    const gchar *fontname = gtk_font_button_get_font_name(btn);
    
    if(clock_config->clock_plugin->date_font)
        pango_font_description_free(clock_config->clock_plugin->date_font);
    clock_config->clock_plugin->date_font = pango_font_description_from_string(fontname);
    
    xfclock_config_changed(clock_config->clock_plugin);
}

static void
xfclock_config_date_color_set_cb(GtkColorButton *btn,
                                 XfceClockConfig *clock_config)
{
    GdkColor color;
    
    gtk_color_button_get_color(btn, &color);
    memcpy(&clock_config->clock_plugin->date_color, &color, sizeof(color));
    
    xfclock_config_changed(clock_config->clock_plugin);
}

static void
xfclock_configure_plugin_cb(XfcePanelPlugin *plugin,
                            XfceClockPlugin *clock_plugin)
{
    XfceClockConfig *clock_config = g_new0(XfceClockConfig, 1);
    GtkWidget *header, *frame, *frame_bin, *topvbox, *vbox, *hbox, *lbl, *chk,
              *combo, *entry, *btn, *colorbtn;
    gint i;
    gchar *str;
    PangoFontDescription *font_desc;
    
    clock_config->clock_plugin = clock_plugin;
    
    clock_config->dlg = gtk_dialog_new_with_buttons(_("Clock Properties"),
                                                    GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(plugin))),
                                                    GTK_DIALOG_DESTROY_WITH_PARENT
                                                    | GTK_DIALOG_NO_SEPARATOR,
                                                    GTK_STOCK_CLOSE,
                                                    GTK_RESPONSE_ACCEPT, NULL);
    g_signal_connect(G_OBJECT(clock_config->dlg), "response",
                     G_CALLBACK(gtk_widget_destroy), NULL);
    g_signal_connect_swapped(G_OBJECT(clock_config->dlg), "destroy",
                             G_CALLBACK(g_free), clock_config);
    topvbox = GTK_DIALOG(clock_config->dlg)->vbox;
    
    header = xfce_create_header(NULL, _("Clock"));
    gtk_widget_set_size_request(GTK_BIN(header)->child, 200, 32);
    gtk_container_set_border_width(GTK_CONTAINER(header), BORDER/2);
    gtk_widget_show(header);
    gtk_box_pack_start(GTK_BOX(topvbox), header, FALSE, TRUE, 0);
    
    frame = xfce_create_framebox(_("Appearance"), &frame_bin);
    gtk_widget_show(frame);
    gtk_box_pack_start(GTK_BOX(topvbox), frame, FALSE, FALSE, 0);
    
    vbox = gtk_vbox_new(FALSE, BORDER/2);
    gtk_widget_show(vbox);
    gtk_container_add(GTK_CONTAINER(frame_bin), vbox);
    
    chk = gtk_check_button_new_with_mnemonic(_("Show _Frame"));
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk),
                                 clock_plugin->show_frame);
    gtk_widget_show(chk);
    gtk_box_pack_start(GTK_BOX(vbox), chk, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(chk), "toggled",
                     G_CALLBACK(xfclock_config_frame_toggled_cb), clock_config);
    
    hbox = gtk_hbox_new(FALSE, BORDER/2);
    gtk_widget_show(hbox);
    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
    
    lbl = gtk_label_new(_("Display Layout:"));
    gtk_widget_show(lbl);
    gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
    
    combo = gtk_combo_box_new_text();
    for(i = 0; i < N_CLOCK_LAYOUTS; i++)
        gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _(clock_layout_strs[i]));
    gtk_combo_box_set_active(GTK_COMBO_BOX(combo), clock_plugin->layout);
    gtk_widget_show(combo);
    gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0);
    g_signal_connect(G_OBJECT(combo), "changed",
                     G_CALLBACK(xfclock_config_layout_changed_cb), clock_config);
    
    clock_config->time_frame = frame = xfce_create_framebox(_("Time Format"),
                                                            &frame_bin);
    gtk_widget_show(frame);
    gtk_box_pack_start(GTK_BOX(topvbox), frame, FALSE, FALSE, 0);
    
    vbox = gtk_vbox_new(FALSE, BORDER/2);
    gtk_widget_show(vbox);
    gtk_container_add(GTK_CONTAINER(frame_bin), vbox);
    
    combo = gtk_combo_box_new_text();
    for(i = 0; i < N_TIME_FORMATS; i++) {
        str = xfclock_do_strftime(builtin_time_formats[i]);
        gtk_combo_box_append_text(GTK_COMBO_BOX(combo), str);
        g_free(str);
    }
    gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Custom..."));
    if(clock_plugin->use_custom_time_format)
        gtk_combo_box_set_active(GTK_COMBO_BOX(combo), N_TIME_FORMATS);
    else {
        gtk_combo_box_set_active(GTK_COMBO_BOX(combo),
                                 clock_plugin->builtin_time_format);
    }
    gtk_widget_show(combo);
    gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(combo), "changed",
                     G_CALLBACK(xfclock_config_time_fmt_changed_cb), clock_config);
    
    clock_config->time_custom_box = hbox = gtk_hbox_new(FALSE, BORDER/2);
    gtk_widget_show(hbox);
    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
    
    lbl = gtk_label_new_with_mnemonic(_("Custom _time format:"));
    gtk_widget_show(lbl);
    gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
    
    entry = gtk_entry_new();
    if(clock_plugin->custom_time_format)
        gtk_entry_set_text(GTK_ENTRY(entry), clock_plugin->custom_time_format);
    gtk_widget_show(entry);
    gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
    g_signal_connect(G_OBJECT(entry), "focus-out-event",
                     G_CALLBACK(xfclock_config_custom_time_focus_out_cb),
                     clock_config);
    gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), entry);
    
    if(clock_plugin->layout == CLOCK_LAYOUT_DATE_ONLY)
        gtk_widget_set_sensitive(frame, FALSE);
    else if(!clock_plugin->use_custom_time_format)
        gtk_widget_set_sensitive(hbox, FALSE);
    
    hbox = gtk_hbox_new(FALSE, BORDER/2);
    gtk_widget_show(hbox);
    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
    
    chk = gtk_check_button_new_with_mnemonic(_("_Custom font:"));
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk),
                                 clock_plugin->use_custom_time_font);
    gtk_widget_show(chk);
    gtk_box_pack_start(GTK_BOX(hbox), chk, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(chk), "toggled",
                     G_CALLBACK(xfclock_config_custom_time_font_cb),
                     clock_config);
    
    if(clock_plugin->time_font)
        font_desc = clock_plugin->time_font;
    else
        font_desc = clock_plugin->label->style->font_desc;
    str = pango_font_description_to_string(font_desc);
    
    clock_config->time_fontbtn = btn = gtk_font_button_new_with_font(str);
    if(!clock_plugin->use_custom_time_font)
        gtk_widget_set_sensitive(btn, FALSE);
    gtk_widget_show(btn);
    gtk_box_pack_start(GTK_BOX(hbox), btn, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(btn), "font-set",
                     G_CALLBACK(xfclock_config_time_font_set_cb), clock_config);
    g_free(str);
    
    clock_config->time_colorbtn = colorbtn
            = gtk_color_button_new_with_color(&clock_plugin->time_color);
    if(!clock_plugin->use_custom_time_font)
        gtk_widget_set_sensitive(colorbtn, FALSE);
    gtk_widget_show(colorbtn);
    gtk_box_pack_start(GTK_BOX(hbox), colorbtn, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(colorbtn), "color-set",
                     G_CALLBACK(xfclock_config_time_color_set_cb), clock_config);
    
    clock_config->date_frame = frame = xfce_create_framebox(_("Date Format"),
                                                            &frame_bin);
    gtk_widget_show(frame);
    gtk_box_pack_start(GTK_BOX(topvbox), frame, FALSE, FALSE, 0);
    
    vbox = gtk_vbox_new(FALSE, BORDER/2);
    gtk_widget_show(vbox);
    gtk_container_add(GTK_CONTAINER(frame_bin), vbox);
    
    combo = gtk_combo_box_new_text();
    for(i = 0; i < N_DATE_FORMATS; i++) {
        str = xfclock_do_strftime(builtin_date_formats[i]);
        gtk_combo_box_append_text(GTK_COMBO_BOX(combo), str);
        g_free(str);
    }
    gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Custom..."));
    if(clock_plugin->use_custom_date_format)
        gtk_combo_box_set_active(GTK_COMBO_BOX(combo), N_DATE_FORMATS);
    else {
        gtk_combo_box_set_active(GTK_COMBO_BOX(combo),
                                 clock_plugin->builtin_date_format);
    }
    gtk_widget_show(combo);
    gtk_box_pack_start(GTK_BOX(vbox), combo, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(combo), "changed",
                     G_CALLBACK(xfclock_config_date_fmt_changed_cb), clock_config);
    
    clock_config->date_custom_box = hbox = gtk_hbox_new(FALSE, BORDER/2);
    gtk_widget_show(hbox);
    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
    
    lbl = gtk_label_new_with_mnemonic(_("Custom _date format:"));
    gtk_widget_show(lbl);
    gtk_box_pack_start(GTK_BOX(hbox), lbl, FALSE, FALSE, 0);
    
    entry = gtk_entry_new();
    if(clock_plugin->custom_date_format)
        gtk_entry_set_text(GTK_ENTRY(entry), clock_plugin->custom_date_format);
    gtk_widget_show(entry);
    gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 0);
    g_signal_connect(G_OBJECT(entry), "focus-out-event",
                     G_CALLBACK(xfclock_config_custom_date_focus_out_cb),
                     clock_config);
    gtk_label_set_mnemonic_widget(GTK_LABEL(lbl), entry);
    
    if(clock_plugin->layout == CLOCK_LAYOUT_TIME_ONLY)
        gtk_widget_set_sensitive(frame, FALSE);
    else if(!clock_plugin->use_custom_date_format)
        gtk_widget_set_sensitive(hbox, FALSE);
    
    hbox = gtk_hbox_new(FALSE, BORDER/2);
    gtk_widget_show(hbox);
    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
    
    chk = gtk_check_button_new_with_mnemonic(_("Custom _font:"));
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(chk),
                                 clock_plugin->use_custom_date_font);
    gtk_widget_show(chk);
    gtk_box_pack_start(GTK_BOX(hbox), chk, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(chk), "toggled",
                     G_CALLBACK(xfclock_config_custom_date_font_cb),
                     clock_config);
    
    if(clock_plugin->date_font)
        font_desc = clock_plugin->date_font;
    else
        font_desc = clock_plugin->label->style->font_desc;
    str = pango_font_description_to_string(font_desc);
    
    clock_config->date_fontbtn = btn = gtk_font_button_new_with_font(str);
    if(!clock_plugin->use_custom_date_font)
        gtk_widget_set_sensitive(btn, FALSE);
    gtk_widget_show(btn);
    gtk_box_pack_start(GTK_BOX(hbox), btn, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(btn), "font-set",
                     G_CALLBACK(xfclock_config_date_font_set_cb), clock_config);
    g_free(str);
    
    clock_config->date_colorbtn = colorbtn
            = gtk_color_button_new_with_color(&clock_plugin->date_color);
    if(!clock_plugin->use_custom_date_font)
        gtk_widget_set_sensitive(colorbtn, FALSE);
    gtk_widget_show(colorbtn);
    gtk_box_pack_start(GTK_BOX(hbox), colorbtn, FALSE, FALSE, 0);
    g_signal_connect(G_OBJECT(colorbtn), "color-set",
                     G_CALLBACK(xfclock_config_date_color_set_cb), clock_config);
    
    gtk_widget_show(clock_config->dlg);
}

static void
xfclock_free_data_cb(XfcePanelPlugin *plugin,
                     XfceClockPlugin *clock_plugin)
{
    if(clock_plugin->clock_timeout)
        g_source_remove(clock_plugin->clock_timeout);
    
    gtk_object_sink(GTK_OBJECT(clock_plugin->tooltip));
    
    g_free(clock_plugin->overall_format);
    g_free(clock_plugin->custom_time_format);
    g_free(clock_plugin->custom_date_format);
    if(clock_plugin->time_font)
        pango_font_description_free(clock_plugin->time_font);
    if(clock_plugin->date_font)
        pango_font_description_free(clock_plugin->date_font);
    
    g_free(clock_plugin);
}

static void
xfclock_save_cb(XfcePanelPlugin *plugin,
                XfceClockPlugin *clock_plugin)
{
    XfceRc *rcfile;
    char *filename;
    
    filename = xfce_panel_plugin_save_location(plugin, TRUE);
    if(!filename)
        return;
    
    rcfile = xfce_rc_simple_open(filename, FALSE);
    if(!rcfile) {
        g_free(filename);
        return;
    }
    
    xfce_rc_set_group(rcfile, "plugin");
    xfce_rc_write_bool_entry(rcfile, "show_frame", clock_plugin->show_frame);
    xfce_rc_write_int_entry(rcfile, "layout", clock_plugin->layout);
    
    xfce_rc_set_group(rcfile, "date");
    xfce_rc_write_int_entry(rcfile, "builtin_format",
                            clock_plugin->builtin_date_format);
    xfce_rc_write_bool_entry(rcfile, "use_custom_format",
                             clock_plugin->use_custom_date_format);
    if(clock_plugin->custom_date_format) {
        xfce_rc_write_entry(rcfile, "custom_format",
                            clock_plugin->custom_date_format);
    }
    xfce_rc_write_bool_entry(rcfile, "use_custom_font",
                             clock_plugin->use_custom_date_font);
    if(clock_plugin->date_font) {
        gchar *str = pango_font_description_to_string(clock_plugin->date_font);
        xfce_rc_write_entry(rcfile, "font", str);
        g_free(str);
    }
    xfce_rc_write_int_entry(rcfile, "color_r", clock_plugin->date_color.red);
    xfce_rc_write_int_entry(rcfile, "color_g", clock_plugin->date_color.green);
    xfce_rc_write_int_entry(rcfile, "color_b", clock_plugin->date_color.blue);
    
    xfce_rc_set_group(rcfile, "time");
    xfce_rc_write_int_entry(rcfile, "builtin_format",
                            clock_plugin->builtin_time_format);
    xfce_rc_write_bool_entry(rcfile, "use_custom_format",
                             clock_plugin->use_custom_time_format);
    if(clock_plugin->custom_time_format) {
        xfce_rc_write_entry(rcfile, "custom_format",
                            clock_plugin->custom_time_format);
    }
    xfce_rc_write_bool_entry(rcfile, "use_custom_font",
                             clock_plugin->use_custom_time_font);
    if(clock_plugin->time_font) {
        gchar *str = pango_font_description_to_string(clock_plugin->time_font);
        xfce_rc_write_entry(rcfile, "font", str);
        g_free(str);
    }
    xfce_rc_write_int_entry(rcfile, "color_r", clock_plugin->time_color.red);
    xfce_rc_write_int_entry(rcfile, "color_g", clock_plugin->time_color.green);
    xfce_rc_write_int_entry(rcfile, "color_b", clock_plugin->time_color.blue);
    
    xfce_rc_close(rcfile);
    g_free(filename);
}

static gboolean
xfclock_size_changed_cb(XfcePanelPlugin *plugin,
                        gint size,
                        XfceClockPlugin *clock_plugin)
{
    if(GTK_ORIENTATION_HORIZONTAL == xfce_panel_plugin_get_orientation(plugin)) {
        /* ensure the clock doesn't force the panel larger */
        gtk_widget_set_size_request(clock_plugin->frame, -1, size);
        return TRUE;
    }
    
    return FALSE;
}

static void
xfclock_construct(XfcePanelPlugin *plugin)
{
    XfceClockPlugin *clock_plugin;
    
    xfce_textdomain(GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
    
    clock_plugin = xfclock_plugin_new(plugin);
    gtk_container_add(GTK_CONTAINER(plugin), clock_plugin->evtbox);
    
    xfce_panel_plugin_add_action_widget(plugin, clock_plugin->evtbox);
    xfce_panel_plugin_menu_show_configure(plugin);
    
    g_signal_connect(G_OBJECT(plugin), "configure-plugin",
                     G_CALLBACK(xfclock_configure_plugin_cb), clock_plugin);
    g_signal_connect(G_OBJECT(plugin), "free-data",
                     G_CALLBACK(xfclock_free_data_cb), clock_plugin);
    g_signal_connect(G_OBJECT(plugin), "save",
                     G_CALLBACK(xfclock_save_cb), clock_plugin);
    g_signal_connect(G_OBJECT(plugin), "size-changed",
                     G_CALLBACK(xfclock_size_changed_cb), clock_plugin);
    
    clock_plugin->clock_timeout = g_timeout_add(1000,
                                                (GSourceFunc)xfclock_timeout,
                                                clock_plugin);
    
}

XFCE_PANEL_PLUGIN_REGISTER_INTERNAL(xfclock_construct)
