pidgin/gtkdebug.c

changeset 33095
1e0b4fac0fed
parent 33094
33197cba2b9d
child 33110
a2923f41d05a
child 33163
e15b0467ef3b
equal deleted inserted replaced
33094:33197cba2b9d 33095:1e0b4fac0fed
31 #include "request.h" 31 #include "request.h"
32 #include "util.h" 32 #include "util.h"
33 33
34 #include "gtkdebug.h" 34 #include "gtkdebug.h"
35 #include "gtkdialogs.h" 35 #include "gtkdialogs.h"
36 #include "gtkimhtml.h"
37 #include "gtkutils.h" 36 #include "gtkutils.h"
37 #include "gtkwebview.h"
38 #include "pidginstock.h" 38 #include "pidginstock.h"
39 39
40 #include <gdk/gdkkeysyms.h> 40 #include <gdk/gdkkeysyms.h>
41 41
42 typedef struct 42 typedef struct
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());
123 if ((fp = g_fopen(filename, "w+")) == NULL) { 130 if ((fp = g_fopen(filename, "w+")) == NULL) {
124 purple_notify_error(win, NULL, _("Unable to open file."), NULL); 131 purple_notify_error(win, NULL, _("Unable to open file."), NULL);
125 return; 132 return;
126 } 133 }
127 134
128 tmp = gtk_imhtml_get_text(GTK_IMHTML(win->text), NULL, NULL); 135 tmp = gtk_webview_get_body_text(GTK_WEBVIEW(win->text));
129 fprintf(fp, "Pidgin Debug Log : %s\n", purple_date_format_full(NULL)); 136 fprintf(fp, "Pidgin Debug Log : %s\n", purple_date_format_full(NULL));
130 fprintf(fp, "%s", tmp); 137 fprintf(fp, "%s", tmp);
131 g_free(tmp); 138 g_free(tmp);
132 139
133 fclose(fp); 140 fclose(fp);
143 } 150 }
144 151
145 static void 152 static void
146 clear_cb(GtkWidget *w, DebugWindow *win) 153 clear_cb(GtkWidget *w, DebugWindow *win)
147 { 154 {
148 gtk_imhtml_clear(GTK_IMHTML(win->text)); 155 gtk_webview_load_html_string(GTK_WEBVIEW(win->text), EMPTY_HTML);
149
150 gtk_list_store_clear(win->store);
151 } 156 }
152 157
153 static void 158 static void
154 pause_cb(GtkWidget *w, DebugWindow *win) 159 pause_cb(GtkWidget *w, DebugWindow *win)
155 { 160 {
156 win->paused = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(w)); 161 win->paused = gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(w));
157 162
158 if(!win->paused) { 163 if (win->paused) {
159 if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) 164 gtk_webview_append_html(GTK_WEBVIEW(win->text), "<div id=pause></div>");
160 regex_filter_all(win); 165 } else {
161 else 166 WebKitDOMDocument *dom;
162 regex_show_all(win); 167 WebKitDOMElement *pause;
168
169 dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(win->text));
170 pause = webkit_dom_document_get_element_by_id(dom, "pause");
171 if (pause) {
172 WebKitDOMNode *parent;
173 parent = webkit_dom_node_get_parent_node(WEBKIT_DOM_NODE(pause));
174 webkit_dom_node_remove_child(parent, WEBKIT_DOM_NODE(pause), NULL);
175 }
163 } 176 }
164 } 177 }
165 178
166 /****************************************************************************** 179 /******************************************************************************
167 * regex stuff 180 * regex stuff
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 &&
502 G_CALLBACK(regex_menu_cb), 536 G_CALLBACK(regex_menu_cb),
503 PIDGIN_PREFS_ROOT "/debug/highlight", win->highlight); 537 PIDGIN_PREFS_ROOT "/debug/highlight", win->highlight);
504 } 538 }
505 539
506 static void 540 static void
507 regex_filter_toggled_cb(GtkToggleToolButton *button, DebugWindow *win) { 541 regex_filter_toggled_cb(GtkToggleToolButton *button, DebugWindow *win)
542 {
508 gboolean active; 543 gboolean active;
509 544
510 active = gtk_toggle_tool_button_get_active(button); 545 active = gtk_toggle_tool_button_get_active(button);
511 546
512 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/debug/filter", active); 547 purple_prefs_set_bool(PIDGIN_PREFS_ROOT "/debug/filter", active);
513 548
514 if(!GTK_IS_IMHTML(win->text)) 549 if (!GTK_IS_WEBVIEW(win->text))
515 return; 550 return;
516 551
517 if(active) 552 regex_toggle_filter(win, active);
518 regex_filter_all(win);
519 else
520 regex_show_all(win);
521 } 553 }
522 554
523 static void 555 static void
524 filter_level_pref_changed(const char *name, PurplePrefType type, gconstpointer value, gpointer data) 556 filter_level_pref_changed(const char *name, PurplePrefType type, gconstpointer value, gpointer data)
525 { 557 {
526 DebugWindow *win = data; 558 DebugWindow *win = data;
527 559 WebKitDOMDocument *dom;
528 if (GPOINTER_TO_INT(value) != gtk_combo_box_get_active(GTK_COMBO_BOX(win->filterlevel))) 560 WebKitDOMHTMLElement *body;
529 gtk_combo_box_set_active(GTK_COMBO_BOX(win->filterlevel), GPOINTER_TO_INT(value)); 561 int level = GPOINTER_TO_INT(value);
530 if(gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(win->filter))) 562 char *tmp;
531 regex_filter_all(win); 563
532 else 564 if (level != gtk_combo_box_get_active(GTK_COMBO_BOX(win->filterlevel)))
533 regex_show_all(win); 565 gtk_combo_box_set_active(GTK_COMBO_BOX(win->filterlevel), level);
566
567 dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(win->text));
568 body = webkit_dom_document_get_body(dom);
569 tmp = g_strdup_printf("l%d", level);
570 webkit_dom_html_element_set_class_name(body, tmp);
571 g_free(tmp);
534 } 572 }
535 573
536 static void 574 static void
537 filter_level_changed_cb(GtkWidget *combo, gpointer null) 575 filter_level_changed_cb(GtkWidget *combo, gpointer null)
538 { 576 {
614 G_CALLBACK(debug_window_destroy), NULL); 652 G_CALLBACK(debug_window_destroy), NULL);
615 g_signal_connect(G_OBJECT(win->window), "configure_event", 653 g_signal_connect(G_OBJECT(win->window), "configure_event",
616 G_CALLBACK(configure_cb), win); 654 G_CALLBACK(configure_cb), win);
617 655
618 handle = pidgin_debug_get_handle(); 656 handle = pidgin_debug_get_handle();
619
620 /* the list store for all the messages */
621 win->store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
622
623 /* row-changed gets called when we do gtk_list_store_set, and row-inserted
624 * gets called with gtk_list_store_append, which is a
625 * completely empty row. So we just ignore row-inserted, and deal with row
626 * changed. -Gary
627 */
628 g_signal_connect(G_OBJECT(win->store), "row-changed",
629 G_CALLBACK(regex_row_changed_cb), win);
630 657
631 /* Setup the vbox */ 658 /* Setup the vbox */
632 vbox = gtk_vbox_new(FALSE, 0); 659 vbox = gtk_vbox_new(FALSE, 0);
633 gtk_container_add(GTK_CONTAINER(win->window), vbox); 660 gtk_container_add(GTK_CONTAINER(win->window), vbox);
634 661
781 filter_level_pref_changed, win); 808 filter_level_pref_changed, win);
782 g_signal_connect(G_OBJECT(win->filterlevel), "changed", 809 g_signal_connect(G_OBJECT(win->filterlevel), "changed",
783 G_CALLBACK(filter_level_changed_cb), NULL); 810 G_CALLBACK(filter_level_changed_cb), NULL);
784 } 811 }
785 812
786 /* Add the gtkimhtml */ 813 /* Add the gtkwebview */
787 frame = pidgin_create_imhtml(FALSE, &win->text, NULL, NULL); 814 frame = pidgin_create_webview(FALSE, &win->text, NULL, NULL);
788 gtk_imhtml_set_format_functions(GTK_IMHTML(win->text), 815 gtk_webview_set_format_functions(GTK_WEBVIEW(win->text),
789 GTK_IMHTML_ALL ^ GTK_IMHTML_SMILEY ^ GTK_IMHTML_IMAGE); 816 GTK_WEBVIEW_ALL ^ GTK_WEBVIEW_SMILEY ^ GTK_WEBVIEW_IMAGE);
790 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0); 817 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 0);
791 gtk_widget_show(frame); 818 gtk_widget_show(frame);
792 819
793 /* add the tag for regex highlighting */ 820 gtk_webview_load_html_string(GTK_WEBVIEW(win->text), EMPTY_HTML);
794 gtk_text_buffer_create_tag(GTK_IMHTML(win->text)->text_buffer, "regex",
795 "background", "#FFAFAF",
796 "weight", "bold",
797 NULL);
798 821
799 gtk_widget_show_all(win->window); 822 gtk_widget_show_all(win->window);
800 823
801 return win; 824 return win;
802 } 825 }
959 982
960 static void 983 static void
961 pidgin_debug_print(PurpleDebugLevel level, const char *category, 984 pidgin_debug_print(PurpleDebugLevel level, const char *category,
962 const char *arg_s) 985 const char *arg_s)
963 { 986 {
964 GtkTreeIter iter;
965 gchar *ts_s; 987 gchar *ts_s;
966 gchar *esc_s, *cat_s, *tmp, *s; 988 gchar *esc_s, *cat_s, *tmp, *s;
967 const char *mdate; 989 const char *mdate;
968 time_t mtime; 990 time_t mtime;
969 991
982 cat_s = g_strdup_printf("<b>%s:</b> ", category); 1004 cat_s = g_strdup_printf("<b>%s:</b> ", category);
983 1005
984 tmp = purple_utf8_try_convert(arg_s); 1006 tmp = purple_utf8_try_convert(arg_s);
985 esc_s = g_markup_escape_text(tmp, -1); 1007 esc_s = g_markup_escape_text(tmp, -1);
986 1008
987 s = g_strdup_printf("<font color=\"%s\">%s%s%s</font>", 1009 s = g_strdup_printf("<div class=\"l%d\">%s%s%s</div>",
988 debug_fg_colors[level], ts_s, cat_s, esc_s); 1010 level, ts_s, cat_s, esc_s);
989 1011
990 g_free(ts_s); 1012 g_free(ts_s);
991 g_free(cat_s); 1013 g_free(cat_s);
992 g_free(esc_s); 1014 g_free(esc_s);
993 g_free(tmp); 1015 g_free(tmp);
994 1016
995 if (level == PURPLE_DEBUG_FATAL) { 1017 gtk_webview_append_html(GTK_WEBVIEW(debug_win->text), s);
996 tmp = g_strdup_printf("<b>%s</b>", s); 1018
997 g_free(s); 1019 if (gtk_toggle_tool_button_get_active(GTK_TOGGLE_TOOL_BUTTON(debug_win->filter))) {
998 s = tmp; 1020 WebKitDOMDocument *dom = NULL;
999 } 1021 WebKitDOMHTMLElement *body = NULL;
1000 1022 WebKitDOMNode *div = NULL;
1001 /* add the text to the list store */ 1023 dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(debug_win->text));
1002 gtk_list_store_append(debug_win->store, &iter); 1024 if (dom)
1003 gtk_list_store_set(debug_win->store, &iter, 0, s, 1, level, -1); 1025 body = webkit_dom_document_get_body(dom);
1026 if (body)
1027 div = webkit_dom_node_get_last_child(WEBKIT_DOM_NODE(body));
1028 if (div)
1029 regex_match(debug_win, dom, div);
1030 }
1004 1031
1005 g_free(s); 1032 g_free(s);
1006 } 1033 }
1007 1034
1008 static gboolean 1035 static gboolean
1032 pidgin_debug_get_handle() { 1059 pidgin_debug_get_handle() {
1033 static int handle; 1060 static int handle;
1034 1061
1035 return &handle; 1062 return &handle;
1036 } 1063 }
1064

mercurial