/* $Id: calendar.c,v 1.4 2010/12/10 21:59:18 khorben Exp $ */ /* Copyright (c) 2010 Pierre Pronchery */ /* This file is part of DeforaOS Desktop Accessories */ /* 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 3 of the License. * * 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, see . */ #include #include #include #include #include #include #include /* Calendar */ /* private */ /* types */ typedef struct _Calendar { struct tm today; Config * config; /* widgets */ GtkWidget * window; GtkWidget * widget; } Calendar; /* constants */ #define CALENDAR_CONFIG_FILE ".calendar" /* prototypes */ static Calendar * _calendar_new(void); static void _calendar_delete(Calendar * calendar); /* accessors */ static char const * _calendar_get_detail(Calendar * calendar, unsigned int year, unsigned int month, unsigned int day); static int _calendar_set_detail(Calendar * calendar, unsigned int year, unsigned int month, unsigned int day, char const * detail); static char * _config_get_filename(void); /* functions */ /* calendar_new */ static void _new_config(Calendar * calendar); static gboolean _calendar_on_closex(gpointer data); static void _calendar_on_today(gpointer data); #if GTK_CHECK_VERSION(2, 14, 0) static void _calendar_on_details(GtkWidget * widget, gpointer data); static gchar * _calendar_on_detail(GtkWidget * widget, guint year, guint month, guint day, gpointer data); #endif static void _calendar_on_edit(gpointer data); static Calendar * _calendar_new(void) { Calendar * calendar; time_t now; GtkWidget * vbox; GtkWidget * widget; GtkToolItem * toolitem; if((calendar = malloc(sizeof(*calendar))) == NULL) return NULL; /* XXX report error */ if((now = time(NULL)) == -1) { _calendar_delete(calendar); return NULL; /* XXX report error */ } localtime_r(&now, &calendar->today); _new_config(calendar); /* window */ calendar->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(calendar->window), "Calendar"); g_signal_connect_swapped(G_OBJECT(calendar->window), "delete-event", G_CALLBACK(_calendar_on_closex), calendar); vbox = gtk_vbox_new(FALSE, 4); /* toolbar */ widget = gtk_toolbar_new(); toolitem = gtk_tool_button_new(NULL, "Today"); gtk_tool_button_set_icon_name(GTK_TOOL_BUTTON(toolitem), "go-jump"); g_signal_connect_swapped(G_OBJECT(toolitem), "clicked", G_CALLBACK( _calendar_on_today), calendar); gtk_toolbar_insert(GTK_TOOLBAR(widget), toolitem, -1); #if GTK_CHECK_VERSION(2, 14, 0) toolitem = gtk_separator_tool_item_new(); gtk_toolbar_insert(GTK_TOOLBAR(widget), toolitem, -1); toolitem = gtk_toggle_tool_button_new(); gtk_tool_button_set_label(GTK_TOOL_BUTTON(toolitem), "Details"); g_signal_connect(G_OBJECT(toolitem), "toggled", G_CALLBACK( _calendar_on_details), calendar); gtk_toolbar_insert(GTK_TOOLBAR(widget), toolitem, -1); toolitem = gtk_tool_button_new_from_stock(GTK_STOCK_EDIT); g_signal_connect_swapped(G_OBJECT(toolitem), "clicked", G_CALLBACK( _calendar_on_edit), calendar); gtk_toolbar_insert(GTK_TOOLBAR(widget), toolitem, -1); #endif gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); /* calendar */ calendar->widget = gtk_calendar_new(); gtk_calendar_set_display_options(GTK_CALENDAR(calendar->widget), GTK_CALENDAR_SHOW_HEADING | GTK_CALENDAR_SHOW_DAY_NAMES | GTK_CALENDAR_SHOW_WEEK_NUMBERS); #if GTK_CHECK_VERSION(2, 14, 0) gtk_calendar_set_detail_height_rows(GTK_CALENDAR(calendar->widget), 1); gtk_calendar_set_detail_func(GTK_CALENDAR(calendar->widget), (GtkCalendarDetailFunc)_calendar_on_detail, calendar, NULL); #endif g_signal_connect_swapped(G_OBJECT(calendar->widget), "day-selected-double-click", G_CALLBACK( _calendar_on_edit), calendar); gtk_box_pack_start(GTK_BOX(vbox), calendar->widget, TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(calendar->window), vbox); gtk_widget_show_all(calendar->window); return calendar; } static void _new_config(Calendar * calendar) { char * filename; if((calendar->config = config_new()) == NULL) return; if((filename = _config_get_filename()) != NULL) config_load(calendar->config, filename); free(filename); } static gboolean _calendar_on_closex(gpointer data) { Calendar * calendar = data; gtk_widget_hide(calendar->window); gtk_main_quit(); return FALSE; } static void _calendar_on_today(gpointer data) { Calendar * calendar = data; gtk_calendar_select_month(GTK_CALENDAR(calendar->widget), calendar->today.tm_year, calendar->today.tm_mon); gtk_calendar_select_day(GTK_CALENDAR(calendar->widget), calendar->today.tm_mday); } #if GTK_CHECK_VERSION(2, 14, 0) static void _calendar_on_details(GtkWidget * widget, gpointer data) { Calendar * calendar = data; gboolean active; GtkCalendarDisplayOptions options; active = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON( widget)); options = gtk_calendar_get_display_options(GTK_CALENDAR( calendar->widget)); if(active) options |= GTK_CALENDAR_SHOW_DETAILS; else options &= ~GTK_CALENDAR_SHOW_DETAILS; gtk_calendar_set_display_options(GTK_CALENDAR(calendar->widget), options); } #endif #if GTK_CHECK_VERSION(2, 14, 0) static gchar * _calendar_on_detail(GtkWidget * widget, guint year, guint month, guint day, gpointer data) { Calendar * calendar = data; char * ret; char const * p; size_t i; size_t cnt; #ifdef DEBUG fprintf(stderr, "DEBUG: %s() %u/%u/%u\n", __func__, day, month, year); #endif if((p = _calendar_get_detail(calendar, year, month + 1, day)) == NULL) return NULL; /* XXX we have to escape pango markup */ for(i = 0, cnt = 0; p[i] != '\0'; i++) if(p[i] == '<') cnt++; if((ret = malloc(i + 1 + cnt * 3)) == NULL) return NULL; for(i = 0, cnt = 0; p[i] != '\0'; i++) if(p[i] != '<') ret[cnt++] = p[i]; else { ret[cnt++] = '&'; ret[cnt++] = 'l'; ret[cnt++] = 't'; ret[cnt++] = ';'; } ret[cnt] = '\0'; return ret; } #endif static void _calendar_on_edit(gpointer data) { Calendar * calendar = data; guint year; guint month; guint day; char buf[32]; char const * p; GtkWidget * dialog; GtkWidget * vbox; GtkWidget * entry; int res; dialog = gtk_dialog_new_with_buttons("Edit detail", GTK_WINDOW(calendar->window), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); #if GTK_CHECK_VERSION(2, 14, 0) vbox = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); #else vbox = GTK_DIALOG(dialog)->vbox; #endif gtk_calendar_get_date(GTK_CALENDAR(calendar->widget), &year, &month, &day); snprintf(buf, sizeof(buf), "%s%02u/%02u/%u:", "Edit detail for ", day, ++month, year); gtk_box_pack_start(GTK_BOX(vbox), gtk_label_new(buf), FALSE, TRUE, 0); entry = gtk_entry_new(); if((p = _calendar_get_detail(calendar, year, month, day)) != NULL) gtk_entry_set_text(GTK_ENTRY(entry), p); gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 0); gtk_widget_show_all(vbox); res = gtk_dialog_run(GTK_DIALOG(dialog)); if(res == GTK_RESPONSE_OK) { p = gtk_entry_get_text(GTK_ENTRY(entry)); _calendar_set_detail(calendar, year, month, day, p); } gtk_widget_destroy(dialog); } /* calendar_delete */ static void _calendar_delete(Calendar * calendar) { if(calendar->config != NULL) config_delete(calendar->config); free(calendar); } /* accessors */ /* calendar_get_detail */ static char const * _calendar_get_detail(Calendar * calendar, unsigned int year, unsigned int month, unsigned int day) { char buf[16]; snprintf(buf, sizeof(buf), "%u%02u%02u", year, month, day); return config_get(calendar->config, NULL, buf); } /* calendar_set_detail */ static int _calendar_set_detail(Calendar * calendar, unsigned int year, unsigned int month, unsigned int day, char const * detail) { int ret; char buf[16]; char * filename; #ifdef DEBUG fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, detail); #endif snprintf(buf, sizeof(buf), "%u%02u%02u", year, month, day); if(detail != NULL && detail[0] == '\0') detail = NULL; /* unset if empty */ ret = config_set(calendar->config, NULL, buf, detail); if((filename = _config_get_filename()) != NULL) ret |= config_save(calendar->config, filename); free(filename); return ret; } /* config_get_filename */ static char * _config_get_filename(void) { char * filename; char const * homedir; size_t len; if((homedir = getenv("HOME")) == NULL) homedir = g_get_home_dir(); len = strlen(homedir) + 1 + sizeof(CALENDAR_CONFIG_FILE); if((filename = malloc(len)) == NULL) return NULL; snprintf(filename, len, "%s/%s", homedir, CALENDAR_CONFIG_FILE); return filename; } /* usage */ static int _usage(void) { fputs("Usage: calendar\n", stderr); return 1; } /* main */ int main(int argc, char * argv[]) { int o; Calendar * calendar; gtk_init(&argc, &argv); while((o = getopt(argc, argv, "")) != -1) switch(o) { default: return _usage(); } calendar = _calendar_new(); gtk_main(); _calendar_delete(calendar); return 0; }