
/*
 * $Header: /cvs/gnome/gperfmeter/src/props.c,v 1.45 2005/03/10 18:38:17 richb Exp $
 *
 * Copyright (c) 1990-2004 Sun Microsystems, Inc. All Rights Reserved.
 *
 * 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; either version 2, or (at your option)
 * any later version.
 *
 * 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 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.
 *
 */

#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#include <glade/glade.h>
#include <glib/gstrfuncs.h>

#include "callbacks.h"
#include "perfmeter.h"

/* Used in layout */
#define PmMARGIN            5
#define PmSPACE             10
#define PmRC_SPACE          3
#define PmDEFAULT_THICKNESS 0
#define PmNROWS             9
#define PmARROW_SIZE        30
#define PmMAX_CONTROLS      200
#define PmCHIP_SIZE         20
#define PmRANGE_MAX         10000
#define PmTOFFSET           159
#define PmCOLOR_MENU        20
#define PmButtonSize        105
#define PmButtonHeight      30
#define PmHGUTTER           3
#define PmVGUTTER           2
#define PmBUTTONSPACING     17
#define PmCHKSIZE           20
#define PmMAX_ABOUTCONTROLS 20
#define PmKill              1
#define PmClose             2

static char *old_value;

/* IMPORTANT NOTE: need to keep these enum values grouped correctly. */

enum {
   /* Meter indices */
   P_CPU = 0, P_LOAD, P_DISK, P_PAGE, P_CNTX, P_SWAP, P_INTR,
   P_PKTS, P_COLL, P_ERRS,

   /* Meter unit indices */
   P_UCPU, P_ULOAD, P_UDISK, P_UPAGE, P_UCNTX, P_USWAP, P_UINTR,
   P_UPKTS, P_UCOLL, P_UERRS,

   /* Label indicies */
   P_LVIEW, P_LTHRS, P_LUNIT, P_LABOV, P_LBELO, P_LSHOW, P_LHOST, P_LSTYLE, 

   /* New Box Controls */
   P_TVIEW, P_TPREF, P_TCONTROL, P_TABSEP, P_SHOWBOX, 
   P_SAMPLEMOD,
   P_DIR , P_LMULT , P_CHKBOX, P_TIMEBOX, P_LSAMPLE, P_LOGBOX , P_OUTBOX,  
   P_RSHOW, P_NOTE, P_BBOX,

   /* Indices for meter threshold */
   P_CPUTH, P_LOADTH, P_DISKTH, P_PAGETH, P_CNTXTH, P_SWAPTH, P_INTRTH,
   P_PKTSTH, P_COLLTH, P_ERRSTH,

   /* Miscellaneous controls */
   P_VERTICAL, P_HORIZONTAL, P_LINE, P_SOLID, P_LOCAL, P_REMOTE, P_HOSTSCOMBO,
   P_TIME, P_LOG, P_LOGFILE, P_LIVE, P_STRIP, P_BOTH, P_PREFSEP,P_PREFSEP2,
   P_TVIEWBOT,P_TPREFBOT, P_MCTL,


   P_COLLECT, P_HOSTNAME, P_MENUBAR, P_RESIZE, P_STATUS, 
   P_TITLE, P_CURMAX, P_MAXMAX, P_MINMAX, P_LIMIT, P_RANGEINC, P_METERCOLOR, 
   P_CANVASCOLOR, 
   P_LIMITCOLOR,
   P_LABELCOLOR, P_SHOWLIMIT, P_AUTORES, 
   P_SAVERES, P_READRES, P_CLOSE, P_APPLY, P_SAVE,P_RESET, P_CANCEL, P_HELP,

   P_SELVIEW, P_SELPREF, 

   P_CPUBELIMITCOLOR, 
   P_LOADBELIMITCOLOR, 
   P_DISKBELIMITCOLOR, 
   P_PAGEBELIMITCOLOR, 
   P_CNTXBELIMITCOLOR, 
   P_SWAPBELIMITCOLOR, 
   P_INTRBELIMITCOLOR, 
   P_PKTSBELIMITCOLOR, 
   P_COLLBELIMITCOLOR, 
   P_ERRSBELIMITCOLOR, 

   P_CPUABLIMITCOLOR,
   P_LOADABLIMITCOLOR,
   P_DISKABLIMITCOLOR,
   P_PAGEABLIMITCOLOR,
   P_CNTXABLIMITCOLOR, 
   P_SWAPABLIMITCOLOR,
   P_INTRABLIMITCOLOR,
   P_PKTSABLIMITCOLOR,
   P_COLLABLIMITCOLOR,
   P_ERRSABLIMITCOLOR
};

static gboolean CommandKeyEvent(GtkWidget *, GdkEventKey *, gpointer);
static gboolean EntryKeyHandler(GtkWidget *, GdkEventKey *, gpointer);
static gboolean FocusOutHandler(GtkWidget *, GdkEventKey *, gpointer);
static gboolean FocusInHandler(GtkWidget *, GdkEventKey *, gpointer);
static gboolean IsValueChanged();
static gboolean PmColorChk(GdkColor *PMColor, GdkColor *UIPColor);

static void ApplyProps();
static void colorpicker_set_default_colors(GtkColorButton *, GdkColor, gint);
static void CreateProps();
static void InstantApply();
static void PMColorSetCB(GtkColorButton *picker, gpointer user_data);
static void PropsSpinValueChanged(GtkSpinButton *, gpointer);
static void ResetSheet(void);
static void SetSensitive(GtkWidget *, gboolean);
static void SetupColorPickerTooltips();


typedef struct _PmUIMeterProps {
    int CurMax;
    int MaxMax;
    int MinMax;
    int Limit;
    int RangeInc;
    GdkColor MeterColor;
    GdkColor LimitColor;
    gboolean Showing;
} PmUIMeterProps;


typedef struct _PmUIProps {
    GtkWidget *Top;
    GtkWidget *Controls[PmMAX_CONTROLS];
    PmUIMeterProps Meters[PmMAX_METERS];
    int DisplayList[PmMAX_METERS];
    int NMeters;
    PmOrientationType Orientation;
    int WrapCount;
    PmGraphType GraphType;
    gboolean IsRemote;
    char Hostname[MAXHOSTNAMELEN];
    int SampleInterval;
    int LongInterval;
    int ShortInterval;
    int SampleModifier;
    gboolean Log;
    gboolean ShowLimit;
    gboolean ShowHostName;
    gboolean ShowMenubar;
    gboolean ShowStripChart;
    gboolean ShowLiveActionBar;
    gboolean Resizeable;
    gboolean Showing;
    int Busy;
    gboolean CollectWhenIconized;
    gboolean AutoLoadByHost;
    gboolean SaveByHost;
    gboolean LoadByHost;
    gboolean ColorMenuAllocated;
    GdkColor LabelColor;
    GdkColor CanvasColor;
} PmUIProps;
  
static PmUIProps *UIP = NULL;

static GladeXML *xml;


static GtkWidget *
SetPropsData(gchar *name, int data)
{
    GtkWidget *w = glade_xml_get_widget (xml, name);

    g_object_set_data(G_OBJECT (w), "PropsData", (gpointer) data);
    return(w);
}


static void
SetPickerColor(int ci, int mi, gboolean is_meter)
{
    if (is_meter) {
        colorpicker_set_default_colors(GTK_COLOR_BUTTON(UIP->Controls[ci]), 
                                       PM->Meters[mi].MeterColor, mi);
    } else {
        colorpicker_set_default_colors(GTK_COLOR_BUTTON(UIP->Controls[ci]), 
                                       PM->Meters[mi].LimitColor, mi);
    }
}


static void
SetPropsToggle(int ci, gboolean state)
{
    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(UIP->Controls[ci]), state);
}


/* Callback to handle items selected from the samples option menu. */

/*ARGSUSED*/
static void
SampleMenuCB(GtkComboBox *combo_box, gpointer user_data)
{
    int value = gtk_combo_box_get_active(combo_box);

    if (value == 0) {
        UIP->SampleModifier = 1;
    } else if (value == 1) {
        UIP->SampleModifier = 60;
    } else if (value == 2) {
        UIP->SampleModifier = 3600;
    }

    InstantApply();
}


static void
SetupColorPickerTooltips()
{
    GtkTooltips *tooltips;

    tooltips = gtk_tooltips_new ();
    g_return_if_fail(tooltips != NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "CPU_BelowColor"), 
       _("Pick a color to indicate below threshold CPU activity"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "CPU_AboveColor"), 
       _("Pick a color to indicate above threshold CPU activity"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Load_BelowColor"),
       _("Pick a color to indicate below threshold load activity"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Load_AboveColor"),
       _("Pick a color to indicate above threshold load activity"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Disk_BelowColor"),
       _("Pick a color to indicate below threshold disk usage"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Disk_AboveColor"),
       _("Pick a color to indicate above threshold disk usage"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Page_BelowColor"),
       _("Pick a color to indicate below threshold paging rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Page_AboveColor"),
       _("Pick a color to indicate above threshold paging rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Context_BelowColor"),
       _("Pick a color to indicate below threshold context switching rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Context_AboveColor"),
       _("Pick a color to indicate above threshold context switching rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Swap_BelowColor"),
       _("Pick a color to indicate below threshold swapping rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Swap_AboveColor"),
       _("Pick a color to indicate above threshold swapping rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Interrupts_BelowColor"),
       _("Pick a color to indicate below threshold interrupts rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Interrupts_AboveColor"),
       _("Pick a color to indicate above threshold interrupts rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Packets_BelowColor"),
       _("Pick a color to indicate below threshold packet traffic"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Packets_AboveColor"), 
       _("Pick a color to indicate above threshold packets traffic"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Collisions_BelowColor"),
       _("Pick a color to indicate below threshold collision rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Collisions_AboveColor"),
       _("Pick a color to indicate above threshold collision rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Errors_BelowColor"),
       _("Pick a color to indicate below threshold error rate"), NULL);

    gtk_tooltips_set_tip(tooltips, glade_xml_get_widget(xml, "Errors_AboveColor"),
       _("Pick a color to indicate above threshold error rate"), NULL);
}


static void
set_remote_host_list(GtkWidget *combo_box, GList *list)
{
    gint i, len;
    gchar *str;

    if (list != NULL) {
        len = g_list_length(list);

        for (i = 0; i < len; i++) {
            str = g_strdup((gchar *) g_list_nth_data(list, i));

            gtk_combo_box_append_text(GTK_COMBO_BOX(combo_box),  str);
        }
    }
}


/*ARGSUSED*/
static gboolean
CommandKeyEvent(GtkWidget *widget, GdkEventKey *event, gpointer data)
{
    guint key = event->keyval;

    if (key == GDK_Escape) {
        gtk_widget_activate(UIP->Controls[P_CLOSE]);
        return(TRUE);
    } else {
        return(FALSE);
    }
}


/* Create property dialog. Ie. do all the things that Glade can't.*/

static void 
CreateProps()
{
    int i;

    UIP = (PmUIProps *) g_malloc0(sizeof(PmUIProps));
    
    /* Loads the preferences dialog from the Glade file */
    xml = glade_xml_new(GPERF_GLADEDIR "/gperfmeter.glade", NULL, NULL);
    if (!xml) {
        g_message("CreateProps(): Could not load the Glade XML file");
        exit(1);
    }
    glade_xml_signal_autoconnect(xml);

    UIP->Top = glade_xml_get_widget(xml, "PropsWindow");

    g_signal_connect(G_OBJECT(UIP->Top), "key_press_event", 
                     GTK_SIGNAL_FUNC(CommandKeyEvent), NULL);

    UIP->Controls[P_CPU]  = SetPropsData("CPU_CheckB",        P_CPU);
    UIP->Controls[P_LOAD] = SetPropsData("Load_CheckB",       P_LOAD);
    UIP->Controls[P_DISK] = SetPropsData("Disk_CheckB",       P_DISK);
    UIP->Controls[P_PAGE] = SetPropsData("Page_CheckB",       P_PAGE);
    UIP->Controls[P_CNTX] = SetPropsData("Context_CheckB",    P_CNTX);
    UIP->Controls[P_SWAP] = SetPropsData("Swap_CheckB",       P_SWAP);
    UIP->Controls[P_INTR] = SetPropsData("Interrupts_CheckB", P_INTR);
    UIP->Controls[P_PKTS] = SetPropsData("Packets_CheckB",    P_PKTS);
    UIP->Controls[P_COLL] = SetPropsData("Collisions_CheckB", P_COLL);
    UIP->Controls[P_ERRS] = SetPropsData("Errors_CheckB",     P_ERRS);

    UIP->Controls[P_HOSTSCOMBO] = glade_xml_get_widget(xml, "Hosts_Combo");
    set_remote_host_list(UIP->Controls[P_HOSTSCOMBO], remote_hosts);

    SetSensitive(UIP->Controls[P_HOSTSCOMBO], PM->IsRemote);

    g_signal_connect(
        G_OBJECT(GTK_ENTRY(GTK_BIN(UIP->Controls[P_HOSTSCOMBO])->child)),
        "key_press_event", GTK_SIGNAL_FUNC(EntryKeyHandler), NULL);

    UIP->Controls[P_LOG]       = glade_xml_get_widget(xml, "LogSamples");
    UIP->Controls[P_LOGFILE]   = glade_xml_get_widget(xml, "LogFile_Entry");
    SetSensitive(UIP->Controls[P_LOGFILE], FALSE);

    UIP->Controls[P_CPUBELIMITCOLOR] = SetPropsData("CPU_BelowColor", 
                                                    P_CPUBELIMITCOLOR);
    UIP->Controls[P_CPUABLIMITCOLOR] = SetPropsData("CPU_AboveColor", 
                                                    P_CPUABLIMITCOLOR);
    UIP->Controls[P_LOADBELIMITCOLOR] = SetPropsData("Load_BelowColor", 
                                                     P_LOADBELIMITCOLOR);
    UIP->Controls[P_LOADABLIMITCOLOR] = SetPropsData("Load_AboveColor",
                                                     P_LOADABLIMITCOLOR);
    UIP->Controls[P_DISKBELIMITCOLOR] = SetPropsData("Disk_BelowColor",
                                                     P_DISKBELIMITCOLOR);
    UIP->Controls[P_DISKABLIMITCOLOR] = SetPropsData("Disk_AboveColor",
                                                     P_DISKABLIMITCOLOR);
    UIP->Controls[P_PAGEBELIMITCOLOR] = SetPropsData("Page_BelowColor",
                                                     P_PAGEBELIMITCOLOR);
    UIP->Controls[P_PAGEABLIMITCOLOR] = SetPropsData("Page_AboveColor",
                                                     P_PAGEABLIMITCOLOR);
    UIP->Controls[P_CNTXBELIMITCOLOR] = SetPropsData("Context_BelowColor",
                                                     P_CNTXBELIMITCOLOR);
    UIP->Controls[P_CNTXABLIMITCOLOR] = SetPropsData("Context_AboveColor",
                                                     P_CNTXABLIMITCOLOR);
    UIP->Controls[P_SWAPBELIMITCOLOR] = SetPropsData("Swap_BelowColor",
                                                     P_SWAPBELIMITCOLOR);
    UIP->Controls[P_SWAPABLIMITCOLOR] = SetPropsData("Swap_AboveColor",
                                                     P_SWAPABLIMITCOLOR);
    UIP->Controls[P_INTRBELIMITCOLOR] = SetPropsData("Interrupts_BelowColor",
                                                     P_INTRBELIMITCOLOR);
    UIP->Controls[P_INTRABLIMITCOLOR] = SetPropsData("Interrupts_AboveColor",
                                                     P_INTRABLIMITCOLOR);
    UIP->Controls[P_PKTSBELIMITCOLOR] = SetPropsData("Packets_BelowColor",
                                                     P_PKTSBELIMITCOLOR);
    UIP->Controls[P_PKTSABLIMITCOLOR] = SetPropsData("Packets_AboveColor",
                                                     P_PKTSABLIMITCOLOR);
    UIP->Controls[P_COLLBELIMITCOLOR] = SetPropsData("Collisions_BelowColor",
                                                     P_COLLBELIMITCOLOR);
    UIP->Controls[P_COLLABLIMITCOLOR] = SetPropsData("Collisions_AboveColor",
                                                     P_COLLABLIMITCOLOR);
    UIP->Controls[P_ERRSBELIMITCOLOR] = SetPropsData("Errors_BelowColor",
                                                     P_ERRSBELIMITCOLOR);
    UIP->Controls[P_ERRSABLIMITCOLOR] = SetPropsData("Errors_AboveColor",
                                                     P_ERRSABLIMITCOLOR);

    SetupColorPickerTooltips();

    for (i = 0; i < PmMAX_METERS; i++) {
        SetPickerColor(P_CPUBELIMITCOLOR+i, PM_CPU+i, TRUE);
        SetPickerColor(P_CPUABLIMITCOLOR+i, PM_CPU+i, FALSE);
    }

    UIP->Controls[P_CLOSE]  = SetPropsData("OKButton",     P_CLOSE);
    UIP->Controls[P_HELP]   = SetPropsData("HelpButton",   P_HELP);

    UIP->Controls[P_CPUTH]  = SetPropsData("CPU_Entry",        P_CPU);
    UIP->Controls[P_LOADTH] = SetPropsData("Load_Entry",       P_LOAD);
    UIP->Controls[P_DISKTH] = SetPropsData("Disk_Entry",       P_DISK);
    UIP->Controls[P_PAGETH] = SetPropsData("Page_Entry",       P_PAGE);
    UIP->Controls[P_CNTXTH] = SetPropsData("Context_Entry",    P_CNTX);
    UIP->Controls[P_SWAPTH] = SetPropsData("Swap_Entry",       P_SWAP);
    UIP->Controls[P_INTRTH] = SetPropsData("Interrupts_Entry", P_INTR);
    UIP->Controls[P_PKTSTH] = SetPropsData("Packets_Entry",    P_PKTS);
    UIP->Controls[P_COLLTH] = SetPropsData("Collisions_Entry", P_COLL);
    UIP->Controls[P_ERRSTH] = SetPropsData("Errors_Entry",     P_ERRS);

    for (i = P_CPUTH; i <= P_ERRSTH; i++) {
        g_signal_connect(G_OBJECT(UIP->Controls[i]), "key_press_event",
                         GTK_SIGNAL_FUNC(EntryKeyHandler), NULL);
        g_signal_connect(G_OBJECT(UIP->Controls[i]), "focus_out_event",
                         GTK_SIGNAL_FUNC(FocusOutHandler), NULL);
        g_signal_connect(G_OBJECT(UIP->Controls[i]), "focus_in_event",
                         GTK_SIGNAL_FUNC(FocusInHandler), NULL);
    }

    UIP->Controls[P_SAMPLEMOD]  = SetPropsData("SampleMod", P_SAMPLEMOD);
    gtk_combo_box_set_active(GTK_COMBO_BOX(UIP->Controls[P_SAMPLEMOD]), 1);
    g_signal_connect(G_OBJECT(UIP->Controls[P_SAMPLEMOD]), "changed",
                     G_CALLBACK(SampleMenuCB), NULL);
    UIP->SampleModifier = 1;

    UIP->Controls[P_HORIZONTAL] = SetPropsData("HorizontalRB",  P_HORIZONTAL);
    UIP->Controls[P_VERTICAL]   = SetPropsData("VerticalRB",    P_VERTICAL);
    UIP->Controls[P_LINE]       = SetPropsData("LineRB",        P_LINE);
    UIP->Controls[P_SOLID]      = SetPropsData("SolidRB",       P_SOLID);
    UIP->Controls[P_STRIP]      = SetPropsData("StripChartRB",  P_STRIP);
    UIP->Controls[P_LIVE]       = SetPropsData("BarChartRB",    P_LIVE);
    UIP->Controls[P_BOTH]       = SetPropsData("BothRB",        P_BOTH);
    UIP->Controls[P_LOCAL]      = SetPropsData("LocalRB",       P_LOCAL);
    UIP->Controls[P_REMOTE]     = SetPropsData("RemoteRB",      P_REMOTE);
    UIP->Controls[P_LOG]        = SetPropsData("LogSamples",    P_LOG);
    UIP->Controls[P_HOSTNAME]   = SetPropsData("ShowHostName",  P_HOSTNAME);
    UIP->Controls[P_MENUBAR]    = SetPropsData("HideMenuBar",   P_MENUBAR);
    UIP->Controls[P_SHOWLIMIT]  = SetPropsData("ShowLimit",     P_SHOWLIMIT);
    UIP->Controls[P_TIME]       = SetPropsData("TimeSB",        P_TIME);
    UIP->Controls[P_LOGFILE]    = SetPropsData("LogFile_Entry", P_LOGFILE);

    g_signal_connect(G_OBJECT(UIP->Controls[P_TIME]), "value_changed",
                     G_CALLBACK(PropsSpinValueChanged), NULL);

    g_signal_connect(G_OBJECT(UIP->Controls[P_LOGFILE]), "key_press_event",
                     GTK_SIGNAL_FUNC(EntryKeyHandler), NULL);

    gtk_window_set_position(GTK_WINDOW(UIP->Top), GTK_WIN_POS_CENTER);
    gtk_widget_show_all(UIP->Top);
}


/*ARGSUSED*/
static gboolean
FocusOutHandler(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
    char *s = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));

    if (old_value && s) {
        if (strcmp (old_value, s) != 0) {
            InstantApply();
        }
    }

    g_free(old_value);
    g_free(s);

    return(FALSE);
}


/*ARGSUSED*/
static gboolean
FocusInHandler(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
    old_value = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));

    return(FALSE);
}


static gboolean
IsValueChanged()
{
    /* Check if any value in the toggle group is changed */

    if ((UIP->Orientation       != PM->Orientation) ||
        (UIP->GraphType         != PM->GraphType) ||
        (UIP->ShowLiveActionBar != PM->ShowLiveActionBar) ||
        (UIP->ShowStripChart    != PM->ShowStripChart) ||
        (UIP->Log               != PM->Log) ||
        (UIP->ShowLimit         != PM->ShowLimit) ||
        (UIP->ShowHostName      != PM->ShowHostName) || 
        (UIP->ShowMenubar       != PM->ShowMenubar) || 
        (UIP->IsRemote          != PM->IsRemote)) {
        return(TRUE);
    }

    return(FALSE);
}


/*ARGSUSED*/
void
PropsToggleCB(GtkToggleButton *tb, gpointer user_data)
{
    gboolean flag = FALSE;
    int ptype = (int) g_object_get_data(G_OBJECT(tb), "PropsData");
    int set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb));

    switch (ptype) {
        case P_HORIZONTAL:
            if (set) {
                ToggleDirection(PM_HORIZONTAL);
                UIP->Orientation = PM_HORIZONTAL;
            }
            break;

        case P_VERTICAL:
            if (set) {
                ToggleDirection(PM_VERTICAL);
                UIP->Orientation = PM_VERTICAL;
            }
            break;

        case P_LINE:
            if (set) {
                UIP->GraphType = PM_LINE;
            }
            break;

        case P_SOLID:
            if (set) {
                UIP->GraphType = PM_SOLID;
            }
            break;

        case P_STRIP:
            if (set) {
                UIP->ShowLiveActionBar = FALSE;
                UIP->ShowStripChart = TRUE;
            }  
            break;

        case P_LIVE:
            if (set) {
                UIP->ShowLiveActionBar = TRUE;
                UIP->ShowStripChart = FALSE;
            }  
            break;

        case P_BOTH:
            if (set) {
                UIP->ShowLiveActionBar = TRUE;
                UIP->ShowStripChart = TRUE;
            }  
            break;

        case P_LOCAL:
            if (set) {
                UIP->IsRemote = FALSE;
            }
            SetSensitive(UIP->Controls[P_HOSTSCOMBO], UIP->IsRemote);
            break;

        case P_REMOTE:
            if (set) {
                UIP->IsRemote = TRUE;
            }
            SetSensitive(UIP->Controls[P_HOSTSCOMBO], UIP->IsRemote);
            break;

        case P_LOG:
            UIP->Log = set;
            SetSensitive(UIP->Controls[P_LOGFILE], set);
            break;

        case P_HOSTNAME:
            UIP->ShowHostName = set;
            break;

        case P_MENUBAR:
            UIP->ShowMenubar = !set;
            break;

        case P_SHOWLIMIT:
            UIP->ShowLimit = set;
            break;
    }

    flag = IsValueChanged();   
    if (flag && ptype != P_REMOTE) {
        InstantApply();
    }
}


/* Show the specified meters. */

/*ARGSUSED*/
void
PropsMeterCB(GtkToggleButton *tb, gpointer user_data)
{
    int i, j;

    int meter = (int) g_object_get_data(G_OBJECT(tb), "PropsData");
    int set = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(tb));

    if (set) {
        /* Add to the display list */
        for (i = 0; i < PmMAX_METERS; i++) {
            if (UIP->DisplayList[i] == meter) {   /* Already set? */
                break;
            }
            if (UIP->DisplayList[i] < 0) {        /* First empty slot? */
                UIP->DisplayList[i] = meter;
                UIP->NMeters++;
                InstantApply();
                break;
            }

            SetSensitive(UIP->Controls[P_CPUTH+meter], TRUE);
            SetSensitive(UIP->Controls[P_CPUBELIMITCOLOR+meter], TRUE);
            SetSensitive(UIP->Controls[P_CPUABLIMITCOLOR+meter], TRUE);
        }    
    } else {
        /* Remove from the display list */
        for (i = 0; i < PmMAX_METERS; i++) {
            if (UIP->DisplayList[i] == meter) {
                SetSensitive(UIP->Controls[P_CPUTH+meter], FALSE);
                SetSensitive(UIP->Controls[P_CPUBELIMITCOLOR+meter], FALSE);
                SetSensitive(UIP->Controls[P_CPUABLIMITCOLOR+meter], FALSE);
                /* Move the rest to the left */
                for (j = i + 1; j < PmMAX_METERS; j++, i++) {
                    UIP->DisplayList[i] = UIP->DisplayList[j];
                }
                UIP->NMeters--;
                for (i = UIP->NMeters; i < PmMAX_METERS; i++) {
                    UIP->DisplayList[i] = -1;
                }
                break;
            }
        }
        InstantApply();
    }

    if (UIP->NMeters == 0) {
        /* Turn back on the first meter */
        SetPropsToggle(P_CPU, TRUE);
        SetSensitive(UIP->Controls[P_CPUTH], TRUE);
        SetSensitive(UIP->Controls[P_CPUBELIMITCOLOR], TRUE);
        SetSensitive(UIP->Controls[P_CPUABLIMITCOLOR], TRUE);
        UIP->NMeters = 1;
        UIP->DisplayList[0] = 0;
        for (i = UIP->NMeters; i < PmMAX_METERS; i++) {
            UIP->DisplayList[i] = -1;
        }
        InstantApply();
    }

#ifdef DEBUG
    g_print("Display List = %d %d %d %d %d %d %d %d %d %d\n",
            UIP->DisplayList[0], UIP->DisplayList[1], UIP->DisplayList[2],
            UIP->DisplayList[3], UIP->DisplayList[4], UIP->DisplayList[5],
            UIP->DisplayList[6], UIP->DisplayList[7], UIP->DisplayList[8],
            UIP->DisplayList[9]);
#endif
}


/* Limit spin boxes. */

/*ARGSUSED*/
void
PropsTextAdd(GtkEditable *editable, gchar *text,
             gint length, gint *position, gpointer user_data)
{
    gint i;

    for (i = 0; i < length; i++) {
        if (!isdigit((int) text[i])) {
            g_signal_stop_emission_by_name(G_OBJECT(editable), "insert_text");
            gdk_beep();
            return;
        }
    }
}


/*ARGSUSED*/
void
PropsLimitCB(GtkEditable *widget, gpointer user_data)
{
    long value = 0;
    char *s;
    int limit;
    int code = (int) g_object_get_data(G_OBJECT(widget), "PropsData");
    gchar *buf;

    if ((s = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget))))) {
        value = strtol(s, NULL, 10);
    } else {
        value = 0;
    }
    g_free(s);

    if (value > PmMAX_VALUE) {
        GtkWidget *dialog;

        dialog = gtk_message_dialog_new (NULL,
                     GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                     GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, 
                     "The threshold value exceeded the maximum limit(%ld)",
                     PmMAX_VALUE);
        g_signal_connect_swapped(GTK_OBJECT(dialog), "response", 
                                 G_CALLBACK(gtk_widget_destroy), 
                                 GTK_OBJECT(dialog));
        gtk_widget_show_all(dialog);

        value = UIP->Meters[code].Limit;
        buf = g_strdup_printf("%ld", value);
        gtk_entry_set_text(GTK_ENTRY(widget), buf);
	g_free(buf);
    } else if (value < 0) {
        value = 0;
        buf = g_strdup_printf(buf, "%ld", value);
        gtk_entry_set_text(GTK_ENTRY(widget), buf);
	g_free(buf);
    }

    limit = (int) value;

#ifdef DEBUG
    g_print("Limit %d Value = %d\n", code, limit);
#endif

    UIP->Meters[code].Limit = (int) PmMax(limit, 0);
}


/*ARGSUSED*/
static void 
PropsSpinValueChanged(GtkSpinButton *widget, gpointer data)
{
    gint limit;
    gchar *buf;

    limit = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));

    if (limit > PmMAX_SAMPLETIME) {
        limit = PmMAX_SAMPLETIME;
        buf = g_strdup_printf("%d", limit);
        gtk_spin_button_set_value(GTK_SPIN_BUTTON(UIP->Controls[P_TIME]),
                                  (gfloat) limit);
	g_free(buf);
    }

    UIP->SampleInterval = limit;
    InstantApply();
}


/* Show the property dialog. */

void 
PmShowProps()
{
    /* Create the popup if the first time */
    if (!UIP || UIP->Top == NULL) {
        PmBusy(TRUE);
        CreateProps();
        UIP->Showing = TRUE;
        PmResetProps();
        PmBusy(FALSE);
        gtk_widget_show(UIP->Top);
    } else if (UIP->Showing) {
        gdk_window_raise(UIP->Top->window);
        return;
    } else {
        /* Display the popup */
        UIP->Showing = TRUE;
        PmResetProps();
        gtk_widget_show(UIP->Top);
    }
}


/* Hide the property dialog */

gboolean 
PmHideProps()
{
    gboolean currentState;

    if (UIP) {
        gtk_widget_hide(UIP->Top);
        currentState = UIP->Showing;
        UIP->Showing = FALSE;

        return(currentState);
    }

    return(FALSE);
}


/* Reset the property dialog */

void 
PmResetProps()
{
    gchar *str = NULL;
    gint i;

    if (!UIP || !UIP->Showing) {
        return;
    }

    /* Initialize the property data structures */

    PmPropsSetDisplayList();

    UIP->Orientation = PM->Orientation;
    UIP->GraphType = PM->GraphType;

    UIP->IsRemote = PM->IsRemote;
    PmStrcpy(UIP->Hostname, PM->Hostname);
 
    UIP->SampleInterval      = PM->SampleInterval;
    UIP->Log                 = PM->Log;
    UIP->ShowLimit           = PM->ShowLimit;
    UIP->ShowHostName        = PM->ShowHostName;
    UIP->ShowMenubar         = PM->ShowMenubar;
    UIP->ShowStripChart      = PM->ShowStripChart; /* S C */
    UIP->ShowLiveActionBar   = PM->ShowLiveActionBar;
    UIP->Resizeable          = PM->Resizeable;
    UIP->CollectWhenIconized = PM->CollectWhenIconized;
    UIP->CanvasColor         = PM->CanvasColor;
    UIP->LabelColor          = PM->LabelColor;
    UIP->AutoLoadByHost      = PM->AutoLoadByHost;
    UIP->SaveByHost          = PM->SaveByHost;
    UIP->LoadByHost          = PM->LoadByHost;
 
    for (i = 0; i < PmMAX_METERS; i++) {
        UIP->Meters[i].CurMax   = PM->Meters[i].CurMax;
        UIP->Meters[i].MaxMax   = PM->Meters[i].MaxMax;
        UIP->Meters[i].MinMax   = PM->Meters[i].MinMax;
        UIP->Meters[i].Limit    = PM->Meters[i].Limit;
        UIP->Meters[i].RangeInc = PM->Meters[i].RangeInc;

        UIP->Meters[i].MeterColor = PM->Meters[i].MeterColor;
        UIP->Meters[i].LimitColor = PM->Meters[i].LimitColor;
    }

    /* Update the UI */

    if (PM->ShowStripChart) {
        if (PM->ShowLiveActionBar) {
            SetPropsToggle(P_BOTH, TRUE);
        } else {
            SetPropsToggle(P_STRIP, TRUE);
        }
    } else {
        SetPropsToggle(P_LIVE, TRUE);
    }

    if (UIP->Orientation == PM_HORIZONTAL) {
        SetPropsToggle(P_HORIZONTAL, TRUE);
    } else {
        SetPropsToggle(P_VERTICAL, TRUE);
    }

    if (UIP->GraphType == PM_LINE) {
        SetPropsToggle(P_LINE, TRUE);
    } else {
        SetPropsToggle(P_SOLID, TRUE);
    }

    if (UIP->IsRemote) {
        SetPropsToggle(P_REMOTE, TRUE);
    } else {
        SetPropsToggle(P_LOCAL, TRUE);
    }

    str = g_strdup_printf("%d", UIP->SampleInterval);
    gtk_entry_set_text(GTK_ENTRY(UIP->Controls[P_TIME]), str);
    g_free(str);

    SetPropsToggle(P_HOSTNAME, UIP->ShowHostName);
    SetPropsToggle(P_MENUBAR, !UIP->ShowMenubar);
    SetPropsToggle(P_LOG, UIP->Log);
    SetPropsToggle(P_SHOWLIMIT, UIP->ShowLimit);
    gtk_entry_set_text(GTK_ENTRY(UIP->Controls[P_LOGFILE]), PM->LogFilename);

    /* Set the selected sample modifier UI */
    if (PM->SampleModifier == 1) {
        gtk_combo_box_set_active(GTK_COMBO_BOX(UIP->Controls[P_SAMPLEMOD]), 0);
    }
    if (PM->SampleModifier == 60) {
        gtk_combo_box_set_active(GTK_COMBO_BOX(UIP->Controls[P_SAMPLEMOD]), 1);
    }
    if (PM->SampleModifier == 3600) {
        gtk_combo_box_set_active(GTK_COMBO_BOX(UIP->Controls[P_SAMPLEMOD]), 2);
    }

    ResetSheet();
}


/* Set the property display list. */

void 
PmPropsSetDisplayList()
{
    if (UIP && UIP->Showing) {
        int i;

        MEMCPY(UIP->DisplayList, PM->DisplayList, PmMAX_METERS * sizeof(int));
        UIP->NMeters = PM->NMeters;

        for (i = 0; i < PmMAX_METERS; i++) {
            UIP->Meters[i].Showing = PM->Meters[i].Showing;

            SetPropsToggle(i, UIP->Meters[i].Showing);

            SetSensitive(UIP->Controls[P_CPUTH+i], UIP->Meters[i].Showing);
            SetSensitive(UIP->Controls[P_CPUBELIMITCOLOR+i],
                         UIP->Meters[i].Showing);
            SetSensitive(UIP->Controls[P_CPUABLIMITCOLOR+i],
                         UIP->Meters[i].Showing);
        }
    }
}


/* Reset the property dialog menubar toggle. */

void 
PmResetPropsDecor()
{
    if (UIP && UIP->Showing) {
        UIP->ShowMenubar = PM->ShowMenubar;
        SetPropsToggle(P_MENUBAR, !UIP->ShowMenubar);
        UIP->ShowStripChart = PM->ShowStripChart;
    }
}


/* Reset the meter current maximum. */

void 
PmResetCurMax(int meter)
{
    if (UIP && UIP->Showing) {
        UIP->Meters[meter].CurMax = PM->Meters[meter].CurMax;
    }
}


static void
SetLimit(int ci, int mi)
{
    gchar *buf;

    buf = g_strdup_printf("%d", UIP->Meters[mi].Limit);
    gtk_entry_set_text(GTK_ENTRY(UIP->Controls[ci]), buf);
    g_free(buf);

#ifdef DEBUG
    g_print("\tLimit = %d\n", UIP->Meters[mi].Limit);
#endif
}


/* Reset the meter properties. */

static void 
ResetSheet()
{
#ifdef DEBUG
    g_print("Reset Meters\n");
#endif

    SetLimit(P_CPUTH, P_CPU);
    SetLimit(P_PKTSTH, P_PKTS);
    SetLimit(P_PAGETH, P_PAGE);
    SetLimit(P_SWAPTH, P_SWAP);
    SetLimit(P_INTRTH, P_INTR);
    SetLimit(P_DISKTH, P_DISK);
    SetLimit(P_CNTXTH, P_CNTX);
    SetLimit(P_LOADTH, P_LOAD);
    SetLimit(P_COLLTH, P_COLL);
    SetLimit(P_ERRSTH, P_ERRS);
}


/* Apply the properties. */

static void 
ApplyProps()
{
    gboolean redisplay   = FALSE;
    gboolean reset       = FALSE;
    gboolean refresh     = FALSE;
    gboolean change_host = FALSE;
    gboolean redraw, tmpRedraw;
    int i;
    char *s;

    PmLock();

    /* Transfer the data to the PM structure and redisplay the meters */

    /* Reset the display list */
    refresh = redisplay = PmSetDisplayList(UIP->DisplayList);

    tmpRedraw = PmAssign(PM->ShowLimit, UIP->ShowLimit);

    for (i = 0; i < PmMAX_METERS; i++) {
        redraw = FALSE;
        redraw |= PmColorChk(&PM->Meters[i].MeterColor, 
                             &UIP->Meters[i].MeterColor);
        redraw |= PmColorChk(&PM->Meters[i].LimitColor, 
                             &UIP->Meters[i].LimitColor);
        if (redraw) {
            PmSetMeterColor(i);
        }

        redraw |= PmAssign(PM->Meters[i].Limit, UIP->Meters[i].Limit);
        redraw |= tmpRedraw;
        PM->Meters[i].Redisplay = redraw;
        redisplay |= redraw;
    }

    PM->ShowStripChart = UIP->ShowStripChart;
    PM->ShowLiveActionBar = UIP->ShowLiveActionBar;

    if (PmColorChk(&PM->CanvasColor, &UIP->CanvasColor)) {
        PMCOLORCHK(&PM->LabelColor, &UIP->LabelColor);

        PmSetColors();

        for (i = 0; i < PmMAX_METERS; i++) {
            PmSetMeterColor(i);
        }

        refresh = redisplay = TRUE;
    } else if (PmColorChk(&PM->LabelColor, &UIP->LabelColor)) { 
        gdk_gc_set_foreground(UI->LabelGC, &PM->LabelColor); 
        redisplay = TRUE;
    }

    (void) PmAssign(PM->SampleInterval, UIP->SampleInterval);

    PmSetScaleFactors();

    (void) PmAssign(PM->Resizeable, UIP->Resizeable);
    (void) PmAssign(PM->CollectWhenIconized, UIP->CollectWhenIconized);

    /* Sample log file */
    PM->Log = UIP->Log;
    PM->SampleModifier = UIP->SampleModifier;
    s = g_strdup(gtk_entry_get_text(GTK_ENTRY(UIP->Controls[P_LOGFILE])));
    PM->LogFilename = expand_tilde(s);
    g_free(s);

    if (PM->Log) {
        if ((PM->Log = PmLogOpen())) {
            gtk_entry_set_text(GTK_ENTRY(UIP->Controls[P_LOGFILE]), 
                               PM->LogFilename);
        } else {                              /* Couldn't open log file */
            gchar *buf;

            buf = g_strdup_printf("Can't open %s", PM->LogFilename);
            gtk_entry_set_text(GTK_ENTRY(UIP->Controls[P_LOGFILE]), buf);
            g_free(buf);

            gdk_flush();
            SLEEP(2);
            gtk_entry_set_text(GTK_ENTRY(UIP->Controls[P_LOGFILE]), 
                               PM->LogFilename);
            UIP->Log = PM->Log;
            SetPropsToggle(P_LOG, UIP->Log);
        }
    } else {
        PmLogClose();
    }
    PM->ShowLimit = UIP->ShowLimit;

    if (PmAssign(PM->Orientation, UIP->Orientation)) {
        refresh = redisplay = TRUE;
    }

    if (PM->GraphType != UIP->GraphType) {
        PmSetGraphType(UIP->GraphType);
        redisplay = TRUE;
    }
       
    if (PmAssign(PM->IsRemote, UIP->IsRemote)) {
        /* The remote flag has changed */

        if (PM->IsRemote) {
            s = g_strdup(gtk_entry_get_text(GTK_ENTRY(
                                GTK_BIN(UIP->Controls[P_HOSTSCOMBO])->child)));
            if (s != NULL &&
                strlen(s) && (g_ascii_strcasecmp(s, PM->LocalMachine) != 0)) {
                PmStrcpy(PM->Hostname, s);

                if (PmMonitor()) {
                    if (PM->IsRemote == FALSE) {
                        /* Reset back to local */
                        PM->IsRemote = FALSE;
                        SetPropsToggle(P_LOCAL, TRUE);
                        SetPropsToggle(P_REMOTE, FALSE);
                    } else {
                        change_host = TRUE;
                        redisplay = TRUE;
                    }
                } else {
                    GtkWidget *dialog;

                    dialog = gtk_message_dialog_new(NULL,
                             GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
                             GTK_MESSAGE_ERROR,
                             GTK_BUTTONS_CLOSE,
                             ("Unable to Show the Performance of the \nRemote Host %s . Please ensure \nthe host is connented and rstatd is enabled."),
                             PM->Hostname);

                    gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
                    gtk_dialog_run(GTK_DIALOG(dialog));
                    gtk_widget_destroy(dialog);

                    PM->IsRemote = FALSE;
                    SetPropsToggle(P_LOCAL, TRUE);
                    SetPropsToggle(P_REMOTE, FALSE);
                    PMMONITOR();
                    redisplay = TRUE;
                    change_host = TRUE;
                }
            } else {
                /* Reset back to local */
                PM->IsRemote = FALSE;
                SetPropsToggle(P_LOCAL, TRUE);
                SetPropsToggle(P_REMOTE, FALSE);
                redisplay = TRUE;
            }
            g_free(s);
        } else {
            /* Monitor local machine */
            PMMONITOR();
            change_host = TRUE;
            redisplay = TRUE;
        }
    } else if (PM->IsRemote) {
        /* Check to see if the machine has changed */
        s = g_strdup(gtk_entry_get_text(GTK_ENTRY(
                                GTK_BIN(UIP->Controls[P_HOSTSCOMBO])->child)));
        if (s != NULL && strlen(s) && 
            g_ascii_strcasecmp(s, PM->LocalMachine) != 0) {
            if (g_ascii_strcasecmp(PM->Hostname, s)) {
                PmStrcpy(PM->Hostname, s);
                PMMONITOR();
                redisplay = TRUE;
                change_host = TRUE;
            }
        } else {
            PM->IsRemote = FALSE;
            SetPropsToggle(P_LOCAL, TRUE);
            SetPropsToggle(P_REMOTE, FALSE);
            PMMONITOR();
            redisplay = TRUE;
            change_host = TRUE;
        }
        g_free(s);
    }          

    if (PmAssign(PM->ShowHostName, UIP->ShowHostName)) {
        if (PM->ShowHostName) {
            gtk_widget_show(UI->HostName);
        } else {
            gtk_widget_hide(UI->HostName);
        }
    }

    if (PmAssign(PM->ShowMenubar, UIP->ShowMenubar)) {
        PmSetMinSize();
        if (PM->ShowMenubar) {
            ToggleMenuBar(TRUE);
        } else {
            ToggleMenuBar(FALSE);
        }
        redisplay = TRUE;
    }

    PmUnLock();

    if (change_host) {
        if (PM->AutoLoadByHost) {
            PmShow(FALSE);
            PmReset(NULL);
            PmShow(TRUE);
            return;
        }
    }

    /* Reset the display */
    if (redisplay) {
        if (reset) {
            PmShow(FALSE);
        } else if (refresh) {
            PmRefresh(FALSE);
        }
        PmSetMinSize();
        PmRedisplay();
        if (reset) {
            PmShow(TRUE);
            PmShowProps();
        }
    }

    (void) InterruptTimer(NULL);
}


/*ARGSUSED*/
static void
PMColorSetCB(GtkColorButton *picker, gpointer user_data)
{
    gint data;    
    GdkColor color;
    int index = (int) user_data;

    gtk_color_button_get_color(picker, &color);
    data = (gint) g_object_get_data(G_OBJECT(picker), "PropsData");

    switch (index) {
        case P_CPU:
            if (data == P_CPUBELIMITCOLOR) {
                UIP->Meters[P_CPU].MeterColor = color;
            } else {
                UIP->Meters[P_CPU].LimitColor = color;
            }
            break;        

        case P_LOAD:
            if (data == P_LOADBELIMITCOLOR) {
                UIP->Meters[P_LOAD].MeterColor = color;
            } else {
                UIP->Meters[P_LOAD].LimitColor = color;
            }
            break;

        case P_DISK:
            if (data == P_DISKBELIMITCOLOR) {
                UIP->Meters[P_DISK].MeterColor = color;
            } else {
                UIP->Meters[P_DISK].LimitColor = color;
            }
            break;

        case P_PAGE:
            if (data == P_PAGEBELIMITCOLOR) {
                UIP->Meters[P_PAGE].MeterColor = color;
            } else {
                UIP->Meters[P_PAGE].LimitColor = color;
            }
            break;

        case P_CNTX:
            if (data == P_CNTXBELIMITCOLOR) {
                UIP->Meters[P_CNTX].MeterColor = color;
            } else {
                UIP->Meters[P_CNTX].LimitColor = color;
            }
            break;
        
        case P_SWAP:
            if (data == P_SWAPBELIMITCOLOR) {
                UIP->Meters[P_SWAP].MeterColor = color;
            } else {
                UIP->Meters[P_SWAP].LimitColor = color;
            }
            break;
 
        case P_INTR:
            if (data == P_INTRBELIMITCOLOR) {
                UIP->Meters[P_INTR].MeterColor = color;
            } else {
                UIP->Meters[P_INTR].LimitColor = color;
            }
            break;
            
        case P_PKTS:
            if (data == P_PKTSBELIMITCOLOR) {
                UIP->Meters[P_PKTS].MeterColor = color;
            } else {
                UIP->Meters[P_PKTS].LimitColor = color;
            }
            break;

        case P_COLL:
            if (data == P_COLLBELIMITCOLOR) {
                UIP->Meters[P_COLL].MeterColor = color;
            } else {
                UIP->Meters[P_COLL].LimitColor = color;
            }
            break;

        case P_ERRS:
            if (data == P_ERRSBELIMITCOLOR) {
                UIP->Meters[P_ERRS].MeterColor = color;
            } else {
                UIP->Meters[P_ERRS].LimitColor = color;
            }
            break;
    }

    InstantApply();
}


/* Change the sensitivity of a field. */

static void 
SetSensitive(GtkWidget *w, gboolean sensitive)
{
    if (w == NULL) {
        return;
    }

    if (sensitive) {
        if (!GTK_WIDGET_IS_SENSITIVE(w)) {
            gtk_widget_set_sensitive(w, TRUE);
        }
    } else if (GTK_WIDGET_IS_SENSITIVE(w)) {
        gtk_widget_set_sensitive(w, FALSE);
    }
}


/*ARGSUSED*/
static gboolean
EntryKeyHandler(GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
    switch (event->keyval) {
        case GDK_Return:
        case GDK_KP_Enter:
            InstantApply();
            break;

        default:
            return(FALSE);
     }

     return(TRUE);
}


void
PmAddHostToList(char *name)
{
    if (g_list_find_custom(remote_hosts, name, 
                           (GCompareFunc) g_ascii_strcasecmp) == NULL) {
        remote_hosts = g_list_insert_sorted(remote_hosts, name, 
                                            (GCompareFunc) g_ascii_strcasecmp);
    }

    if (UIP != NULL) {
        set_remote_host_list(UIP->Controls[P_HOSTSCOMBO], remote_hosts);
    }
}


void 
PmPropsBusy(gboolean busy)
{
    if (UIP && UIP->Showing) {
        if (busy) {
            UIP->Busy++;
            gdk_window_set_cursor(UIP->Top->window, UI->WaitCursor);
        } else if (UIP->Busy > 0) {
            UIP->Busy--;

            if (UIP->Busy == 0) {
                gdk_window_set_cursor(UIP->Top->window, NULL);
            }
        }
    }
}


static void
InstantApply()
{
    ApplyProps();   
    PmSaveResources();
    ValidateStripBarMenu();
    PmSetMinSize(); 
    PmRedisplay();
}


/* Handle the buttons. */

/*ARGSUSED*/
void
PropsButtonCB(GtkButton *button, gpointer user_data)
{
    GError *error = NULL;
    int btype = (int) g_object_get_data(G_OBJECT(button), "PropsData");

    switch (btype) {
        case P_CLOSE:
            PMHIDEPROPS();
            break;

        case P_HELP:
            gnome_help_display("gnome-perfmeter", "gperfmeter-prefs", &error);
            if (error) {
                g_warning("help error: %s\n", error->message);
                g_error_free(error);
                error = NULL;
            }
            break;
    }
}


/* Callback to handle delete events for the Property popup window. */

/*ARGSUSED*/
gboolean
DismissPropsCB(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
    PMHIDEPROPS();
    return(TRUE);
}


static void
colorpicker_set_default_colors(GtkColorButton *color_picker, 
                               GdkColor color, gint index)
{
    gtk_color_button_set_color(GTK_COLOR_BUTTON(color_picker), &color);
    g_signal_connect(G_OBJECT(color_picker), "color-set",
             G_CALLBACK(PMColorSetCB), (gpointer) index);    
}


static gboolean
PmColorChk(GdkColor *PMColor, GdkColor *UIPColor)
{

/* FIXME = Change the following chk to be simple as if (PMColor != UIPColor */
    
    if ((PMColor->red   != UIPColor->red) || 
        (PMColor->green != UIPColor->green) || 
        (PMColor->blue  != UIPColor->blue)) {
        *PMColor = *UIPColor;    
        return(TRUE);
    } else {
        return(FALSE);
    }
}    
