summaryrefslogtreecommitdiff
path: root/plugins/clock/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/clock/clock.c')
-rw-r--r--plugins/clock/clock.c691
1 files changed, 691 insertions, 0 deletions
diff --git a/plugins/clock/clock.c b/plugins/clock/clock.c
new file mode 100644
index 00000000..2a0170ec
--- /dev/null
+++ b/plugins/clock/clock.c
@@ -0,0 +1,691 @@
+/* $Id$
+ *
+ * Copyright 2002,2004 Jasper Huijsmans(jasper@xfce.org)
+ * Olivier Fourdan (fourdan@xfce.org)
+ * Xavier Maillard (zedek@fxgsproject.org)
+ *
+ * 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 of the License, 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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <libxfce4util/libxfce4util.h>
+#include <libxfcegui4/xfce_clock.h>
+
+#include <panel/global.h>
+#include <panel/controls.h>
+#include <panel/icons.h>
+#include <panel/plugins.h>
+
+#define BORDER 6
+
+/* Clock module
+ * ------------
+*/
+typedef struct
+{
+ GtkWidget *eventbox;
+ GtkWidget *clock; /* our XfceClock widget */
+
+ int timeout_id; /* update the date tooltip */
+}
+t_clock;
+
+typedef struct
+{
+ /* the clock */
+ t_clock *clock;
+
+ /* backup */
+ int mode;
+ int military;
+ int ampm;
+ int secs;
+
+ /* controls dialog */
+ GtkWidget *dialog;
+
+ /* clock options */
+ GtkWidget *type_menu;
+
+ GtkWidget *twentyfour_rb;
+ GtkWidget *twelve_rb;
+ GtkWidget *ampm_rb;
+
+ GtkWidget *seconds_cb;
+}
+ClockDialog;
+
+/* start xfcalendar or send a client message
+ * NOTE: keep message format in sync with xfcalendar */
+
+static gboolean
+popup_xfcalendar (GtkWidget * widget)
+{
+ GdkAtom atom;
+ Window xwindow;
+
+ /* send message to xfcalendar if it is running */
+ atom = gdk_atom_intern ("_XFCE_CALENDAR_RUNNING", FALSE);
+ if ((xwindow = XGetSelectionOwner (GDK_DISPLAY (),
+ gdk_x11_atom_to_xatom (atom))) != None)
+ {
+ char msg[20];
+ const char *fmt = "%lx:%s";
+ Window xid = GDK_WINDOW_XID (widget->window);
+ GdkEventClient gev;
+
+ /* popup in the same direction as menus */
+ switch (panel_get_arrow_direction (get_current_panel()))
+ {
+ case GTK_ARROW_UP:
+ sprintf (msg, fmt, xid, "up");
+ break;
+ case GTK_ARROW_DOWN:
+ sprintf (msg, fmt, xid, "down");
+ break;
+ case GTK_ARROW_LEFT:
+ sprintf (msg, fmt, xid, "left");
+ break;
+ case GTK_ARROW_RIGHT:
+ sprintf (msg, fmt, xid, "right");
+ break;
+ default:
+ return FALSE;
+ }
+
+ gev.type = GDK_CLIENT_EVENT;
+ gev.window = widget->window;
+ gev.send_event = TRUE;
+ gev.message_type =
+ gdk_atom_intern ("_XFCE_CALENDAR_TOGGLE_HERE", FALSE);
+ gev.data_format = 8;
+ strcpy (gev.data.b, msg);
+
+ gdk_event_send_client_message ((GdkEvent *) & gev,
+ (GdkNativeWindow) xwindow);
+ gdk_flush ();
+
+ return TRUE;
+ }
+ else
+ {
+ exec_cmd_silent ("xfcalendar", FALSE, FALSE);
+ exec_cmd_silent ("xfcalendar", FALSE, FALSE); /* actually only RAISE */
+ }
+
+ return FALSE;
+}
+
+static gboolean
+on_button_press_event_cb (GtkWidget * widget,
+ GdkEventButton * event, Control * control)
+{
+ if (event->button == 1)
+ {
+ return popup_xfcalendar (control->base);
+ }
+
+ return FALSE;
+}
+
+/* creation and destruction */
+gboolean
+clock_date_tooltip (GtkWidget * widget)
+{
+ time_t ticks;
+ struct tm *tm;
+ static gint mday = -1;
+ char date_s[255];
+ char *utf8date = NULL;
+
+ g_return_val_if_fail (widget != NULL, TRUE);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
+
+ ticks = time (0);
+ tm = localtime (&ticks);
+
+ if (mday != tm->tm_mday)
+ {
+ mday = tm->tm_mday;
+ /* Use format characters from strftime(3)
+ * to get the proper string for your locale.
+ * I used these:
+ * %A : full weekday name
+ * %d : day of the month
+ * %B : full month name
+ * %Y : four digit year
+ */
+ strftime (date_s, 255, _("%A, %d %B %Y"), tm);
+
+ /* Conversion to utf8
+ * patch by Oliver M. Bolzer <oliver@fakeroot.net>
+ */
+ if (!g_utf8_validate (date_s, -1, NULL))
+ utf8date = g_locale_to_utf8 (date_s, -1, NULL, NULL, NULL);
+
+ if (utf8date)
+ {
+ add_tooltip (widget, utf8date);
+ g_free (utf8date);
+ }
+ else
+ {
+ add_tooltip (widget, date_s);
+ }
+ }
+
+ return TRUE;
+}
+
+static t_clock *
+clock_new (void)
+{
+ t_clock *clock = g_new (t_clock, 1);
+
+ clock->eventbox = gtk_event_box_new ();
+ gtk_widget_set_name (clock->eventbox, "xfce_clock");
+ gtk_widget_show (clock->eventbox);
+
+ clock->clock = xfce_clock_new ();
+ gtk_widget_show (clock->clock);
+ gtk_container_add (GTK_CONTAINER (clock->eventbox), clock->clock);
+
+ /* Add tooltip to show the current date */
+ clock_date_tooltip (clock->eventbox);
+
+ clock->timeout_id =
+ g_timeout_add (60000, (GSourceFunc) clock_date_tooltip,
+ clock->eventbox);
+
+ /* callback for calendar popup */
+ g_signal_connect (G_OBJECT (clock->eventbox), "button-press-event",
+ G_CALLBACK (on_button_press_event_cb), clock);
+
+ return clock;
+}
+
+static void
+clock_free (Control * control)
+{
+ t_clock *clock = control->data;
+
+ g_return_if_fail (clock != NULL);
+
+ if (clock->timeout_id)
+ {
+ g_source_remove (clock->timeout_id);
+ clock->timeout_id = 0;
+ }
+
+ g_free (clock);
+}
+
+static void
+clock_attach_callback (Control * control, const char *signal,
+ GCallback callback, gpointer data)
+{
+ t_clock *clock = control->data;
+
+ g_signal_connect (clock->eventbox, signal, callback, data);
+}
+
+/* panel preferences */
+void
+update_clock_size (XfceClock * clock, int size)
+{
+ if ((xfce_clock_get_mode (clock) == XFCE_CLOCK_LEDS) ||
+ (xfce_clock_get_mode (clock) == XFCE_CLOCK_DIGITAL))
+ {
+ gtk_widget_set_size_request (GTK_WIDGET (clock), -1, -1);
+ }
+ else
+ {
+ gtk_widget_set_size_request (GTK_WIDGET (clock), icon_size[size],
+ icon_size[size]);
+ }
+ gtk_widget_queue_resize (GTK_WIDGET (clock));
+}
+
+void
+clock_set_size (Control * control, int size)
+{
+ t_clock *clock = (t_clock *) control->data;
+ XfceClock *tmp = XFCE_CLOCK (clock->clock);
+
+ switch (size)
+ {
+ case 0:
+ xfce_clock_set_led_size (tmp, DIGIT_SMALL);
+ break;
+ case 1:
+ xfce_clock_set_led_size (tmp, DIGIT_MEDIUM);
+ break;
+ case 2:
+ xfce_clock_set_led_size (tmp, DIGIT_LARGE);
+ break;
+ default:
+ xfce_clock_set_led_size (tmp, DIGIT_HUGE);
+ }
+ update_clock_size (tmp, size);
+}
+
+/* Write the configuration at exit */
+void
+clock_write_config (Control * control, xmlNodePtr parent)
+{
+ xmlNodePtr root;
+ char value[MAXSTRLEN + 1];
+
+ t_clock *cl = (t_clock *) control->data;
+ XfceClock *clock = XFCE_CLOCK (cl->clock);
+
+ /* I use my own node even if we only have 4 settings
+ It's safer and easier to check
+ */
+ root = xmlNewTextChild (parent, NULL, "XfceClock", NULL);
+ g_snprintf (value, 2, "%d", clock->mode);
+ xmlSetProp (root, "Clock_type", value);
+ g_snprintf (value, 2, "%d", clock->military_time);
+ xmlSetProp (root, "Toggle_military", value);
+ g_snprintf (value, 2, "%d", clock->display_am_pm);
+ xmlSetProp (root, "Toggle_am_pm", value);
+ g_snprintf (value, 2, "%d", clock->display_secs);
+ xmlSetProp (root, "Toggle_secs", value);
+}
+
+/* Read the configuration file at init */
+void
+clock_read_config (Control * control, xmlNodePtr node)
+{
+ xmlChar *value;
+
+ t_clock *cl = (t_clock *) control->data;
+
+ if (!node || !node->children)
+ return;
+
+ node = node->children;
+
+ /* Leave if we can't find the node XfceClock */
+ if (!xmlStrEqual (node->name, "XfceClock"))
+ return;
+
+ if ((value = xmlGetProp (node, (const xmlChar *) "Clock_type")))
+ {
+ XFCE_CLOCK (cl->clock)->mode = atoi (value);
+ g_free (value);
+ }
+
+ if ((value = xmlGetProp (node, (const xmlChar *) "Toggle_military")))
+ {
+ XFCE_CLOCK (cl->clock)->military_time = atoi (value);
+ g_free (value);
+ }
+ if ((value = xmlGetProp (node, (const xmlChar *) "Toggle_am_pm")))
+ {
+ XFCE_CLOCK (cl->clock)->display_am_pm = atoi (value);
+ g_free (value);
+ }
+ if ((value = xmlGetProp (node, (const xmlChar *) "Toggle_secs")))
+ {
+ XFCE_CLOCK (cl->clock)->display_secs = atoi (value);
+ g_free (value);
+ }
+
+ /* Try to resize the clock to fit the user settings */
+ clock_set_size (control, settings.size);
+}
+
+/* Clock options dialog
+ * --------------------
+*/
+static void
+make_sensitive (GtkWidget * w)
+{
+ gtk_widget_set_sensitive (w, TRUE);
+}
+
+static void
+make_insensitive (GtkWidget * w)
+{
+ gtk_widget_set_sensitive (w, FALSE);
+}
+
+/* clock type */
+static void
+clock_type_changed (GtkOptionMenu * om, ClockDialog * cd)
+{
+ XfceClock *xclock = XFCE_CLOCK (cd->clock->clock);
+
+ xclock->mode = gtk_option_menu_get_history (om);
+
+ xfce_clock_set_mode (xclock, xclock->mode);
+ update_clock_size (xclock, settings.size);
+
+ if (xclock->mode == XFCE_CLOCK_ANALOG)
+ {
+ make_insensitive (cd->twentyfour_rb);
+ make_insensitive (cd->twelve_rb);
+ make_insensitive (cd->ampm_rb);
+ }
+ else
+ {
+ make_sensitive (cd->twentyfour_rb);
+ make_sensitive (cd->twelve_rb);
+ make_sensitive (cd->ampm_rb);
+ }
+}
+
+static void
+add_type_box (GtkWidget * vbox, GtkSizeGroup * sg, ClockDialog * cd)
+{
+ GtkWidget *hbox, *label, *menu, *mi, *om;
+
+ hbox = gtk_hbox_new (FALSE, BORDER);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+
+ label = gtk_label_new (_("Clock type:"));
+ gtk_widget_show (label);
+ gtk_size_group_add_widget (sg, label);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ om = cd->type_menu = gtk_option_menu_new ();
+ gtk_widget_show (om);
+ gtk_box_pack_start (GTK_BOX (hbox), om, FALSE, FALSE, 0);
+
+ menu = gtk_menu_new ();
+ gtk_option_menu_set_menu (GTK_OPTION_MENU (om), menu);
+
+ mi = gtk_menu_item_new_with_label (_("Analog"));
+ gtk_widget_show (mi);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+
+ mi = gtk_menu_item_new_with_label (_("Digital"));
+ gtk_widget_show (mi);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+
+ mi = gtk_menu_item_new_with_label (_("LED"));
+ gtk_widget_show (mi);
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), mi);
+
+ gtk_option_menu_set_history (GTK_OPTION_MENU (om),
+ XFCE_CLOCK (cd->clock->clock)->mode);
+
+ g_signal_connect (om, "changed", G_CALLBACK (clock_type_changed), cd);
+}
+
+/* hour mode */
+static void
+set_24hr_mode (GtkToggleButton * tb, ClockDialog * cd)
+{
+ XfceClock *xclock = XFCE_CLOCK (cd->clock->clock);
+
+ if (!gtk_toggle_button_get_active (tb))
+ return;
+
+ xfce_clock_show_military (xclock, 1);
+
+ update_clock_size (xclock, settings.size);
+}
+
+static void
+set_12hr_mode (GtkToggleButton * tb, ClockDialog * cd)
+{
+ XfceClock *xclock = XFCE_CLOCK (cd->clock->clock);
+
+ if (!gtk_toggle_button_get_active (tb))
+ return;
+
+ xfce_clock_show_military (xclock, 0);
+ xfce_clock_show_ampm (xclock, 0);
+
+ update_clock_size (xclock, settings.size);
+}
+
+static void
+set_ampm_mode (GtkToggleButton * tb, ClockDialog * cd)
+{
+ XfceClock *xclock = XFCE_CLOCK (cd->clock->clock);
+
+ if (!gtk_toggle_button_get_active (tb))
+ return;
+
+ xfce_clock_show_military (xclock, 0);
+ xfce_clock_show_ampm (xclock, 1);
+
+ update_clock_size (xclock, settings.size);
+}
+
+static void
+add_hour_mode_box (GtkWidget * vbox, GtkSizeGroup * sg, ClockDialog * cd)
+{
+ GtkWidget *hbox, *label, *rb1, *rb2, *rb3;
+ XfceClock *xclock;
+
+ hbox = gtk_hbox_new (FALSE, BORDER);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new (_("Hour mode:"));
+ gtk_widget_show (label);
+ gtk_size_group_add_widget (sg, label);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ rb1 = cd->twentyfour_rb =
+ gtk_radio_button_new_with_label (NULL, _("24 hour"));
+ gtk_widget_show (rb1);
+ gtk_box_pack_start (GTK_BOX (hbox), rb1, FALSE, FALSE, 0);
+
+ rb2 = cd->twelve_rb =
+ gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (rb1),
+ _("12 hour"));
+ gtk_widget_show (rb2);
+ gtk_box_pack_start (GTK_BOX (hbox), rb2, FALSE, FALSE, 0);
+
+ rb3 = cd->ampm_rb =
+ gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (rb1),
+ _("AM/PM"));
+ gtk_widget_show (rb3);
+ gtk_box_pack_start (GTK_BOX (hbox), rb3, FALSE, FALSE, 0);
+
+ xclock = XFCE_CLOCK (cd->clock->clock);
+
+ if (xclock->military_time)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rb1), TRUE);
+ else if (xclock->display_am_pm)
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rb3), TRUE);
+ else
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (rb2), TRUE);
+
+ g_signal_connect (rb1, "toggled", G_CALLBACK (set_24hr_mode), cd);
+ g_signal_connect (rb2, "toggled", G_CALLBACK (set_12hr_mode), cd);
+ g_signal_connect (rb3, "toggled", G_CALLBACK (set_ampm_mode), cd);
+}
+
+/* show seconds */
+static void
+clock_seconds_changed (GtkToggleButton * tb, ClockDialog * cd)
+{
+ XfceClock *xclock = XFCE_CLOCK (cd->clock->clock);
+
+ xfce_clock_show_secs (xclock, gtk_toggle_button_get_active (tb));
+ update_clock_size (xclock, settings.size);
+}
+
+static void
+add_seconds_box (GtkWidget * vbox, GtkSizeGroup * sg, ClockDialog * cd)
+{
+ GtkWidget *hbox, *label, *cb;
+ XfceClock *xclock = XFCE_CLOCK (cd->clock->clock);
+
+ hbox = gtk_hbox_new (FALSE, BORDER);
+ gtk_widget_show (hbox);
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new (_("Show seconds:"));
+ gtk_widget_show (label);
+ gtk_size_group_add_widget (sg, label);
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ cb = cd->seconds_cb = gtk_check_button_new ();
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (cb),
+ xclock->display_secs);
+ gtk_widget_show (cb);
+ gtk_box_pack_start (GTK_BOX (hbox), cb, FALSE, FALSE, 0);
+
+ g_signal_connect (cb, "toggled", G_CALLBACK (clock_seconds_changed), cd);
+}
+
+#if 0
+/* backup */
+static void
+clock_create_backup (ClockDialog * cd)
+{
+ XfceClock *clock = XFCE_CLOCK (cd->clock->clock);
+
+ g_return_if_fail (clock != NULL);
+
+ cd->mode = clock->mode;
+ cd->military = clock->military_time;
+ cd->ampm = clock->display_am_pm;
+ cd->secs = clock->display_secs;
+}
+
+static void
+clock_restore_backup (ClockDialog * cd)
+{
+ GtkToggleButton *tb;
+
+ /* clock type */
+ gtk_option_menu_set_history (GTK_OPTION_MENU (cd->type_menu), cd->mode);
+
+ /* hour mode */
+ if (cd->military)
+ tb = GTK_TOGGLE_BUTTON (cd->twentyfour_rb);
+ else if (cd->ampm)
+ tb = GTK_TOGGLE_BUTTON (cd->ampm_rb);
+ else
+ tb = GTK_TOGGLE_BUTTON (cd->twelve_rb);
+
+ gtk_toggle_button_set_active (tb, TRUE);
+
+ /* seconds */
+ tb = GTK_TOGGLE_BUTTON (cd->seconds_cb);
+ gtk_toggle_button_set_active (tb, cd->secs);
+}
+#endif
+
+/* clock options box */
+void
+clock_create_options (Control * control, GtkContainer * container,
+ GtkWidget * done)
+{
+ GtkWidget *vbox;
+ GtkSizeGroup *sg = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+ ClockDialog *cd;
+
+ xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
+
+ cd = g_new0 (ClockDialog, 1);
+
+ cd->clock = control->data;
+ cd->dialog = gtk_widget_get_toplevel (done);
+
+ g_signal_connect_swapped (cd->dialog, "destroy-event",
+ G_CALLBACK (g_free), cd);
+
+ /* the options box */
+ vbox = gtk_vbox_new (FALSE, BORDER);
+ gtk_widget_show (vbox);
+
+ add_type_box (vbox, sg, cd);
+
+ add_hour_mode_box (vbox, sg, cd);
+
+ add_seconds_box (vbox, sg, cd);
+
+ gtk_container_add (container, vbox);
+}
+
+/* Clock panel control
+ * -------------------
+*/
+gboolean
+create_clock_control (Control * control)
+{
+ t_clock *clock = clock_new ();
+
+ gtk_container_add (GTK_CONTAINER (control->base), clock->eventbox);
+
+ control->data = (gpointer) clock;
+ control->with_popup = FALSE;
+
+ gtk_widget_set_size_request (control->base, -1, -1);
+ clock_set_size (control, settings.size);
+
+ return TRUE;
+}
+
+/* calculate position of calendar popup */
+
+G_MODULE_EXPORT void
+xfce_control_class_init (ControlClass * cc)
+{
+ xfce_textdomain (GETTEXT_PACKAGE, LOCALEDIR, "UTF-8");
+
+ cc->name = "clock";
+ cc->caption = _("Xfce Clock");
+
+ cc->create_control = (CreateControlFunc) create_clock_control;
+
+ cc->free = clock_free;
+ cc->read_config = clock_read_config;
+ cc->write_config = clock_write_config;
+ cc->attach_callback = clock_attach_callback;
+
+ cc->create_options = clock_create_options;
+
+ cc->set_size = clock_set_size;
+
+ control_class_set_unique (cc, TRUE);
+}
+
+/* macro defined in plugins.h */
+XFCE_PLUGIN_CHECK_INIT