4 * Finch is the legal property of its developers, whose names are too numerous
5 * to list here. Please refer to the COPYRIGHT file distributed with this
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
27 #include <gntbutton.h>
28 #include <gntcheckbox.h>
30 #include <gntfilesel.h>
33 #include <gnttextview.h>
43 #define PREF_ROOT "/finch/debug"
49 /* Other members, including private data. */
52 static void finch_debug_ui_finalize(GObject
*gobject
);
53 static void finch_debug_ui_interface_init(PurpleDebugUiInterface
*iface
);
55 G_DEFINE_TYPE_WITH_CODE(FinchDebugUi
, finch_debug_ui
, G_TYPE_OBJECT
,
56 G_IMPLEMENT_INTERFACE(PURPLE_TYPE_DEBUG_UI
,
57 finch_debug_ui_interface_init
));
60 handle_fprintf_stderr_cb(GIOChannel
*source
, GIOCondition cond
, gpointer null
)
65 size
= read(g_io_channel_unix_get_fd(source
), message
, sizeof(message
) - 1);
67 /* Something bad probably happened elsewhere ... let's ignore */
70 g_log("stderr", G_LOG_LEVEL_WARNING
, "%s", message
);
77 handle_fprintf_stderr(gboolean stop
)
80 static int readhandle
= -1;
84 if (readhandle
>= 0) {
85 g_source_remove(readhandle
);
90 if (purple_input_pipe(pipes
)) {
94 dup2(pipes
[1], STDERR_FILENO
);
96 stderrch
= g_io_channel_unix_new(pipes
[0]);
97 g_io_channel_set_close_on_unref(stderrch
, TRUE
);
98 readhandle
= g_io_add_watch_full(stderrch
, G_PRIORITY_HIGH
,
99 G_IO_IN
| G_IO_ERR
| G_IO_PRI
,
100 handle_fprintf_stderr_cb
, NULL
, NULL
);
101 g_io_channel_unref(stderrch
);
113 match_string(const char *category
, const char *args
)
115 const char *str
= gnt_entry_get_text(GNT_ENTRY(debug
.search
));
118 if (g_strrstr(category
, str
) != NULL
)
120 if (g_strrstr(args
, str
) != NULL
)
126 finch_debug_print(PurpleDebugUi
*self
,
127 PurpleDebugLevel level
, const char *category
,
130 if (debug
.window
&& !debug
.paused
&& match_string(category
, args
))
132 int pos
= gnt_text_view_get_lines_below(GNT_TEXT_VIEW(debug
.tview
));
133 GntTextFormatFlags flag
= GNT_TEXT_FLAG_NORMAL
;
135 time_t mtime
= time(NULL
);
136 mdate
= purple_utf8_strftime("%H:%M:%S ", localtime(&mtime
));
137 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
),
140 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
),
141 category
, GNT_TEXT_FLAG_BOLD
);
142 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
),
143 ": ", GNT_TEXT_FLAG_BOLD
);
147 case PURPLE_DEBUG_WARNING
:
148 flag
|= GNT_TEXT_FLAG_UNDERLINE
;
150 case PURPLE_DEBUG_ERROR
:
151 case PURPLE_DEBUG_FATAL
:
152 flag
|= GNT_TEXT_FLAG_BOLD
;
158 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
), args
, flag
);
159 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
), "\n", GNT_TEXT_FLAG_NORMAL
);
161 gnt_text_view_scroll(GNT_TEXT_VIEW(debug
.tview
), 0);
166 finch_debug_is_enabled(PurpleDebugUi
*self
, PurpleDebugLevel level
, const char *category
)
168 return debug
.window
&& !debug
.paused
;
172 finch_debug_ui_interface_init(PurpleDebugUiInterface
*iface
)
174 iface
->print
= finch_debug_print
;
175 iface
->is_enabled
= finch_debug_is_enabled
;
179 reset_debug_win(GntWidget
*w
, gpointer null
)
181 debug
.window
= debug
.tview
= debug
.search
= NULL
;
185 clear_debug_win(GntWidget
*w
, GntTextView
*tv
)
187 gnt_text_view_clear(tv
);
191 print_stderr(const char *string
)
193 g_printerr("%s", string
);
197 toggle_pause(GntWidget
*w
, gpointer n
)
199 debug
.paused
= !debug
.paused
;
204 purple_glib_log_handler(const gchar
*domain
, GLogLevelFlags flags
,
205 const gchar
*msg
, gpointer user_data
)
207 PurpleDebugLevel level
;
208 char *new_msg
= NULL
;
209 char *new_domain
= NULL
;
211 if ((flags
& G_LOG_LEVEL_ERROR
) == G_LOG_LEVEL_ERROR
)
212 level
= PURPLE_DEBUG_ERROR
;
213 else if ((flags
& G_LOG_LEVEL_CRITICAL
) == G_LOG_LEVEL_CRITICAL
)
214 level
= PURPLE_DEBUG_FATAL
;
215 else if ((flags
& G_LOG_LEVEL_WARNING
) == G_LOG_LEVEL_WARNING
)
216 level
= PURPLE_DEBUG_WARNING
;
217 else if ((flags
& G_LOG_LEVEL_MESSAGE
) == G_LOG_LEVEL_MESSAGE
)
218 level
= PURPLE_DEBUG_INFO
;
219 else if ((flags
& G_LOG_LEVEL_INFO
) == G_LOG_LEVEL_INFO
)
220 level
= PURPLE_DEBUG_INFO
;
221 else if ((flags
& G_LOG_LEVEL_DEBUG
) == G_LOG_LEVEL_DEBUG
)
222 level
= PURPLE_DEBUG_MISC
;
225 purple_debug_warning("gntdebug",
226 "Unknown glib logging level in %d\n", flags
);
228 level
= PURPLE_DEBUG_MISC
; /* This will never happen. */
232 new_msg
= purple_utf8_try_convert(msg
);
235 new_domain
= purple_utf8_try_convert(domain
);
239 purple_debug(level
, (new_domain
!= NULL
? new_domain
: "g_log"),
249 size_changed_cb(GntWidget
*widget
, int oldw
, int oldh
)
252 gnt_widget_get_size(widget
, &w
, &h
);
253 purple_prefs_set_int(PREF_ROOT
"/size/width", w
);
254 purple_prefs_set_int(PREF_ROOT
"/size/height", h
);
258 for_real(gpointer entry
)
260 purple_prefs_set_string(PREF_ROOT
"/filter", gnt_entry_get_text(entry
));
265 update_filter_string(GntEntry
*entry
, gpointer null
)
267 int id
= g_timeout_add(1000, for_real
, entry
);
268 g_object_set_data_full(G_OBJECT(entry
), "update-filter", GINT_TO_POINTER(id
),
269 (GDestroyNotify
)g_source_remove
);
273 file_save(GntFileSel
*fs
, const char *path
, const char *file
, GntTextView
*tv
)
277 if ((fp
= g_fopen(path
, "w+")) == NULL
) {
278 purple_notify_error(NULL
, NULL
, _("Unable to open file."), NULL
, NULL
);
282 fprintf(fp
, "Finch Debug Log : %s\n", purple_date_format_full(NULL
));
283 fprintf(fp
, "%s", gnt_text_view_get_text(tv
));
285 gnt_widget_destroy(GNT_WIDGET(fs
));
289 save_debug_win(GntWidget
*w
, GntTextView
*tv
)
291 GntWidget
*window
= gnt_file_sel_new();
292 GntFileSel
*sel
= GNT_FILE_SEL(window
);
293 gnt_file_sel_set_current_location(sel
, purple_home_dir());
294 gnt_file_sel_set_suggested_filename(sel
, "debug.txt");
295 g_signal_connect(G_OBJECT(sel
), "file_selected", G_CALLBACK(file_save
), tv
);
296 g_signal_connect(G_OBJECT(sel
), "cancelled", G_CALLBACK(gnt_widget_destroy
), NULL
);
297 gnt_widget_show(window
);
300 void finch_debug_window_show()
302 GntWidget
*wid
, *box
, *label
;
304 debug
.paused
= FALSE
;
306 gnt_window_present(debug
.window
);
310 debug
.window
= gnt_vbox_new(FALSE
);
311 gnt_box_set_toplevel(GNT_BOX(debug
.window
), TRUE
);
312 gnt_box_set_title(GNT_BOX(debug
.window
), _("Debug Window"));
313 gnt_box_set_pad(GNT_BOX(debug
.window
), 0);
314 gnt_box_set_alignment(GNT_BOX(debug
.window
), GNT_ALIGN_MID
);
316 debug
.tview
= gnt_text_view_new();
317 gnt_box_add_widget(GNT_BOX(debug
.window
), debug
.tview
);
318 gnt_widget_set_size(debug
.tview
,
319 purple_prefs_get_int(PREF_ROOT
"/size/width"),
320 purple_prefs_get_int(PREF_ROOT
"/size/height"));
321 g_signal_connect(G_OBJECT(debug
.tview
), "size_changed", G_CALLBACK(size_changed_cb
), NULL
);
323 gnt_box_add_widget(GNT_BOX(debug
.window
), gnt_line_new(FALSE
));
325 box
= gnt_hbox_new(FALSE
);
326 gnt_box_set_alignment(GNT_BOX(box
), GNT_ALIGN_MID
);
327 gnt_box_set_fill(GNT_BOX(box
), FALSE
);
329 /* XXX: Setting the GROW_Y for the following widgets don't make sense. But right now
330 * it's necessary to make the width of the debug window resizable ... like I said,
331 * it doesn't make sense. The bug is likely in the packing in gntbox.c.
333 wid
= gnt_button_new(_("Clear"));
334 g_signal_connect(G_OBJECT(wid
), "activate", G_CALLBACK(clear_debug_win
), debug
.tview
);
335 gnt_widget_set_grow_y(wid
, TRUE
);
336 gnt_box_add_widget(GNT_BOX(box
), wid
);
338 wid
= gnt_button_new(_("Save"));
339 g_signal_connect(G_OBJECT(wid
), "activate", G_CALLBACK(save_debug_win
), debug
.tview
);
340 gnt_widget_set_grow_y(wid
, TRUE
);
341 gnt_box_add_widget(GNT_BOX(box
), wid
);
343 debug
.search
= gnt_entry_new(purple_prefs_get_string(PREF_ROOT
"/filter"));
344 label
= gnt_label_new(_("Filter:"));
345 gnt_widget_set_grow_x(label
, FALSE
);
346 gnt_box_add_widget(GNT_BOX(box
), label
);
347 gnt_box_add_widget(GNT_BOX(box
), debug
.search
);
348 g_signal_connect(G_OBJECT(debug
.search
), "text_changed", G_CALLBACK(update_filter_string
), NULL
);
350 wid
= gnt_check_box_new(_("Pause"));
351 g_signal_connect(G_OBJECT(wid
), "toggled", G_CALLBACK(toggle_pause
), NULL
);
352 gnt_widget_set_grow_y(wid
, TRUE
);
353 gnt_box_add_widget(GNT_BOX(box
), wid
);
355 gnt_box_add_widget(GNT_BOX(debug
.window
), box
);
356 gnt_widget_set_grow_y(box
, TRUE
);
358 gnt_widget_set_name(debug
.window
, "debug-window");
360 g_signal_connect(G_OBJECT(debug
.window
), "destroy", G_CALLBACK(reset_debug_win
), NULL
);
361 gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(debug
.tview
), debug
.window
);
362 gnt_text_view_attach_pager_widget(GNT_TEXT_VIEW(debug
.tview
), debug
.window
);
364 gnt_widget_show(debug
.window
);
368 start_with_debugwin(gpointer null
)
370 finch_debug_window_show();
375 finch_debug_ui_class_init(FinchDebugUiClass
*klass
)
377 GObjectClass
*object_class
= G_OBJECT_CLASS(klass
);
379 object_class
->finalize
= finch_debug_ui_finalize
;
383 finch_debug_ui_init(FinchDebugUi
*self
)
386 #define REGISTER_G_LOG_HANDLER(name) \
387 g_log_set_handler((name), G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL \
388 | G_LOG_FLAG_RECURSION, \
389 purple_glib_log_handler, NULL)
391 /* Register the glib log handlers. */
392 REGISTER_G_LOG_HANDLER(NULL
);
393 REGISTER_G_LOG_HANDLER("GLib");
394 REGISTER_G_LOG_HANDLER("GModule");
395 REGISTER_G_LOG_HANDLER("GLib-GObject");
396 REGISTER_G_LOG_HANDLER("GThread");
397 REGISTER_G_LOG_HANDLER("Gnt");
399 REGISTER_G_LOG_HANDLER("GStreamer");
401 REGISTER_G_LOG_HANDLER("stderr");
403 g_set_print_handler(print_stderr
); /* Redirect the debug messages to stderr */
404 if (!purple_debug_is_enabled())
405 handle_fprintf_stderr(FALSE
);
407 purple_prefs_add_none(PREF_ROOT
);
408 purple_prefs_add_string(PREF_ROOT
"/filter", "");
409 purple_prefs_add_none(PREF_ROOT
"/size");
410 purple_prefs_add_int(PREF_ROOT
"/size/width", 60);
411 purple_prefs_add_int(PREF_ROOT
"/size/height", 15);
413 if (purple_debug_is_enabled())
414 g_timeout_add(0, start_with_debugwin
, NULL
);
418 finch_debug_ui_finalize(GObject
*gobject
)
420 handle_fprintf_stderr(TRUE
);
421 G_OBJECT_CLASS(finch_debug_ui_parent_class
)->finalize(gobject
);
425 finch_debug_ui_new(void)
427 return g_object_new(FINCH_TYPE_DEBUG_UI
, NULL
);