Index: applets/gen_util/GNOME_ClockApplet.xml
===================================================================
RCS file: /cvs/gnome/gnome-panel/applets/gen_util/GNOME_ClockApplet.xml,v
retrieving revision 1.4
diff -u -p -u -r1.4 GNOME_ClockApplet.xml
--- applets/gen_util/GNOME_ClockApplet.xml	15 May 2002 07:51:50 -0000	1.4
+++ applets/gen_util/GNOME_ClockApplet.xml	10 Jul 2002 20:50:57 -0000
@@ -7,6 +7,7 @@
     		    pixtype="stock" pixname="gtk-copy"/>
       <menuitem name="Clock Copy Date Item" verb="ClockCopyDate" _label="Copy _date"
     		    pixtype="stock" pixname="gtk-copy"/>
+      <menuitem name="Clock Configure Item" verb="ClockConfig" _label="Ad_just Date &amp; Time..."/>
       <menuitem name="Clock Help Item" verb="ClockHelp" _label="_Help"
     		    pixtype="stock" pixname="gtk-help"/>
       <menuitem name="Clock About Item" verb="ClockAbout" _label="_About..."
Index: applets/gen_util/clock.c
===================================================================
RCS file: /cvs/gnome/gnome-panel/applets/gen_util/clock.c,v
retrieving revision 1.77
diff -u -p -u -r1.77 clock.c
--- applets/gen_util/clock.c	6 Jun 2002 00:31:08 -0000	1.77
+++ applets/gen_util/clock.c	10 Jul 2002 20:50:57 -0000
@@ -1,3 +1,4 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
 /*
  * GNOME time/date display module.
  * (C) 1997 The Free Software Foundation
@@ -30,13 +31,14 @@
 #define INTERNETSECOND (864)
 #define INTERNETBEAT   (86400)
 
-#define N_GCONF_PREFS 6
+#define N_GCONF_PREFS 7
 static const char* KEY_HOUR_FORMAT	= "hour_format";
 static const char* KEY_SHOW_SECONDS 	= "show_seconds";
 static const char* KEY_SHOW_DATE 	= "show_date";
 static const char* KEY_GMT_TIME		= "gmt_time";
 static const char* KEY_UNIX_TIME	= "unix_time";
 static const char* KEY_INTERNET_TIME	= "internet_time";
+static const char* KEY_CONFIG_TOOL      = "config_tool";
 
 extern GtkTooltips *panel_tooltips;
 
@@ -46,6 +48,7 @@ struct _ClockData {
 	/* widgets */
 	GtkWidget *applet;
 	GtkWidget *clockw;
+        GtkWidget *toggle;
 	GtkWidget *props;
   
 	/* preferences */
@@ -55,7 +58,9 @@ struct _ClockData {
 	gboolean unixtime;
 	gboolean internettime;
 	gboolean gmt_time;
-	
+
+        char *config_tool;
+        
 	/* runtime data */
 	char *timeformat;
 	guint timeout;
@@ -350,19 +355,197 @@ destroy_clock(GtkWidget * widget, ClockD
 		cd->props = NULL;
 	}
 
+        g_free (cd->config_tool);
+        
 	g_free (cd);
 }
 
+static gboolean
+close_on_escape (GtkWidget   *widget,
+                 GdkEventKey *event,
+                 void        *data)
+{
+        ClockData *cd = data;
+        
+        if (event->keyval == GDK_Escape) {             
+                gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cd->toggle),
+                                              FALSE);
+                return TRUE;
+        } else {
+                return FALSE;
+        }
+}
+
+static void
+update_popup (ClockData *cd)
+{
+        GtkWidget *window;
+        GtkWidget *button;
+
+        button = cd->toggle;
+        
+        window = g_object_get_data (G_OBJECT (button), "calendar");
+        
+        if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
+                if (window == NULL) {
+                        GtkWidget *calendar;
+
+                        window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+                        /* set dialog type so it will skip the tasklist,
+                         * kinda broken. This window should really be override
+                         * redirect I suppose. But I hate override redirect
+                         * windows that don't have a pointer/keyboard grab.
+                         */
+                        gtk_window_set_type_hint (GTK_WINDOW (window),
+                                                  GDK_WINDOW_TYPE_HINT_DIALOG);
+                        gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
+                        gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+                        gtk_window_stick (GTK_WINDOW (window));
+                        gtk_window_set_title (GTK_WINDOW (window),
+                                              _("Calendar"));
+                        
+                        g_signal_connect (G_OBJECT (window), "key_press_event",
+                                          G_CALLBACK (close_on_escape),
+                                          cd);
+                        
+                        calendar = gtk_calendar_new ();                        
+
+                        gtk_container_add (GTK_CONTAINER (window), calendar);
+
+                        gtk_widget_show (calendar);
+
+                        g_object_set_data_full (G_OBJECT (button), "calendar",
+                                                window,
+                                                (GDestroyNotify)gtk_widget_destroy);
+                }
+        } else {
+                if (window != NULL) {
+                        /* Destroys the calendar */
+                        g_object_set_data (G_OBJECT (button), "calendar",
+                                           NULL);
+                        window = NULL;
+                }
+        }
+
+        if (window) {
+                /* Get root origin of the toggle button, and position above that. */
+                int x, y;
+                int w, h;
+                int button_w, button_h;
+                int screen_w, screen_h;
+                GtkRequisition req;
+                
+                if (!GTK_WIDGET_REALIZED (button))
+                        return;
+
+                gdk_window_get_origin (button->window, &x, &y);
+
+                gtk_window_get_size (GTK_WINDOW (window), &w, &h);
+                gtk_widget_size_request (window, &req);
+                w = req.width;
+                h = req.height;
+
+                button_w = button->allocation.width;
+                button_h = button->allocation.height;
+
+                /* FIXME use xinerama extents for xinerama containing
+                 * the applet.
+                 */
+                screen_w = gdk_screen_width ();
+                screen_h = gdk_screen_height ();
+                
+                /* Based on panel orientation, position the popup.
+                 * Ignore window gravity since the window is undecorated.
+                 * The orientations are all named backward from what
+                 * I expected.
+                 */
+                switch (cd->orient) {
+                case PANEL_APPLET_ORIENT_RIGHT:
+                        x += button_w;
+                        if ((y + h) > screen_h)
+                                y -= (y+h) - screen_h;
+                        break;
+                case PANEL_APPLET_ORIENT_LEFT:
+                        x -= w;
+                        if ((y + h) > screen_h)
+                                y -= (y+h) - screen_h;
+                        break;
+                case PANEL_APPLET_ORIENT_DOWN:
+                        y += button_h;
+                        if ((x + w) > screen_w)
+                                x -= (x+w) - screen_w;
+                        break;
+                case PANEL_APPLET_ORIENT_UP:
+                        y -= h;
+                        if ((x + w) > screen_w)
+                                x -= (x+w) - screen_w;
+                        break;
+                }
+                
+                gtk_window_move (GTK_WINDOW (window), x, y);
+                
+                gtk_window_present (GTK_WINDOW (window));
+        }
+}
+
+static void
+toggle_calendar (GtkWidget *button,
+                 void      *data)
+{
+        update_popup ((ClockData*) data);
+}
+
+static gboolean
+do_not_eat_button_press (GtkWidget      *widget,
+                         GdkEventButton *event)
+{
+        if (event->button != 1) {
+                g_signal_stop_emission_by_name (widget, "button_press_event");
+        }
+
+        return FALSE;
+}
+
 static void
 create_clock_widget (ClockData *cd)
 {
 	GtkWidget *clock;
-
+        GtkWidget *toggle;
+        static gboolean rc_parsed = FALSE;
+        
+        if (!rc_parsed) {
+                gtk_rc_parse_string ("\n"
+                                     "   style \"clock-button-style\"\n"
+                                     "   {\n"
+                                     "      GtkWidget::focus-line-width=0\n"
+                                     "      GtkWidget::focus-padding=0\n"
+                                     "   }\n"
+                                     "\n"
+                                     "    widget \"*.clock-button\" style \"clock-button-style\"\n"
+                                     "\n");
+                rc_parsed = TRUE;
+        }
+        
 	clock = gtk_label_new ("hmm?");
 	gtk_label_set_justify (GTK_LABEL (clock), GTK_JUSTIFY_CENTER);
 	gtk_label_set_line_wrap (GTK_LABEL (clock), TRUE);
 	gtk_widget_show (clock);
 
+        toggle = gtk_toggle_button_new ();
+        gtk_button_set_relief (GTK_BUTTON (toggle), GTK_RELIEF_NONE);
+        gtk_widget_set_name (toggle, "clock-button");  
+        
+        gtk_container_add (GTK_CONTAINER (toggle), clock);
+
+        g_signal_connect (toggle, "button_press_event",
+                          G_CALLBACK (do_not_eat_button_press), NULL);
+
+        g_signal_connect (toggle, "toggled",
+                          G_CALLBACK (toggle_calendar), cd);
+        
+        gtk_widget_show (toggle);        
+        
+        cd->toggle = toggle;
 	cd->clockw = clock;
 
 	cd->props = NULL;
@@ -393,6 +576,7 @@ applet_change_orient (PanelApplet       
 	time (&current_time);
 	cd->orient = orient;
 	update_clock (cd, current_time);
+        update_popup (cd);
 }
 
 static void
@@ -511,6 +695,81 @@ copy_date (BonoboUIComponent *uic,
 	g_free (utf8);
 }
 
+static gboolean
+try_config_tool (const char *tool)
+{
+        char *app;
+
+        g_return_val_if_fail (tool != NULL, FALSE);
+
+        app = g_find_program_in_path (tool);
+
+        if (app != NULL) {
+                char *argv[2];
+                GError *err;
+                
+                argv[0] = app;
+                argv[1] = NULL;                
+
+                err = NULL;
+                if (!g_spawn_async (NULL, argv, NULL, 0,
+                                    NULL, NULL,
+                                    NULL, &err)) {
+                        GtkWidget *dialog;
+                        
+                        dialog = gtk_message_dialog_new (NULL,
+                                                         GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                         GTK_MESSAGE_ERROR,
+                                                         GTK_BUTTONS_CLOSE,
+                                                         _("Failed to launch time configuration tool: %s"),
+                                                         err->message);
+                        
+                        g_signal_connect (G_OBJECT (dialog), "response",
+                                          G_CALLBACK (gtk_widget_destroy),
+                                          NULL);
+                        
+                        gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+                        
+                        gtk_widget_show_all (dialog);                        
+                }
+
+                g_free (app);
+                
+                return TRUE;
+        } else {
+                return FALSE;
+        }
+}
+
+static void
+config_date (BonoboUIComponent *uic,
+             ClockData         *cd,
+             const gchar       *verbname)
+{
+        if (cd->config_tool && try_config_tool (cd->config_tool))
+                return;
+        else if (try_config_tool ("redhat-config-date"))
+                return;
+        /* FIXME add XST, etc. */
+        else {
+                GtkWidget *dialog;
+                
+                dialog = gtk_message_dialog_new (NULL,
+                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
+                                                 GTK_MESSAGE_ERROR,
+                                                 GTK_BUTTONS_CLOSE,
+                                                 _("Failed to locate a program for configuring the date and time. Perhaps none is installed?"));
+                
+                g_signal_connect (G_OBJECT (dialog), "response",
+                                  G_CALLBACK (gtk_widget_destroy),
+                                  NULL);
+                
+                gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+                
+                gtk_widget_show_all (dialog);
+        }
+}
+
 /* current timestamp */
 static const BonoboUIVerb clock_menu_verbs [] = {
 	BONOBO_UI_UNSAFE_VERB ("ClockPreferences", display_properties_dialog),
@@ -518,6 +777,7 @@ static const BonoboUIVerb clock_menu_ver
 	BONOBO_UI_UNSAFE_VERB ("ClockAbout",       display_about_dialog),
 	BONOBO_UI_UNSAFE_VERB ("ClockCopyTime",    copy_time),
 	BONOBO_UI_UNSAFE_VERB ("ClockCopyDate",    copy_date),
+        BONOBO_UI_UNSAFE_VERB ("ClockConfig",      config_date),
 	BONOBO_UI_VERB_END
 };
 
@@ -630,6 +890,25 @@ gmt_time_changed (GConfClient  *client,
 }
 
 static void
+config_tool_changed (GConfClient  *client,
+                     guint         cnxn_id,
+                     GConfEntry   *entry,
+                     ClockData    *clock)
+{
+	const char *value;
+	
+	if (!entry->value || entry->value->type != GCONF_VALUE_STRING)
+		return;
+
+	value = gconf_value_get_string (entry->value);
+
+        g_free (clock->config_tool);
+	clock->config_tool = g_strdup (value);
+        
+	refresh_clock_timeout (clock);
+}
+
+static void
 setup_gconf (ClockData *clock)
 {
 	GConfClient *client;
@@ -690,6 +969,15 @@ setup_gconf (ClockData *clock)
 				(GConfClientNotifyFunc)internet_time_changed,
 				clock, NULL, NULL);
 	g_free (key);
+
+        key = panel_applet_gconf_get_full_key (PANEL_APPLET (clock->applet),
+					       KEY_CONFIG_TOOL);
+	clock->listeners [6] =
+		gconf_client_notify_add (
+				client, key,
+				(GConfClientNotifyFunc)config_tool_changed,
+				clock, NULL, NULL);
+	g_free (key);
 }
 
 gboolean
@@ -734,12 +1022,14 @@ fill_clock_applet(PanelApplet *applet)
 	cd->unixtime = panel_applet_gconf_get_bool (applet, KEY_UNIX_TIME, NULL);
 	cd->internettime = panel_applet_gconf_get_bool (applet, KEY_INTERNET_TIME, NULL);
 
+	cd->config_tool = panel_applet_gconf_get_string (applet, KEY_CONFIG_TOOL, NULL);
+        
 	cd->timeformat = NULL;
 
 	create_clock_widget (cd);
 
-	gtk_container_set_border_width (GTK_CONTAINER (cd->applet), 4);
-	gtk_container_add (GTK_CONTAINER (cd->applet), cd->clockw);
+	gtk_container_set_border_width (GTK_CONTAINER (cd->applet), 2);
+	gtk_container_add (GTK_CONTAINER (cd->applet), cd->toggle);
 
 	gtk_widget_show (cd->applet);
 
@@ -1131,7 +1421,7 @@ display_about_dialog (BonoboUIComponent 
 	};
 	static const char *documenters[] =
 	{
-		"Dan Mueth (d-mueth@uchicago.edu)",
+		"Dan Mueth <d-mueth@uchicago.edu>",
 		NULL
 	};
 	/* Translator credits */
@@ -1173,4 +1463,3 @@ display_about_dialog (BonoboUIComponent 
 	
 	gtk_widget_show (about);
 }
-
Index: applets/gen_util/clock.schemas.in
===================================================================
RCS file: /cvs/gnome/gnome-panel/applets/gen_util/clock.schemas.in,v
retrieving revision 1.4
diff -u -p -u -r1.4 clock.schemas.in
--- applets/gen_util/clock.schemas.in	2 Jul 2002 16:43:18 -0000	1.4
+++ applets/gen_util/clock.schemas.in	10 Jul 2002 20:50:57 -0000
@@ -77,6 +77,17 @@
           <long>Display Internet time, which is same all over the world</long>
         </locale>
       </schema>
+
+      <schema>
+        <key>/schemas/apps/clock_applet/prefs/config_tool</key>
+        <owner>clock-applet</owner>
+        <type>string</type>
+        <default> </default>
+        <locale name="C">
+          <short>Time configuration tool</short>
+          <long>Program to run in order to configure the time.</long>
+        </locale>
+      </schema>
                  
   </schemalist>
   
