/* * G-ToDo Gkrellm Plugin * Copyright 2003-2004 Dimitar Haralanov * */ /* 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 */ #include #include #include #include #include #include #include #include #include "gtodo-timer.xpm" #include "warn.xpm" /* we will use only labs () */ #define abs labs #define PIXMAP_DEPTH 6 #define MAX_REMINDER_WINDOWS 64 static GkrellmMonitor *mon; static GkrellmPanel *panel; static GkrellmTicks *pGK; static GkrellmDecal *title_decal; static GkrellmDecal *gtodo_icon_decal; static GkrellmPiximage *gtodo_icon_image; static gint gtodo_style_id; static gchar *decal_init_string = "G-ToDo Plugin - No Tasks"; static GtkTooltips *panel_tips; typedef struct _reminder { GtkTreeIter *iter; GtkWidget *window; } Reminder; static Reminder reminder_list[MAX_REMINDER_WINDOWS]; static void gtodo_update_plugin (void); static void gtodo_create_plugin (GtkWidget *vbox, gint first_create); static void gtodo_button_pressed (void *); static gint gtodo_panel_pressed (GtkWidget *, GdkEventButton *, gpointer); static gint gtodo_panel_expose_event (GtkWidget *, GdkEventExpose *); static void gtodo_ack_task (GtkTreeIter *); static GtkWidget *gtodo_add_reminder_window (GtkTreeIter *); static gboolean gtodo_have_reminder_window (GtkTreeIter *); static GtkWidget *gtodo_clear_reminder_window (GtkTreeIter *); static void gtodo_exec_command (gchar *, GtkTreeIter *); static gint get_current_pixmap_depth (void); static __inline__ gint gtodo_get_tasks_list (void); static gint gtodo_get_tasks_today (void); static void gtodo_clean_old_tasks (void); static gint gtodo_get_tasks_due (void); static void gtodo_update_task_timers (void); static void gtodo_reset_task_timers (void); static GtkWidget *gtodo_create_reminder_window (gchar *, gchar *, GtkTreeIter); static gboolean on_reminder_window_destroy (GtkWidget *, gpointer); static void on_reminder_ok_button_clicked (GtkButton *, gpointer); static void on_reminder_change_button_clicked (GtkButton *, gpointer); static void on_reminder_dismiss_button_clicked (GtkButton *, gpointer); static GkrellmMonitor plugin_mon = { "G-ToDo", /* Name, for config tab. */ 0, /* Id, 0 if a plugin */ gtodo_create_plugin, /* The create_plugin() function */ gtodo_update_plugin, /* The update_plugin() function */ gtodo_create_config_tab, /* The create_plugin_tab() config function */ gtodo_apply_plugin_config, /* The apply_plugin_config() function */ gtodo_save_plugin_config, /* The save_plugin_config() function */ gtodo_load_plugin_config, /* The load_plugin_config() function */ CONFIG_NAME, /* config keyword */ NULL, /* Undefined 2 */ NULL, /* Undefined 1 */ NULL, /* Undefined 0 */ PLUGIN_PLACEMENT, /* Insert plugin before this monitor. */ NULL, /* Handle if a plugin, filled in by GKrellM */ NULL /* path if a plugin, filled in by GKrellM */ }; GkrellmMonitor * gkrellm_init_plugin (void) { gtodo_set_default_config (); pGK = gkrellm_ticks (); mon = &plugin_mon; gtodo_style_id = gkrellm_add_meter_style (mon, STYLE_NAME); #ifdef ENABLE_NLS bind_textdomain_codeset(PACKAGE, "UTF-8"); #endif /* ENABLE_NLS */ return mon; } static void gtodo_update_plugin (void) { static gint x_scroll, w, len, toggle; static gint today, total; static gboolean checked; gchar *decal_str = NULL; if (w == 0 || len == 0) w = gkrellm_chart_width(); if (global_config.auto_delete && global_config.acked) gtodo_clean_old_tasks (); if (!checked || !global_config.clean || pGK->day_tick) { /* we want to get the tasks to display but we * we want to get them only once or if the day has switched * and not every time the function is called */ total = gtodo_get_tasks_list (); today = gtodo_get_tasks_today (); gtodo_save_task_list (global_config.file); checked = TRUE; global_config.clean = TRUE; } /* every minute we check whether there are any task * that are due */ if (pGK->minute_tick) gtodo_get_tasks_due (); /* prepare the text decal of the panel */ if (total) decal_str = g_strdup_printf ("%d/%d", today, total); else decal_str = g_strdup (decal_init_string); /* computer the value for the text offset in the text decal * we only scroll if the length of the text (in pixels) is longer * then the width of the text decal */ len = gdk_string_width ((GdkFont *)(title_decal->text_style.font), decal_str); if (len > w) { x_scroll = (x_scroll + 1) % (len + w/2); title_decal->x_off = (w/2) - x_scroll; } else title_decal->x_off = w/2 - len; if (global_config.timer_on && pGK->second_tick) { gtodo_update_task_timers (); toggle = ~toggle; } gkrellm_draw_decal_text (panel, title_decal, decal_str, -1); /* blink the icon if we have any tasks due and the config says so */ if (global_config.enable_reminders && global_config.flash && !global_config.acked) { gkrellm_draw_decal_pixmap (panel, gtodo_icon_decal, get_current_pixmap_depth ()); } else { if (global_config.timer_on && total) gkrellm_draw_decal_pixmap (panel, gtodo_icon_decal, (PIXMAP_DEPTH - 1) + toggle); else gkrellm_draw_decal_pixmap (panel, gtodo_icon_decal, 0); } gkrellm_draw_panel_layers (panel); g_free (decal_str); } static void gtodo_create_plugin (GtkWidget *vbox, gint first_create) { GkrellmStyle *style; GkrellmTextstyle *ts, *ts_alt; #ifndef GKRELLM_HAVE_THEME_SCALE static GdkPixmap *gtodo_icon_pixmap; static GdkBitmap *gtodo_icon_mask; #endif gint text_decal_offset; if (first_create) panel = gkrellm_panel_new0 (); else gkrellm_destroy_decal_list (panel); style = gkrellm_meter_style (gtodo_style_id); ts = gkrellm_meter_textstyle (gtodo_style_id); ts_alt = gkrellm_meter_alt_textstyle (gtodo_style_id); /* Now, we take care of the pixmap * This is ripped from the gkrellm-reminder code for now * until I understand it */ gkrellm_load_piximage (NULL, gtodo_timer_xpm, >odo_icon_image, STYLE_NAME); #ifdef GKRELLM_HAVE_THEME_SCALE gtodo_icon_decal = gkrellm_make_scaled_decal_pixmap (panel, gtodo_icon_image, style, PIXMAP_DEPTH, -1, -1, 0, 0); #else gkrellm_scale_piximage_to_pixmap (gtodo_icon_image, >odo_icon_pixmap, &reminder_icon_mask, 0, 0); gtodo_icon_decal = gkrellm_create_decal_pixmap (panel, gtodo_icon_pixmap, gtodo_icon_mask, PIXMAP_DEPTH, style, -1, -1); #endif /* make the text decal */ text_decal_offset = style->margin.left + (style->label_position>=50?gtodo_icon_decal->w:0); title_decal = gkrellm_create_decal_text(panel, "Og", ts, style, text_decal_offset, -1, -1); /* make the text decal into a button */ gkrellm_put_decal_in_meter_button (panel, title_decal, gtodo_button_pressed, NULL, NULL); gkrellm_panel_configure (panel, NULL, style); gkrellm_panel_create (vbox, mon, panel); /* connect any signals for the meter */ if (first_create) { int i; for (i=0; idrawing_area), "expose-event", G_CALLBACK (gtodo_panel_expose_event), NULL); g_signal_connect (G_OBJECT (panel->drawing_area), "scroll-event", G_CALLBACK (gtodo_mouse_wheel_scrolled), NULL); g_signal_connect (G_OBJECT (panel->drawing_area), "button-press-event", G_CALLBACK (gtodo_panel_pressed), NULL); gtodo_load_task_list (global_config.file); } } static __inline__ gint gtodo_get_tasks_list (void) { return gtk_tree_model_iter_n_children (GTK_TREE_MODEL (task_list_store), NULL); } static gint gtodo_get_tasks_today (void) { GtkTreeIter iter; gboolean valid; glong deadline, reminder; gint perc; int count = 0; gtodo_time_struct_t now, task; valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (task_list_store), &iter); while (valid) { gtk_tree_model_get (GTK_TREE_MODEL (task_list_store), &iter, DEADLINE_COLUMN, &deadline, REMINDER_COLUMN, &reminder, COMPLETE_COLUMN, &perc, -1); gtodo_get_date_from_time (deadline, &task); gtodo_get_date_from_time (0, &now); if (reminder != 0 && // we have not acknowledged the task ((task.year == now.year) && (task.month == now.month) && // the task due take is today (task.day == now.day)) && ((global_config.remind_complete) || // we want complete notification (!global_config.remind_complete && perc < 100))) count++; // we don't want complete notification valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (task_list_store), &iter); } return count; } static gint gtodo_get_tasks_due (void) { GtkTreeIter iter; gboolean valid; glong deadline, reminder; gint count; gint perc; gchar *title = NULL, *comment = NULL; time_t now = time (NULL); valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (task_list_store), &iter); while (valid) { gtk_tree_model_get (GTK_TREE_MODEL (task_list_store), &iter, TITLE_COLUMN, &title, DEADLINE_COLUMN, &deadline, REMINDER_COLUMN, &reminder, COMPLETE_COLUMN, &perc, COMMENT_COLUMN, &comment, -1); if (reminder != 0 && ((labs (reminder) == now) || /* if the reminder is now */ (labs (reminder) < now && global_config.remind_old)) && /* we match the late tasks */ ((global_config.remind_complete) || /* we want complete notification and */ (!global_config.remind_complete && perc < 100))) { /* we don't want complete notification */ DPRINTF ("alart match, task %s", title); global_config.acked = FALSE; if (global_config.enable_reminders && global_config.popup && !gtodo_have_reminder_window (&iter)) { DPRINTF ("creating a window for task %s", title); gtodo_create_reminder_window (title, (global_config.text?global_config.text:comment), iter); } if (global_config.enable_reminders && global_config.exec) { DPRINTF ("executing command for task %s", title); gtodo_exec_command (global_config.command, &iter); } } if (reminder != 0) count++; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (task_list_store), &iter); if (title) g_free (title); if (comment) g_free (comment); } return count; } static void gtodo_exec_command (gchar *command, GtkTreeIter *iter) { gchar *s, *final=NULL, *pointer; gchar *filled, *title, *comment; glong deadline, perc, spent; gboolean active; int i = 0; DPRINTF ("original command: %s", command); if (iter == NULL) { g_spawn_command_line_async (command, NULL); return; } if (iter) gtk_tree_model_get (GTK_TREE_MODEL (task_list_store), iter, ACTIVE_COLUMN, &active, TITLE_COLUMN, &title, COMPLETE_COLUMN, &perc, DEADLINE_COLUMN, &deadline, TIME_COLUMN, &spent, COMMENT_COLUMN, &comment, -1); else { DPRINTF ("Invalid iter!"); return; } pointer = command; for (s=command; *s != '\0'; s++) { if (*s == '$' && *(s+1) != '\0') { final = g_strconcat ((final?final:""), g_strndup (pointer, i), NULL); pointer = s+2; i = 0; switch (*(s+1)) { case 'a': filled = g_strdup_printf ("%d", active); break; case 'T': filled = g_strdup (title); g_free (title); break; case 'P': filled = g_strdup_printf ("%ld%%", perc); break; case 'D': filled = gtodo_get_date_from_time_str (deadline, NULL); break; case 't': { int sec, min, hour, day; sec = spent % 60; min = (spent>=60)?(spent / 60)%60:0; hour = (spent>=3600)?(spent / 3600)%24:0; day = (spent>=86400)?(spent/86400):0; filled = g_strdup_printf ("%dd %dh %02dm %02ds", day, hour, min, sec); } break; case 'C': filled = g_strdup (comment); g_free (comment); break; case 'L': default: alert (gtk_widget_get_toplevel (GTK_WIDGET (panel->hbox)), _("While parsing command line:\nFormat '$%c' not supported!"), *(s+1)); } s++; final = g_strconcat ((final?final:""), g_strescape (filled, NULL), NULL); g_free (filled); } else i++; } if (i) final = g_strconcat ((final?final:""), g_strndup (pointer, i), NULL); DPRINTF ("parsed command: %s", final); g_spawn_command_line_async (final, NULL); g_free (final); } static void gtodo_reset_task_timers (void) { GtkTreeIter iter; gboolean valid; gboolean this; gulong value; valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (task_list_store), &iter); while (valid) { gtk_tree_model_get (GTK_TREE_MODEL (task_list_store), &iter, ACTIVE_COLUMN, &this, -1); if (this == TRUE) break; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (task_list_store), &iter); } if (valid) { gtk_tree_model_get (GTK_TREE_MODEL (task_list_store), &iter, TIME_COLUMN, &value, -1); gtk_list_store_set (GTK_LIST_STORE (task_list_store), &iter, TIME_COLUMN, 0, -1); global_config.clean = FALSE; } } static void gtodo_update_task_timers (void) { GtkTreeIter iter; gboolean valid; gboolean this; glong value; valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (task_list_store), &iter); while (valid) { gtk_tree_model_get (GTK_TREE_MODEL (task_list_store), &iter, ACTIVE_COLUMN, &this, -1); if (this == TRUE) break; valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (task_list_store), &iter); } if (valid) { gtk_tree_model_get (GTK_TREE_MODEL (task_list_store), &iter, TIME_COLUMN, &value, -1); gtk_list_store_set (GTK_LIST_STORE (task_list_store), &iter, TIME_COLUMN, value+1, -1); global_config.clean = FALSE; } } static void gtodo_clean_old_tasks (void) { GtkTreeIter iter; gboolean valid; glong deadline, reminder; valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (task_list_store), &iter); while (valid) { gtk_tree_model_get (GTK_TREE_MODEL (task_list_store), &iter, DEADLINE_COLUMN, &deadline, REMINDER_COLUMN, &reminder, -1); if ((global_config.if_acked && (deadline < time (NULL) && reminder == 0)) || (!global_config.if_acked && (deadline < time (NULL) || reminder == 0))) { valid = gtk_list_store_remove (GTK_LIST_STORE (task_list_store), &iter); global_config.clean = FALSE; } else { valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (task_list_store), &iter); } } } void gtodo_set_panel_tooltip (gchar *title, glong time, gint complete) { if (!panel_tips) panel_tips = gtk_tooltips_new (); if (title) { gtk_tooltips_set_tip (GTK_TOOLTIPS (panel_tips), GTK_WIDGET (panel->drawing_area), g_strdup_printf ("%s / %s / %d%%", title, gtodo_get_date_from_time_str (time, NULL), complete), NULL); gtk_tooltips_enable (GTK_TOOLTIPS (panel_tips)); } else gtk_tooltips_disable (GTK_TOOLTIPS (panel_tips)); } /* Gets the frame of the pixmap that should be currently * displayed. Normally, this function is not called because * the icon displayed is static. However, when an alarm/reminder * is triggered, the icon changes according to this function */ static gint get_current_pixmap_depth (void) { static gint depth; static gboolean dir; if (dir == TRUE) { /* up */ if (depth < PIXMAP_DEPTH - 3) depth++; else dir = FALSE; } else { /* down */ if (depth > 0) depth--; else dir = TRUE; } return depth; } /* Callback for any button press events * This is the callback which is called when the panel * receives an event, not the krell_button. That is why * we have to do some checking to figure out where and what * was clicked */ static gint gtodo_panel_pressed (GtkWidget *widget, GdkEventButton *event, gpointer data) { if (event->x >= gtodo_icon_decal->x && event->x < gtodo_icon_decal->x + gtodo_icon_decal->w) { switch (event->button) { case 1: gtodo_ack_task (NULL); break; case 2: if (global_config.have_active) { global_config.timer_on = !global_config.timer_on; global_config.clean = FALSE; } break; case 3: gtodo_reset_task_timers (); break; } } else if (event->button == 3) gkrellm_open_config_window (mon); return TRUE; } /* This is the callback for the text decal button, which is not the same * as the panel drawing area. This function gets called only when you left click * on the text decal. All other events go to gtodo_panel_pressed() */ static void gtodo_button_pressed (void *data) { GtkWidget *quick_view; if (!global_config.window) { quick_view = gtodo_create_quick_view (mon, NULL); gtk_widget_show_all (quick_view); global_config.window = TRUE; } } /* I really have no idea what this does or what the purpose of it is * I guess, I am going to have to read more GTK docs. The only thing * I know is that if it isn't here, the border of the panel is not * drawn and the panel looks like crap.... */ static gint gtodo_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 void gtodo_ack_task (GtkTreeIter *iter) { if (iter != NULL) { /* we only destroy the window if we are not given an * iterator, otherwise, the callback should take care * of it */ DPRINTF ("acking task"); gtk_list_store_set (GTK_LIST_STORE (task_list_store), iter, REMINDER_COLUMN, 0, -1); } else { int i; DPRINTF ("acking all active tasks"); /* we have gotten here because the blinking icon was clicked * therefore, we ack all active tasks and we close all * reminder windows */ for (i=0; istamp, reminder_list[i].window); break; } } return reminder_list[i].window; } /* check whether a window exists in the array */ static gboolean gtodo_have_reminder_window (GtkTreeIter *iter) { int i; for (i=0; istamp, reminder_list[i].window); return TRUE; } } return FALSE; } /* remove a window from the array * this function should be called only from the "destroy" callback * so the windows are properly cleaned. */ static GtkWidget *gtodo_clear_reminder_window (GtkTreeIter *iter) { int i; GtkWidget *w; for (i=0; istamp); if (reminder_list[i].window) { DPRINTF ("found task window: window=%p", reminder_list[i].window); w = reminder_list[i].window; reminder_list[i].window = NULL; } gtk_tree_iter_free (reminder_list[i].iter); break; } } return w; } static GtkWidget* gtodo_create_reminder_window (gchar *title, gchar *comment, GtkTreeIter i) { GtkWidget *reminder_window; GtkWidget *reminder_frame; GtkWidget *reminder_table; GtkWidget *remineder_hbuttonbox; GtkWidget *reminder_ok_button; GtkWidget *reminder_change_button; GtkWidget *reminder_dismiss_button; GtkWidget *reminder_scrolledwindow; GtkWidget *reminder_comment_textview; GtkWidget *reminder_icon; GtkWidget *reminder_title_lable; GdkPixmap *pixmap; GdkBitmap *mask; GtkStyle *style; GtkTextBuffer *buffer; GtkTreeIter *iter = malloc (sizeof (GtkTreeIter)); memcpy (iter, &i, sizeof (GtkTreeIter)); reminder_window = gtodo_add_reminder_window (iter); gtk_widget_show (reminder_window); gtk_window_set_title (GTK_WINDOW (reminder_window), _("G-ToDo Reminder")); reminder_frame = gtk_frame_new (_("G-ToDo Task Reminder")); gtk_container_add (GTK_CONTAINER (reminder_window), reminder_frame); gtk_frame_set_label_align (GTK_FRAME (reminder_frame), 0.04, 0.5); reminder_table = gtk_table_new (3, 3, FALSE); gtk_container_add (GTK_CONTAINER (reminder_frame), reminder_table); gtk_container_set_border_width (GTK_CONTAINER (reminder_table), 5); gtk_table_set_row_spacings (GTK_TABLE (reminder_table), 3); gtk_table_set_col_spacings (GTK_TABLE (reminder_table), 5); remineder_hbuttonbox = gtk_hbutton_box_new (); gtk_table_attach (GTK_TABLE (reminder_table), remineder_hbuttonbox, 0, 3, 2, 3, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); gtk_container_set_border_width (GTK_CONTAINER (remineder_hbuttonbox), 3); gtk_box_set_spacing (GTK_BOX (remineder_hbuttonbox), 5); reminder_ok_button = gtk_button_new_with_mnemonic (_("Acknowledge")); gtk_container_add (GTK_CONTAINER (remineder_hbuttonbox), reminder_ok_button); GTK_WIDGET_SET_FLAGS (reminder_ok_button, GTK_CAN_DEFAULT); reminder_change_button = gtk_button_new_with_mnemonic (_("Reschedule")); gtk_container_add (GTK_CONTAINER (remineder_hbuttonbox), reminder_change_button); GTK_WIDGET_SET_FLAGS (reminder_change_button, GTK_CAN_DEFAULT); reminder_dismiss_button = gtk_button_new_with_mnemonic (_("Snooze")); gtk_container_add (GTK_CONTAINER (remineder_hbuttonbox), reminder_dismiss_button); GTK_WIDGET_SET_FLAGS (reminder_dismiss_button, GTK_CAN_DEFAULT); reminder_scrolledwindow = gtk_scrolled_window_new (NULL, NULL); gtk_table_attach (GTK_TABLE (reminder_table), reminder_scrolledwindow, 0, 3, 1, 2, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); gtk_container_set_border_width (GTK_CONTAINER (reminder_scrolledwindow), 3); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (reminder_scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); reminder_comment_textview = gtk_text_view_new (); gtk_container_add (GTK_CONTAINER (reminder_scrolledwindow), reminder_comment_textview); gtk_text_view_set_editable (GTK_TEXT_VIEW (reminder_comment_textview), FALSE); gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (reminder_comment_textview), GTK_WRAP_WORD); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (reminder_comment_textview), FALSE); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (reminder_comment_textview)); gtk_text_buffer_set_text (GTK_TEXT_BUFFER (buffer), comment, -1); style = gtk_widget_get_style (reminder_window); pixmap = gdk_pixmap_create_from_xpm_d ((GdkDrawable *)(reminder_window->window), &mask, &style->bg[GTK_STATE_NORMAL], gnome_warning_xpm); reminder_icon = gtk_image_new_from_pixmap (pixmap, NULL); gtk_table_attach (GTK_TABLE (reminder_table), reminder_icon, 0, 1, 0, 1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); reminder_title_lable = gtk_label_new (title); gtk_table_attach (GTK_TABLE (reminder_table), reminder_title_lable, 1, 3, 0, 1, (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), (GtkAttachOptions) (GTK_FILL), 0, 0); gtk_label_set_justify (GTK_LABEL (reminder_title_lable), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (reminder_title_lable), 0, 0.5); g_signal_connect (G_OBJECT (reminder_window), "destroy", G_CALLBACK (on_reminder_window_destroy), iter); g_signal_connect (G_OBJECT (reminder_ok_button), "clicked", G_CALLBACK (on_reminder_ok_button_clicked), iter); g_signal_connect (G_OBJECT (reminder_change_button), "clicked", G_CALLBACK (on_reminder_change_button_clicked), iter); g_signal_connect (G_OBJECT (reminder_dismiss_button), "clicked", G_CALLBACK (on_reminder_dismiss_button_clicked), iter); gtk_widget_show_all (reminder_window); return reminder_window; } static gboolean on_reminder_window_destroy (GtkWidget *widget, gpointer data) { gtk_widget_destroy (GTK_WIDGET (gtodo_clear_reminder_window ((GtkTreeIter *)data))); return FALSE; } static void on_reminder_ok_button_clicked (GtkButton *button, gpointer data) { gtodo_ack_task ((GtkTreeIter *)data); gtk_widget_destroy (GTK_WIDGET (gtk_widget_get_toplevel (GTK_WIDGET (button)))); } static void on_reminder_change_button_clicked (GtkButton *button, gpointer data) { if (!global_config.window) { GtkWidget *window = gtodo_create_quick_view (mon, (GtkTreeIter *)data); gtk_widget_show_all (GTK_WIDGET (window)); global_config.acked = TRUE; global_config.window = TRUE; gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (button))); } } static void on_reminder_dismiss_button_clicked (GtkButton *button, gpointer data) { if (global_config.repeat_reminders) { glong value; time_t now = time (NULL); gtodo_time_struct_t ts; now += global_config.repeat_interval * 60; gtodo_get_date_from_time (now, &ts); ts.sec = 0; value = gtodo_get_time_from_date (ts); gtk_list_store_set (GTK_LIST_STORE (task_list_store), (GtkTreeIter *)data, REMINDER_COLUMN, value, -1); } global_config.acked = TRUE; gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (button))); }