Statistics
| Revision:

root / src / logwindow.c @ 3047

History | View | Annotate | Download (8.4 kB)

1 1 hiro
/*
2 1 hiro
 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 2259 hiro
 * Copyright (C) 1999-2009 Hiroyuki Yamamoto
4 1 hiro
 *
5 1 hiro
 * This program is free software; you can redistribute it and/or modify
6 1 hiro
 * it under the terms of the GNU General Public License as published by
7 1 hiro
 * the Free Software Foundation; either version 2 of the License, or
8 1 hiro
 * (at your option) any later version.
9 1 hiro
 *
10 1 hiro
 * This program is distributed in the hope that it will be useful,
11 1 hiro
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 1 hiro
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 1 hiro
 * GNU General Public License for more details.
14 1 hiro
 *
15 1 hiro
 * You should have received a copy of the GNU General Public License
16 1 hiro
 * along with this program; if not, write to the Free Software
17 1 hiro
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 1 hiro
 */
19 1 hiro
20 1 hiro
#ifdef HAVE_CONFIG_H
21 1 hiro
#  include "config.h"
22 1 hiro
#endif
23 1 hiro
24 1 hiro
#include <glib.h>
25 92 hiro
#include <glib/gi18n.h>
26 1 hiro
#include <gdk/gdkkeysyms.h>
27 1 hiro
#include <gtk/gtkwidget.h>
28 1 hiro
#include <gtk/gtkwindow.h>
29 1 hiro
#include <gtk/gtksignal.h>
30 1 hiro
#include <gtk/gtkscrolledwindow.h>
31 1 hiro
#include <gtk/gtktextview.h>
32 1 hiro
#include <gtk/gtkstyle.h>
33 1 hiro
34 1 hiro
#include "logwindow.h"
35 122 hiro
#include "prefs_common.h"
36 1 hiro
#include "utils.h"
37 1 hiro
#include "gtkutils.h"
38 734 hiro
#include "codeconv.h"
39 1 hiro
40 1 hiro
#define TRIM_LINES        25
41 1 hiro
42 1 hiro
static LogWindow *logwindow;
43 1 hiro
44 2259 hiro
#if USE_THREADS
45 2259 hiro
static GThread *main_thread;
46 2259 hiro
#endif
47 2259 hiro
48 523 hiro
static void log_window_print_func        (const gchar        *str);
49 523 hiro
static void log_window_message_func        (const gchar        *str);
50 523 hiro
static void log_window_warning_func        (const gchar        *str);
51 523 hiro
static void log_window_error_func        (const gchar        *str);
52 523 hiro
53 1 hiro
static void hide_cb                (GtkWidget        *widget,
54 1 hiro
                                 LogWindow        *logwin);
55 1 hiro
static gboolean key_pressed        (GtkWidget        *widget,
56 1 hiro
                                 GdkEventKey        *event,
57 1 hiro
                                 LogWindow        *logwin);
58 1 hiro
59 1 hiro
LogWindow *log_window_create(void)
60 1 hiro
{
61 1 hiro
        LogWindow *logwin;
62 1 hiro
        GtkWidget *window;
63 1 hiro
        GtkWidget *scrolledwin;
64 1 hiro
        GtkWidget *text;
65 1 hiro
        GtkTextBuffer *buffer;
66 1 hiro
        GtkTextIter iter;
67 1 hiro
68 1 hiro
        debug_print("Creating log window...\n");
69 1 hiro
        logwin = g_new0(LogWindow, 1);
70 1 hiro
71 1 hiro
        window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
72 1 hiro
        gtk_window_set_title(GTK_WINDOW(window), _("Protocol log"));
73 1 hiro
        gtk_window_set_wmclass(GTK_WINDOW(window), "log_window", "Sylpheed");
74 1 hiro
        gtk_window_set_policy(GTK_WINDOW(window), TRUE, TRUE, FALSE);
75 1 hiro
        gtk_widget_set_size_request(window, 520, 400);
76 1 hiro
        g_signal_connect(G_OBJECT(window), "delete_event",
77 1 hiro
                         G_CALLBACK(gtk_widget_hide_on_delete), NULL);
78 1 hiro
        g_signal_connect(G_OBJECT(window), "key_press_event",
79 1 hiro
                         G_CALLBACK(key_pressed), logwin);
80 1 hiro
        g_signal_connect(G_OBJECT(window), "hide",
81 1 hiro
                         G_CALLBACK(hide_cb), logwin);
82 1 hiro
        gtk_widget_realize(window);
83 1 hiro
84 1 hiro
        scrolledwin = gtk_scrolled_window_new(NULL, NULL);
85 1 hiro
        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
86 1 hiro
                                       GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
87 4 hiro
        gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwin),
88 4 hiro
                                            GTK_SHADOW_IN);
89 1 hiro
        gtk_container_add(GTK_CONTAINER(window), scrolledwin);
90 1 hiro
        gtk_widget_show(scrolledwin);
91 1 hiro
92 1 hiro
        text = gtk_text_view_new();
93 1 hiro
        gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
94 1 hiro
        gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
95 1 hiro
        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
96 1 hiro
        gtk_text_buffer_get_start_iter(buffer, &iter);
97 1 hiro
        gtk_text_buffer_create_mark(buffer, "end", &iter, FALSE);
98 1 hiro
        gtk_container_add(GTK_CONTAINER(scrolledwin), text);
99 1 hiro
        gtk_widget_show(text);
100 1 hiro
101 1 hiro
        logwin->window = window;
102 1 hiro
        logwin->scrolledwin = scrolledwin;
103 1 hiro
        logwin->text = text;
104 122 hiro
        logwin->lines = 1;
105 1 hiro
106 2259 hiro
#if USE_THREADS
107 2259 hiro
        logwin->aqueue = g_async_queue_new();
108 2259 hiro
109 2259 hiro
        main_thread = g_thread_self();
110 2259 hiro
        debug_print("main_thread = %p\n", main_thread);
111 2259 hiro
#endif
112 2259 hiro
113 1 hiro
        logwindow = logwin;
114 1 hiro
115 1 hiro
        return logwin;
116 1 hiro
}
117 1 hiro
118 1 hiro
void log_window_init(LogWindow *logwin)
119 1 hiro
{
120 1 hiro
        GtkTextBuffer *buffer;
121 1 hiro
        GdkColormap *colormap;
122 1 hiro
        GdkColor color[3] =
123 1 hiro
                {{0, 0, 0xafff, 0}, {0, 0xefff, 0, 0}, {0, 0xefff, 0, 0}};
124 1 hiro
        gboolean success[3];
125 1 hiro
        gint i;
126 1 hiro
127 1 hiro
        logwin->msg_color   = color[0];
128 1 hiro
        logwin->warn_color  = color[1];
129 1 hiro
        logwin->error_color = color[2];
130 1 hiro
131 1 hiro
        colormap = gdk_window_get_colormap(logwin->window->window);
132 1 hiro
        gdk_colormap_alloc_colors(colormap, color, 3, FALSE, TRUE, success);
133 1 hiro
134 1 hiro
        for (i = 0; i < 3; i++) {
135 1 hiro
                if (success[i] == FALSE) {
136 1 hiro
                        GtkStyle *style;
137 1 hiro
138 1 hiro
                        g_warning("LogWindow: color allocation failed\n");
139 1 hiro
                        style = gtk_widget_get_style(logwin->window);
140 1 hiro
                        logwin->msg_color = logwin->warn_color =
141 1 hiro
                        logwin->error_color = style->black;
142 1 hiro
                        break;
143 1 hiro
                }
144 1 hiro
        }
145 1 hiro
146 1 hiro
        buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(logwin->text));
147 1 hiro
        gtk_text_buffer_create_tag(buffer, "message",
148 1 hiro
                                   "foreground-gdk", &logwindow->msg_color,
149 1 hiro
                                   NULL);
150 1 hiro
        gtk_text_buffer_create_tag(buffer, "warn",
151 1 hiro
                                   "foreground-gdk", &logwindow->warn_color,
152 1 hiro
                                   NULL);
153 1 hiro
        gtk_text_buffer_create_tag(buffer, "error",
154 1 hiro
                                   "foreground-gdk", &logwindow->error_color,
155 1 hiro
                                   NULL);
156 523 hiro
157 2262 hiro
        set_log_ui_func_full(log_window_print_func, log_window_message_func,
158 2262 hiro
                             log_window_warning_func, log_window_error_func,
159 2262 hiro
                             log_window_flush);
160 1 hiro
}
161 1 hiro
162 1 hiro
void log_window_show(LogWindow *logwin)
163 1 hiro
{
164 1 hiro
        GtkTextView *text = GTK_TEXT_VIEW(logwin->text);
165 1 hiro
        GtkTextBuffer *buffer;
166 1 hiro
        GtkTextMark *mark;
167 1 hiro
168 1 hiro
        buffer = gtk_text_view_get_buffer(text);
169 1 hiro
        mark = gtk_text_buffer_get_mark(buffer, "end");
170 1 hiro
        gtk_text_view_scroll_mark_onscreen(text, mark);
171 1 hiro
172 122 hiro
        gtk_window_present(GTK_WINDOW(logwin->window));
173 1 hiro
}
174 1 hiro
175 2259 hiro
static void log_window_append_real(const gchar *str, LogType type)
176 1 hiro
{
177 1 hiro
        GtkTextView *text;
178 1 hiro
        GtkTextBuffer *buffer;
179 1 hiro
        GtkTextIter iter;
180 1 hiro
        GdkColor *color = NULL;
181 1 hiro
        gchar *head = NULL;
182 1 hiro
        const gchar *tag;
183 122 hiro
        gint line_limit = prefs_common.logwin_line_limit;
184 1 hiro
185 1 hiro
        g_return_if_fail(logwindow != NULL);
186 1 hiro
187 2259 hiro
#if USE_THREADS
188 2259 hiro
        if (g_thread_self() != main_thread) {
189 2272 hiro
                g_fprintf(stderr, "log_window_append_real called from non-main thread (%p)\n", g_thread_self());
190 2259 hiro
                return;
191 2259 hiro
        }
192 2259 hiro
#endif
193 2259 hiro
194 2259 hiro
        gdk_threads_enter();
195 2259 hiro
196 1 hiro
        text = GTK_TEXT_VIEW(logwindow->text);
197 1 hiro
        buffer = gtk_text_view_get_buffer(text);
198 1 hiro
199 122 hiro
        if (line_limit > 0 && logwindow->lines >= line_limit) {
200 122 hiro
                GtkTextIter start, end;
201 122 hiro
202 122 hiro
                gtk_text_buffer_get_start_iter(buffer, &start);
203 122 hiro
                end = start;
204 122 hiro
                gtk_text_iter_forward_lines(&end, TRIM_LINES);
205 122 hiro
                gtk_text_buffer_delete(buffer, &start, &end);
206 122 hiro
                logwindow->lines = gtk_text_buffer_get_line_count(buffer);
207 122 hiro
        }
208 122 hiro
209 1 hiro
        switch (type) {
210 1 hiro
        case LOG_MSG:
211 1 hiro
                color = &logwindow->msg_color;
212 1 hiro
                tag = "message";
213 1 hiro
                head = "* ";
214 1 hiro
                break;
215 1 hiro
        case LOG_WARN:
216 1 hiro
                color = &logwindow->warn_color;
217 1 hiro
                tag = "warn";
218 1 hiro
                head = "** ";
219 1 hiro
                break;
220 1 hiro
        case LOG_ERROR:
221 1 hiro
                color = &logwindow->error_color;
222 1 hiro
                tag = "error";
223 1 hiro
                head = "*** ";
224 1 hiro
                break;
225 1 hiro
        default:
226 1 hiro
                tag = NULL;
227 1 hiro
                break;
228 1 hiro
        }
229 1 hiro
230 122 hiro
        gtk_text_buffer_get_end_iter(buffer, &iter);
231 1 hiro
232 1 hiro
        if (head)
233 1 hiro
                gtk_text_buffer_insert_with_tags_by_name
234 1 hiro
                        (buffer, &iter, head, -1, tag, NULL);
235 1 hiro
236 734 hiro
        if (!g_utf8_validate(str, -1, NULL)) {
237 734 hiro
                gchar *str_;
238 734 hiro
239 734 hiro
                str_ = conv_utf8todisp(str, NULL);
240 734 hiro
                if (str_) {
241 734 hiro
                        gtk_text_buffer_insert_with_tags_by_name
242 734 hiro
                                (buffer, &iter, str_, -1, tag, NULL);
243 734 hiro
                        g_free(str_);
244 734 hiro
                }
245 734 hiro
        } else {
246 734 hiro
                gtk_text_buffer_insert_with_tags_by_name
247 734 hiro
                        (buffer, &iter, str, -1, tag, NULL);
248 734 hiro
        }
249 734 hiro
250 122 hiro
        if (GTK_WIDGET_VISIBLE(text)) {
251 122 hiro
                GtkTextMark *mark;
252 122 hiro
                mark = gtk_text_buffer_get_mark(buffer, "end");
253 1 hiro
                gtk_text_view_scroll_mark_onscreen(text, mark);
254 122 hiro
        }
255 1 hiro
256 1 hiro
        logwindow->lines++;
257 2259 hiro
258 2259 hiro
        gdk_threads_leave();
259 1 hiro
}
260 1 hiro
261 2259 hiro
void log_window_append(const gchar *str, LogType type)
262 2259 hiro
{
263 2259 hiro
#if USE_THREADS
264 2259 hiro
        if (g_thread_self() != main_thread) {
265 2259 hiro
                log_window_append_queue(str, type);
266 2259 hiro
                return;
267 2259 hiro
        }
268 2259 hiro
269 2259 hiro
        log_window_flush();
270 2259 hiro
#endif
271 2259 hiro
        log_window_append_real(str, type);
272 2259 hiro
}
273 2259 hiro
274 2259 hiro
typedef struct _LogData
275 2259 hiro
{
276 2259 hiro
        gchar *str;
277 2259 hiro
        LogType type;
278 2259 hiro
} LogData;
279 2259 hiro
280 2259 hiro
void log_window_append_queue(const gchar *str, LogType type)
281 2259 hiro
{
282 2259 hiro
#if USE_THREADS
283 2259 hiro
        LogData *logdata;
284 2259 hiro
285 2259 hiro
        logdata = g_new(LogData, 1);
286 2259 hiro
        logdata->str = g_strdup(str);
287 2259 hiro
        logdata->type = type;
288 2259 hiro
289 2259 hiro
        g_async_queue_push(logwindow->aqueue, logdata);
290 2259 hiro
#endif
291 2259 hiro
}
292 2259 hiro
293 2259 hiro
void log_window_flush(void)
294 2259 hiro
{
295 2259 hiro
#if USE_THREADS
296 2259 hiro
        LogData *logdata;
297 2259 hiro
298 2259 hiro
        if (g_thread_self() != main_thread) {
299 2269 hiro
                g_fprintf(stderr, "log_window_flush called from non-main thread (%p)\n", g_thread_self());
300 2259 hiro
                return;
301 2259 hiro
        }
302 2259 hiro
303 2259 hiro
        while ((logdata = g_async_queue_try_pop(logwindow->aqueue))) {
304 2259 hiro
                log_window_append_real(logdata->str, logdata->type);
305 2259 hiro
                g_free(logdata->str);
306 2259 hiro
                g_free(logdata);
307 2259 hiro
        }
308 2259 hiro
#endif
309 2259 hiro
}
310 2259 hiro
311 523 hiro
static void log_window_print_func(const gchar *str)
312 523 hiro
{
313 523 hiro
        log_window_append(str, LOG_NORMAL);
314 523 hiro
}
315 523 hiro
316 523 hiro
static void log_window_message_func(const gchar *str)
317 523 hiro
{
318 523 hiro
        log_window_append(str, LOG_MSG);
319 523 hiro
}
320 523 hiro
321 523 hiro
static void log_window_warning_func(const gchar *str)
322 523 hiro
{
323 523 hiro
        log_window_append(str, LOG_WARN);
324 523 hiro
}
325 523 hiro
326 523 hiro
static void log_window_error_func(const gchar *str)
327 523 hiro
{
328 523 hiro
        log_window_append(str, LOG_ERROR);
329 523 hiro
}
330 523 hiro
331 1 hiro
static void hide_cb(GtkWidget *widget, LogWindow *logwin)
332 1 hiro
{
333 1 hiro
}
334 1 hiro
335 1 hiro
static gboolean key_pressed(GtkWidget *widget, GdkEventKey *event,
336 1 hiro
                            LogWindow *logwin)
337 1 hiro
{
338 1 hiro
        if (event && event->keyval == GDK_Escape)
339 1 hiro
                gtk_widget_hide(logwin->window);
340 1 hiro
        return FALSE;
341 1 hiro
}