gtk/plugins/timestamp.c

changeset 15415
ed1c30414686
parent 14253
b63ebf84c42b
child 20470
77693555855f
child 20472
6a6d2ef151e6
equal deleted inserted replaced
15414:3a9711edfe83 15415:ed1c30414686
1 /* 1 /*
2 * Gaim - iChat-like timestamps 2 * Gaim - iChat-style timestamps
3 * 3 *
4 * Copyright (C) 2002-2003, Sean Egan 4 * Copyright (C) 2002-2003, Sean Egan
5 * Copyright (C) 2003, Chris J. Friesen <Darth_Sebulba04@yahoo.com> 5 * Copyright (C) 2003, Chris J. Friesen <Darth_Sebulba04@yahoo.com>
6 * Copyright (C) 2007, Andrew Gaul <andrew@gaul.org>
6 * 7 *
7 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version. 11 * (at your option) any later version.
32 #include "gtkplugin.h" 33 #include "gtkplugin.h"
33 #include "gtkutils.h" 34 #include "gtkutils.h"
34 35
35 #define TIMESTAMP_PLUGIN_ID "gtk-timestamp" 36 #define TIMESTAMP_PLUGIN_ID "gtk-timestamp"
36 37
37 /* Set the default to 5 minutes. */ 38 /* minutes externally, seconds internally, and milliseconds in preferences */
38 static int interval = 5 * 60 * 1000; 39 static int interval = 5 * 60;
39 40
40 static GSList *timestamp_timeouts = NULL; 41 static void
41 42 timestamp_display(GaimConversation *conv, time_t then, time_t now)
42 static gboolean 43 {
43 do_timestamp(gpointer data) 44 GaimGtkConversation *gtk_conv = GAIM_GTK_CONVERSATION(conv);
44 { 45 GtkWidget *imhtml = gtk_conv->imhtml;
45 GaimConversation *c = (GaimConversation *)data; 46 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imhtml));
46 GaimGtkConversation *conv = GAIM_GTK_CONVERSATION(c);
47 GtkTextIter iter; 47 GtkTextIter iter;
48 const char *mdate; 48 const char *mdate;
49 int is_conversation_active; 49 int y, height;
50 time_t tim = time(NULL); 50 GdkRectangle rect;
51 51
52 if (!g_list_find(gaim_get_conversations(), c)) 52 /* display timestamp */
53 return FALSE; 53 mdate = gaim_utf8_strftime(then == 0 ? "%H:%M" : "\n%H:%M",
54 54 localtime(&now));
55 /* is_conversation_active is true if an im has been displayed since the last timestamp */ 55 gtk_text_buffer_get_end_iter(buffer, &iter);
56 is_conversation_active = GPOINTER_TO_INT(gaim_conversation_get_data(c, "timestamp-conv-active")); 56 gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, mdate,
57 57 strlen(mdate), "TIMESTAMP", NULL);
58 if (is_conversation_active){ 58
59 int y, height; 59 /* scroll view if necessary */
60 GdkRectangle rect; 60 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect);
61 gboolean scroll = TRUE; 61 gtk_text_view_get_line_yrange(
62 GtkWidget *imhtml = conv->imhtml; 62 GTK_TEXT_VIEW(imhtml), &iter, &y, &height);
63 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(imhtml)); 63 if (((y + height) - (rect.y + rect.height)) > height &&
64 gtk_text_buffer_get_end_iter(buffer, &iter); 64 gtk_text_buffer_get_char_count(buffer)) {
65 gaim_conversation_set_data(c, "timestamp-conv-active", GINT_TO_POINTER(FALSE)); 65 gboolean smooth = gaim_prefs_get_bool(
66 mdate = gaim_utf8_strftime("\n%H:%M", localtime(&tim)); 66 "/gaim/gtk/conversations/use_smooth_scrolling");
67 gtk_text_view_get_visible_rect(GTK_TEXT_VIEW(imhtml), &rect); 67 gtk_imhtml_scroll_to_end(GTK_IMHTML(imhtml), smooth);
68 gtk_text_view_get_line_yrange(GTK_TEXT_VIEW(imhtml), &iter, &y, &height);
69 if(((y + height) - (rect.y + rect.height)) > height
70 && gtk_text_buffer_get_char_count(buffer)){
71 scroll = FALSE;
72 }
73 gtk_text_buffer_insert_with_tags_by_name(buffer, &iter, mdate, strlen(mdate), "TIMESTAMP", NULL);
74 if (scroll)
75 gtk_imhtml_scroll_to_end(GTK_IMHTML(imhtml), gaim_prefs_get_bool("/gaim/gtk/conversations/use_smooth_scrolling"));
76 } 68 }
77 else 69 }
78 gaim_conversation_set_data(c, "timestamp-enabled", GINT_TO_POINTER(FALSE));
79
80 return TRUE;
81 }
82
83 70
84 static gboolean 71 static gboolean
85 timestamp_displaying_conv_msg(GaimAccount *account, const char *who, char **buffer, 72 timestamp_displaying_conv_msg(GaimAccount *account, const char *who,
86 GaimConversation *conv, GaimMessageFlags flags, void *data) 73 char **buffer, GaimConversation *conv,
87 { 74 GaimMessageFlags flags, void *data)
88 int is_timestamp_enabled; 75 {
76 time_t now = time(NULL) / interval * interval;
77 time_t then;
89 78
90 if (!g_list_find(gaim_get_conversations(), conv)) 79 if (!g_list_find(gaim_get_conversations(), conv))
91 return FALSE; 80 return FALSE;
92 81
93 /* set to true, since there has been an im since the last timestamp */ 82 then = GPOINTER_TO_INT(gaim_conversation_get_data(
94 gaim_conversation_set_data(conv, "timestamp-conv-active", GINT_TO_POINTER(TRUE)); 83 conv, "timestamp-last"));
95 84
96 is_timestamp_enabled = GPOINTER_TO_INT(gaim_conversation_get_data(conv, "timestamp-enabled")); 85 if (now - then >= interval) {
97 86 timestamp_display(conv, then, now);
98 if (!is_timestamp_enabled){ 87 gaim_conversation_set_data(
99 gaim_conversation_set_data(conv, "timestamp-enabled", GINT_TO_POINTER(TRUE)); 88 conv, "timestamp-last", GINT_TO_POINTER(now));
100 do_timestamp((gpointer)conv);
101 } 89 }
102 90
103 return FALSE; 91 return FALSE;
104 } 92 }
105 93
106 static void timestamp_new_convo(GaimConversation *conv) 94 static void
107 { 95 timestamp_new_convo(GaimConversation *conv)
108 GaimGtkConversation *c = GAIM_GTK_CONVERSATION(conv); 96 {
97 GaimGtkConversation *gtk_conv = GAIM_GTK_CONVERSATION(conv);
98 GtkTextBuffer *buffer;
109 99
110 if (!g_list_find(gaim_get_conversations(), conv)) 100 if (!g_list_find(gaim_get_conversations(), conv))
111 return; 101 return;
112 102
113 /* 103 buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(gtk_conv->imhtml));
114 This if statement stops conversations that have already been initialized for timestamps 104 gtk_text_buffer_create_tag(buffer, "TIMESTAMP",
115 from being reinitialized. This prevents every active conversation from immediately being spammed 105 "foreground", "#888888", "justification", GTK_JUSTIFY_CENTER,
116 with a new timestamp when the user modifies the timer interval. 106 "weight", PANGO_WEIGHT_BOLD, NULL);
117 */ 107
118 if (!gaim_conversation_get_data(conv, "timestamp-initialized")){ 108 gaim_conversation_set_data(conv, "timestamp-last", GINT_TO_POINTER(0));
119 GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(c->imhtml)); 109 }
120 gaim_conversation_set_data(conv, "timestamp-initialized", GINT_TO_POINTER(TRUE)); 110
121 gaim_conversation_set_data(conv, "timestamp-enabled", GINT_TO_POINTER(TRUE)); 111 static void
122 gaim_conversation_set_data(conv, "timestamp-conv-active", GINT_TO_POINTER(TRUE)); 112 set_timestamp(GtkWidget *spinner, void *null)
123 gtk_text_buffer_create_tag (buffer, "TIMESTAMP", "foreground", "#888888", "justification", GTK_JUSTIFY_CENTER, 113 {
124 "weight", PANGO_WEIGHT_BOLD, NULL);
125 do_timestamp(conv);
126 }
127
128 timestamp_timeouts = g_slist_append(timestamp_timeouts,
129 GINT_TO_POINTER(g_timeout_add(interval, do_timestamp, conv)));
130 }
131
132
133 static void destroy_timer_list()
134 {
135 GSList *to;
136
137 for (to = timestamp_timeouts; to != NULL; to = to->next)
138 g_source_remove(GPOINTER_TO_INT(to->data));
139
140 g_slist_free(timestamp_timeouts);
141
142 timestamp_timeouts = NULL;
143 }
144
145 static void init_timer_list()
146 {
147 GList *cnvs;
148 GaimConversation *c;
149
150 if (timestamp_timeouts != NULL)
151 destroy_timer_list();
152
153 for (cnvs = gaim_get_conversations(); cnvs != NULL; cnvs = cnvs->next) {
154 c = cnvs->data;
155 timestamp_new_convo(c);
156 }
157 }
158
159
160
161 static void set_timestamp(GtkWidget *spinner, void *null) {
162 int tm; 114 int tm;
163 115
164 tm = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinner)); 116 tm = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinner));
165 gaim_debug(GAIM_DEBUG_MISC, "timestamp", "setting time to %d mins\n", tm); 117 gaim_debug(GAIM_DEBUG_MISC, "timestamp",
166 118 "setting interval to %d minutes\n", tm);
167 interval = tm * 60 * 1000; 119
168 gaim_prefs_set_int("/plugins/gtk/timestamp/interval", interval); 120 interval = tm * 60;
169 121 gaim_prefs_set_int("/plugins/gtk/timestamp/interval", interval * 1000);
170 destroy_timer_list();
171 init_timer_list();
172 } 122 }
173 123
174 static GtkWidget * 124 static GtkWidget *
175 get_config_frame(GaimPlugin *plugin) 125 get_config_frame(GaimPlugin *plugin)
176 { 126 {
177 GtkWidget *ret; 127 GtkWidget *ret;
178 GtkWidget *frame, *label; 128 GtkWidget *frame, *label;
179 GtkWidget *vbox, *hbox; 129 GtkWidget *vbox, *hbox;
180 GtkAdjustment *adj; 130 GtkObject *adj;
181 GtkWidget *spinner; 131 GtkWidget *spinner;
182 132
183 ret = gtk_vbox_new(FALSE, 18); 133 ret = gtk_vbox_new(FALSE, 18);
184 gtk_container_set_border_width (GTK_CONTAINER (ret), 12); 134 gtk_container_set_border_width (GTK_CONTAINER (ret), 12);
185 135
186 frame = gaim_gtk_make_frame(ret, _("iChat Timestamp")); 136 frame = gaim_gtk_make_frame(ret, _("Display Timestamps Every"));
187 vbox = gtk_vbox_new(FALSE, 5); 137 vbox = gtk_vbox_new(FALSE, 5);
188 gtk_container_add(GTK_CONTAINER(frame), vbox); 138 gtk_container_add(GTK_CONTAINER(frame), vbox);
189 139
190 hbox = gtk_hbox_new(FALSE, 5); 140 hbox = gtk_hbox_new(FALSE, 5);
191 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5); 141 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 5);
192 142
193 label = gtk_label_new(_("Delay")); 143 /* XXX limit to divisors of 60? */
194 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); 144 adj = gtk_adjustment_new(interval / 60, 1, 60, 1, 0, 0);
195 145 spinner = gtk_spin_button_new(GTK_ADJUSTMENT(adj), 0, 0);
196 adj = (GtkAdjustment *)gtk_adjustment_new(interval/(60*1000), 1, G_MAXINT, 1, 0, 0);
197 spinner = gtk_spin_button_new(adj, 0, 0);
198 gtk_box_pack_start(GTK_BOX(hbox), spinner, TRUE, TRUE, 0); 146 gtk_box_pack_start(GTK_BOX(hbox), spinner, TRUE, TRUE, 0);
199 g_signal_connect(G_OBJECT(spinner), "value-changed", G_CALLBACK(set_timestamp), NULL); 147 g_signal_connect(G_OBJECT(spinner), "value-changed",
200 label = gtk_label_new(_("minutes.")); 148 G_CALLBACK(set_timestamp), NULL);
149 label = gtk_label_new(_("minutes"));
201 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5); 150 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 5);
202 151
203 gtk_widget_show_all(ret); 152 gtk_widget_show_all(ret);
204 return ret; 153 return ret;
205 } 154 }
208 plugin_load(GaimPlugin *plugin) 157 plugin_load(GaimPlugin *plugin)
209 { 158 {
210 void *conv_handle = gaim_conversations_get_handle(); 159 void *conv_handle = gaim_conversations_get_handle();
211 void *gtkconv_handle = gaim_gtk_conversations_get_handle(); 160 void *gtkconv_handle = gaim_gtk_conversations_get_handle();
212 161
213 init_timer_list(); 162 /* lower priority to display initial timestamp after logged messages */
214 163 gaim_signal_connect_priority(conv_handle, "conversation-created",
215 gaim_signal_connect(conv_handle, "conversation-created", 164 plugin, GAIM_CALLBACK(timestamp_new_convo), NULL,
216 plugin, GAIM_CALLBACK(timestamp_new_convo), NULL); 165 GAIM_SIGNAL_PRIORITY_DEFAULT + 1);
217 166
218 gaim_signal_connect(gtkconv_handle, "displaying-chat-msg", 167 gaim_signal_connect(gtkconv_handle, "displaying-chat-msg",
219 plugin, GAIM_CALLBACK(timestamp_displaying_conv_msg), NULL); 168 plugin, GAIM_CALLBACK(timestamp_displaying_conv_msg), NULL);
220 gaim_signal_connect(gtkconv_handle, "displaying-im-msg", 169 gaim_signal_connect(gtkconv_handle, "displaying-im-msg",
221 plugin, GAIM_CALLBACK(timestamp_displaying_conv_msg), NULL); 170 plugin, GAIM_CALLBACK(timestamp_displaying_conv_msg), NULL);
222 171
223 interval = gaim_prefs_get_int("/plugins/gtk/timestamp/interval"); 172 interval = gaim_prefs_get_int("/plugins/gtk/timestamp/interval") / 1000;
224
225 return TRUE;
226 }
227
228
229
230 static gboolean
231 plugin_unload(GaimPlugin *plugin)
232 {
233 destroy_timer_list();
234 173
235 return TRUE; 174 return TRUE;
236 } 175 }
237 176
238 static GaimGtkPluginUiInfo ui_info = 177 static GaimGtkPluginUiInfo ui_info =
254 193
255 TIMESTAMP_PLUGIN_ID, /**< id */ 194 TIMESTAMP_PLUGIN_ID, /**< id */
256 N_("Timestamp"), /**< name */ 195 N_("Timestamp"), /**< name */
257 VERSION, /**< version */ 196 VERSION, /**< version */
258 /** summary */ 197 /** summary */
259 N_("Adds iChat-style timestamps to conversations every N minutes."), 198 N_("Display iChat-style timestamps"),
260 /** description */ 199 /** description */
261 N_("Adds iChat-style timestamps to conversations every N minutes."), 200 N_("Display iChat-style timestamps every N minutes."),
262 "Sean Egan <seanegan@gmail.com>", /**< author */ 201 "Sean Egan <seanegan@gmail.com>", /**< author */
263 GAIM_WEBSITE, /**< homepage */ 202 GAIM_WEBSITE, /**< homepage */
264 203
265 plugin_load, /**< load */ 204 plugin_load, /**< load */
266 plugin_unload, /**< unload */ 205 NULL, /**< unload */
267 NULL, /**< destroy */ 206 NULL, /**< destroy */
268 207
269 &ui_info, /**< ui_info */ 208 &ui_info, /**< ui_info */
270 NULL, /**< extra_info */ 209 NULL, /**< extra_info */
271 NULL, 210 NULL,
274 213
275 static void 214 static void
276 init_plugin(GaimPlugin *plugin) 215 init_plugin(GaimPlugin *plugin)
277 { 216 {
278 gaim_prefs_add_none("/plugins/gtk/timestamp"); 217 gaim_prefs_add_none("/plugins/gtk/timestamp");
279 gaim_prefs_add_int("/plugins/gtk/timestamp/interval", interval); 218 gaim_prefs_add_int("/plugins/gtk/timestamp/interval", interval * 1000);
280 } 219 }
281 220
282 GAIM_INIT_PLUGIN(interval, init_plugin, info) 221 GAIM_INIT_PLUGIN(interval, init_plugin, info)

mercurial