3 * Finch is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * 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 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 #include <gntbutton.h>
27 #include <gntcheckbox.h>
29 #include <gntfilesel.h>
32 #include <gnttextview.h>
42 #define PREF_ROOT "/finch/debug"
48 /* Other members, including private data. */
51 static void finch_debug_ui_finalize(GObject
*gobject
);
52 static void finch_debug_ui_interface_init(PurpleDebugUiInterface
*iface
);
54 G_DEFINE_TYPE_WITH_CODE(FinchDebugUi
, finch_debug_ui
, G_TYPE_OBJECT
,
55 G_IMPLEMENT_INTERFACE(PURPLE_TYPE_DEBUG_UI
,
56 finch_debug_ui_interface_init
));
59 handle_fprintf_stderr_cb(GIOChannel
*source
, GIOCondition cond
, gpointer null
)
64 size
= read(g_io_channel_unix_get_fd(source
), message
, sizeof(message
) - 1);
66 /* Something bad probably happened elsewhere ... let's ignore */
69 g_log("stderr", G_LOG_LEVEL_WARNING
, "%s", message
);
76 handle_fprintf_stderr(gboolean stop
)
79 static int readhandle
= -1;
83 if (readhandle
>= 0) {
84 g_source_remove(readhandle
);
89 if (purple_input_pipe(pipes
)) {
93 dup2(pipes
[1], STDERR_FILENO
);
95 stderrch
= g_io_channel_unix_new(pipes
[0]);
96 g_io_channel_set_close_on_unref(stderrch
, TRUE
);
97 readhandle
= g_io_add_watch_full(stderrch
, G_PRIORITY_HIGH
,
98 G_IO_IN
| G_IO_ERR
| G_IO_PRI
,
99 handle_fprintf_stderr_cb
, NULL
, NULL
);
100 g_io_channel_unref(stderrch
);
112 match_string(const char *category
, const char *args
)
114 const char *str
= gnt_entry_get_text(GNT_ENTRY(debug
.search
));
117 if (g_strrstr(category
, str
) != NULL
)
119 if (g_strrstr(args
, str
) != NULL
)
125 finch_debug_print(PurpleDebugUi
*self
,
126 PurpleDebugLevel level
, const char *category
,
129 if (debug
.window
&& !debug
.paused
&& match_string(category
, args
))
131 int pos
= gnt_text_view_get_lines_below(GNT_TEXT_VIEW(debug
.tview
));
132 GntTextFormatFlags flag
= GNT_TEXT_FLAG_NORMAL
;
134 time_t mtime
= time(NULL
);
135 mdate
= purple_utf8_strftime("%H:%M:%S ", localtime(&mtime
));
136 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
),
139 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
),
140 category
, GNT_TEXT_FLAG_BOLD
);
141 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
),
142 ": ", GNT_TEXT_FLAG_BOLD
);
146 case PURPLE_DEBUG_WARNING
:
147 flag
|= GNT_TEXT_FLAG_UNDERLINE
;
149 case PURPLE_DEBUG_ERROR
:
150 case PURPLE_DEBUG_FATAL
:
151 flag
|= GNT_TEXT_FLAG_BOLD
;
157 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
), args
, flag
);
158 gnt_text_view_append_text_with_flags(GNT_TEXT_VIEW(debug
.tview
), "\n", GNT_TEXT_FLAG_NORMAL
);
160 gnt_text_view_scroll(GNT_TEXT_VIEW(debug
.tview
), 0);
165 finch_debug_is_enabled(PurpleDebugUi
*self
, PurpleDebugLevel level
, const char *category
)
167 return debug
.window
&& !debug
.paused
;
171 finch_debug_ui_interface_init(PurpleDebugUiInterface
*iface
)
173 iface
->print
= finch_debug_print
;
174 iface
->is_enabled
= finch_debug_is_enabled
;
178 reset_debug_win(GntWidget
*w
, gpointer null
)
180 debug
.window
= debug
.tview
= debug
.search
= NULL
;
184 clear_debug_win(GntWidget
*w
, GntTextView
*tv
)
186 gnt_text_view_clear(tv
);
190 print_stderr(const char *string
)
192 g_printerr("%s", string
);
196 toggle_pause(GntWidget
*w
, gpointer n
)
198 debug
.paused
= !debug
.paused
;
203 purple_glib_log_handler(const gchar
*domain
, GLogLevelFlags flags
,
204 const gchar
*msg
, gpointer user_data
)
206 PurpleDebugLevel level
;
207 char *new_msg
= NULL
;
208 char *new_domain
= NULL
;
210 if ((flags
& G_LOG_LEVEL_ERROR
) == G_LOG_LEVEL_ERROR
)
211 level
= PURPLE_DEBUG_ERROR
;
212 else if ((flags
& G_LOG_LEVEL_CRITICAL
) == G_LOG_LEVEL_CRITICAL
)
213 level
= PURPLE_DEBUG_FATAL
;
214 else if ((flags
& G_LOG_LEVEL_WARNING
) == G_LOG_LEVEL_WARNING
)
215 level
= PURPLE_DEBUG_WARNING
;
216 else if ((flags
& G_LOG_LEVEL_MESSAGE
) == G_LOG_LEVEL_MESSAGE
)
217 level
= PURPLE_DEBUG_INFO
;
218 else if ((flags
& G_LOG_LEVEL_INFO
) == G_LOG_LEVEL_INFO
)
219 level
= PURPLE_DEBUG_INFO
;
220 else if ((flags
& G_LOG_LEVEL_DEBUG
) == G_LOG_LEVEL_DEBUG
)
221 level
= PURPLE_DEBUG_MISC
;
224 purple_debug_warning("gntdebug",
225 "Unknown glib logging level in %d\n", flags
);
227 level
= PURPLE_DEBUG_MISC
; /* This will never happen. */
231 new_msg
= purple_utf8_try_convert(msg
);
234 new_domain
= purple_utf8_try_convert(domain
);
238 purple_debug(level
, (new_domain
!= NULL
? new_domain
: "g_log"),
248 size_changed_cb(GntWidget
*widget
, int oldw
, int oldh
)
251 gnt_widget_get_size(widget
, &w
, &h
);
252 purple_prefs_set_int(PREF_ROOT
"/size/width", w
);
253 purple_prefs_set_int(PREF_ROOT
"/size/height", h
);
257 for_real(gpointer entry
)
259 purple_prefs_set_string(PREF_ROOT
"/filter", gnt_entry_get_text(entry
));
264 update_filter_string(GntEntry
*entry
, gpointer null
)
266 int id
= g_timeout_add(1000, for_real
, entry
);
267 g_object_set_data_full(G_OBJECT(entry
), "update-filter", GINT_TO_POINTER(id
),
268 (GDestroyNotify
)g_source_remove
);
272 file_save(GntFileSel
*fs
, const char *path
, const char *file
, GntTextView
*tv
)
276 if ((fp
= g_fopen(path
, "w+")) == NULL
) {
277 purple_notify_error(NULL
, NULL
, _("Unable to open file."), NULL
, NULL
);
281 fprintf(fp
, "Finch Debug Log : %s\n", purple_date_format_full(NULL
));
282 fprintf(fp
, "%s", gnt_text_view_get_text(tv
));
284 gnt_widget_destroy(GNT_WIDGET(fs
));
288 save_debug_win(GntWidget
*w
, GntTextView
*tv
)
290 GntWidget
*window
= gnt_file_sel_new();
291 GntFileSel
*sel
= GNT_FILE_SEL(window
);
292 gnt_file_sel_set_current_location(sel
, purple_home_dir());
293 gnt_file_sel_set_suggested_filename(sel
, "debug.txt");
294 g_signal_connect(G_OBJECT(sel
), "file_selected", G_CALLBACK(file_save
), tv
);
295 g_signal_connect(G_OBJECT(sel
), "cancelled", G_CALLBACK(gnt_widget_destroy
), NULL
);
296 gnt_widget_show(window
);
299 void finch_debug_window_show()
301 GntWidget
*wid
, *box
, *label
;
303 debug
.paused
= FALSE
;
305 gnt_window_present(debug
.window
);
309 debug
.window
= gnt_vbox_new(FALSE
);
310 gnt_box_set_toplevel(GNT_BOX(debug
.window
), TRUE
);
311 gnt_box_set_title(GNT_BOX(debug
.window
), _("Debug Window"));
312 gnt_box_set_pad(GNT_BOX(debug
.window
), 0);
313 gnt_box_set_alignment(GNT_BOX(debug
.window
), GNT_ALIGN_MID
);
315 debug
.tview
= gnt_text_view_new();
316 gnt_box_add_widget(GNT_BOX(debug
.window
), debug
.tview
);
317 gnt_widget_set_size(debug
.tview
,
318 purple_prefs_get_int(PREF_ROOT
"/size/width"),
319 purple_prefs_get_int(PREF_ROOT
"/size/height"));
320 g_signal_connect(G_OBJECT(debug
.tview
), "size_changed", G_CALLBACK(size_changed_cb
), NULL
);
322 gnt_box_add_widget(GNT_BOX(debug
.window
), gnt_line_new(FALSE
));
324 box
= gnt_hbox_new(FALSE
);
325 gnt_box_set_alignment(GNT_BOX(box
), GNT_ALIGN_MID
);
326 gnt_box_set_fill(GNT_BOX(box
), FALSE
);
328 /* XXX: Setting the GROW_Y for the following widgets don't make sense. But right now
329 * it's necessary to make the width of the debug window resizable ... like I said,
330 * it doesn't make sense. The bug is likely in the packing in gntbox.c.
332 wid
= gnt_button_new(_("Clear"));
333 g_signal_connect(G_OBJECT(wid
), "activate", G_CALLBACK(clear_debug_win
), debug
.tview
);
334 gnt_widget_set_grow_y(wid
, TRUE
);
335 gnt_box_add_widget(GNT_BOX(box
), wid
);
337 wid
= gnt_button_new(_("Save"));
338 g_signal_connect(G_OBJECT(wid
), "activate", G_CALLBACK(save_debug_win
), debug
.tview
);
339 gnt_widget_set_grow_y(wid
, TRUE
);
340 gnt_box_add_widget(GNT_BOX(box
), wid
);
342 debug
.search
= gnt_entry_new(purple_prefs_get_string(PREF_ROOT
"/filter"));
343 label
= gnt_label_new(_("Filter:"));
344 gnt_widget_set_grow_x(label
, FALSE
);
345 gnt_box_add_widget(GNT_BOX(box
), label
);
346 gnt_box_add_widget(GNT_BOX(box
), debug
.search
);
347 g_signal_connect(G_OBJECT(debug
.search
), "text_changed", G_CALLBACK(update_filter_string
), NULL
);
349 wid
= gnt_check_box_new(_("Pause"));
350 g_signal_connect(G_OBJECT(wid
), "toggled", G_CALLBACK(toggle_pause
), NULL
);
351 gnt_widget_set_grow_y(wid
, TRUE
);
352 gnt_box_add_widget(GNT_BOX(box
), wid
);
354 gnt_box_add_widget(GNT_BOX(debug
.window
), box
);
355 gnt_widget_set_grow_y(box
, TRUE
);
357 gnt_widget_set_name(debug
.window
, "debug-window");
359 g_signal_connect(G_OBJECT(debug
.window
), "destroy", G_CALLBACK(reset_debug_win
), NULL
);
360 gnt_text_view_attach_scroll_widget(GNT_TEXT_VIEW(debug
.tview
), debug
.window
);
361 gnt_text_view_attach_pager_widget(GNT_TEXT_VIEW(debug
.tview
), debug
.window
);
363 gnt_widget_show(debug
.window
);
367 start_with_debugwin(gpointer null
)
369 finch_debug_window_show();
374 finch_debug_ui_class_init(FinchDebugUiClass
*klass
)
376 GObjectClass
*object_class
= G_OBJECT_CLASS(klass
);
378 object_class
->finalize
= finch_debug_ui_finalize
;
382 finch_debug_ui_init(FinchDebugUi
*self
)
385 #define REGISTER_G_LOG_HANDLER(name) \
386 g_log_set_handler((name), G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL \
387 | G_LOG_FLAG_RECURSION, \
388 purple_glib_log_handler, NULL)
390 /* Register the glib log handlers. */
391 REGISTER_G_LOG_HANDLER(NULL
);
392 REGISTER_G_LOG_HANDLER("GLib");
393 REGISTER_G_LOG_HANDLER("GModule");
394 REGISTER_G_LOG_HANDLER("GLib-GObject");
395 REGISTER_G_LOG_HANDLER("GThread");
396 REGISTER_G_LOG_HANDLER("Gnt");
398 REGISTER_G_LOG_HANDLER("GStreamer");
400 REGISTER_G_LOG_HANDLER("stderr");
402 g_set_print_handler(print_stderr
); /* Redirect the debug messages to stderr */
403 if (!purple_debug_is_enabled())
404 handle_fprintf_stderr(FALSE
);
406 purple_prefs_add_none(PREF_ROOT
);
407 purple_prefs_add_string(PREF_ROOT
"/filter", "");
408 purple_prefs_add_none(PREF_ROOT
"/size");
409 purple_prefs_add_int(PREF_ROOT
"/size/width", 60);
410 purple_prefs_add_int(PREF_ROOT
"/size/height", 15);
412 if (purple_debug_is_enabled())
413 g_timeout_add(0, start_with_debugwin
, NULL
);
417 finch_debug_ui_finalize(GObject
*gobject
)
419 handle_fprintf_stderr(TRUE
);
420 G_OBJECT_CLASS(finch_debug_ui_parent_class
)->finalize(gobject
);
424 finch_debug_ui_new(void)
426 return g_object_new(FINCH_TYPE_DEBUG_UI
, NULL
);