/* * gkrellm-reminder * * Copyright 2001, 2002 James Simonsen * */ /* 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 */ #if 0 /* Many deprecated functions are still used. */ #define GDK_DISABLE_DEPRECATED #define GTK_DISABLE_DEPRECATED #endif #if !defined(WIN32) #include #else #include #include #define F_RDLCK 0 #define S_IRUSR 0 #define S_IWUSR 0 #define S_IXUSR 0 #define F_WRLCK 0 #endif #include static gchar *str_title = "gkrellm-reminder"; static gchar *str_version = "2.0.0"; static gchar *str_date = "12/3/2002"; static gchar *str_copyright = "Copyright (c) 2001, 2002"; static gchar *str_author = "James Simonsen"; static gchar *str_email = "simonjam@ucs.orst.edu"; static gchar *str_url = "http://www.engr.orst.edu/~simonsen/reminder/"; static gchar *str_gpl = "Released under the GNU Public License"; #include "calendar.xpm" #define STYLE_NAME "reminder" /* Theme subdirectory name and gkrellmrc */ /* style name. */ #define CONFIG_NAME "gkrellm-reminder" #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) long bsd_timezone = 0; # define TIMEZONE_DIFF ( bsd_timezone ) #else # define TIMEZONE_DIFF ( timezone ) #endif #define SECS_PER_DAY (86400) #define SECS_PER_HOUR (3600) #define SECS_PER_MIN (60) #define FOREVER (0) static struct reminder_config { gint remind_early; gint remind_early_diff; guint list_sort; guint alert; gboolean remind_old; gboolean delete_old; gboolean ampm; gboolean mdy; gchar *notify; gchar *event_file; } config; struct event_stored { gchar *name; guint id; gint days; gint occurs; time_t start; time_t end; time_t last_displayed; struct event_stored *next; }; struct event_today { gchar *name; guint id; time_t occurs; gboolean last; struct event_today *next; }; struct id_list { guint id; struct id_list *next; }; enum { OPT_DAILY = 0, OPT_WEEKLY = 1, OPT_MONTHLY = 2 }; enum { ALERT_FLASH = 1, ALERT_POPUP = 2, ALERT_EXECUTE = 4 }; static struct event_today event_active; static struct event_today *head_today; static struct event_today *last_active; static struct event_stored *head_stored; static struct event_stored *head_temp; static struct id_list *head_delete; static GkrellmMonitor *reminder_mon; static GkrellmPanel *panel; static GkrellmDecal *reminder_icon_decal; static GkrellmDecal *reminder_text_decal; static GkrellmDecalbutton *reminder_text_button; static GkrellmPiximage *reminder_icon_image; static gint style_id; static GkrellmTicks *pGK; static gint num_active, num_today; static glong today_day; /* Calendar window */ static GtkWidget *hbox_date; static GtkWidget *hbox_start; static GtkWidget *hbox_end; static GtkWidget *notebook_occurs; static GtkWidget *entry_event; static GtkWidget *radio_daily; static GtkWidget *radio_weekly; static GtkWidget *radio_monthly; static GtkWidget *spin_days; static GtkWidget *spin_weeks; static GtkWidget *spin_months; static GtkWidget *spin_daymonth; static GtkWidget *check_sun; static GtkWidget *check_mon; static GtkWidget *check_tue; static GtkWidget *check_wed; static GtkWidget *check_thu; static GtkWidget *check_fri; static GtkWidget *check_sat; static GtkWidget *spin_start_month; static GtkWidget *spin_start_day; static GtkWidget *spin_start_year; static GtkWidget *spin_end_month; static GtkWidget *spin_end_day; static GtkWidget *spin_end_year; static GtkWidget *spin_time_hour; static GtkWidget *spin_time_minute; static GtkObject *adj_time_hour; static GtkWidget *check_forever; static GtkWidget *button_ampm; static GtkWidget *label_ampm; static GtkWidget *button_remove; static GtkWidget *button_update; static GtkWidget *list_main; static gint occurs_option; static gint list_main_row_selected; static struct tm tm_input; static gboolean is_pm; /* Reminder window */ static GtkWidget *window_reminder; static GtkWidget *spin_minutes; /* Config window */ static GtkWidget *spin_remind_early; static GtkWidget *check_remind_old; static GtkWidget *check_delete_old; static GtkWidget *check_alert_flash; static GtkWidget *check_alert_popup; static GtkWidget *check_alert_execute; static GtkWidget *radio_12hour; static GtkWidget *radio_24hour; static GtkWidget *radio_mdy; static GtkWidget *radio_dmy; static GtkWidget *entry_notify; /* Today window */ static GtkWidget *window_today; static const gchar *str_delayed = "(Delayed) "; static const gchar *str_null; static const gchar *str_12hour = "%I:%M %p"; static const gchar *str_24hour = "%H:%M"; static const gchar *str_mdy = "%a %b %d %Y"; static const gchar *str_dmy = "%a %d %b %Y"; /* necessary prototypes */ static void reminder_display_reminder( void ); static int reminder_lock_db( FILE *fp, int type ) { #if !defined(WIN32) struct flock lock; lock.l_type = type; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; return fcntl( fileno( fp ), F_SETLKW, &lock ); #else return 0; #endif } static int reminder_unlock_db( FILE *fp ) { #if !defined(WIN32) struct flock lock; lock.l_type = F_UNLCK; lock.l_start = 0; lock.l_whence = SEEK_SET; lock.l_len = 0; return fcntl( fileno( fp ), F_SETLK, &lock ); #else return 0; #endif } static void reminder_free_id_list() { struct id_list *current, *next; current = head_delete; while( current ) { next = current->next; free( current ); current = next; } head_delete = NULL; } static void reminder_free_stored( struct event_stored **head_list ) { struct event_stored *current, *next; current = *head_list; while( current ) { next = current->next; g_free( current->name ); free( current ); current = next; } *head_list = NULL; } static void reminder_load_stored() { FILE *fp; gchar buffer[1024]; struct event_stored *current, *tail = NULL; if( head_stored ) return; fp = fopen( config.event_file, "r" ); if( !fp ) return; /* User hasn't saved any events yet */ if( reminder_lock_db( fp, F_RDLCK ) ) { gkrellm_message_window( str_title, "ERROR: Unable to lock event database for reading.", NULL ); return; } while( fscanf( fp, "%[^\n]\n", buffer ) ) { current = malloc( sizeof( struct event_stored ) ); if( !current ) break; // current->name = malloc( strlen( buffer ) + 1 ); // if( !current->name ) // { // free( current ); // break; // } // strcpy( current->name, buffer ); current->name = g_strdup(buffer); if( fscanf( fp, "%u %d %d %ld %ld %ld\n", ¤t->id, ¤t->days, ¤t->occurs, ¤t->start, ¤t->end, ¤t->last_displayed ) != 6 ) { g_free( current->name ); free( current ); break; } if( current->occurs == TRUE && current->days >> 16 == 0 ) { current->occurs = OPT_WEEKLY; current->days |= 1 << 16; } current->next = NULL; if( head_stored ) tail->next = current; else head_stored = current; tail = current; } reminder_unlock_db( fp ); fclose( fp ); } static void reminder_save_stored() { FILE *fp; struct event_stored *current; fp = fopen( config.event_file, "a" ); /* "a" cuz we don't want to delete everything before we get the write lock */ if( !fp ) { if( errno == ENOENT ) { char *dir; char *slash; dir = malloc( strlen( config.event_file ) ); if( !dir ) return; strcpy( dir, config.event_file ); slash = strrchr( dir, '/' ); if( !slash ) { gkrellm_message_window( str_title, "ERROR: Unable to create event database.", NULL ); return; } *slash = '\0'; #if !defined(WIN32) mkdir( dir, S_IRUSR | S_IWUSR | S_IXUSR ); #else mkdir(dir); #endif fp = fopen( config.event_file, "w" ); if( !fp ) { gkrellm_message_window( str_title, "ERROR: Unable to open event database for writing.", NULL ); return; } } else { gkrellm_message_window( str_title, "ERROR: Unable to open event database for writing.", NULL ); return; } } if( reminder_lock_db( fp, F_WRLCK ) ) { gkrellm_message_window( str_title, "ERROR: Unable to lock event database for writing.", NULL ); return; } #if defined(WIN32) // win32 can't lock the file, so just overwrite it fclose(fp); fopen( config.event_file, "w" ); #else if( ftruncate( fileno( fp ), 0 ) ) { gkrellm_message_window( str_title, "ERROR: Unable to truncate event database.", NULL ); return; } #endif current = head_stored; while( current ) { fprintf( fp, "%s\n%u %d %d %ld %ld %ld\n", current->name, current->id, current->days, current->occurs, current->start, current->end, current->last_displayed ); current = current->next; } reminder_unlock_db( fp ); fclose( fp ); } static void reminder_remove_event_today( guint id ) { struct event_today *current, *temp; if( !head_today ) return; if( head_today->id == id ) { temp = head_today->next; g_free( head_today->name ); free( head_today ); head_today = temp; } else { current = head_today; while( current->next ) { if( current->next->id == id ) { temp = current->next->next; g_free( current->next->name ); free( current->next ); current->next = temp; break; } current = current->next; } } } static gboolean reminder_remove_event_stored( struct event_stored **head_list, guint id ) { struct event_stored *current, *temp; if( !*head_list ) reminder_load_stored(); if( !*head_list ) return FALSE; if( (*head_list)->id == id ) { temp = (*head_list)->next; g_free( (*head_list)->name ); free( *head_list ); *head_list = temp; return TRUE; } else { current = *head_list; while( current->next ) { if( current->next->id == id ) { temp = current->next->next; g_free( current->next->name ); free( current->next ); current->next = temp; return TRUE; } current = current->next; } } return FALSE; } static struct event_stored * reminder_find_event_stored( struct event_stored *head_list, guint id ) { struct event_stored *current; current = head_list; while( current ) { if( current->id == id ) return current; current = current->next; } return NULL; } static void reminder_free_today() { struct event_today *current, *next; current = head_today; while( current ) { next = current->next; g_free( current->name ); free( current ); current = next; } head_today = NULL; } static struct event_today * reminder_merge_sort( struct event_today *list ) { struct event_today *l, *r, *start_l, *start_r, *tail, *start; gboolean use_l = TRUE; if( !list || !list->next ) return list; l = NULL; r = NULL; start = NULL; start_l = NULL; start_r = NULL; while( list ) { if( use_l ) { if( l ) { l->next = list; l = l->next; } else start_l = l = list; } else { if( r ) { r->next = list; r = r->next; } else start_r = r = list; } list = list->next; use_l = !use_l; } l->next = NULL; r->next = NULL; l = reminder_merge_sort( start_l ); r = reminder_merge_sort( start_r ); tail = NULL; while( l && r ) { if( l->occurs < r->occurs ) { if( tail ) { tail->next = l; tail = tail->next; } else start = tail = l; l = l->next; } else { if( tail ) { tail->next = r; tail = tail->next; } else start = tail = r; r = r->next; } } while( l ) { if( tail ) { tail->next = l; tail = tail->next; } else start = tail = l; l = l->next; } while( r ) { if( tail ) { tail->next = r; tail = tail->next; } else start = tail = r; r = r->next; } tail->next = NULL; return start; } static void reminder_add_event_today( struct event_today **list, struct event_today *new, struct event_today *tail ) { if( !(*list) ) { *list = new; } else if( tail ) { tail->next = new; } else { struct event_today *current = *list; while( current->next ) current = current->next; current->next = new; } } static struct event_today * reminder_create_event_today( struct event_stored *stored, struct tm *tm_stored, gboolean last, gboolean is_tomorrow ) { struct event_today *new; struct tm tm_new; new = malloc( sizeof( struct event_today ) ); if( !new ) return NULL; // new->name = malloc( strlen( stored->name ) + 1 ); // if( !new->name ) // return NULL; //strcpy( new->name, stored->name ); new->name = g_strdup(stored->name); memcpy( &tm_new, gkrellm_get_current_time(), sizeof( tm_new ) ); tm_new.tm_mday += is_tomorrow ? 1 : 0; tm_new.tm_hour = tm_stored->tm_hour; tm_new.tm_min = tm_stored->tm_min - config.remind_early; tm_new.tm_sec = 0; tm_new.tm_isdst = -1; new->occurs = mktime( &tm_new ); new->id = stored->id; new->last = last; new->next = NULL; return new; } static struct event_today * reminder_weed_today( time_t now ) { struct event_today *current, *next, *tail, *weed; if( !head_today ) return NULL; weed = NULL; tail = NULL; head_today->occurs += config.remind_early_diff * SECS_PER_MIN; if( ( now < head_today->occurs ) || ( now > head_today->occurs + config.remind_early * SECS_PER_MIN && config.remind_old ) ) { weed = head_today; head_today = NULL; } else { num_active = 1; num_today = 1; tail = current = head_today; while( current->next ) { next = current->next; current->next->occurs += config.remind_early_diff; if( ( now < current->next->occurs ) || ( now > current->next->occurs + config.remind_early * SECS_PER_MIN && config.remind_old ) ) { current->next = NULL; weed = next; break; } else { tail = next; num_active++; num_today++; } current = next; } } while( weed ) { next = weed->next; g_free( weed->name ); free( weed ); weed = next; } return tail; } static void reminder_notify() { gchar *cmd; if( !config.notify ) return; // cmd = malloc( strlen( config.notify ) + 2 + 1 ); // if( !cmd ) // return; // strcpy( cmd, config.notify ); // strcpy( cmd + strlen( cmd ), " &" ); cmd = g_strdup_printf("%s &", config.notify); // gkrellm_system( cmd ); g_spawn_command_line_async(cmd, NULL); g_free( cmd ); } static void reminder_check_new_active( struct event_today *list, struct event_today *active, time_t now ) { gint num_old_active = num_active; struct event_today *current; if( active ) current = active->next; else current = list; while( current && current->occurs <= now ) { num_active++; active = current; current = current->next; } last_active = active; if( num_active != num_old_active ) { if( config.alert & ALERT_POPUP ) reminder_display_reminder(); if( config.alert & ALERT_EXECUTE ) reminder_notify(); } } static void reminder_build_today( gboolean rebuild ) { time_t time_today; struct tm tm_today, tm_current, tm_start; struct event_stored *current, *next; struct event_today *new_today, *tail; long day_today, day_current, day_start, day_end, day_last_displayed; int secs_today, secs_start; gboolean is_today, is_tomorrow; int time_case, i; tail = NULL; last_active = NULL; num_today = 0; num_active = 0; /* Get current time */ memcpy( &tm_today, gkrellm_get_current_time(), sizeof( tm_today ) ); time_today = mktime( &tm_today ); day_today = ( time_today - TIMEZONE_DIFF ) / SECS_PER_DAY; secs_today = ( time_today - TIMEZONE_DIFF ) % SECS_PER_DAY; if( head_today ) { /* Don't delete old items if we're rebuilding */ if( rebuild ) tail = reminder_weed_today( time_today ); else reminder_free_today(); } current = head_stored; while( current ) { next = current->next; if( rebuild && strstr( current->name, str_delayed ) ) current->start += config.remind_early_diff * SECS_PER_MIN; memcpy( &tm_start, localtime( ¤t->start ), sizeof( tm_start ) ); day_start = ( current->start - TIMEZONE_DIFF ) / SECS_PER_DAY; day_end = ( current->end - TIMEZONE_DIFF ) / SECS_PER_DAY; day_last_displayed = ( current->last_displayed - TIMEZONE_DIFF ) / SECS_PER_DAY; day_current = 0; secs_start = ( current->start - TIMEZONE_DIFF ) % SECS_PER_DAY; is_today = is_tomorrow = FALSE; /* is_tomorrow handles remind_early wrapping midnight */ if( day_start <= day_today && ( day_today <= day_end || current->end == FOREVER ) ) { is_today = TRUE; day_current = day_today; } else if( secs_start < config.remind_early * SECS_PER_MIN && day_start <= day_today+1 && ( day_today+1 <= day_end || current->end == FOREVER ) ) { is_tomorrow = TRUE; day_current = day_today + 1; } /* * 1) Event happens well in the future * 2) Event happens in future, but we've already past the remind_early time * 3) Event happened in the past */ if( secs_today > secs_start ) time_case = 3; else if( secs_today < secs_start - config.remind_early * SECS_PER_MIN ) time_case = 1; else time_case = 2; if( ( is_today && time_case == 1 ) || ( is_today && time_case == 2 && !rebuild && day_last_displayed < day_current ) || ( is_today && time_case == 2 && rebuild && day_last_displayed == 0 ) || ( is_today && time_case == 3 && config.remind_old && day_last_displayed < day_current ) || ( is_tomorrow ) ) { if( !current->last_displayed ) current->last_displayed = 10 * SECS_PER_DAY; memcpy( &tm_current, localtime( ¤t->start ), sizeof( tm_current ) ); if( current->occurs == OPT_DAILY ) { if( ( day_current - day_start ) % current->days == 0 ) { new_today = reminder_create_event_today( current, &tm_current, day_end == day_current, is_tomorrow); reminder_add_event_today( &head_today, new_today, tail ); tail = new_today; num_today++; } } else if( current->occurs == OPT_WEEKLY ) { if( ( 1 << tm_today.tm_wday ) & current->days && ( ( day_today - ( day_start - tm_start.tm_wday ) ) / 7 ) % ( current->days >> 16 ) == 0 ) { new_today = reminder_create_event_today( current, &tm_current, day_end == day_current, is_tomorrow ); reminder_add_event_today( &head_today, new_today, tail ); tail = new_today; num_today++; } } else if( current->occurs == OPT_MONTHLY ) { if( ( tm_today.tm_mon - tm_start.tm_mon ) % ( current->days >> 16 ) == 0 && tm_today.tm_mday == ( current->days & 31 ) ) { new_today = reminder_create_event_today( current, &tm_current, day_end == day_current, is_tomorrow ); reminder_add_event_today( &head_today, new_today, tail ); tail = new_today; num_today++; } } } else if( config.delete_old && day_end <= day_today && current->end != FOREVER ) { reminder_remove_event_stored( &head_stored, current->id ); } current = next; } head_today = reminder_merge_sort( head_today ); for( i = 0; i < num_active; i++ ) { if( last_active ) last_active = last_active->next; else last_active = head_today; } reminder_save_stored(); reminder_free_stored( &head_stored ); reminder_check_new_active( head_today, last_active, time_today ); } static void cb_set_days( GtkWidget *window, gpointer data ) { gint weekdays = (gint) data & 1; gint weekends = (gint) data & 2; gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_sun ), weekends ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_sat ), weekends ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_mon ), weekdays ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_tue ), weekdays ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_wed ), weekdays ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_thu ), weekdays ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_fri ), weekdays ); } static void cb_select_radio( GtkWidget *window, gpointer data ) { gint option = -1; /* Figure out which one is selected */ if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( radio_daily ) ) ) option = OPT_DAILY; else if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( radio_weekly ) ) ) option = OPT_WEEKLY; else if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( radio_monthly ) ) ) option = OPT_MONTHLY; if( occurs_option == option ) return; gtk_notebook_set_page( GTK_NOTEBOOK( notebook_occurs ), option ); occurs_option = option; } static gchar * reminder_get_days_string( struct event_stored *current ) { gchar *string = NULL; gchar *string2; // string = malloc( 37 ); // if( !string ) // return NULL; if( current->occurs == OPT_DAILY ) { if( current->days == 1 ) //sprintf( string, "Everyday" ); string = g_strdup_printf("Everyday"); else //sprintf( string, "Every %d days", current->days ); string = g_strdup_printf("Every %d days", current->days); } else if( current->occurs == OPT_WEEKLY ) { int weeks = current->days >> 16; int days = current->days & 127; if( days == 127 ) { //pos = sprintf( string, "Everyday" ); string = g_strdup_printf("Everyday"); } else if( days == 62 ) { //pos = sprintf( string, "Every weekday" ); string = g_strdup_printf("Every weekday"); } else if( days == 65 ) { //pos = sprintf( string, "Every weekend" ); string = g_strdup_printf("Every weekend"); } else { //pos = sprintf( string, "%s%s%s%s%s%s%s", string = g_strdup_printf("%s%s%s%s%s%s%s", current->days & 1 ? "Sun " : str_null, current->days & 2 ? "Mon " : str_null, current->days & 4 ? "Tue " : str_null, current->days & 8 ? "Wed " : str_null, current->days & 16 ? "Thu " : str_null, current->days & 32 ? "Fri " : str_null, current->days & 64 ? "Sat" : str_null ); } if( weeks > 1 ) //sprintf( string + pos, "; Every %d weeks", weeks ); { string2 = g_strdup_printf("; Every %d weeks", weeks ); g_strconcat(string, string2, NULL); g_free(string2); } } else if( current->occurs == OPT_MONTHLY ) { int day = current->days & 31; int month = current->days >> 16; if( day % 10 == 1 ) //pos = sprintf( string, "%dst", day ); string = g_strdup_printf("%dst", day ); else if( day % 10 == 2 ) //pos = sprintf( string, "%dnd", day ); string = g_strdup_printf("%dnd", day ); else if( day % 10 == 3 ) //pos = sprintf( string, "%drd", day ); string = g_strdup_printf("%drd", day ); else //pos = sprintf( string, "%dth", day ); string = g_strdup_printf("%dth", day ); if( month == 1 ) { //sprintf( string + pos, " of every month" ); string2 = g_strdup_printf(" of every month" ); g_strconcat(string, string2, NULL); g_free(string2); } else { //sprintf( string + pos, " of every %d months", month ); string2 = g_strdup_printf(" of every %d months", month ); g_strconcat(string, string2, NULL); g_free(string2); } } return string; } static struct event_stored * reminder_ui_to_event_stored( struct event_stored *current ) { gchar *name; name = (gchar *) gtk_entry_get_text( GTK_ENTRY( entry_event ) ); if( strlen( name ) < 1 ) { gkrellm_message_window( str_title, "ERROR: You must enter a name for this event.", entry_event ); return NULL; } // current->name = malloc( strlen( name ) ); // if( !current->name ) // return NULL; current->name = g_strdup(name ); tm_input.tm_mon = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_month ) ) - 1; tm_input.tm_mday = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_day ) ); tm_input.tm_year = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_year ) ) - 1900; tm_input.tm_hour = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_time_hour ) ); tm_input.tm_min = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_time_minute ) ); tm_input.tm_sec = 0; tm_input.tm_isdst = -1; if( config.ampm ) { if( tm_input.tm_hour == 12 ) tm_input.tm_hour = 0; if( is_pm ) tm_input.tm_hour += 12; } current->start = mktime( &tm_input ); if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_forever ) ) ) { current->end = FOREVER; } else { tm_input.tm_mon = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_month ) ) - 1; tm_input.tm_mday = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_day ) ); tm_input.tm_year = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_year ) ) - 1900; tm_input.tm_hour = 23; tm_input.tm_min = 59; tm_input.tm_sec = 59; tm_input.tm_isdst = -1; current->end = mktime( &tm_input ); } if( current->end < current->start && current->end != FOREVER ) { gkrellm_message_window( str_title, "ERROR: End date can't be smaller than start date.", spin_start_day ); g_free( current->name ); return NULL; } current->occurs = occurs_option; if( occurs_option == OPT_DAILY ) { current->days = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_days ) ); } else if( occurs_option == OPT_WEEKLY ) { current->days = 0; current->days |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_sun ) ) ? 1 : 0; current->days |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_mon ) ) ? 2 : 0; current->days |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_tue ) ) ? 4 : 0; current->days |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_wed ) ) ? 8 : 0; current->days |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_thu ) ) ? 16 : 0; current->days |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_fri ) ) ? 32 : 0; current->days |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_sat ) ) ? 64 : 0; if( !current->days ) { gkrellm_message_window( str_title, "ERROR: You must select at least one day.", check_sun ); g_free( current->name ); return NULL; } current->days |= gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_weeks ) ) << 16; } else if( occurs_option == OPT_MONTHLY ) { current->days = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_daymonth ) ) | gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_months ) ) << 16; } return current; } static void cb_add_entry( struct event_stored *event, gint row ) { gchar *array[] = { NULL, NULL, NULL, NULL, NULL }; time_t real_start; array[2] = malloc( 9 ); array[3] = malloc( 50 ); array[4] = malloc( 50 ); if( !array[2] || !array[3] || !array[4] ) return; real_start = event->start; if( strstr( event->name, str_delayed ) ) real_start -= config.remind_early * SECS_PER_MIN; array[0] = event->name; array[1] = reminder_get_days_string( event ); if( config.ampm ) strftime( array[2], 9, str_12hour, localtime( &real_start ) ); else strftime( array[2], 9, str_24hour, localtime( &real_start ) ); strftime( array[3], 50, config.mdy ? str_mdy : str_dmy, localtime( &real_start ) ); if( event->end == FOREVER ) strcpy( array[4], "Never" ); else strftime( array[4], 50, config.mdy ? str_mdy : str_dmy, localtime( &event->end ) ); if( row == -1 ) { row = gtk_clist_append( GTK_CLIST( list_main ), array ); gtk_clist_set_row_data( GTK_CLIST( list_main ), row, (gpointer) event->id ); } else { gtk_clist_insert( GTK_CLIST( list_main ), row, array ); gtk_clist_set_row_data( GTK_CLIST( list_main ), row, (gpointer) event->id ); } gtk_clist_columns_autosize( GTK_CLIST( list_main ) ); if( array[1] ) g_free( array[1] ); if( array[2] ) free( array[2] ); if( array[3] ) free( array[3] ); if( array[4] ) free( array[4] ); } static void cb_populate() { struct event_stored *current; gtk_clist_clear( GTK_CLIST( list_main ) ); if( !head_stored ) reminder_load_stored(); current = head_stored; while( current ) { cb_add_entry( current, -1 ); current = current->next; } current = head_temp; while( current ) { cb_add_entry( current, -1 ); current = current->next; } } static void reminder_add_event_stored( struct event_stored **list, struct event_stored *new, struct event_stored *tail ) { struct event_stored *current; if( !new ) return; if( !(*list) ) { *list = new; } else if( tail ) { tail->next = new; } else { current = *list; while( current->next ) current = current->next; current->next = new; } new->next = NULL; } static void cb_add( GtkWidget *window, gpointer data ) { guint id; struct event_stored *current, *tail; id = (guint) time( NULL ); tail = head_temp; if( tail ) { if( tail->id == id ) return; while( tail->next ) { if( tail->id == id ) return; tail = tail->next; } } current = malloc( sizeof( struct event_stored ) ); if( !current ) return; if( !reminder_ui_to_event_stored( current ) ) { free( current ); return; } current->id = id; current->next = NULL; current->last_displayed = 0; reminder_add_event_stored( &head_temp, current, tail ); cb_add_entry( current, -1 ); } static void cb_remove( GtkWidget *window, gpointer data ) { struct id_list *current; guint id; if( list_main_row_selected == -1 ) return; id = (guint) gtk_clist_get_row_data( GTK_CLIST( list_main ), list_main_row_selected ); /* Try to remove event from temp list. If not, add to to-be-deleted list */ if( !reminder_remove_event_stored( &head_temp, id ) ) { if( head_delete ) { current = head_delete; while( current->next ) current = current->next; current->next = malloc( sizeof( struct id_list ) ); if( !current->next ) return; current = current->next; } else { current = head_delete = malloc( sizeof( struct id_list ) ); if( !current ) return; } current->id = id; current->next = NULL; } gtk_clist_remove( GTK_CLIST( list_main ), list_main_row_selected ); } static void cb_update( GtkWidget *window, gpointer data ) { if( list_main_row_selected == -1 ) return; cb_remove( window, data ); cb_add( window, data ); } static void cb_reset( GtkWidget *widget, gpointer data ) { gtk_entry_set_text( GTK_ENTRY( entry_event ), str_null ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_daily ), TRUE ); cb_set_days( widget, 0 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_days ), 1 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_weeks ), 1 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_months ), 1 ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_daily ), TRUE ); memcpy( &tm_input, gkrellm_get_current_time(), sizeof( tm_input ) ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_start_month ), tm_input.tm_mon+1 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_start_day ), tm_input.tm_mday ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_start_year ), tm_input.tm_year+1900 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_end_month ), tm_input.tm_mon+1 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_end_day ), tm_input.tm_mday ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_end_year ), tm_input.tm_year+1900 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_daymonth ), tm_input.tm_mday ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_forever ), FALSE ); is_pm = tm_input.tm_hour >= 12; if( config.ampm ) { gint val = tm_input.tm_hour; if( is_pm ) val -= 12; if( val == 0 ) val = 12; gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_time_hour ), val ); } else gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_time_hour ), tm_input.tm_hour ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_time_minute ), tm_input.tm_min ); gtk_label_set_text( GTK_LABEL( label_ampm ), is_pm ? "PM" : "AM" ); } static void cb_row_select( GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data) { struct event_stored *current; struct tm tm_event; list_main_row_selected = row; gtk_widget_set_sensitive( GTK_WIDGET( button_remove ), TRUE ); gtk_widget_set_sensitive( GTK_WIDGET( button_update ), TRUE ); if( !head_stored ) reminder_load_stored(); current = reminder_find_event_stored( head_stored, (glong) gtk_clist_get_row_data( GTK_CLIST( list_main ), row ) ); if( !current ) { current = reminder_find_event_stored( head_temp, (glong) gtk_clist_get_row_data( GTK_CLIST( list_main ), row ) ); if( !current ) return; } gtk_entry_set_text( GTK_ENTRY( entry_event ), current->name ); if( current->occurs == OPT_DAILY ) { gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_daily ), TRUE ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_days ), current->days ); } else if( current->occurs == OPT_WEEKLY ) { gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_weekly ), TRUE); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_sun ), current->days & 1 ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_mon ), current->days & 2 ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_tue ), current->days & 4 ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_wed ), current->days & 8 ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_thu ), current->days & 16 ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_fri ), current->days & 32 ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_sat ), current->days & 64 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_weeks ), current->days >> 16 ); } else if( current->occurs == OPT_MONTHLY ) { gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_monthly ), TRUE ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_daymonth ), current->days & 31 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_months ), current->days >> 16 ); } memcpy( &tm_event, localtime( ¤t->start ), sizeof( tm_event ) ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_start_month ), tm_event.tm_mon + 1 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_start_day ), tm_event.tm_mday ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_start_year ), tm_event.tm_year + 1900 ); is_pm = tm_event.tm_hour >= 12; if( config.ampm ) { gint val = tm_event.tm_hour; if( is_pm ) val -= 12; if( val == 0 ) val = 12; gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_time_hour ), val ); } else gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_time_hour ), tm_event.tm_hour ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_time_minute ), tm_event.tm_min ); gtk_label_set_text( GTK_LABEL( label_ampm ), is_pm ? "PM" : "AM" ); if( current->end == FOREVER ) { gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_forever ), TRUE ); } else { gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_forever ), FALSE ); memcpy( &tm_event, localtime( ¤t->end ), sizeof( tm_event ) ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_end_month ), tm_event.tm_mon + 1 ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_end_day ), tm_event.tm_mday ); gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_end_year ), tm_event.tm_year + 1900 ); } } static void cb_row_unselect( GtkWidget *widget, gint row, gint column, GdkEventButton *event, gpointer data) { if( list_main_row_selected == row ) { list_main_row_selected = -1; gtk_widget_set_sensitive( GTK_WIDGET( button_remove ), FALSE ); gtk_widget_set_sensitive( GTK_WIDGET( button_update ), FALSE ); } } static void cb_clamp_date( gboolean isStart ) { gint month, year, day; GtkAdjustment *adj; if( isStart ) { month = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_month ) ); year = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_year ) ); adj = gtk_spin_button_get_adjustment( GTK_SPIN_BUTTON( spin_start_day ) ); } else { month = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_month ) ); year = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_year ) ); adj = gtk_spin_button_get_adjustment( GTK_SPIN_BUTTON( spin_end_day ) ); } if( month == 2 ) { if( ( year % 400 == 0 ) || ( year % 100 != 0 && year % 4 == 0 ) ) day = 29; else day = 28; } else if( ( month <= 7 && month % 2 == 1 ) || ( month >= 8 && month % 2 == 0 ) ) day = 31; else day = 30; adj->upper = day; if( adj->value > day ) adj->value = day; if( isStart ) gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON( spin_start_day ), GTK_ADJUSTMENT( adj ) ); else gtk_spin_button_set_adjustment( GTK_SPIN_BUTTON( spin_end_day ), GTK_ADJUSTMENT( adj ) ); } static void cb_date_changed( GtkWidget *widget, gpointer data ) { if( data == spin_start_month || data == spin_start_year ) cb_clamp_date( TRUE ); else if( data == spin_end_month || data == spin_end_year ) cb_clamp_date( FALSE ); if( data == spin_start_month && gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_year ) ) == gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_year ) ) && gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_month ) ) > gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_month ) ) ) { gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_end_month ), gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_month ) ) ); } else if( data == spin_start_day && gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_year ) ) == gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_year ) ) && gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_month ) ) == gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_month ) ) && gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_day ) ) > gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_day ) ) ) { gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_end_day ), gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_day ) ) ); } else if( data == spin_start_year && gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_year ) ) > gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_end_year ) ) ) { gtk_spin_button_set_value( GTK_SPIN_BUTTON( spin_end_year ), gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_start_year ) ) ); } } static gint cb_sort_days( GtkCList *clist, gconstpointer *p1, gconstpointer *p2 ) { GtkCListRow *row1 = (GtkCListRow *) p1; GtkCListRow *row2 = (GtkCListRow *) p2; struct event_stored *es1, *es2; es1 = reminder_find_event_stored( head_stored, (guint) row1->data ); if( !es1 ) es1 = reminder_find_event_stored( head_temp, (guint) row1->data ); es2 = reminder_find_event_stored( head_stored, (guint) row2->data ); if( !es2 ) es2 = reminder_find_event_stored( head_temp, (guint) row2->data ); if( es1 && es2 ) { if( es1->occurs != es2->occurs ) { return es1->occurs - es2->occurs; } else { return es1->days - es2->days; } } else return 0; } static gint cb_sort_time( GtkCList *clist, gconstpointer *p1, gconstpointer *p2 ) { GtkCListRow *row1 = (GtkCListRow *) p1; GtkCListRow *row2 = (GtkCListRow *) p2; struct event_stored *es1, *es2; es1 = reminder_find_event_stored( head_stored, (guint) row1->data ); if( !es1 ) es1 = reminder_find_event_stored( head_temp, (guint) row1->data ); es2 = reminder_find_event_stored( head_stored, (guint) row2->data ); if( !es2 ) es2 = reminder_find_event_stored( head_temp, (guint) row2->data ); if( es1 && es2 ) return( ( ( es1->start - TIMEZONE_DIFF ) % SECS_PER_DAY ) - ( ( es2->start - TIMEZONE_DIFF ) % SECS_PER_DAY ) ); else return 0; } static gint cb_sort_start( GtkCList *clist, gconstpointer *p1, gconstpointer *p2 ) { GtkCListRow *row1 = (GtkCListRow *) p1; GtkCListRow *row2 = (GtkCListRow *) p2; struct event_stored *es1, *es2; es1 = reminder_find_event_stored( head_stored, (guint) row1->data ); if( !es1 ) es1 = reminder_find_event_stored( head_temp, (guint) row1->data ); es2 = reminder_find_event_stored( head_stored, (guint) row2->data ); if( !es2 ) es2 = reminder_find_event_stored( head_temp, (guint) row2->data ); if( es1 && es2 ) return es1->start - es2->start; else return 0; } static gint cb_sort_end( GtkCList *clist, gconstpointer *p1, gconstpointer *p2 ) { GtkCListRow *row1 = (GtkCListRow *) p1; GtkCListRow *row2 = (GtkCListRow *) p2; struct event_stored *es1, *es2; es1 = reminder_find_event_stored( head_stored, (guint) row1->data ); if( !es1 ) es1 = reminder_find_event_stored( head_temp, (guint) row1->data ); es2 = reminder_find_event_stored( head_stored, (guint) row2->data ); if( !es2 ) es2 = reminder_find_event_stored( head_temp, (guint) row2->data ); if( es1 && es2 ) return es1->end - es2->end; else return 0; } static void cb_sort() { /* 0: GTK_SORT_ASCENDING 1: GTK_SORT_DESCENDING 2: name 4: days 8: time 16: start 32: end */ if( config.list_sort & 1 ) gtk_clist_set_sort_type( GTK_CLIST( list_main ), GTK_SORT_DESCENDING ); else gtk_clist_set_sort_type( GTK_CLIST( list_main ), GTK_SORT_ASCENDING ); if( config.list_sort & 2 ) { gtk_clist_set_sort_column( GTK_CLIST( list_main ), 0 ); gtk_clist_set_compare_func( GTK_CLIST( list_main ), NULL ); } else if( config.list_sort & 4 ) { gtk_clist_set_sort_column( GTK_CLIST( list_main ), 1 ); gtk_clist_set_compare_func( GTK_CLIST( list_main ), (GtkCListCompareFunc) cb_sort_days ); } else if( config.list_sort & 8 ) { gtk_clist_set_sort_column( GTK_CLIST( list_main ), 1 ); gtk_clist_set_compare_func( GTK_CLIST( list_main ), (GtkCListCompareFunc) cb_sort_time ); } else if( config.list_sort & 16 ) { gtk_clist_set_sort_column( GTK_CLIST( list_main ), 2 ); gtk_clist_set_compare_func( GTK_CLIST( list_main ), (GtkCListCompareFunc) cb_sort_start ); } else if( config.list_sort & 32 ) { gtk_clist_set_sort_column( GTK_CLIST( list_main ), 3 ); gtk_clist_set_compare_func( GTK_CLIST( list_main ), (GtkCListCompareFunc) cb_sort_end ); } gtk_clist_sort( GTK_CLIST( list_main ) ); } static void cb_column_click( GtkWidget *widget, gint column, gpointer data ) { column = 1 << ( column + 1 ); if( config.list_sort & column ) { if( config.list_sort & 1 ) config.list_sort &= ~1; else config.list_sort |= 1; } else { config.list_sort = column; } cb_sort(); } static void cb_ampm_clicked( GtkWidget *window, gpointer data ) { is_pm = !is_pm; gtk_label_set_text( GTK_LABEL( label_ampm ), is_pm ? "PM" : "AM" ); } static void cb_reorder_date() { if( config.mdy ) { gtk_box_reorder_child( GTK_BOX( hbox_start ), spin_start_month, 1 ); gtk_box_reorder_child( GTK_BOX( hbox_end ), spin_end_month, 1 ); } else { gtk_box_reorder_child( GTK_BOX( hbox_start ), spin_start_month, 2 ); gtk_box_reorder_child( GTK_BOX( hbox_end ), spin_end_month, 2 ); } } static void cb_forever( GtkWidget *window, gpointer data ) { if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_forever ) ) ) { gtk_widget_set_sensitive( spin_end_month, FALSE ); gtk_widget_set_sensitive( spin_end_day, FALSE ); gtk_widget_set_sensitive( spin_end_year, FALSE ); } else { gtk_widget_set_sensitive( spin_end_month, TRUE ); gtk_widget_set_sensitive( spin_end_day, TRUE ); gtk_widget_set_sensitive( spin_end_year, TRUE ); } } static GtkWidget * create_calendar_event() { GtkWidget *hbox_event; GtkWidget *label_event; /* *entry_event */ hbox_event = gtk_hbox_new( FALSE, 2 ); label_event = gtk_label_new( "Event:" ); entry_event = gtk_entry_new(); gtk_box_pack_start( GTK_BOX( hbox_event ), label_event, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_event ), entry_event, TRUE, TRUE, 2 ); return hbox_event; } static GtkWidget * create_calendar_time() { GtkWidget *hbox_time; GtkWidget *label_time; /* *adj_time_hour */ GtkObject *adj_time_minute; /* *spin_time_hour */ /* *spin_time_minute */ /* *button_ampm */ hbox_time = gtk_hbox_new( FALSE, 2 ); adj_time_hour = gtk_adjustment_new( 0, 0, 23, 1, 10, 0 ); adj_time_minute = gtk_adjustment_new( 0, 0, 59, 1, 10, 0 ); label_time = gtk_label_new( "Time:" ); spin_time_hour = gtk_spin_button_new( GTK_ADJUSTMENT( adj_time_hour ), 0.0, 0 ); spin_time_minute = gtk_spin_button_new( GTK_ADJUSTMENT( adj_time_minute ), 0.0, 0 ); button_ampm = gtk_button_new(); label_ampm = gtk_label_new( is_pm ? "PM" : "AM" ); gtk_container_add( GTK_CONTAINER( button_ampm ), label_ampm ); gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spin_time_hour ), TRUE ); gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spin_time_minute ), TRUE ); if( !config.ampm ) gtk_widget_set_sensitive( button_ampm, FALSE ); else { GTK_ADJUSTMENT( adj_time_hour )->lower = 1; GTK_ADJUSTMENT( adj_time_hour )->upper = 12; gtk_spin_button_update( GTK_SPIN_BUTTON( spin_time_hour ) ); } g_signal_connect( G_OBJECT( button_ampm ), "clicked", G_CALLBACK(cb_ampm_clicked), NULL ); gtk_box_pack_start( GTK_BOX( hbox_time ), label_time, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_time ), spin_time_hour, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_time ), spin_time_minute, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_time ), button_ampm, FALSE, FALSE, 2 ); return hbox_time; } static GtkWidget * create_calendar_date_date( gboolean isStart ) { GtkWidget *hbox_date_date; GtkWidget *label; GtkWidget **spin_month; GtkWidget **spin_day; GtkWidget **spin_year; GtkObject *adj_month; GtkObject *adj_day; GtkObject *adj_year; hbox_date_date = gtk_hbox_new( FALSE, 2 ); adj_month = gtk_adjustment_new( 0, 1, 12, 1, 3, 0 ); adj_day = gtk_adjustment_new( 0, 1, 31, 1, 10, 0 ); adj_year = gtk_adjustment_new( 0, 1971, 2037, 1, 10, 0 ); if( isStart ) { label = gtk_label_new( "Start:" ); spin_month = &spin_start_month; spin_day = &spin_start_day; spin_year = &spin_start_year; } else { label = gtk_label_new( "End:" ); spin_month = &spin_end_month; spin_day = &spin_end_day; spin_year = &spin_end_year; } *spin_month = gtk_spin_button_new( GTK_ADJUSTMENT( adj_month ), 0.0, 0 ); *spin_day = gtk_spin_button_new( GTK_ADJUSTMENT( adj_day ), 0.0, 0 ); *spin_year = gtk_spin_button_new( GTK_ADJUSTMENT( adj_year ), 0.0, 0 ); gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( *spin_month ), TRUE ); gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( *spin_day ), TRUE ); gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( *spin_year ), TRUE ); g_signal_connect( adj_month, "value-changed", G_CALLBACK( cb_date_changed ), *spin_month ); g_signal_connect( adj_day, "value-changed", G_CALLBACK( cb_date_changed ), *spin_day ); g_signal_connect( adj_year, "value-changed", G_CALLBACK( cb_date_changed ), *spin_year ); gtk_box_pack_start( GTK_BOX( hbox_date_date ), label, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_date_date ), *spin_month, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_date_date ), *spin_day, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_date_date ), *spin_year, TRUE, TRUE, 2 ); cb_clamp_date( isStart ); return hbox_date_date; } static GtkWidget * create_calendar_date() { GtkWidget *hbox_date; /* *hbox_start */ /* *hbox_end */ hbox_date = gtk_hbox_new( FALSE, 2 ); hbox_start = create_calendar_date_date( TRUE ); hbox_end = create_calendar_date_date( FALSE ); check_forever = gtk_check_button_new_with_label( "Forever" ); g_signal_connect( G_OBJECT( check_forever ), "clicked", G_CALLBACK( cb_forever ), NULL ); gtk_box_pack_start( GTK_BOX( hbox_date ), hbox_start, TRUE, TRUE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_date ), hbox_end, TRUE, TRUE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_date ), check_forever, FALSE, FALSE, 2 ); return hbox_date; } static GtkWidget * create_calendar_ops() { GtkWidget *hbox_ops; GtkWidget *button_add; GtkWidget *button_reset; /* *button_remove */ /* *button_update */ hbox_ops = gtk_hbox_new( TRUE, 2 ); button_add = gtk_button_new_with_label( "Add" ); button_remove = gtk_button_new_with_label( "Remove" ); button_update = gtk_button_new_with_label( "Update" ); button_reset = gtk_button_new_with_label( "Reset" ); gtk_widget_set_sensitive( GTK_WIDGET( button_remove ), FALSE ); gtk_widget_set_sensitive( GTK_WIDGET( button_update ), FALSE ); g_signal_connect( G_OBJECT( button_add ), "clicked", G_CALLBACK( cb_add ), NULL ); g_signal_connect( G_OBJECT( button_remove ), "clicked", G_CALLBACK( cb_remove ), NULL ); g_signal_connect( G_OBJECT( button_update ), "clicked", G_CALLBACK( cb_update ), NULL ); g_signal_connect( G_OBJECT( button_reset ), "clicked", G_CALLBACK( cb_reset ), NULL ); gtk_box_pack_start( GTK_BOX( hbox_ops ), button_add, TRUE, TRUE, 10 ); gtk_box_pack_start( GTK_BOX( hbox_ops ), button_remove, TRUE, TRUE, 10 ); gtk_box_pack_start( GTK_BOX( hbox_ops ), button_update, TRUE, TRUE, 10 ); gtk_box_pack_start( GTK_BOX( hbox_ops ), button_reset, TRUE, TRUE, 10 ); return hbox_ops; } static GtkWidget * create_calendar_list() { GtkWidget *hbox_list; GtkWidget *list_scroll; /* *list_main */ static gchar *list_titles[] = { "Event", "Days", "Time", "Start", "End" }; hbox_list = gtk_hbox_new( FALSE, 2 ); list_scroll = gtk_scrolled_window_new( NULL, NULL ); list_main = gtk_clist_new_with_titles( 5, list_titles ); list_main_row_selected = -1; g_signal_connect( G_OBJECT( list_main ), "select_row", G_CALLBACK( cb_row_select ), NULL ); g_signal_connect( G_OBJECT( list_main ), "unselect_row", G_CALLBACK( cb_row_unselect ), NULL ); g_signal_connect( G_OBJECT( list_main ), "click_column", G_CALLBACK( cb_column_click ), NULL ); gtk_clist_set_selection_mode( GTK_CLIST( list_main ), GTK_SELECTION_SINGLE ); gtk_clist_column_titles_active( GTK_CLIST( list_main ) ); gtk_clist_set_auto_sort( GTK_CLIST( list_main ), TRUE ); gtk_container_add( GTK_CONTAINER( list_scroll ), list_main ); gtk_box_pack_start( GTK_BOX( hbox_list ), list_scroll, TRUE, TRUE, 2 ); return hbox_list; } static GtkWidget * create_calendar_occurs() { GtkWidget *vbox_occurs; vbox_occurs = gtk_vbox_new( FALSE, 2 ); radio_daily = gtk_radio_button_new_with_label( NULL, "Daily" ); radio_weekly = gtk_radio_button_new_with_label( gtk_radio_button_group( GTK_RADIO_BUTTON( radio_daily ) ), "Weekly" ); radio_monthly = gtk_radio_button_new_with_label( gtk_radio_button_group( GTK_RADIO_BUTTON( radio_daily ) ), "Monthly" ); g_signal_connect( G_OBJECT( radio_daily ), "clicked", G_CALLBACK( cb_select_radio ), NULL ); g_signal_connect( G_OBJECT( radio_weekly ), "clicked", G_CALLBACK( cb_select_radio ), NULL ); g_signal_connect( G_OBJECT( radio_monthly ), "clicked", G_CALLBACK( cb_select_radio ), NULL ); gtk_box_pack_start( GTK_BOX( vbox_occurs ), radio_daily, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_occurs ), radio_weekly, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_occurs ), radio_monthly, FALSE, FALSE, 2 ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_daily ), TRUE ); return vbox_occurs; } static GtkWidget * create_calendar_daily() { GtkWidget *vbox_daily; GtkWidget *hbox_days; GtkWidget *label_every; GtkWidget *label_days; GtkObject *adj_days; vbox_daily = gtk_vbox_new( FALSE, 2 ); hbox_days = gtk_hbox_new( FALSE, 2 ); label_every = gtk_label_new( "Every" ); adj_days = gtk_adjustment_new( 1, 1, 365, 1, 10, 0 ); spin_days = gtk_spin_button_new( GTK_ADJUSTMENT( adj_days ), 0.0, 0 ); label_days = gtk_label_new( "day(s)" ); gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spin_days ), TRUE ); gtk_box_pack_start( GTK_BOX( hbox_days ), label_every, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_days ), spin_days, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_days ), label_days, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_daily ), hbox_days, FALSE, FALSE, 2 ); return vbox_daily; } static GtkWidget * create_calendar_weekly() { GtkWidget *vbox_weekly; GtkWidget *hbox_weekly_checks; GtkWidget *hbox_weekly_buttons; GtkWidget *hbox_weekly_label; GtkWidget *button_weekdays; GtkWidget *button_weekends; GtkWidget *button_clear; GtkWidget *label_every; GtkWidget *label_weeks; /* *spin_weeks */ GtkObject *adj_weeks; vbox_weekly = gtk_vbox_new( FALSE, 2 ); hbox_weekly_checks = gtk_hbox_new( TRUE, 2 ); hbox_weekly_buttons = gtk_hbox_new( FALSE, 2 ); hbox_weekly_label = gtk_hbox_new( FALSE, 2 ); /* labels */ label_every = gtk_label_new( "Every" ); label_weeks = gtk_label_new( "week(s)" ); adj_weeks = gtk_adjustment_new( 1, 1, 100, 1, 4, 0 ); spin_weeks = gtk_spin_button_new( GTK_ADJUSTMENT( adj_weeks ), 0.0, 0 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_label ), label_every, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_label ), spin_weeks, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_label ), label_weeks, FALSE, FALSE, 2 ); /* hbox_weekly_checks */ check_sun = gtk_check_button_new_with_label( "Sun" ); check_mon = gtk_check_button_new_with_label( "Mon" ); check_tue = gtk_check_button_new_with_label( "Tue" ); check_wed = gtk_check_button_new_with_label( "Wed" ); check_thu = gtk_check_button_new_with_label( "Thu" ); check_fri = gtk_check_button_new_with_label( "Fri" ); check_sat = gtk_check_button_new_with_label( "Sat" ); gtk_box_pack_start( GTK_BOX( hbox_weekly_checks ), check_sun, FALSE, FALSE, 1 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_checks ), check_mon, FALSE, FALSE, 1 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_checks ), check_tue, FALSE, FALSE, 1 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_checks ), check_wed, FALSE, FALSE, 1 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_checks ), check_thu, FALSE, FALSE, 1 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_checks ), check_fri, FALSE, FALSE, 1 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_checks ), check_sat, FALSE, FALSE, 1 ); /* hbox_weekly_buttons */ button_weekdays = gtk_button_new_with_label( " Weekdays " ); button_weekends = gtk_button_new_with_label( " Weekends " ); button_clear = gtk_button_new_with_label( " Clear " ); g_signal_connect( G_OBJECT( button_weekdays ), "clicked", G_CALLBACK( cb_set_days ), GINT_TO_POINTER( 1 ) ); g_signal_connect( G_OBJECT( button_weekends ), "clicked", G_CALLBACK( cb_set_days ), GINT_TO_POINTER( 2 ) ); g_signal_connect( G_OBJECT( button_clear ), "clicked", G_CALLBACK( cb_set_days ), GINT_TO_POINTER( 0 ) ); gtk_box_pack_start( GTK_BOX( hbox_weekly_buttons ), button_weekdays, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_buttons ), button_weekends, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_weekly_buttons ), button_clear, FALSE, FALSE, 2 ); gtk_box_pack_end( GTK_BOX( hbox_weekly_label ), hbox_weekly_buttons, FALSE, FALSE, 2 ); /* pack into vbox_weekly */ gtk_box_pack_start( GTK_BOX( vbox_weekly ), hbox_weekly_label, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_weekly ), hbox_weekly_checks, FALSE, FALSE, 2 ); return vbox_weekly; } static GtkWidget * create_calendar_monthly() { GtkWidget *vbox_monthly; GtkWidget *hbox_top; GtkWidget *hbox_bottom; GtkWidget *label_every; GtkWidget *label_months; GtkWidget *label_repeat; GtkWidget *label_daymonth; GtkObject *adj_daymonth; GtkObject *adj_months; /* *spin_months */ /* *spin_daymonth */ vbox_monthly = gtk_vbox_new( FALSE, 2 ); hbox_top = gtk_hbox_new( FALSE, 2 ); hbox_bottom = gtk_hbox_new( FALSE, 2 ); label_every = gtk_label_new( "Every" ); label_months = gtk_label_new( "month(s)" ); adj_months = gtk_adjustment_new( 1, 1, 12, 1, 3, 0 ); spin_months = gtk_spin_button_new( GTK_ADJUSTMENT( adj_months ), 0.0, 0 ); label_repeat = gtk_label_new( "Repeat on the" ); adj_daymonth = gtk_adjustment_new( tm_input.tm_mday, 1, 31, 1, 10, 0 ); spin_daymonth = gtk_spin_button_new( GTK_ADJUSTMENT( adj_daymonth ), 0.0, 0 ); label_daymonth = gtk_label_new( "day of the month" ); gtk_box_pack_start( GTK_BOX( hbox_top ), label_every, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_top ), spin_months, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_top ), label_months, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_bottom ), label_repeat, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_bottom ), spin_daymonth, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_bottom ), label_daymonth, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_monthly ), hbox_top, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_monthly ), hbox_bottom, FALSE, FALSE, 2 ); return vbox_monthly; } static GtkWidget * create_calendar_details() { GtkWidget *hbox_details; GtkWidget *vbox_occurs; GtkWidget *vbox_right; GtkWidget *vseparator; GtkWidget *hbox_daily; GtkWidget *hbox_weekly; GtkWidget *hbox_monthly; hbox_details = gtk_hbox_new( FALSE, 2 ); vbox_occurs = create_calendar_occurs(); vbox_right = gtk_vbox_new( FALSE, 2 ); vseparator = gtk_vseparator_new(); hbox_date = create_calendar_date(); hbox_daily = create_calendar_daily(); hbox_weekly = create_calendar_weekly(); hbox_monthly = create_calendar_monthly(); notebook_occurs = gtk_notebook_new(); gtk_notebook_append_page( GTK_NOTEBOOK( notebook_occurs ), hbox_daily, NULL ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook_occurs ), hbox_weekly, NULL ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook_occurs ), hbox_monthly, NULL ); gtk_notebook_set_show_tabs( GTK_NOTEBOOK( notebook_occurs ), FALSE ); gtk_notebook_set_show_border( GTK_NOTEBOOK( notebook_occurs ), FALSE ); gtk_box_pack_start( GTK_BOX( vbox_right ), notebook_occurs, TRUE, TRUE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_right ), hbox_date, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_details ), vbox_occurs, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_details ), vseparator, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_details ), vbox_right, TRUE, TRUE, 2 ); return hbox_details; } static void create_calendar_frame( GtkWidget *frame ) { GtkWidget *separator; GtkWidget *separator2; GtkWidget *vbox_main; GtkWidget *hbox_event; GtkWidget *hbox_time; GtkWidget *hbox_details; GtkWidget *hbox_ops; GtkWidget *hbox_list; /* Get time from gkrellm and copy it to our struct so it can be modified */ memcpy( &tm_input, gkrellm_get_current_time(), sizeof( tm_input ) ); /* separators */ separator = gtk_hseparator_new(); separator2 = gtk_hseparator_new(); /* Initialize boxes */ vbox_main = gtk_vbox_new( FALSE, 0 ); hbox_event = create_calendar_event(); hbox_time = create_calendar_time(); hbox_details = create_calendar_details(); hbox_ops = create_calendar_ops(); hbox_list = create_calendar_list(); /* pack time */ gtk_box_pack_end( GTK_BOX( hbox_event ), hbox_time, FALSE, FALSE, 2 ); /* containers */ gtk_container_add( GTK_CONTAINER( frame ), vbox_main ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_event, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), separator, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_details, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), separator2, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_ops, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_list, TRUE, TRUE, 2 ); cb_reorder_date(); cb_reset( frame, NULL ); occurs_option = -1; cb_select_radio( frame, NULL ); /* Populate list */ if( !head_stored ) reminder_load_stored(); cb_populate(); gtk_widget_show_all( frame ); } static void create_settings_frame( GtkWidget *tab ) { GtkWidget *label_remind_early; GtkWidget *label_remind_early_end; GtkWidget *label_alert; GtkWidget *label_time_format; GtkWidget *label_date_format; GtkWidget *label_notify; GtkWidget *vbox_main; GtkWidget *hbox_remind_early; GtkWidget *hbox_remind_old; GtkWidget *hbox_delete_old; GtkWidget *hbox_alert; GtkWidget *hbox_time_format; GtkWidget *hbox_date_format; GtkWidget *hbox_notify; GtkObject *adj_remind_early; vbox_main = gtk_vbox_new( TRUE, 2 ); /* remind early */ hbox_remind_early = gtk_hbox_new( FALSE, 2 ); label_remind_early = gtk_label_new( "Remind me about events" ); label_remind_early_end = gtk_label_new( "minutes early" ); adj_remind_early = gtk_adjustment_new( config.remind_early, 0, 120, 1, 10, 0 ); spin_remind_early = gtk_spin_button_new( GTK_ADJUSTMENT( adj_remind_early ), 0.0, 0 ); gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spin_remind_early ), TRUE ); gtk_box_pack_start( GTK_BOX( hbox_remind_early ), label_remind_early, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_remind_early ), spin_remind_early, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_remind_early ), label_remind_early_end, FALSE, FALSE, 2 ); /* remind old */ hbox_remind_old = gtk_hbox_new( FALSE, 2 ); check_remind_old = gtk_check_button_new_with_label( "Remind of events that I may have missed today" ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_remind_old ), config.remind_old ); gtk_box_pack_start( GTK_BOX( hbox_remind_old ), check_remind_old, FALSE, FALSE, 2 ); /* delete old */ hbox_delete_old = gtk_hbox_new( FALSE, 2 ); check_delete_old = gtk_check_button_new_with_label( "Automatically delete events that have expired" ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_delete_old ), config.delete_old ); gtk_box_pack_start( GTK_BOX( hbox_delete_old ), check_delete_old, FALSE, FALSE, 2 ); /* AM/PM */ hbox_time_format = gtk_hbox_new( FALSE, 2 ); label_time_format = gtk_label_new( "Time format:" ); radio_12hour = gtk_radio_button_new_with_label( NULL, "12-hour" ); radio_24hour = gtk_radio_button_new_with_label( gtk_radio_button_group( GTK_RADIO_BUTTON( radio_12hour ) ), "24-hour" ); if( config.ampm ) gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_12hour ), TRUE ); else gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_24hour ), TRUE ); gtk_box_pack_start( GTK_BOX( hbox_time_format ), label_time_format, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_time_format ), radio_12hour, TRUE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_time_format ), radio_24hour, TRUE, FALSE, 2 ); /* date format */ hbox_date_format = gtk_hbox_new( FALSE, 2 ); label_date_format = gtk_label_new( "Date format:" ); radio_mdy = gtk_radio_button_new_with_label( NULL, "MM/DD/YYYY" ); radio_dmy = gtk_radio_button_new_with_label( gtk_radio_button_group( GTK_RADIO_BUTTON( radio_mdy ) ), "DD/MM/YYYY" ); if( config.mdy ) gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_mdy ), TRUE ); else gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( radio_dmy ), TRUE ); gtk_box_pack_start( GTK_BOX( hbox_date_format ), label_date_format, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_date_format ), radio_mdy, TRUE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_date_format ), radio_dmy, TRUE, FALSE, 2 ); /* alert */ hbox_alert = gtk_hbox_new( FALSE, 2 ); label_alert = gtk_label_new( "Reminder method:" ); check_alert_flash = gtk_check_button_new_with_label( "Flash icon" ); check_alert_popup = gtk_check_button_new_with_label( "Popup reminder" ); check_alert_execute = gtk_check_button_new_with_label( "Execute command" ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_alert_flash ), config.alert & ALERT_FLASH ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_alert_popup ), config.alert & ALERT_POPUP ); gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( check_alert_execute ), config.alert & ALERT_EXECUTE ); gtk_box_pack_start( GTK_BOX( hbox_alert ), label_alert, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_alert ), check_alert_flash, TRUE, TRUE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_alert ), check_alert_popup, TRUE, TRUE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_alert ), check_alert_execute, TRUE, TRUE, 2 ); /* notify */ hbox_notify = gtk_hbox_new( FALSE, 2 ); label_notify = gtk_label_new( "Notification (play sound) command:" ); entry_notify = gtk_entry_new_with_max_length( 63 ); if( config.notify ) gtk_entry_set_text( GTK_ENTRY( entry_notify ), config.notify ); gtk_box_pack_start( GTK_BOX( hbox_notify ), label_notify, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_notify ), entry_notify, TRUE, TRUE, 2 ); /* main */ gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_remind_early, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_remind_old, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_delete_old, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_time_format, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_date_format, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_alert, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_notify, FALSE, FALSE, 2 ); gtk_widget_show_all( vbox_main ); gtk_container_add( GTK_CONTAINER( tab ), vbox_main ); } static void create_help_frame( GtkWidget *tab ) { GtkWidget *vbox_main; GtkWidget *text_main; static gchar *str_info[] = { "Calendar\n", "Event: ", "Name of event. This will be displayed when you are reminded.\n\n", "Daily: ", "This will remind you every days starting with the start date. If the event\n", "does not occur on the end date, the actual ending date may be several days earlier\n", "than is indicated. ", "Note: ", "Setting to 1 will display the event every day in the\n", "Start/End range.\n\n", "Weekly: ", "This will remind you of the event at the same time every week. You can\n", "select which days you would like to be reminded on with the check boxes and buttons.\n\n", "Monthly: ", "This will remind you at the same time each month. Months can be skipped by\n", "setting the repeat field. Setting this to 12 will result in a yearly reminder.\n\n", "Start/End/Time: ", "This selects the range of days on which the event may occur. The\n", "start and end dates are inclusive. Events will expire at the stroke of midnight on the\n", "day after end date. Time indicates what time of the day the event will appear.\n\n", "Add: ", "Adds the current event to the list.\n", "Remove: ", "Removes the currently selected event in the list.\n", "Update: ", "Replaces the currently selected list item with the current event.\n", "Today: ", "Resets the Start/End/Time to the current time and date.\n\n", "Settings\n", "Remind Early: ", "Reminders will appear minutes before they are scheduled.\n", "Remind Missed: ", "Reminders that happened before GKrellM was started will appear\n", "at startup.\n", "Delete Expired: ", "Events that will never occur again (after end date) will automatically\n", "be deleted.\n", "Time Format: ", "Select either 12 hour (with AM/PM) or 24-hour time display\n", "Date Format: ", "The format to use when displaying dates.\n", "Notification Command: ", "This command will be executed whenever a new event occurs\n\n", "Reminders\n", "Never: ", "Deletes the event from the calendar. It will never appear again.\n", "Later: ", "Will display this reminder again in minutes.\n", "Dismiss: ", "Acknowledges the reminder. It will not be displayed again today.\n\n", "Panel\n", "The first number indicates the number of events pending. The second number\n", "indicates the total number of events for today. The calendar will also flash when\n", "there are pending events.\n\n", "Left mouse button: ", "Clicking on the numbers will display the first pending event.\n", "Clicking on the calendar will list all events scheduled for today.\n", "Right mouse button: ", "Clicking anywhere within the panel will display the calendar." }; vbox_main = gtk_vbox_new( TRUE, 2 ); text_main = gkrellm_gtk_scrolled_text_view( vbox_main, NULL, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); // gkrellm_add_info_text( text_main, str_info, 59 ); gkrellm_gtk_text_view_append_strings(text_main, str_info, 59); gtk_widget_show_all( vbox_main ); gtk_container_add( GTK_CONTAINER( tab ), vbox_main ); } static void create_about_frame( GtkWidget *tab ) { GtkWidget *vbox_main; GtkWidget *label_info; gchar *str_info; vbox_main = gtk_vbox_new( TRUE, 2 ); str_info = g_strdup_printf( "%s %s\n%s\n\n%s %s\n%s\n%s\n\n%s", str_title, str_version, str_date, str_copyright, str_author, str_email, str_url, str_gpl ); label_info = gtk_label_new( str_info ); gtk_box_pack_start( GTK_BOX( vbox_main ), label_info, TRUE, TRUE, 2 ); g_free( str_info ); gtk_widget_show_all( GTK_WIDGET( vbox_main ) ); gtk_container_add( GTK_CONTAINER( tab ), vbox_main ); } static void display_config( GtkWidget *tab ) { GtkWidget *notebook; GtkWidget *label_calendar; GtkWidget *label_settings; GtkWidget *label_help; GtkWidget *label_about; GtkWidget *frame_calendar; GtkWidget *frame_settings; GtkWidget *frame_help; GtkWidget *frame_about; /* Delete any previously unsaved changes to the settings */ reminder_free_id_list(); if( head_temp ) reminder_free_stored( &head_temp ); notebook = gtk_notebook_new(); gtk_notebook_set_tab_pos( GTK_NOTEBOOK( notebook ), GTK_POS_TOP ); label_calendar = gtk_label_new( "Calendar" ); frame_calendar = gtk_frame_new( NULL ); gtk_container_border_width( GTK_CONTAINER( frame_calendar ), 3 ); create_calendar_frame( frame_calendar ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), frame_calendar, label_calendar ); label_settings = gtk_label_new( "Settings" ); frame_settings = gtk_frame_new( NULL ); gtk_container_border_width( GTK_CONTAINER( frame_settings ), 3 ); create_settings_frame( frame_settings ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), frame_settings, label_settings ); label_help = gtk_label_new( "Help" ); frame_help = gtk_frame_new( NULL ); gtk_container_border_width( GTK_CONTAINER( frame_help ), 3 ); create_help_frame( frame_help ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), frame_help, label_help ); label_about = gtk_label_new( "About" ); frame_about = gtk_frame_new( NULL ); gtk_container_border_width( GTK_CONTAINER( frame_about ), 3 ); create_about_frame( frame_about ); gtk_notebook_append_page( GTK_NOTEBOOK( notebook ), frame_about, label_about ); gtk_widget_show_all( notebook ); gtk_box_pack_start( GTK_BOX( tab ), notebook, TRUE, TRUE, 0 ); } static void update_config(void) { struct id_list *dl_current; struct event_stored *es_tail; /* settings */ config.remind_early_diff = config.remind_early; config.remind_early = gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_remind_early ) ); config.remind_early_diff -= config.remind_early; config.remind_old = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_remind_old ) ); config.delete_old = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_delete_old ) ); config.alert = 0; config.alert |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_alert_flash ) ) ? ALERT_FLASH : 0; config.alert |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_alert_popup ) ) ? ALERT_POPUP : 0; config.alert |= gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( check_alert_execute ) ) ? ALERT_EXECUTE : 0; config.ampm = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( radio_12hour ) ); if( !config.ampm ) { GTK_ADJUSTMENT( adj_time_hour )->lower = 0; GTK_ADJUSTMENT( adj_time_hour )->upper = 23; gtk_spin_button_update( GTK_SPIN_BUTTON( spin_time_hour ) ); gtk_widget_set_sensitive( button_ampm, FALSE ); } else { GTK_ADJUSTMENT( adj_time_hour )->lower = 1; GTK_ADJUSTMENT( adj_time_hour )->upper = 12; gtk_spin_button_update( GTK_SPIN_BUTTON( spin_time_hour ) ); gtk_widget_set_sensitive( button_ampm, TRUE ); } config.mdy = gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( radio_mdy ) ); cb_reorder_date(); if( !strlen( gtk_entry_get_text( GTK_ENTRY( entry_notify ) ) ) ) { g_free( config.notify ); config.notify = g_strdup(str_null); } else if( !config.notify || strcmp( config.notify, gtk_entry_get_text( GTK_ENTRY( entry_notify ) ) ) ) { if( config.notify ) g_free( config.notify ); // config.notify = malloc( strlen( gtk_entry_get_text( GTK_ENTRY( entry_notify ) ) ) + 1 ); // if( !config.notify ) // return; // strcpy( config.notify, gtk_entry_get_text( GTK_ENTRY( entry_notify ) ) ); config.notify = g_strdup(gtk_entry_get_text( GTK_ENTRY( entry_notify ) ) ); } /* Make sure that the list is loaded (fixes apply/ok bug) */ if( !head_stored ) reminder_load_stored(); /* Remove anything deleted from the list */ dl_current = head_delete; while( dl_current ) { reminder_remove_event_stored( &head_stored, dl_current->id ); reminder_remove_event_today( dl_current->id ); dl_current = dl_current->next; } reminder_free_id_list(); /* Add anything added to the list */ if( head_temp ) { if( head_stored ) { es_tail = head_stored; while( es_tail->next ) es_tail = es_tail->next; es_tail->next = head_temp; } else head_stored = head_temp; } head_temp = NULL; /* Save changes to disk and update today's list */ reminder_build_today( TRUE ); /* repopulate the list */ cb_populate(); } static void default_config() { config.remind_early = 15; config.remind_early_diff = 0; config.list_sort = 2; config.alert = ALERT_FLASH; config.remind_old = TRUE; config.delete_old = FALSE; config.ampm = TRUE; config.mdy = TRUE; // config.event_file = malloc( strlen( gkrellm_homedir() ) + 29 ); // if( !config.event_file ) // return; //sprintf( config.event_file, "%s/.gkrellm-reminder/event.dat", gkrellm_homedir() ); config.event_file = g_strdup_printf("%s/.gkrellm-reminder/event.dat", gkrellm_homedir() ); } static void save_config( FILE *fp ) { fprintf( fp, "%s remind_early %d\n", CONFIG_NAME, config.remind_early ); fprintf( fp, "%s list_sort %d\n", CONFIG_NAME, config.list_sort ); fprintf( fp, "%s remind_old %d\n", CONFIG_NAME, config.remind_old ); fprintf( fp, "%s delete_old %d\n", CONFIG_NAME, config.delete_old ); fprintf( fp, "%s ampm %d\n", CONFIG_NAME, config.ampm ); fprintf( fp, "%s mdy %d\n", CONFIG_NAME, config.mdy ); fprintf( fp, "%s alert %d\n", CONFIG_NAME, config.alert ); if (config.notify && strcmp(config.notify, str_null)) fprintf( fp, "%s notify %s\n", CONFIG_NAME, config.notify ? config.notify : str_null ); } static void load_config( gchar *arg ) { gchar keyword[32], value[64]; sscanf( arg, "%s %[^\n]", keyword, value ); if( !strcmp( keyword, "remind_early" ) ) config.remind_early = atoi( value ); else if( !strcmp( keyword, "list_sort" ) ) config.list_sort = atoi( value ); else if( !strcmp( keyword, "remind_old" ) ) config.remind_old = atoi( value ); else if( !strcmp( keyword, "delete_old" ) ) config.delete_old = atoi( value ); else if( !strcmp( keyword, "ampm" ) ) config.ampm = atoi( value ); else if( !strcmp( keyword, "mdy" ) ) config.mdy = atoi( value ); else if( !strcmp( keyword, "alert" ) ) config.alert = atoi( value ); else if( !strcmp( keyword, "notify" ) ) { if( config.notify ) g_free( config.notify ); if( strcmp( value, str_null ) ) { // config.notify = malloc( strlen( value ) + 1 ); // if( !config.notify ) // return; // strcpy( config.notify, value ); config.notify = g_strdup(value); } } } static void cb_today_delete( GtkWidget *window, GdkEvent *event, gpointer data ) { gtk_widget_destroy( window_today ); window_today = NULL; } static void reminder_display_today( void ) { GtkWidget *vbox_main; GtkWidget *list_today; GtkWidget *scroll_today; GtkWidget *separator; GtkWidget *button_close; static gchar *list_titles[] = { "Time", "Event" }; struct event_today *current; if( window_today ) return; window_today = gtk_window_new( GTK_WINDOW_TOPLEVEL ); gtk_window_set_policy( GTK_WINDOW( window_today ), TRUE, TRUE, FALSE ); gtk_window_set_title( GTK_WINDOW( window_today ), str_title ); gtk_widget_set_usize( window_today, 200, 200 ); g_signal_connect( G_OBJECT( window_today ), "delete_event", G_CALLBACK(cb_today_delete), NULL ); vbox_main = gtk_vbox_new( FALSE, 5 ); gtk_container_add( GTK_CONTAINER( window_today ), vbox_main ); scroll_today = gtk_scrolled_window_new( NULL, NULL ); list_today = gtk_clist_new_with_titles( 2, list_titles ); gtk_clist_set_selection_mode( GTK_CLIST( list_today ), GTK_SELECTION_SINGLE ); gtk_clist_column_titles_active( GTK_CLIST( list_today ) ); current = head_today; while( current ) { gchar *array[] = { NULL, NULL, }; time_t time_current; array[0] = malloc( 9 ); if( !array[0] ) return; time_current = current->occurs; if( !strstr( current->name, str_delayed ) ) time_current += config.remind_early * SECS_PER_MIN; if( config.ampm ) strftime( array[0], 9, "%I:%M %p", localtime( &time_current ) ); else strftime( array[0], 9, "%H:%M", localtime( &time_current ) ); array[1] = current->name; gtk_clist_append( GTK_CLIST( list_today ), array ); if( array[0] ) free( array[0] ); current = current->next; } gtk_clist_columns_autosize( GTK_CLIST( list_today ) ); gtk_container_add( GTK_CONTAINER( scroll_today ), list_today ); separator = gtk_hseparator_new(); button_close = gtk_button_new_with_label( "Close" ); g_signal_connect_swapped( G_OBJECT( button_close ), "clicked", G_CALLBACK(cb_today_delete), GTK_OBJECT( window_today ) ); gtk_box_pack_start( GTK_BOX( vbox_main ), scroll_today, TRUE, TRUE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), separator, FALSE, FALSE, 2 ); gtk_box_pack_end( GTK_BOX( vbox_main ), button_close, FALSE, FALSE, 2 ); gtk_widget_show_all( window_today ); } static void reminder_text_button_enable( void ) { if( window_reminder ) reminder_text_button->sensitive = FALSE; else reminder_text_button->sensitive = TRUE; } static void reminder_window_never( GtkWidget *window, gpointer data ) { guint id = (guint) data; /* delete event from today */ num_active--; num_today--; if( num_active ) last_active = head_today->next; else last_active = NULL; reminder_remove_event_today( id ); if( !head_stored ) reminder_load_stored(); reminder_remove_event_stored( &head_stored, id ); reminder_save_stored(); reminder_free_stored( &head_stored ); gtk_widget_destroy( window_reminder ); window_reminder = NULL; reminder_text_button_enable(); if( num_active && config.alert & ALERT_POPUP ) reminder_display_reminder(); } static void reminder_window_later( GtkWidget *window, gpointer data ) { guint id = (guint) data; struct event_stored *new, *old; /* delete event from today */ num_active--; num_today--; if( num_active ) last_active = head_today->next; else last_active = NULL; reminder_remove_event_today( id ); if( event_active.last && config.delete_old ) { if( !head_stored ) reminder_load_stored(); reminder_remove_event_stored( &head_stored, id ); } new = malloc( sizeof( struct event_stored ) ); if( new ) { if( !strstr( event_active.name, str_delayed ) ) { // new->name = malloc( strlen( event_active.name ) + 1 + 10 ); // strcpy( new->name, str_delayed ); // strcpy( new->name + 10, event_active.name ); new->name = g_strdup_printf("%10s%s", str_delayed, event_active.name); } else { // new->name = malloc( strlen( event_active.name ) + 1 ); // strcpy( new->name, event_active.name ); new->name = g_strdup(event_active.name); if( !head_stored ) reminder_load_stored(); reminder_remove_event_stored( &head_stored, id ); } new->id = event_active.id - 1000 * SECS_PER_DAY; new->last_displayed = 0; new->start = mktime( gkrellm_get_current_time() ) + config.remind_early * SECS_PER_MIN + gtk_spin_button_get_value_as_int( GTK_SPIN_BUTTON( spin_minutes ) ) * SECS_PER_MIN; new->start = new->start - new->start % SECS_PER_MIN; new->end = new->start + ( SECS_PER_DAY - ( new->start - TIMEZONE_DIFF ) % SECS_PER_DAY ) - 1; new->occurs = OPT_DAILY; new->days = 1; if( !head_stored ) reminder_load_stored(); old = reminder_find_event_stored( head_stored, id ); if( old ) old->last_displayed = mktime( gkrellm_get_current_time() ); reminder_add_event_stored( &head_stored, new, NULL ); reminder_build_today( TRUE ); } gtk_widget_destroy( window_reminder ); window_reminder = NULL; reminder_text_button_enable(); if( num_active && config.alert & ALERT_POPUP ) reminder_display_reminder(); } static void reminder_window_dismiss( GtkWidget *window, gpointer data ) { guint id = (guint) data; /* delete event from today */ num_active--; num_today--; if( num_active ) last_active = head_today->next; else last_active = NULL; reminder_remove_event_today( id ); if( event_active.last && config.delete_old ) { if( !head_stored ) reminder_load_stored(); reminder_remove_event_stored( &head_stored, id ); reminder_save_stored(); } else { struct event_stored *current; if( !head_stored ) reminder_load_stored(); current = reminder_find_event_stored( head_stored, id ); current->last_displayed = mktime( gkrellm_get_current_time() ); reminder_save_stored(); } gtk_widget_destroy( window_reminder ); window_reminder = NULL; reminder_text_button_enable(); if( num_active && config.alert & ALERT_POPUP ) reminder_display_reminder(); } static guint reminder_get_active() { if( last_active ) { memcpy( &event_active, head_today, sizeof( struct event_today ) ); // event_active.name = malloc( strlen( head_today->name ) + 1 ); // if( !event_active.name ) // return 0; // strcpy( event_active.name, head_today->name ); event_active.name = g_strdup(head_today->name); if( !strstr( event_active.name, str_delayed ) ) event_active.occurs += config.remind_early * SECS_PER_MIN; return event_active.id; } else return 0; } static void cb_reminder_delete( GtkWidget *widget, GdkEvent *event, gpointer user_data ) { gtk_widget_destroy( window_reminder ); window_reminder = NULL; reminder_text_button_enable(); } static void reminder_display_reminder( void ) { guint id_active; GtkWidget *vbox_main; GtkWidget *hbox_later; GtkWidget *hbox_buttons; GtkWidget *label_time; GtkWidget *label_event; GtkWidget *label_remind; GtkWidget *label_minutes; GtkWidget *separator; GtkWidget *button_dismiss; GtkWidget *button_later; GtkWidget *button_never; GtkObject *adj_minutes; struct tm tm_active; gchar str_time[27]; int length; if( window_reminder ) { gtk_window_activate_focus( GTK_WINDOW( window_reminder ) ); return; } id_active = reminder_get_active(); if( !id_active ) return; window_reminder = gtk_window_new( GTK_WINDOW_TOPLEVEL ); gtk_window_set_policy( GTK_WINDOW( window_reminder ), TRUE, TRUE, FALSE ); gtk_window_set_title( GTK_WINDOW( window_reminder ), str_title ); g_signal_connect( G_OBJECT( window_reminder ), "delete-event", G_CALLBACK( cb_reminder_delete ), NULL ); vbox_main = gtk_vbox_new( FALSE, 5 ); gtk_container_add( GTK_CONTAINER( window_reminder ), vbox_main ); memcpy( &tm_active, localtime( &event_active.occurs ), sizeof( tm_active ) ); if( config.ampm ) length = strftime( str_time, 27, str_12hour, &tm_active ); else length = strftime( str_time, 27, str_24hour, &tm_active ); str_time[length] = ' '; strftime( str_time + length + 1, 27 - length - 2, config.mdy ? str_mdy : str_dmy, &tm_active ); label_time = gtk_label_new( str_time ); label_event = gtk_label_new( event_active.name ); gtk_box_pack_start( GTK_BOX( vbox_main ), label_time, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), label_event, FALSE, FALSE, 2 ); /* separator */ separator = gtk_hseparator_new(); gtk_box_pack_start( GTK_BOX( vbox_main ), separator, FALSE, FALSE, 4 ); /* hbox_later */ hbox_later = gtk_hbox_new( FALSE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_later, FALSE, FALSE, 2 ); label_remind = gtk_label_new( "Remind me again in" ); label_minutes = gtk_label_new( "minutes" ); adj_minutes = gtk_adjustment_new( 5, 1, 999, 1, 10, 0 ); spin_minutes = gtk_spin_button_new( GTK_ADJUSTMENT( adj_minutes ), 0.0, 0 ); gtk_spin_button_set_numeric( GTK_SPIN_BUTTON( spin_minutes ), TRUE ); gtk_box_pack_start( GTK_BOX( hbox_later ), label_remind, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_later ), spin_minutes, FALSE, FALSE, 2 ); gtk_box_pack_start( GTK_BOX( hbox_later ), label_minutes, FALSE, FALSE, 2 ); /* hbox_buttons */ hbox_buttons = gtk_hbox_new( TRUE, 2 ); gtk_box_pack_start( GTK_BOX( vbox_main ), hbox_buttons, FALSE, FALSE, 2 ); button_never = gtk_button_new_with_label( " Never " ); button_later = gtk_button_new_with_label( " Later " ); button_dismiss = gtk_button_new_with_label( " Dismiss " ); g_signal_connect( G_OBJECT( button_never ), "clicked", G_CALLBACK(reminder_window_never), GINT_TO_POINTER( head_today->id ) ); g_signal_connect( G_OBJECT( button_later ), "clicked", G_CALLBACK(reminder_window_later), GINT_TO_POINTER( head_today->id ) ); g_signal_connect( G_OBJECT( button_dismiss ), "clicked", G_CALLBACK(reminder_window_dismiss), GINT_TO_POINTER( head_today->id ) ); gtk_box_pack_start( GTK_BOX( hbox_buttons ), button_never, FALSE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX( hbox_buttons ), button_later, FALSE, FALSE, 0 ); gtk_box_pack_start( GTK_BOX( hbox_buttons ), button_dismiss, FALSE, FALSE, 0 ); gtk_widget_show_all( window_reminder ); reminder_text_button_enable(); } static void reminder_draw_panel_text( gint num_active, gint num_today ) { GkrellmStyle *style; GkrellmTextstyle ts, ts_old; gint new_value; gint x, w; gchar buf[16]; new_value = ( num_active << 16 ) + num_today; if( new_value == reminder_text_decal->value ) return; snprintf( buf, sizeof( buf ), "%d/%d", num_active, num_today ); ts_old = ts = reminder_text_decal->text_style; w = gdk_string_width( ts.font, buf ); if( w > reminder_text_decal->w ) { ts.font = gkrellm_meter_alt_textstyle( style_id )->font; w = gdk_string_width( ts.font, buf ); } style = gkrellm_meter_style( style_id ); x = gkrellm_chart_width() * panel->label->position / GKRELLM_LABEL_MAX; x -= style->margin.left + w / 2; if ( panel->label->position >= 50 ) x -= reminder_icon_decal->w / 2; if ( x > reminder_text_decal->w - w ) x = reminder_text_decal->w - w; if ( x < 0 ) x = 0; reminder_text_decal->text_style = ts; reminder_text_decal->x_off = x; gkrellm_draw_decal_text( panel, reminder_text_decal, buf, new_value ); reminder_text_decal->text_style = ts_old; } static void update_plugin(void) { static gint frame = 0; if( pGK->day_tick ) { if( !head_stored ) reminder_load_stored(); reminder_build_today( FALSE ); } if( pGK->minute_tick ) { time_t now; now = mktime( gkrellm_get_current_time() ); reminder_check_new_active( head_today, last_active, now ); } if( ( pGK->timer_ticks % 2 ) == 0 ) { if( config.alert & ALERT_FLASH ) { if( num_active ) frame = frame ? 0 : 1; else frame = 0; } else frame = 0; gkrellm_draw_decal_pixmap( panel, DECAL( panel ), frame ); reminder_draw_panel_text( num_active, num_today ); gkrellm_draw_panel_layers( panel ); } } static gint panel_expose_event(GtkWidget *widget, GdkEventExpose *ev) { gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], panel->pixmap, ev->area.x, ev->area.y, ev->area.x, ev->area.y, ev->area.width, ev->area.height); return FALSE; } static gint cb_panel_press( GtkWidget * widget, GdkEventButton * ev ) { if ( ev->button == 1 && ev->x >= reminder_icon_decal->x && ev->x < reminder_icon_decal->x + reminder_icon_decal->w ) reminder_display_today(); else if( ev->button == 3 ) gkrellm_open_config_window( reminder_mon ); return TRUE; } static void cb_reminder_button( GkrellmDecalbutton *button ) { if( num_active ) reminder_display_reminder(); } static void create_plugin(GtkWidget *vbox, gint first_create) { GkrellmStyle *style; gint x, w; #if !defined(GKRELLM_HAVE_THEME_SCALE) static GdkPixmap *reminder_icon_pixmap; static GdkBitmap *reminder_icon_mask; #endif if (first_create) panel = gkrellm_panel_new0(); else gkrellm_destroy_decal_list( panel ); style = gkrellm_meter_style(style_id); /* Load icon image */ gkrellm_load_piximage( NULL, calendar_xpm, &reminder_icon_image, STYLE_NAME); #if defined(GKRELLM_HAVE_THEME_SCALE) reminder_icon_decal = gkrellm_make_scaled_decal_pixmap(panel, reminder_icon_image, style, 2, -1, -1, 0, 0); #else gkrellm_scale_piximage_to_pixmap(reminder_icon_image, &reminder_icon_pixmap, &reminder_icon_mask, 0, 0); reminder_icon_decal = gkrellm_create_decal_pixmap( panel, reminder_icon_pixmap, reminder_icon_mask, 2, style, -1, -1 ); #endif /* Setup text decal for numbers */ x = style->margin.left; if( style->label_position >= 50 ) x += reminder_icon_decal->w; w = gkrellm_chart_width() - reminder_icon_decal->w - 2 * style->margin.left; panel->textstyle = gkrellm_meter_textstyle(style_id); reminder_text_decal = gkrellm_create_decal_text( panel, "0", panel->textstyle, style, x, -1, w ); if( reminder_icon_decal->h > reminder_text_decal->h ) reminder_text_decal->y += (reminder_icon_decal->h - reminder_text_decal->h ) / 2; else reminder_icon_decal->y += ( reminder_text_decal->h - reminder_icon_decal->h ) / 2; reminder_text_button = gkrellm_put_decal_in_meter_button( panel, reminder_text_decal, cb_reminder_button, NULL, NULL ); gkrellm_panel_configure( panel, NULL, style ); gkrellm_panel_create( vbox, reminder_mon, panel); //, gkrellm_bg_meter_image( style_id ) ); reminder_text_button_enable(); // gkrellm_monitor_height_adjust(panel->h); if (first_create) { g_signal_connect(G_OBJECT (panel->drawing_area), "expose_event", G_CALLBACK(panel_expose_event), NULL); g_signal_connect( G_OBJECT( panel->drawing_area ), "button_press_event", G_CALLBACK(cb_panel_press), NULL ); reminder_load_stored(); reminder_build_today( FALSE ); } } static GkrellmMonitor reminder_monitor = { "Reminder", /* Title for config clist. */ 0, /* Id, 0 if a plugin */ create_plugin, /* The create function */ update_plugin, /* The update function */ display_config, /* The config tab create function */ update_config, /* Apply the config function */ save_config, /* Save user config */ load_config, /* Load user config */ CONFIG_NAME, /* config keyword */ NULL, /* Undefined 2 */ NULL, /* Undefined 1 */ NULL, /* private */ MON_MAIL, /* Insert plugin before this monitor */ NULL, /* Handle if a plugin, filled in by GKrellM */ NULL /* path if a plugin, filled in by GKrellM */ }; #if defined(WIN32) __declspec(dllexport) GkrellmMonitor * gkrellm_init_plugin(win32_plugin_callbacks* calls) #else GkrellmMonitor * gkrellm_init_plugin() #endif { #if defined(WIN32) callbacks = calls; #endif pGK = gkrellm_ticks(); reminder_mon = &reminder_monitor; head_stored = NULL; head_today = NULL; head_temp = NULL; head_delete = NULL; last_active = NULL; str_null = g_strdup(""); num_active = 0; num_today = 0; today_day = 0; window_reminder = NULL; window_today = NULL; #if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__) bsd_timezone = gkrellm_get_current_time()->tm_gmtoff; #endif default_config(); style_id = gkrellm_add_meter_style(reminder_mon, STYLE_NAME); return reminder_mon; }