| 164 |
164 |
| 165 gtk_widget_modify_base(w, GTK_STATE_NORMAL, &color); |
165 gtk_widget_modify_base(w, GTK_STATE_NORMAL, &color); |
| 166 } |
166 } |
| 167 |
167 |
| 168 static void |
168 static void |
| 169 regex_toggle_div(WebKitDOMNode *div) |
|
| 170 { |
|
| 171 WebKitDOMDOMTokenList *classes; |
|
| 172 |
|
| 173 if (!WEBKIT_DOM_IS_HTML_ELEMENT(div)) |
|
| 174 return; |
|
| 175 |
|
| 176 #if (WEBKIT_MAJOR_VERSION == 1 && \ |
|
| 177 WEBKIT_MINOR_VERSION == 9 && \ |
|
| 178 WEBKIT_MICRO_VERSION == 90) |
|
| 179 /* Workaround WebKit API bug. */ |
|
| 180 classes = webkit_dom_element_get_class_list(WEBKIT_DOM_ELEMENT(div)); |
|
| 181 #else |
|
| 182 classes = webkit_dom_html_element_get_class_list(WEBKIT_DOM_HTML_ELEMENT(div)); |
|
| 183 #endif |
|
| 184 webkit_dom_dom_token_list_toggle(classes, "hide", NULL); |
|
| 185 g_object_unref(classes); |
|
| 186 } |
|
| 187 |
|
| 188 static void |
|
| 189 regex_highlight_clear(WebKitDOMDocument *dom) |
|
| 190 { |
|
| 191 WebKitDOMNodeList *nodes; |
|
| 192 gulong i; |
|
| 193 |
|
| 194 /* Remove highlighting SPANs */ |
|
| 195 nodes = webkit_dom_document_get_elements_by_class_name(dom, "regex"); |
|
| 196 i = webkit_dom_node_list_get_length(nodes); |
|
| 197 while (i--) { |
|
| 198 WebKitDOMNode *span, *parent; |
|
| 199 char *content; |
|
| 200 WebKitDOMText *text; |
|
| 201 GError *err = NULL; |
|
| 202 |
|
| 203 span = webkit_dom_node_list_item(nodes, i); |
|
| 204 parent = webkit_dom_node_get_parent_node(span); |
|
| 205 |
|
| 206 content = webkit_dom_node_get_text_content(span); |
|
| 207 text = webkit_dom_document_create_text_node(dom, content); |
|
| 208 g_free(content); |
|
| 209 |
|
| 210 webkit_dom_node_replace_child(parent, WEBKIT_DOM_NODE(text), span, &err); |
|
| 211 } |
|
| 212 |
|
| 213 g_object_unref(nodes); |
|
| 214 } |
|
| 215 |
|
| 216 static void |
|
| 217 regex_highlight_text_nodes(WebKitDOMDocument *dom, WebKitDOMNode *div, |
|
| 218 gint start_pos, gint end_pos) |
|
| 219 { |
|
| 220 GSList *data = NULL; |
|
| 221 WebKitDOMNode *node; |
|
| 222 WebKitDOMRange *range; |
|
| 223 WebKitDOMElement *span; |
|
| 224 gint ind, end_ind; |
|
| 225 gint this_start, this_end; |
|
| 226 |
|
| 227 ind = 0; |
|
| 228 webkit_dom_node_normalize(div); |
|
| 229 node = div; |
|
| 230 |
|
| 231 /* First, find the container nodes and offsets to apply highlighting. */ |
|
| 232 do { |
|
| 233 if (webkit_dom_node_get_node_type(node) == 3/*TEXT_NODE*/) { |
|
| 234 /* The GObject model does not correctly reflect the type, hence the |
|
| 235 regular cast. */ |
|
| 236 end_ind = ind + webkit_dom_character_data_get_length((WebKitDOMCharacterData*)node); |
|
| 237 |
|
| 238 if (start_pos <= ind) |
|
| 239 this_start = 0; |
|
| 240 else if (start_pos < end_ind) |
|
| 241 this_start = start_pos - ind; |
|
| 242 else |
|
| 243 this_start = -1; |
|
| 244 |
|
| 245 if (end_pos < end_ind) |
|
| 246 this_end = end_pos - ind; |
|
| 247 else |
|
| 248 this_end = end_ind - ind; |
|
| 249 |
|
| 250 if (this_start != -1 && this_start < this_end) { |
|
| 251 data = g_slist_prepend(data, GINT_TO_POINTER(this_end)); |
|
| 252 data = g_slist_prepend(data, GINT_TO_POINTER(this_start)); |
|
| 253 data = g_slist_prepend(data, node); |
|
| 254 } |
|
| 255 |
|
| 256 ind = end_ind; |
|
| 257 } |
|
| 258 |
|
| 259 if (webkit_dom_node_has_child_nodes(node)) { |
|
| 260 node = webkit_dom_node_get_first_child(node); |
|
| 261 } else { |
|
| 262 while (node != div) { |
|
| 263 WebKitDOMNode *next; |
|
| 264 |
|
| 265 next = webkit_dom_node_get_next_sibling(node); |
|
| 266 if (next) { |
|
| 267 node = next; |
|
| 268 break; |
|
| 269 } else { |
|
| 270 node = webkit_dom_node_get_parent_node(node); |
|
| 271 } |
|
| 272 } |
|
| 273 } |
|
| 274 } while (node != div); |
|
| 275 |
|
| 276 /* Second, apply highlighting to saved sections. Changing the DOM is |
|
| 277 automatically reflected in all WebKit API, so we have to do this after |
|
| 278 finding the offsets, or things could get complicated. */ |
|
| 279 while (data) { |
|
| 280 node = WEBKIT_DOM_NODE(data->data); |
|
| 281 data = g_slist_delete_link(data, data); |
|
| 282 this_start = GPOINTER_TO_INT(data->data); |
|
| 283 data = g_slist_delete_link(data, data); |
|
| 284 this_end = GPOINTER_TO_INT(data->data); |
|
| 285 data = g_slist_delete_link(data, data); |
|
| 286 |
|
| 287 range = webkit_dom_document_create_range(dom); |
|
| 288 webkit_dom_range_set_start(range, node, this_start, NULL); |
|
| 289 webkit_dom_range_set_end(range, node, this_end, NULL); |
|
| 290 span = webkit_dom_document_create_element(dom, "span", NULL); |
|
| 291 webkit_dom_html_element_set_class_name(WEBKIT_DOM_HTML_ELEMENT(span), |
|
| 292 "regex"); |
|
| 293 webkit_dom_range_surround_contents(range, WEBKIT_DOM_NODE(span), NULL); |
|
| 294 } |
|
| 295 } |
|
| 296 |
|
| 297 static void |
|
| 298 regex_match(DebugWindow *win, WebKitDOMDocument *dom, WebKitDOMNode *div) |
|
| 299 { |
|
| 300 GMatchInfo *match_info; |
|
| 301 gchar *text; |
|
| 302 gchar *plaintext; |
|
| 303 |
|
| 304 text = webkit_dom_node_get_text_content(div); |
|
| 305 if (!text) |
|
| 306 return; |
|
| 307 |
|
| 308 /* I don't like having to do this, but we need it for highlighting. Plus |
|
| 309 * it makes the ^ and $ operators work :) |
|
| 310 */ |
|
| 311 plaintext = purple_markup_strip_html(text); |
|
| 312 |
|
| 313 /* We do a first pass to see if it matches at all. If it does we work out |
|
| 314 * the offsets to highlight. |
|
| 315 */ |
|
| 316 if (g_regex_match(win->regex, plaintext, 0, &match_info) != win->invert) { |
|
| 317 /* If we're not highlighting or the expression is inverted, we're |
|
| 318 * done and move on. |
|
| 319 */ |
|
| 320 if (!win->highlight || win->invert) { |
|
| 321 g_free(plaintext); |
|
| 322 g_match_info_free(match_info); |
|
| 323 return; |
|
| 324 } |
|
| 325 |
|
| 326 do { |
|
| 327 gint m, count; |
|
| 328 gint start_pos, end_pos; |
|
| 329 |
|
| 330 if (!g_match_info_matches(match_info)) |
|
| 331 break; |
|
| 332 |
|
| 333 count = g_match_info_get_match_count(match_info); |
|
| 334 if (count == 1) |
|
| 335 m = 0; |
|
| 336 else |
|
| 337 m = 1; |
|
| 338 |
|
| 339 for (; m < count; m++) |
|
| 340 { |
|
| 341 g_match_info_fetch_pos(match_info, m, &start_pos, &end_pos); |
|
| 342 |
|
| 343 if (end_pos == -1) |
|
| 344 break; |
|
| 345 |
|
| 346 regex_highlight_text_nodes(dom, div, start_pos, end_pos); |
|
| 347 } |
|
| 348 } while (g_match_info_next(match_info, NULL)); |
|
| 349 |
|
| 350 g_match_info_free(match_info); |
|
| 351 } else { |
|
| 352 regex_toggle_div(div); |
|
| 353 } |
|
| 354 |
|
| 355 g_free(plaintext); |
|
| 356 g_free(text); |
|
| 357 } |
|
| 358 |
|
| 359 static void |
|
| 360 regex_toggle_filter(DebugWindow *win, gboolean filter) |
169 regex_toggle_filter(DebugWindow *win, gboolean filter) |
| 361 { |
170 { |
| 362 WebKitDOMDocument *dom; |
171 gtk_webview_safe_execute_script(GTK_WEBVIEW(win->text), "regex.clear();"); |
| 363 WebKitDOMNodeList *list; |
|
| 364 gulong i; |
|
| 365 |
|
| 366 dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(win->text)); |
|
| 367 |
|
| 368 if (win->highlight) |
|
| 369 regex_highlight_clear(dom); |
|
| 370 |
|
| 371 /* Re-show debug lines that didn't match regex */ |
|
| 372 list = webkit_dom_document_get_elements_by_class_name(dom, "hide"); |
|
| 373 i = webkit_dom_node_list_get_length(list); |
|
| 374 |
|
| 375 while (i--) { |
|
| 376 WebKitDOMNode *div = webkit_dom_node_list_item(list, i); |
|
| 377 regex_toggle_div(div); |
|
| 378 } |
|
| 379 |
|
| 380 g_object_unref(list); |
|
| 381 |
172 |
| 382 if (filter) { |
173 if (filter) { |
| 383 list = webkit_dom_document_get_elements_by_tag_name(dom, "div"); |
174 const char *text; |
| 384 |
175 char *regex; |
| 385 for (i = 0; i < webkit_dom_node_list_get_length(list); i++) { |
176 char *script; |
| 386 WebKitDOMNode *div = webkit_dom_node_list_item(list, i); |
177 |
| 387 regex_match(win, dom, div); |
178 text = gtk_entry_get_text(GTK_ENTRY(win->expression)); |
| 388 } |
179 regex = gtk_webview_quote_js_string(text); |
| 389 |
180 script = g_strdup_printf("regex.filterAll(%s, %s, %s);", |
| 390 g_object_unref(list); |
181 regex, |
| |
182 win->invert ? "true" : "false", |
| |
183 win->highlight ? "true" : "false"); |
| |
184 gtk_webview_safe_execute_script(GTK_WEBVIEW(win->text), script); |
| |
185 g_free(script); |
| |
186 g_free(regex); |
| 391 } |
187 } |
| 392 } |
188 } |
| 393 |
189 |
| 394 static void |
190 static void |
| 395 regex_pref_filter_cb(const gchar *name, PurplePrefType type, |
191 regex_pref_filter_cb(const gchar *name, PurplePrefType type, |
| 595 } |
395 } |
| 596 |
396 |
| 597 gtk_widget_show_all(menu); |
397 gtk_widget_show_all(menu); |
| 598 |
398 |
| 599 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time); |
399 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, event->time); |
| 600 return FALSE; |
|
| 601 } |
|
| 602 |
|
| 603 static void |
|
| 604 debug_window_appended(DebugWindow *win) |
|
| 605 { |
|
| 606 WebKitDOMDocument *dom; |
|
| 607 WebKitDOMHTMLElement *body; |
|
| 608 WebKitDOMNode *div; |
|
| 609 |
|
| 610 if (!gtk_toggle_tool_button_get_active( |
|
| 611 GTK_TOGGLE_TOOL_BUTTON(win->filter))) |
|
| 612 return; |
|
| 613 |
|
| 614 dom = webkit_web_view_get_dom_document(WEBKIT_WEB_VIEW(win->text)); |
|
| 615 body = webkit_dom_document_get_body(dom); |
|
| 616 div = webkit_dom_node_get_last_child(WEBKIT_DOM_NODE(body)); |
|
| 617 |
|
| 618 if (webkit_dom_element_webkit_matches_selector( |
|
| 619 WEBKIT_DOM_ELEMENT(div), "body>div:not(#pause)", NULL)) |
|
| 620 regex_match(win, dom, div); |
|
| 621 } |
|
| 622 |
|
| 623 static gboolean debug_window_alert_cb(WebKitWebView *webview, |
|
| 624 WebKitWebFrame *frame, gchar *message, gpointer _win) |
|
| 625 { |
|
| 626 DebugWindow *win = _win; |
|
| 627 |
|
| 628 if (!win || !win->window) |
|
| 629 return FALSE; |
|
| 630 |
|
| 631 if (g_strcmp0(message, "appended") == 0) { |
|
| 632 debug_window_appended(win); |
|
| 633 return TRUE; |
|
| 634 } |
|
| 635 |
|
| 636 return FALSE; |
400 return FALSE; |
| 637 } |
401 } |
| 638 |
402 |
| 639 static DebugWindow * |
403 static DebugWindow * |
| 640 debug_window_new(void) |
404 debug_window_new(void) |