| 45 GtkWidget *text; |
45 GtkWidget *text; |
| 46 GtkWidget *filter; |
46 GtkWidget *filter; |
| 47 GtkWidget *expression; |
47 GtkWidget *expression; |
| 48 GtkWidget *filterlevel; |
48 GtkWidget *filterlevel; |
| 49 |
49 |
| 50 GtkListStore *store; |
|
| 51 |
|
| 52 gboolean paused; |
50 gboolean paused; |
| 53 |
51 |
| 54 gboolean invert; |
52 gboolean invert; |
| 55 gboolean highlight; |
53 gboolean highlight; |
| 56 guint timer; |
54 guint timer; |
| 57 GRegex *regex; |
55 GRegex *regex; |
| 58 } DebugWindow; |
56 } DebugWindow; |
| 59 |
57 |
| 60 static const char debug_fg_colors[][8] = { |
58 #define EMPTY_HTML \ |
| 61 "#000000", /**< All debug levels. */ |
59 "<html><head><style>" \ |
| 62 "#666666", /**< Misc. */ |
60 "body{white-space:pre-wrap;}" \ |
| 63 "#000000", /**< Information. */ |
61 "div.l0{color:#000000;}" /* All debug levels. */ \ |
| 64 "#660000", /**< Warnings. */ |
62 "div.l1{color:#666666;}" /* Misc. */ \ |
| 65 "#FF0000", /**< Errors. */ |
63 "div.l2{color:#000000;}" /* Information. */ \ |
| 66 "#FF0000", /**< Fatal errors. */ |
64 "div.l3{color:#660000;}" /* Warnings. */ \ |
| 67 }; |
65 "div.l4{color:#FF0000;}" /* Errors. */ \ |
| |
66 "div.l5{color:#FF0000;font-weight:bold;}" /* Fatal errors. */ \ |
| |
67 /* Filter levels */ \ |
| |
68 "div#pause~div{display:none;}" \ |
| |
69 "body.l1 div.l0{display:none;}" \ |
| |
70 "body.l2 div.l0,body.l2 div.l1{display:none;}" \ |
| |
71 "body.l3 div.l0,body.l3 div.l1,body.l3 div.l2{display:none;}" \ |
| |
72 "body.l4 div.l0,body.l4 div.l1,body.l4 div.l2,body.l4 div.l3{display:none;}" \ |
| |
73 "body.l5 div.l0,body.l5 div.l1,body.l5 div.l2,body.l5 div.l3,body.l5 div.l4{display:none;}" \ |
| |
74 /* Regex */ \ |
| |
75 "div.hide{display:none;}" \ |
| |
76 "span.regex{background-color:#ffafaf;font-weight:bold;}" \ |
| |
77 "</style></head></html>" |
| 68 |
78 |
| 69 static DebugWindow *debug_win = NULL; |
79 static DebugWindow *debug_win = NULL; |
| 70 static guint debug_enabled_timer = 0; |
80 static guint debug_enabled_timer = 0; |
| 71 |
|
| 72 static void regex_filter_all(DebugWindow *win); |
|
| 73 static void regex_show_all(DebugWindow *win); |
|
| 74 |
81 |
| 75 static gint |
82 static gint |
| 76 debug_window_destroy(GtkWidget *w, GdkEvent *event, void *unused) |
83 debug_window_destroy(GtkWidget *w, GdkEvent *event, void *unused) |
| 77 { |
84 { |
| 78 purple_prefs_disconnect_by_handle(pidgin_debug_get_handle()); |
85 purple_prefs_disconnect_by_handle(pidgin_debug_get_handle()); |
| 181 |
194 |
| 182 gtk_widget_modify_base(w, GTK_STATE_NORMAL, &color); |
195 gtk_widget_modify_base(w, GTK_STATE_NORMAL, &color); |
| 183 } |
196 } |
| 184 |
197 |
| 185 static void |
198 static void |
| 186 regex_highlight_clear(DebugWindow *win) { |
199 regex_toggle_div(WebKitDOMNode *div) |
| 187 GtkIMHtml *imhtml = GTK_IMHTML(win->text); |
200 { |
| 188 GtkTextIter s, e; |
201 WebKitDOMDOMTokenList *classes; |
| 189 |
202 |
| 190 gtk_text_buffer_get_start_iter(imhtml->text_buffer, &s); |
203 if (!WEBKIT_DOM_IS_HTML_ELEMENT(div)) |
| 191 gtk_text_buffer_get_end_iter(imhtml->text_buffer, &e); |
204 return; |
| 192 gtk_text_buffer_remove_tag_by_name(imhtml->text_buffer, "regex", &s, &e); |
205 |
| 193 } |
206 classes = webkit_dom_html_element_get_class_list(WEBKIT_DOM_HTML_ELEMENT(div)); |
| 194 |
207 webkit_dom_dom_token_list_toggle(classes, "hide", NULL); |
| 195 static void |
208 } |
| 196 regex_match(DebugWindow *win, const gchar *text) { |
209 |
| 197 GtkIMHtml *imhtml = GTK_IMHTML(win->text); |
210 static void |
| |
211 regex_highlight_clear(WebKitDOMDocument *dom) |
| |
212 { |
| |
213 WebKitDOMNodeList *nodes; |
| |
214 gulong i; |
| |
215 |
| |
216 /* Remove highlighting SPANs */ |
| |
217 nodes = webkit_dom_document_get_elements_by_class_name(dom, "regex"); |
| |
218 i = webkit_dom_node_list_get_length(nodes); |
| |
219 while (i--) { |
| |
220 WebKitDOMNode *span, *parent; |
| |
221 char *content; |
| |
222 WebKitDOMText *text; |
| |
223 GError *err = NULL; |
| |
224 |
| |
225 span = webkit_dom_node_list_item(nodes, i); |
| |
226 parent = webkit_dom_node_get_parent_node(span); |
| |
227 |
| |
228 content = webkit_dom_node_get_text_content(span); |
| |
229 text = webkit_dom_document_create_text_node(dom, content); |
| |
230 g_free(content); |
| |
231 |
| |
232 webkit_dom_node_replace_child(parent, WEBKIT_DOM_NODE(text), span, &err); |
| |
233 } |
| |
234 } |
| |
235 |
| |
236 static void |
| |
237 regex_highlight_text_nodes(WebKitDOMDocument *dom, WebKitDOMNode *div, |
| |
238 gint start_pos, gint end_pos) |
| |
239 { |
| |
240 GSList *data = NULL; |
| |
241 WebKitDOMNode *node; |
| |
242 WebKitDOMRange *range; |
| |
243 WebKitDOMElement *span; |
| |
244 gint ind, end_ind; |
| |
245 gint this_start, this_end; |
| |
246 |
| |
247 ind = 0; |
| |
248 webkit_dom_node_normalize(div); |
| |
249 node = div; |
| |
250 |
| |
251 /* First, find the container nodes and offsets to apply highlighting. */ |
| |
252 do { |
| |
253 if (webkit_dom_node_get_node_type(node) == 3/*TEXT_NODE*/) { |
| |
254 /* The GObject model does not correctly reflect the type, hence the |
| |
255 regular cast. */ |
| |
256 end_ind = ind + webkit_dom_character_data_get_length((WebKitDOMCharacterData*)node); |
| |
257 |
| |
258 if (start_pos <= ind) |
| |
259 this_start = 0; |
| |
260 else if (start_pos < end_ind) |
| |
261 this_start = start_pos - ind; |
| |
262 else |
| |
263 this_start = -1; |
| |
264 |
| |
265 if (end_pos < end_ind) |
| |
266 this_end = end_pos - ind; |
| |
267 else |
| |
268 this_end = end_ind - ind; |
| |
269 |
| |
270 if (this_start != -1 && this_start < this_end) { |
| |
271 data = g_slist_prepend(data, GINT_TO_POINTER(this_end)); |
| |
272 data = g_slist_prepend(data, GINT_TO_POINTER(this_start)); |
| |
273 data = g_slist_prepend(data, node); |
| |
274 } |
| |
275 |
| |
276 ind = end_ind; |
| |
277 } |
| |
278 |
| |
279 if (webkit_dom_node_has_child_nodes(node)) { |
| |
280 node = webkit_dom_node_get_first_child(node); |
| |
281 } else { |
| |
282 while (node != div) { |
| |
283 WebKitDOMNode *next; |
| |
284 |
| |
285 next = webkit_dom_node_get_next_sibling(node); |
| |
286 if (next) { |
| |
287 node = next; |
| |
288 break; |
| |
289 } else { |
| |
290 node = webkit_dom_node_get_parent_node(node); |
| |
291 } |
| |
292 } |
| |
293 } |
| |
294 } while (node != div); |
| |
295 |
| |
296 /* Second, apply highlighting to saved sections. Changing the DOM is |
| |
297 automatically reflected in all WebKit API, so we have to do this after |
| |
298 finding the offsets, or things could get complicated. */ |
| |
299 while (data) { |
| |
300 node = WEBKIT_DOM_NODE(data->data); |
| |
301 data = g_slist_delete_link(data, data); |
| |
302 this_start = GPOINTER_TO_INT(data->data); |
| |
303 data = g_slist_delete_link(data, data); |
| |
304 this_end = GPOINTER_TO_INT(data->data); |
| |
305 data = g_slist_delete_link(data, data); |
| |
306 |
| |
307 range = webkit_dom_document_create_range(dom); |
| |
308 webkit_dom_range_set_start(range, node, this_start, NULL); |
| |
309 webkit_dom_range_set_end(range, node, this_end, NULL); |
| |
310 span = webkit_dom_document_create_element(dom, "span", NULL); |
| |
311 webkit_dom_html_element_set_class_name(WEBKIT_DOM_HTML_ELEMENT(span), |
| |
312 "regex"); |
| |
313 webkit_dom_range_surround_contents(range, WEBKIT_DOM_NODE(span), NULL); |
| |
314 } |
| |
315 } |
| |
316 |
| |
317 static void |
| |
318 regex_match(DebugWindow *win, WebKitDOMDocument *dom, WebKitDOMNode *div) |
| |
319 { |
| 198 GMatchInfo *match_info; |
320 GMatchInfo *match_info; |
| |
321 gchar *text; |
| 199 gchar *plaintext; |
322 gchar *plaintext; |
| 200 |
323 |
| 201 if(!text) |
324 text = webkit_dom_node_get_text_content(div); |
| |
325 if (!text) |
| 202 return; |
326 return; |
| 203 |
327 |
| 204 /* I don't like having to do this, but we need it for highlighting. Plus |
328 /* I don't like having to do this, but we need it for highlighting. Plus |
| 205 * it makes the ^ and $ operators work :) |
329 * it makes the ^ and $ operators work :) |
| 206 */ |
330 */ |
| 207 plaintext = purple_markup_strip_html(text); |
331 plaintext = purple_markup_strip_html(text); |
| 208 |
332 |
| 209 /* we do a first pass to see if it matches at all. If it does we append |
333 /* We do a first pass to see if it matches at all. If it does we work out |
| 210 * it, and work out the offsets to highlight. |
334 * the offsets to highlight. |
| 211 */ |
335 */ |
| 212 if(g_regex_match(win->regex, plaintext, 0, &match_info) != win->invert) { |
336 if (g_regex_match(win->regex, plaintext, 0, &match_info) != win->invert) { |
| 213 gchar *p = plaintext; |
|
| 214 GtkTextIter ins; |
|
| 215 gint i, offset = 0; |
|
| 216 |
|
| 217 gtk_text_buffer_get_iter_at_mark(imhtml->text_buffer, &ins, |
|
| 218 gtk_text_buffer_get_insert(imhtml->text_buffer)); |
|
| 219 i = gtk_text_iter_get_offset(&ins); |
|
| 220 |
|
| 221 gtk_imhtml_append_text(imhtml, text, 0); |
|
| 222 |
|
| 223 /* If we're not highlighting or the expression is inverted, we're |
337 /* If we're not highlighting or the expression is inverted, we're |
| 224 * done and move on. |
338 * done and move on. |
| 225 */ |
339 */ |
| 226 if(!win->highlight || win->invert) { |
340 if (!win->highlight || win->invert) { |
| 227 g_free(plaintext); |
341 g_free(plaintext); |
| 228 g_match_info_free(match_info); |
342 g_match_info_free(match_info); |
| 229 return; |
343 return; |
| 230 } |
344 } |
| 231 |
345 |
| 232 /* we use a do-while to highlight the first match, and then continue |
346 do { |
| 233 * if necessary... |
|
| 234 */ |
|
| 235 do |
|
| 236 { |
|
| 237 gint m, count; |
347 gint m, count; |
| 238 gint start_pos, end_pos; |
348 gint start_pos, end_pos; |
| 239 GtkTextIter ms, me; |
|
| 240 |
349 |
| 241 if (!g_match_info_matches(match_info)) |
350 if (!g_match_info_matches(match_info)) |
| 242 break; |
351 break; |
| 243 |
352 |
| 244 count = g_match_info_get_match_count(match_info); |
353 count = g_match_info_get_match_count(match_info); |
| 252 g_match_info_fetch_pos(match_info, m, &start_pos, &end_pos); |
361 g_match_info_fetch_pos(match_info, m, &start_pos, &end_pos); |
| 253 |
362 |
| 254 if (end_pos == -1) |
363 if (end_pos == -1) |
| 255 break; |
364 break; |
| 256 |
365 |
| 257 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &ms, |
366 regex_highlight_text_nodes(dom, div, start_pos, end_pos); |
| 258 i + start_pos); |
|
| 259 gtk_text_buffer_get_iter_at_offset(imhtml->text_buffer, &me, |
|
| 260 i + end_pos); |
|
| 261 gtk_text_buffer_apply_tag_by_name(imhtml->text_buffer, "regex", |
|
| 262 &ms, &me); |
|
| 263 offset = end_pos; |
|
| 264 } |
367 } |
| 265 |
368 } while (g_match_info_next(match_info, NULL)); |
| 266 g_match_info_free(match_info); |
369 |
| 267 p += offset; |
|
| 268 i += offset; |
|
| 269 } while (g_regex_match(win->regex, p, G_REGEX_MATCH_NOTBOL, &match_info) != win->invert); |
|
| 270 g_match_info_free(match_info); |
370 g_match_info_free(match_info); |
| |
371 } else { |
| |
372 regex_toggle_div(div); |
| 271 } |
373 } |
| 272 |
374 |
| 273 g_free(plaintext); |
375 g_free(plaintext); |
| |
376 g_free(text); |
| |
377 } |
| |
378 |
| |
379 static void |
| |
380 regex_toggle_filter(DebugWindow *win, gboolean filter) |
| |
381 { |
| |
382 WebKitDOMDocument *dom; |
| |
383 WebKitDOMNodeList *list; |
| |
384 gulong i; |
| |
385 |
| |
386 dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(win->text)); |
| |
387 |
| |
388 if (win->highlight) |
| |
389 regex_highlight_clear(dom); |
| |
390 |
| |
391 /* Re-show debug lines that didn't match regex */ |
| |
392 list = webkit_dom_document_get_elements_by_class_name(dom, "hide"); |
| |
393 i = webkit_dom_node_list_get_length(list); |
| |
394 while (i--) { |
| |
395 WebKitDOMNode *div = webkit_dom_node_list_item(list, i); |
| |
396 regex_toggle_div(div); |
| |
397 } |
| |
398 |
| |
399 if (filter) { |
| |
400 list = webkit_dom_document_get_elements_by_tag_name(dom, "div"); |
| |
401 |
| |
402 for (i = 0; i < webkit_dom_node_list_get_length(list); i++) { |
| |
403 WebKitDOMNode *div = webkit_dom_node_list_item(list, i); |
| |
404 regex_match(win, dom, div); |
| |
405 } |
| |
406 } |
| |
407 } |
| |
408 |
| |
409 static void |
| |
410 regex_pref_filter_cb(const gchar *name, PurplePrefType type, |
| |
411 gconstpointer val, gpointer data) |
| |
412 { |
| |
413 DebugWindow *win = (DebugWindow *)data; |
| |
414 gboolean active = GPOINTER_TO_INT(val), current; |
| |
415 |
| |
416 if (!win || !win->window) |
| |
417 return; |
| |
418 |
| |
419 current = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter)); |
| |
420 if (active != current) |
| |
421 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), active); |
| |
422 } |
| |
423 |
| |
424 static void |
| |
425 regex_pref_expression_cb(const gchar *name, PurplePrefType type, |
| |
426 gconstpointer val, gpointer data) |
| |
427 { |
| |
428 DebugWindow *win = (DebugWindow *)data; |
| |
429 const gchar *exp = (const gchar *)val; |
| |
430 |
| |
431 gtk_entry_set_text(GTK_ENTRY(win->expression), exp); |
| |
432 } |
| |
433 |
| |
434 static void |
| |
435 regex_pref_invert_cb(const gchar *name, PurplePrefType type, |
| |
436 gconstpointer val, gpointer data) |
| |
437 { |
| |
438 DebugWindow *win = (DebugWindow *)data; |
| |
439 gboolean active = GPOINTER_TO_INT(val); |
| |
440 |
| |
441 win->invert = active; |
| |
442 |
| |
443 if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) |
| |
444 regex_toggle_filter(win, TRUE); |
| |
445 } |
| |
446 |
| |
447 static void |
| |
448 regex_pref_highlight_cb(const gchar *name, PurplePrefType type, |
| |
449 gconstpointer val, gpointer data) |
| |
450 { |
| |
451 DebugWindow *win = (DebugWindow *)data; |
| |
452 gboolean active = GPOINTER_TO_INT(val); |
| |
453 |
| |
454 win->highlight = active; |
| |
455 |
| |
456 if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) |
| |
457 regex_toggle_filter(win, TRUE); |
| 274 } |
458 } |
| 275 |
459 |
| 276 static gboolean |
460 static gboolean |
| 277 regex_filter_all_cb(GtkTreeModel *m, GtkTreePath *p, GtkTreeIter *iter, |
461 regex_timer_cb(DebugWindow *win) { |
| 278 gpointer data) |
462 const gchar *text; |
| 279 { |
463 |
| 280 DebugWindow *win = (DebugWindow *)data; |
464 text = gtk_entry_get_text(GTK_ENTRY(win->expression)); |
| 281 gchar *text; |
465 purple_prefs_set_string(PIDGIN_PREFS_ROOT "/debug/regex", text); |
| 282 PurpleDebugLevel level; |
466 |
| 283 |
467 win->timer = 0; |
| 284 gtk_tree_model_get(m, iter, 0, &text, 1, &level, -1); |
|
| 285 |
|
| 286 if (level >= purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/filterlevel")) |
|
| 287 regex_match(win, text); |
|
| 288 |
|
| 289 g_free(text); |
|
| 290 |
468 |
| 291 return FALSE; |
469 return FALSE; |
| 292 } |
470 } |
| 293 |
471 |
| 294 static void |
472 static void |
| 295 regex_filter_all(DebugWindow *win) { |
473 regex_changed_cb(GtkWidget *w, DebugWindow *win) { |
| 296 gtk_imhtml_clear(GTK_IMHTML(win->text)); |
|
| 297 |
|
| 298 if(win->highlight) |
|
| 299 regex_highlight_clear(win); |
|
| 300 |
|
| 301 gtk_tree_model_foreach(GTK_TREE_MODEL(win->store), regex_filter_all_cb, |
|
| 302 win); |
|
| 303 } |
|
| 304 |
|
| 305 static gboolean |
|
| 306 regex_show_all_cb(GtkTreeModel *m, GtkTreePath *p, GtkTreeIter *iter, |
|
| 307 gpointer data) |
|
| 308 { |
|
| 309 DebugWindow *win = (DebugWindow *)data; |
|
| 310 gchar *text; |
|
| 311 PurpleDebugLevel level; |
|
| 312 |
|
| 313 gtk_tree_model_get(m, iter, 0, &text, 1, &level, -1); |
|
| 314 if (level >= purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/filterlevel")) |
|
| 315 gtk_imhtml_append_text(GTK_IMHTML(win->text), text, 0); |
|
| 316 g_free(text); |
|
| 317 |
|
| 318 return FALSE; |
|
| 319 } |
|
| 320 |
|
| 321 static void |
|
| 322 regex_show_all(DebugWindow *win) { |
|
| 323 gtk_imhtml_clear(GTK_IMHTML(win->text)); |
|
| 324 |
|
| 325 if(win->highlight) |
|
| 326 regex_highlight_clear(win); |
|
| 327 |
|
| 328 gtk_tree_model_foreach(GTK_TREE_MODEL(win->store), regex_show_all_cb, |
|
| 329 win); |
|
| 330 } |
|
| 331 |
|
| 332 static void |
|
| 333 regex_compile(DebugWindow *win) { |
|
| 334 const gchar *text; |
474 const gchar *text; |
| 335 |
475 |
| |
476 if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) { |
| |
477 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), |
| |
478 FALSE); |
| |
479 } |
| |
480 |
| |
481 if (win->timer == 0) |
| |
482 win->timer = purple_timeout_add_seconds(5, (GSourceFunc)regex_timer_cb, win); |
| |
483 |
| 336 text = gtk_entry_get_text(GTK_ENTRY(win->expression)); |
484 text = gtk_entry_get_text(GTK_ENTRY(win->expression)); |
| 337 |
485 |
| 338 if(text == NULL || *text == '\0') { |
486 if (text == NULL || *text == '\0') { |
| 339 regex_clear_color(win->expression); |
487 regex_clear_color(win->expression); |
| 340 gtk_widget_set_sensitive(win->filter, FALSE); |
488 gtk_widget_set_sensitive(win->filter, FALSE); |
| 341 return; |
489 return; |
| 342 } |
490 } |
| 343 |
491 |
| 344 if (win->regex) |
492 if (win->regex) |
| 345 g_regex_unref(win->regex); |
493 g_regex_unref(win->regex); |
| 346 win->regex = g_regex_new(text, G_REGEX_CASELESS, 0, NULL); |
494 win->regex = g_regex_new(text, G_REGEX_CASELESS, 0, NULL); |
| 347 if(win->regex == NULL) { |
495 if (win->regex == NULL) { |
| 348 /* failed to compile */ |
496 /* failed to compile */ |
| 349 regex_change_color(win->expression, 0xFFFF, 0xAFFF, 0xAFFF); |
497 regex_change_color(win->expression, 0xFFFF, 0xAFFF, 0xAFFF); |
| 350 gtk_widget_set_sensitive(win->filter, FALSE); |
498 gtk_widget_set_sensitive(win->filter, FALSE); |
| 351 } else { |
499 } else { |
| 352 /* compiled successfully */ |
500 /* compiled successfully */ |
| 353 regex_change_color(win->expression, 0xAFFF, 0xFFFF, 0xAFFF); |
501 regex_change_color(win->expression, 0xAFFF, 0xFFFF, 0xAFFF); |
| 354 gtk_widget_set_sensitive(win->filter, TRUE); |
502 gtk_widget_set_sensitive(win->filter, TRUE); |
| 355 } |
503 } |
| 356 |
|
| 357 /* we check if the filter is on in case it was only of the options that |
|
| 358 * got changed, and not the expression. |
|
| 359 */ |
|
| 360 if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) |
|
| 361 regex_filter_all(win); |
|
| 362 } |
|
| 363 |
|
| 364 static void |
|
| 365 regex_pref_filter_cb(const gchar *name, PurplePrefType type, |
|
| 366 gconstpointer val, gpointer data) |
|
| 367 { |
|
| 368 DebugWindow *win = (DebugWindow *)data; |
|
| 369 gboolean active = GPOINTER_TO_INT(val), current; |
|
| 370 |
|
| 371 if(!win || !win->window) |
|
| 372 return; |
|
| 373 |
|
| 374 current = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter)); |
|
| 375 if(active != current) |
|
| 376 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), active); |
|
| 377 } |
|
| 378 |
|
| 379 static void |
|
| 380 regex_pref_expression_cb(const gchar *name, PurplePrefType type, |
|
| 381 gconstpointer val, gpointer data) |
|
| 382 { |
|
| 383 DebugWindow *win = (DebugWindow *)data; |
|
| 384 const gchar *exp = (const gchar *)val; |
|
| 385 |
|
| 386 gtk_entry_set_text(GTK_ENTRY(win->expression), exp); |
|
| 387 } |
|
| 388 |
|
| 389 static void |
|
| 390 regex_pref_invert_cb(const gchar *name, PurplePrefType type, |
|
| 391 gconstpointer val, gpointer data) |
|
| 392 { |
|
| 393 DebugWindow *win = (DebugWindow *)data; |
|
| 394 gboolean active = GPOINTER_TO_INT(val); |
|
| 395 |
|
| 396 win->invert = active; |
|
| 397 |
|
| 398 if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) |
|
| 399 regex_filter_all(win); |
|
| 400 } |
|
| 401 |
|
| 402 static void |
|
| 403 regex_pref_highlight_cb(const gchar *name, PurplePrefType type, |
|
| 404 gconstpointer val, gpointer data) |
|
| 405 { |
|
| 406 DebugWindow *win = (DebugWindow *)data; |
|
| 407 gboolean active = GPOINTER_TO_INT(val); |
|
| 408 |
|
| 409 win->highlight = active; |
|
| 410 |
|
| 411 if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) |
|
| 412 regex_filter_all(win); |
|
| 413 } |
|
| 414 |
|
| 415 static void |
|
| 416 regex_row_changed_cb(GtkTreeModel *model, GtkTreePath *path, |
|
| 417 GtkTreeIter *iter, DebugWindow *win) |
|
| 418 { |
|
| 419 gchar *text; |
|
| 420 PurpleDebugLevel level; |
|
| 421 |
|
| 422 if(!win || !win->window) |
|
| 423 return; |
|
| 424 |
|
| 425 /* If the debug window is paused, we just return since it's in the store. |
|
| 426 * We don't call regex_match because it doesn't make sense to check the |
|
| 427 * string if it's paused. When we unpause we clear the imhtml and |
|
| 428 * reiterate over the store to handle matches that were outputted when |
|
| 429 * we were paused. |
|
| 430 */ |
|
| 431 if(win->paused) |
|
| 432 return; |
|
| 433 |
|
| 434 gtk_tree_model_get(model, iter, 0, &text, 1, &level, -1); |
|
| 435 |
|
| 436 if (level >= purple_prefs_get_int(PIDGIN_PREFS_ROOT "/debug/filterlevel")) { |
|
| 437 if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) { |
|
| 438 regex_match(win, text); |
|
| 439 } else { |
|
| 440 gtk_imhtml_append_text(GTK_IMHTML(win->text), text, 0); |
|
| 441 } |
|
| 442 } |
|
| 443 |
|
| 444 g_free(text); |
|
| 445 } |
|
| 446 |
|
| 447 static gboolean |
|
| 448 regex_timer_cb(DebugWindow *win) { |
|
| 449 const gchar *text; |
|
| 450 |
|
| 451 text = gtk_entry_get_text(GTK_ENTRY(win->expression)); |
|
| 452 purple_prefs_set_string(PIDGIN_PREFS_ROOT "/debug/regex", text); |
|
| 453 |
|
| 454 win->timer = 0; |
|
| 455 |
|
| 456 return FALSE; |
|
| 457 } |
|
| 458 |
|
| 459 static void |
|
| 460 regex_changed_cb(GtkWidget *w, DebugWindow *win) { |
|
| 461 if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) { |
|
| 462 gtk_toggle_tool_button_set_active(GTK_TOGGLE_TOOL_BUTTON(win->filter), |
|
| 463 FALSE); |
|
| 464 } |
|
| 465 |
|
| 466 if(win->timer == 0) |
|
| 467 win->timer = purple_timeout_add_seconds(5, (GSourceFunc)regex_timer_cb, win); |
|
| 468 |
|
| 469 regex_compile(win); |
|
| 470 } |
504 } |
| 471 |
505 |
| 472 static void |
506 static void |
| 473 regex_key_release_cb(GtkWidget *w, GdkEventKey *e, DebugWindow *win) { |
507 regex_key_release_cb(GtkWidget *w, GdkEventKey *e, DebugWindow *win) { |
| 474 if(e->keyval == GDK_Return && |
508 if(e->keyval == GDK_Return && |