1
/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2
/* logview-window.c - main window of logview
4
* Copyright (C) 1998 Cesar Miquel <miquel@df.uba.ar>
5
* Copyright (C) 2008 Cosimo Cecchi <cosimoc@gnome.org>
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., 675 Mass Ave, Cambridge, MA 02139, USA.
26
#include <gdk/gdkkeysyms.h>
27
#include <glib/gi18n.h>
29
#include "logview-window.h"
31
#include "logview-loglist.h"
32
#include "logview-findbar.h"
33
#include "logview-about.h"
34
#include "logview-prefs.h"
35
#include "logview-manager.h"
36
#include "logview-filter-manager.h"
38
#define APP_NAME _("System Log Viewer")
39
#define SEARCH_START_MARK "lw-search-start-mark"
40
#define SEARCH_END_MARK "lw-search-end-mark"
42
struct _LogviewWindowPrivate {
43
GtkUIManager *ui_manager;
44
GtkActionGroup *action_group;
45
GtkActionGroup *filter_action_group;
50
GtkWidget *version_bar;
51
GtkWidget *version_selector;
56
GtkWidget *message_area;
57
GtkWidget *message_primary;
58
GtkWidget *message_secondary;
60
GtkTextTagTable *tag_table;
62
int original_fontsize, fontsize;
65
LogviewManager *manager;
68
guint search_timeout_id;
70
guint filter_merge_id;
71
GList *active_filters;
72
gboolean matches_only;
75
#define GET_PRIVATE(o) \
76
(G_TYPE_INSTANCE_GET_PRIVATE ((o), LOGVIEW_TYPE_WINDOW, LogviewWindowPrivate))
78
G_DEFINE_TYPE (LogviewWindow, logview_window, GTK_TYPE_WINDOW);
80
static void findbar_close_cb (LogviewFindbar *findbar,
82
static void read_new_lines_cb (LogviewLog *log,
88
/* private functions */
91
logview_version_selector_changed (GtkComboBox *version_selector, gpointer user_data)
96
LogviewWindow *logview = user_data;
97
Log *log = logview->curlog;
100
g_assert (LOGVIEW_IS_WINDOW (logview));
102
selected = gtk_combo_box_get_active (version_selector);
104
if (selected == log->current_version)
107
/* select a new version */
109
logview_select_log (logview, log->parent_log);
112
if (log->parent_log) {
113
new = log->parent_log->older_logs[selected];
115
new = log->older_logs[selected];
118
logview_select_log (logview, new);
124
/* private helpers */
127
populate_tag_table (GtkTextTagTable *tag_table)
131
tag = gtk_text_tag_new ("bold");
132
g_object_set (tag, "weight", PANGO_WEIGHT_BOLD,
133
"weight-set", TRUE, NULL);
135
gtk_text_tag_table_add (tag_table, tag);
137
tag = gtk_text_tag_new ("invisible");
138
g_object_set (tag, "invisible", TRUE, "invisible-set", TRUE, NULL);
139
gtk_text_tag_table_add (tag_table, tag);
141
tag = gtk_text_tag_new ("invisible-filter");
142
g_object_set (tag, "invisible", TRUE, "invisible-set", TRUE, NULL);
143
gtk_text_tag_table_add (tag_table, tag);
148
populate_style_tag_table (GtkStyle *style,
149
GtkTextTagTable *tag_table)
154
tag = gtk_text_tag_table_lookup (tag_table, "gray");
157
/* FIXME: do we need a way to update the buffer/view? */
158
gtk_text_tag_table_remove (tag_table, tag);
161
tag = gtk_text_tag_new ("gray");
162
color = style->text[GTK_STATE_INSENSITIVE];
163
g_object_set (tag, "foreground-gdk", &color, "foreground-set", TRUE, NULL);
165
gtk_text_tag_table_add (tag_table, tag);
169
_gtk_text_buffer_apply_tag_to_rectangle (GtkTextBuffer *buffer, int line_start, int line_end,
170
int offset_start, int offset_end, char *tag_name)
172
GtkTextIter start, end;
175
gtk_text_buffer_get_iter_at_line (buffer, &start, line_start);
176
gtk_text_buffer_get_iter_at_line (buffer, &end, line_start);
178
for (line_cur = line_start; line_cur < line_end + 1; line_cur++) {
180
if (offset_start > 0) {
181
gtk_text_iter_forward_chars (&start, offset_start);
184
gtk_text_iter_forward_chars (&end, offset_end);
186
gtk_text_buffer_apply_tag_by_name (buffer, tag_name, &start, &end);
188
gtk_text_iter_forward_line (&start);
189
gtk_text_iter_forward_line (&end);
194
logview_update_statusbar (LogviewWindow *logview, LogviewLog *active)
196
char *statusbar_text;
197
char *size, *modified, *timestring_utf8;
199
char timestring[255];
201
if (active == NULL) {
202
gtk_statusbar_pop (GTK_STATUSBAR (logview->priv->statusbar), 0);
206
timestamp = logview_log_get_timestamp (active);
207
strftime (timestring, sizeof (timestring), "%a %b %e %T %Y", localtime (×tamp));
208
timestring_utf8 = g_locale_to_utf8 (timestring, -1, NULL, NULL, NULL);
210
modified = g_strdup_printf (_("last update: %s"), timestring_utf8);
212
size = g_format_size_for_display (logview_log_get_file_size (active));
213
statusbar_text = g_strdup_printf (_("%d lines (%s) - %s"),
214
logview_log_get_cached_lines_number (active),
217
gtk_statusbar_pop (GTK_STATUSBAR (logview->priv->statusbar), 0);
218
gtk_statusbar_push (GTK_STATUSBAR (logview->priv->statusbar), 0, statusbar_text);
221
g_free (timestring_utf8);
223
g_free (statusbar_text);
226
#define DEFAULT_LOGVIEW_FONT "Monospace 10"
229
logview_set_font (LogviewWindow *logview,
230
const char *fontname)
232
PangoFontDescription *font_desc;
234
if (fontname == NULL)
235
fontname = DEFAULT_LOGVIEW_FONT;
237
font_desc = pango_font_description_from_string (fontname);
239
gtk_widget_modify_font (logview->priv->text_view, font_desc);
240
pango_font_description_free (font_desc);
245
logview_set_fontsize (LogviewWindow *logview, gboolean store)
247
PangoFontDescription *fontdesc;
248
PangoContext *context;
249
LogviewWindowPrivate *priv = logview->priv;
251
context = gtk_widget_get_pango_context (priv->text_view);
252
fontdesc = pango_context_get_font_description (context);
253
pango_font_description_set_size (fontdesc, (priv->fontsize) * PANGO_SCALE);
254
gtk_widget_modify_font (priv->text_view, fontdesc);
257
logview_prefs_store_fontsize (logview->priv->prefs, priv->fontsize);
262
logview_set_window_title (LogviewWindow *logview, const char * log_name)
267
window_title = g_strdup_printf ("%s - %s", log_name, APP_NAME);
269
window_title = g_strdup_printf (APP_NAME);
272
gtk_window_set_title (GTK_WINDOW (logview), window_title);
274
g_free (window_title);
278
logview_menu_item_set_state (LogviewWindow *logview, char *path, gboolean state)
284
action = gtk_ui_manager_get_action (logview->priv->ui_manager, path);
285
gtk_action_set_sensitive (action, state);
289
logview_window_menus_set_state (LogviewWindow *logview)
293
log = logview_manager_get_active_log (logview->priv->manager);
295
logview_menu_item_set_state (logview, "/LogviewMenu/FileMenu/CloseLog", (log != NULL));
296
logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/Search", (log != NULL));
297
logview_menu_item_set_state (logview, "/LogviewMenu/EditMenu/Copy", (log != NULL));
298
logview_menu_item_set_state (logview, "/LogviewMenu/EditMenu/SelectAll", (log != NULL));
300
g_object_unref (log);
303
/* actions callbacks */
306
open_file_selected_cb (GtkWidget *chooser, gint response, LogviewWindow *logview)
312
gtk_widget_hide (GTK_WIDGET (chooser));
313
if (response != GTK_RESPONSE_OK) {
317
f = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (chooser));
318
file_uri = g_file_get_uri (f);
320
log = logview_manager_get_if_loaded (logview->priv->manager, file_uri);
325
logview_manager_set_active_log (logview->priv->manager, log);
326
g_object_unref (log);
330
logview_manager_add_log_from_gfile (logview->priv->manager, f, TRUE);
337
logview_open_log (GtkAction *action, LogviewWindow *logview)
339
static GtkWidget *chooser = NULL;
342
if (chooser == NULL) {
343
chooser = gtk_file_chooser_dialog_new (_("Open Log"),
344
GTK_WINDOW (logview),
345
GTK_FILE_CHOOSER_ACTION_OPEN,
346
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
347
GTK_STOCK_OPEN, GTK_RESPONSE_OK,
349
gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
350
gtk_window_set_modal (GTK_WINDOW (chooser), TRUE);
351
g_signal_connect (chooser, "response",
352
G_CALLBACK (open_file_selected_cb), logview);
353
g_signal_connect (chooser, "destroy",
354
G_CALLBACK (gtk_widget_destroyed), &chooser);
355
active = logview_prefs_get_active_logfile (logview->priv->prefs);
356
if (active != NULL) {
357
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser), active);
362
gtk_window_present (GTK_WINDOW (chooser));
366
logview_close_log (GtkAction *action, LogviewWindow *logview)
368
findbar_close_cb (LOGVIEW_FINDBAR (logview->priv->find_bar), logview);
369
logview_manager_close_active_log (logview->priv->manager);
373
logview_help (GtkAction *action, GtkWidget *parent_window)
375
GError *error = NULL;
377
gtk_show_uri (gtk_widget_get_screen (parent_window),
378
"ghelp:gnome-system-log", gtk_get_current_event_time (),
382
g_warning (_("There was an error displaying help: %s"), error->message);
383
g_error_free (error);
388
logview_bigger_text (GtkAction *action, LogviewWindow *logview)
390
logview->priv->fontsize = MIN (logview->priv->fontsize + 1, 24);
391
logview_set_fontsize (logview, TRUE);
395
logview_smaller_text (GtkAction *action, LogviewWindow *logview)
397
logview->priv->fontsize = MAX (logview->priv->fontsize-1, 6);
398
logview_set_fontsize (logview, TRUE);
402
logview_normal_text (GtkAction *action, LogviewWindow *logview)
404
logview->priv->fontsize = logview->priv->original_fontsize;
405
logview_set_fontsize (logview, TRUE);
409
logview_select_all (GtkAction *action, LogviewWindow *logview)
411
GtkTextIter start, end;
412
GtkTextBuffer *buffer;
414
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
416
gtk_text_buffer_get_bounds (buffer, &start, &end);
417
gtk_text_buffer_select_range (buffer, &start, &end);
419
gtk_widget_grab_focus (GTK_WIDGET (logview->priv->text_view));
423
logview_copy (GtkAction *action, LogviewWindow *logview)
425
GtkTextBuffer *buffer;
426
GtkClipboard *clipboard;
428
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
429
clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
431
gtk_text_buffer_copy_clipboard (buffer, clipboard);
433
gtk_widget_grab_focus (GTK_WIDGET (logview->priv->text_view));
437
findbar_close_cb (LogviewFindbar *findbar,
440
LogviewWindow *logview = user_data;
442
gtk_widget_hide (GTK_WIDGET (findbar));
443
logview_findbar_set_message (findbar, NULL);
447
logview_search_text (LogviewWindow *logview, gboolean forward)
449
GtkTextBuffer *buffer;
450
GtkTextMark *search_start, *search_end;
451
GtkTextIter search, start_m, end_m;
453
gboolean res, wrapped;
457
text = logview_findbar_get_text (LOGVIEW_FINDBAR (logview->priv->find_bar));
459
if (!text || g_strcmp0 (text, "") == 0) {
463
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
464
search_start = gtk_text_buffer_get_mark (buffer, SEARCH_START_MARK);
465
search_end = gtk_text_buffer_get_mark (buffer, SEARCH_END_MARK);
468
/* this is our first search on the buffer, create a new search mark */
469
gtk_text_buffer_get_start_iter (buffer, &search);
470
search_start = gtk_text_buffer_create_mark (buffer, SEARCH_START_MARK,
472
search_end = gtk_text_buffer_create_mark (buffer, SEARCH_END_MARK,
476
gtk_text_buffer_get_iter_at_mark (buffer, &search, search_end);
478
gtk_text_buffer_get_iter_at_mark (buffer, &search, search_start);
485
res = gtk_text_iter_forward_search (&search, text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start_m, &end_m, NULL);
487
res = gtk_text_iter_backward_search (&search, text, GTK_TEXT_SEARCH_VISIBLE_ONLY, &start_m, &end_m, NULL);
491
gtk_text_buffer_select_range (buffer, &start_m, &end_m);
492
gtk_text_buffer_move_mark (buffer, search_start, &start_m);
493
gtk_text_buffer_move_mark (buffer, search_end, &end_m);
495
gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (logview->priv->text_view), search_end);
498
logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), _("Wrapped"));
506
if (gtk_text_buffer_get_has_selection (buffer)) {
508
mark = gtk_text_buffer_get_mark (buffer, "insert");
509
gtk_text_buffer_get_iter_at_mark (buffer, &iter, mark);
510
gtk_text_buffer_move_mark_by_name (buffer, "selection_bound", &iter);
513
logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), _("Not found"));
516
gtk_text_buffer_get_start_iter (buffer, &search);
518
gtk_text_buffer_get_end_iter (buffer, &search);
528
findbar_previous_cb (LogviewFindbar *findbar,
531
LogviewWindow *logview = user_data;
533
logview_search_text (logview, FALSE);
537
findbar_next_cb (LogviewFindbar *findbar,
540
LogviewWindow *logview = user_data;
542
logview_search_text (logview, TRUE);
546
text_changed_timeout_cb (gpointer user_data)
548
LogviewWindow *logview = user_data;
549
GtkTextMark *search_start, *search_end;
551
GtkTextBuffer *buffer;
553
logview->priv->search_timeout_id = 0;
555
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
556
search_start = gtk_text_buffer_get_mark (buffer, SEARCH_START_MARK);
557
search_end = gtk_text_buffer_get_mark (buffer, SEARCH_END_MARK);
560
/* reset the search mark to the start */
561
gtk_text_buffer_get_start_iter (buffer, &start);
562
gtk_text_buffer_move_mark (buffer, search_start, &start);
563
gtk_text_buffer_move_mark (buffer, search_end, &start);
566
logview_findbar_set_message (LOGVIEW_FINDBAR (logview->priv->find_bar), NULL);
568
logview_search_text (logview, TRUE);
574
findbar_text_changed_cb (LogviewFindbar *findbar,
577
LogviewWindow *logview = user_data;
579
if (logview->priv->search_timeout_id != 0) {
580
g_source_remove (logview->priv->search_timeout_id);
583
logview->priv->search_timeout_id = g_timeout_add (300, text_changed_timeout_cb, logview);
587
logview_search (GtkAction *action, LogviewWindow *logview)
589
logview_findbar_open (LOGVIEW_FINDBAR (logview->priv->find_bar));
593
filter_buffer (LogviewWindow *logview, gint start_line)
595
GtkTextBuffer *buffer;
596
GtkTextIter start, *end;
599
gboolean matched, invisible_set;
602
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
603
lines = gtk_text_buffer_get_line_count (buffer);
605
for (i = start_line; i < lines; i++) {
608
gtk_text_buffer_get_iter_at_line (buffer, &start, i);
609
end = gtk_text_iter_copy (&start);
610
gtk_text_iter_forward_line (end);
612
text = gtk_text_buffer_get_text (buffer, &start, end, TRUE);
614
for (cur_filter = logview->priv->active_filters; cur_filter != NULL;
615
cur_filter = g_list_next (cur_filter))
617
if (logview_filter_filter (LOGVIEW_FILTER (cur_filter->data), text)) {
618
gtk_text_buffer_apply_tag (buffer,
619
logview_filter_get_tag (LOGVIEW_FILTER (cur_filter->data)),
627
if (!matched && logview->priv->matches_only) {
628
gtk_text_buffer_apply_tag_by_name (buffer,
632
gtk_text_buffer_remove_tag_by_name (buffer,
637
gtk_text_iter_free (end);
642
filter_remove (LogviewWindow *logview, LogviewFilter *filter)
644
GtkTextIter start, end;
645
GtkTextBuffer *buffer;
647
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
648
gtk_text_buffer_get_bounds (buffer, &start, &end);
650
gtk_text_buffer_remove_tag (buffer, logview_filter_get_tag (filter),
655
on_filter_toggled (GtkToggleAction *action, LogviewWindow *logview)
657
LogviewWindowPrivate *priv = GET_PRIVATE (logview);
659
LogviewFilter *filter;
661
name = gtk_action_get_name (GTK_ACTION (action));
663
if (gtk_toggle_action_get_active (action)) {
664
priv->active_filters = g_list_append (priv->active_filters,
665
logview_prefs_get_filter (priv->prefs,
667
filter_buffer(logview, 0);
669
filter = logview_prefs_get_filter (priv->prefs, name);
670
priv->active_filters = g_list_remove (priv->active_filters,
673
filter_remove (logview, filter);
677
#define FILTER_PLACEHOLDER "/LogviewMenu/FilterMenu/PlaceholderFilters"
679
update_filter_menu (LogviewWindow *window)
681
LogviewWindowPrivate *priv;
687
GtkTextBuffer *buffer;
688
GtkTextTagTable *table;
690
GtkToggleAction *action;
693
priv = GET_PRIVATE (window);
694
ui = priv->ui_manager;
696
g_return_if_fail (priv->filter_action_group != NULL);
698
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
699
table = priv->tag_table;
701
if (priv->filter_merge_id != 0) {
702
gtk_ui_manager_remove_ui (ui,
703
priv->filter_merge_id);
706
actions = gtk_action_group_list_actions (priv->filter_action_group);
708
for (l = actions; l != NULL; l = g_list_next (l)) {
709
tag = gtk_text_tag_table_lookup (table, gtk_action_get_name (GTK_ACTION (l->data)));
710
gtk_text_tag_table_remove (table, tag);
712
g_signal_handlers_disconnect_by_func (GTK_ACTION (l->data),
713
G_CALLBACK (on_filter_toggled),
715
gtk_action_group_remove_action (priv->filter_action_group,
716
GTK_ACTION (l->data));
719
g_list_free (actions);
721
filters = logview_prefs_get_filters (logview_prefs_get ());
723
id = (g_list_length (filters) > 0) ? gtk_ui_manager_new_merge_id (ui) : 0;
725
for (l = filters; l != NULL; l = g_list_next (l)) {
726
g_object_get (l->data, "name", &name, NULL);
728
action = gtk_toggle_action_new (name, name, NULL, NULL);
729
gtk_action_group_add_action (priv->filter_action_group,
730
GTK_ACTION (action));
732
g_signal_connect (action,
734
G_CALLBACK (on_filter_toggled),
737
gtk_ui_manager_add_ui (ui, id, FILTER_PLACEHOLDER,
738
name, name, GTK_UI_MANAGER_MENUITEM, FALSE);
739
gtk_text_tag_table_add (table,
740
logview_filter_get_tag (LOGVIEW_FILTER (l->data)));
742
g_object_unref (action);
746
g_list_free (filters);
748
priv->filter_merge_id = id;
752
on_logview_filter_manager_response (GtkDialog *dialog,
754
LogviewWindow *logview)
756
update_filter_menu (logview);
758
g_list_free (logview->priv->active_filters);
759
logview->priv->active_filters = NULL;
763
logview_manage_filters (GtkAction *action, LogviewWindow *logview)
767
manager = logview_filter_manager_new ();
769
g_signal_connect (manager, "response",
770
G_CALLBACK (on_logview_filter_manager_response),
773
gtk_window_set_transient_for (GTK_WINDOW (manager),
774
GTK_WINDOW (logview));
775
gtk_widget_show (GTK_WIDGET (manager));
779
logview_about (GtkWidget *widget, GtkWidget *window)
781
g_return_if_fail (GTK_IS_WINDOW (window));
783
char *license_trans = g_strjoin ("\n\n", _(logview_about_license[0]),
784
_(logview_about_license[1]),
785
_(logview_about_license[2]), NULL);
787
gtk_show_about_dialog (GTK_WINDOW (window),
788
"name", _("System Log Viewer"),
790
"copyright", "Copyright \xc2\xa9 1998-2008 Free Software Foundation, Inc.",
791
"license", license_trans,
792
"wrap-license", TRUE,
793
"comments", _("A system log viewer for GNOME."),
794
"authors", logview_about_authors,
795
"documenters", logview_about_documenters,
796
"translator_credits", strcmp (logview_about_translator_credits,
797
"translator-credits") != 0 ?
798
logview_about_translator_credits : NULL,
799
"logo_icon_name", "logviewer",
801
g_free (license_trans);
807
logview_toggle_statusbar (GtkAction *action, LogviewWindow *logview)
809
if (GTK_WIDGET_VISIBLE (logview->priv->statusbar))
810
gtk_widget_hide (logview->priv->statusbar);
812
gtk_widget_show (logview->priv->statusbar);
816
logview_toggle_sidebar (GtkAction *action, LogviewWindow *logview)
818
if (GTK_WIDGET_VISIBLE (logview->priv->sidebar))
819
gtk_widget_hide (logview->priv->sidebar);
821
gtk_widget_show (logview->priv->sidebar);
825
logview_toggle_match_filters (GtkToggleAction *action, LogviewWindow *logview)
827
logview->priv->matches_only = gtk_toggle_action_get_active (action);
828
filter_buffer (logview, 0);
831
/* GObject functions */
835
static GtkActionEntry entries[] = {
836
{ "FileMenu", NULL, N_("_File"), NULL, NULL, NULL },
837
{ "EditMenu", NULL, N_("_Edit"), NULL, NULL, NULL },
838
{ "ViewMenu", NULL, N_("_View"), NULL, NULL, NULL },
839
{ "FilterMenu", NULL, N_("_Filters"), NULL, NULL, NULL },
840
{ "HelpMenu", NULL, N_("_Help"), NULL, NULL, NULL },
842
{ "OpenLog", GTK_STOCK_OPEN, N_("_Open..."), "<control>O", N_("Open a log from file"),
843
G_CALLBACK (logview_open_log) },
844
{ "CloseLog", GTK_STOCK_CLOSE, N_("_Close"), "<control>W", N_("Close this log"),
845
G_CALLBACK (logview_close_log) },
846
{ "Quit", GTK_STOCK_QUIT, N_("_Quit"), "<control>Q", N_("Quit the log viewer"),
847
G_CALLBACK (gtk_main_quit) },
849
{ "Copy", GTK_STOCK_COPY, N_("_Copy"), "<control>C", N_("Copy the selection"),
850
G_CALLBACK (logview_copy) },
851
{ "SelectAll", NULL, N_("Select _All"), "<Control>A", N_("Select the entire log"),
852
G_CALLBACK (logview_select_all) },
853
{ "Search", GTK_STOCK_FIND, N_("_Find..."), "<control>F", N_("Find a word or phrase in the log"),
854
G_CALLBACK (logview_search) },
856
{ "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus", N_("Bigger text size"),
857
G_CALLBACK (logview_bigger_text)},
858
{ "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus", N_("Smaller text size"),
859
G_CALLBACK (logview_smaller_text)},
860
{ "ViewZoom100", GTK_STOCK_ZOOM_100, NULL, "<control>0", N_("Normal text size"),
861
G_CALLBACK (logview_normal_text)},
863
{ "FilterManage", NULL, N_("Manage Filters"), NULL, N_("Manage filters"),
864
G_CALLBACK (logview_manage_filters)},
866
{ "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1", N_("Open the help contents for the log viewer"),
867
G_CALLBACK (logview_help) },
868
{ "AboutAction", GTK_STOCK_ABOUT, N_("_About"), NULL, N_("Show the about dialog for the log viewer"),
869
G_CALLBACK (logview_about) },
872
static GtkToggleActionEntry toggle_entries[] = {
873
{ "ShowStatusBar", NULL, N_("_Statusbar"), NULL, N_("Show Status Bar"),
874
G_CALLBACK (logview_toggle_statusbar), TRUE },
875
{ "ShowSidebar", NULL, N_("Side _Pane"), "F9", N_("Show Side Pane"),
876
G_CALLBACK (logview_toggle_sidebar), TRUE },
877
{ "FilterMatchOnly", NULL, N_("Show matches only"), NULL, N_("Only show lines that match one of the given filters"),
878
G_CALLBACK (logview_toggle_match_filters), FALSE}
882
window_size_changed_cb (GtkWidget *widget, GdkEventConfigure *event,
885
LogviewWindow *window = data;
887
logview_prefs_store_window_size (window->priv->prefs,
888
event->width, event->height);
894
real_select_day (LogviewWindow *logview,
895
GDate *date, int first_line, int last_line)
897
GtkTextBuffer *buffer;
898
GtkTextIter start_iter, end_iter, start_vis, end_vis;
899
GdkRectangle visible_rect;
901
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
903
gtk_text_buffer_get_bounds (buffer, &start_iter, &end_iter);
904
gtk_text_buffer_get_iter_at_line (buffer, &start_vis, first_line);
905
gtk_text_buffer_get_iter_at_line (buffer, &end_vis, last_line + 1);
907
/* clear all previous invisible tags */
908
gtk_text_buffer_remove_tag_by_name (buffer, "invisible",
909
&start_iter, &end_iter);
911
gtk_text_buffer_apply_tag_by_name (buffer, "invisible",
912
&start_iter, &start_vis);
913
gtk_text_buffer_apply_tag_by_name (buffer, "invisible",
914
&end_vis, &end_iter);
916
/* FIXME: why is this needed to update the view when selecting a day back? */
917
gtk_text_view_get_visible_rect (GTK_TEXT_VIEW (logview->priv->text_view),
919
gdk_window_invalidate_rect (gtk_widget_get_window (logview->priv->text_view),
920
&visible_rect, TRUE);
924
loglist_day_selected_cb (LogviewLoglist *loglist,
928
LogviewWindow *logview = user_data;
930
real_select_day (logview, day->date, day->first_line, day->last_line);
934
loglist_day_cleared_cb (LogviewLoglist *loglist,
937
LogviewWindow *logview = user_data;
938
GtkTextBuffer *buffer;
939
GtkTextIter start, end;
941
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (logview->priv->text_view));
942
gtk_text_buffer_get_bounds (buffer, &start, &end);
944
/* clear all previous invisible tags */
945
gtk_text_buffer_remove_tag_by_name (buffer, "invisible",
950
logview_window_select_date (LogviewWindow *logview, GDate *date)
955
gboolean found = FALSE;
957
log = logview_manager_get_active_log (logview->priv->manager);
959
for (l = days; l; l = l->next) {
961
if (g_date_compare (date, day->date) == 0) {
968
real_select_day (logview, day->date, day->first_line, day->last_line);
973
log_monitor_changed_cb (LogviewLog *log,
976
/* reschedule a read */
977
logview_log_read_new_lines (log, (LogviewNewLinesCallback) read_new_lines_cb,
982
paint_timestamps (GtkTextBuffer *buffer, int old_line_count,
987
for (l = days; l; l = l->next) {
990
_gtk_text_buffer_apply_tag_to_rectangle (buffer,
991
old_line_count + day->first_line - 1,
992
old_line_count + day->last_line,
993
0, day->timestamp_len, "gray");
998
read_new_lines_cb (LogviewLog *log,
1004
LogviewWindow *window = user_data;
1005
GtkTextBuffer *buffer;
1006
gboolean boldify = FALSE;
1007
int i, old_line_count, filter_start_line;
1008
GtkTextIter iter, start;
1010
char *converted, *primary;
1013
if (error != NULL) {
1014
primary = g_strdup_printf (_("Can't read from \"%s\""),
1015
logview_log_get_display_name (log));
1016
logview_window_add_error (window, primary, error->message);
1022
if (lines == NULL) {
1023
/* there's no error, but no lines have been read */
1027
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (window->priv->text_view));
1028
old_line_count = gtk_text_buffer_get_line_count (buffer);
1029
filter_start_line = old_line_count > 0 ? (old_line_count - 1) : 0;
1031
if (gtk_text_buffer_get_char_count (buffer) != 0) {
1035
gtk_text_buffer_get_end_iter (buffer, &iter);
1038
mark = gtk_text_buffer_create_mark (buffer, NULL, &iter, TRUE);
1041
for (i = 0; lines[i]; i++) {
1042
len = strlen (lines[i]);
1044
if (!g_utf8_validate (lines[i], len, NULL)) {
1045
converted = g_locale_to_utf8 (lines[i], (gssize) len, NULL, &len, NULL);
1046
gtk_text_buffer_insert (buffer, &iter, lines[i], len);
1048
gtk_text_buffer_insert (buffer, &iter, lines[i], strlen (lines[i]));
1051
gtk_text_iter_forward_to_end (&iter);
1052
gtk_text_buffer_insert (buffer, &iter, "\n", 1);
1053
gtk_text_iter_forward_char (&iter);
1057
gtk_text_buffer_get_iter_at_mark (buffer, &start, mark);
1058
gtk_text_buffer_apply_tag_by_name (buffer, "bold", &start, &iter);
1059
gtk_text_buffer_delete_mark (buffer, mark);
1061
filter_buffer (window, filter_start_line);
1063
gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (window->priv->text_view),
1064
&iter, 0.0, FALSE, 0.0, 0.0);
1066
paint_timestamps (buffer, old_line_count, new_days);
1068
if (window->priv->monitor_id == 0) {
1069
window->priv->monitor_id = g_signal_connect (log, "log-changed",
1070
G_CALLBACK (log_monitor_changed_cb), window);
1073
logview_update_statusbar (window, log);
1074
logview_loglist_update_lines (LOGVIEW_LOGLIST (window->priv->loglist), log);
1078
active_log_changed_cb (LogviewManager *manager,
1080
LogviewLog *old_log,
1083
LogviewWindow *window = data;
1085
GtkTextBuffer *buffer;
1087
findbar_close_cb (LOGVIEW_FINDBAR (window->priv->find_bar),
1090
logview_set_window_title (window, logview_log_get_display_name (log));
1092
if (window->priv->monitor_id) {
1093
g_signal_handler_disconnect (old_log, window->priv->monitor_id);
1094
window->priv->monitor_id = 0;
1097
lines = logview_log_get_cached_lines (log);
1098
buffer = gtk_text_buffer_new (window->priv->tag_table);
1100
if (lines != NULL) {
1104
/* update the text view to show the current lines */
1105
gtk_text_buffer_get_end_iter (buffer, &iter);
1107
for (i = 0; lines[i]; i++) {
1108
gtk_text_buffer_insert (buffer, &iter, lines[i], strlen (lines[i]));
1109
gtk_text_iter_forward_to_end (&iter);
1110
gtk_text_buffer_insert (buffer, &iter, "\n", 1);
1111
gtk_text_iter_forward_char (&iter);
1114
paint_timestamps (buffer, 1, logview_log_get_days_for_cached_lines (log));
1117
if (lines == NULL || logview_log_has_new_lines (log)) {
1118
/* read the new lines */
1119
logview_log_read_new_lines (log, (LogviewNewLinesCallback) read_new_lines_cb, window);
1121
/* start now monitoring the log for changes */
1122
window->priv->monitor_id = g_signal_connect (log, "log-changed",
1123
G_CALLBACK (log_monitor_changed_cb), window);
1126
/* we set the buffer to the view anyway;
1127
* if there are no lines it will be empty for the duration of the thread
1128
* and will help us to distinguish the two cases of the following if
1129
* cause in the callback.
1131
gtk_text_view_set_buffer (GTK_TEXT_VIEW (window->priv->text_view), buffer);
1132
g_object_unref (buffer);
1136
font_changed_cb (LogviewPrefs *prefs,
1137
const char *font_name,
1140
LogviewWindow *window = user_data;
1142
logview_set_font (window, font_name);
1146
tearoff_changed_cb (LogviewPrefs *prefs,
1147
gboolean have_tearoffs,
1150
LogviewWindow *window = user_data;
1152
gtk_ui_manager_set_add_tearoffs (window->priv->ui_manager, have_tearoffs);
1156
style_set_cb (GtkWidget *widget,
1160
LogviewWindow *logview = user_data;
1161
GtkStyle *style = gtk_widget_get_style (widget);
1163
populate_style_tag_table (style, logview->priv->tag_table);
1166
static const struct {
1168
GdkModifierType modifier;
1169
const gchar *action;
1170
} extra_keybindings [] = {
1171
{ GDK_KP_Add, GDK_CONTROL_MASK, "ViewZoomIn" },
1172
{ GDK_KP_Subtract, GDK_CONTROL_MASK, "ViewZoomOut" },
1173
{ GDK_KP_0, GDK_CONTROL_MASK, "ViewZoom100" }
1177
key_press_event_cb (GtkWidget *widget,
1181
LogviewWindow *window = user_data;
1182
guint modifier = event->state & gtk_accelerator_get_default_mod_mask ();
1186
/* handle accelerators that we want bound, but aren't associated with
1188
for (i = 0; i < G_N_ELEMENTS (extra_keybindings); i++) {
1189
if (event->keyval == extra_keybindings[i].keyval &&
1190
modifier == extra_keybindings[i].modifier) {
1192
action = gtk_action_group_get_action (window->priv->action_group,
1193
extra_keybindings[i].action);
1194
gtk_action_activate (action);
1202
/* adapted from GEdit */
1205
message_area_create_error_box (LogviewWindow *window,
1206
GtkWidget *message_area)
1208
GtkWidget *hbox_content;
1211
GtkWidget *primary_label;
1212
GtkWidget *secondary_label;
1214
hbox_content = gtk_hbox_new (FALSE, 8);
1215
gtk_widget_show (hbox_content);
1217
image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR,
1218
GTK_ICON_SIZE_DIALOG);
1219
gtk_widget_show (image);
1220
gtk_box_pack_start (GTK_BOX (hbox_content), image, FALSE, FALSE, 0);
1221
gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0);
1223
vbox = gtk_vbox_new (FALSE, 6);
1224
gtk_widget_show (vbox);
1225
gtk_box_pack_start (GTK_BOX (hbox_content), vbox, TRUE, TRUE, 0);
1227
primary_label = gtk_label_new (NULL);
1228
gtk_widget_show (primary_label);
1229
gtk_box_pack_start (GTK_BOX (vbox), primary_label, TRUE, TRUE, 0);
1230
gtk_label_set_use_markup (GTK_LABEL (primary_label), TRUE);
1231
gtk_label_set_line_wrap (GTK_LABEL (primary_label), TRUE);
1232
gtk_misc_set_alignment (GTK_MISC (primary_label), 0, 0.5);
1233
GTK_WIDGET_SET_FLAGS (primary_label, GTK_CAN_FOCUS);
1234
gtk_label_set_selectable (GTK_LABEL (primary_label), TRUE);
1236
window->priv->message_primary = primary_label;
1238
secondary_label = gtk_label_new (NULL);
1239
gtk_widget_show (secondary_label);
1240
gtk_box_pack_start (GTK_BOX (vbox), secondary_label, TRUE, TRUE, 0);
1241
GTK_WIDGET_SET_FLAGS (secondary_label, GTK_CAN_FOCUS);
1242
gtk_label_set_use_markup (GTK_LABEL (secondary_label), TRUE);
1243
gtk_label_set_line_wrap (GTK_LABEL (secondary_label), TRUE);
1244
gtk_label_set_selectable (GTK_LABEL (secondary_label), TRUE);
1245
gtk_misc_set_alignment (GTK_MISC (secondary_label), 0, 0.5);
1247
window->priv->message_secondary = secondary_label;
1250
(GTK_CONTAINER (gtk_info_bar_get_content_area
1251
(GTK_INFO_BAR (message_area))),
1256
message_area_set_labels (LogviewWindow *window,
1257
const char *primary,
1258
const char *secondary)
1260
char *primary_markup, *secondary_markup;
1262
primary_markup = g_markup_printf_escaped ("<b>%s</b>", primary);
1263
secondary_markup = g_markup_printf_escaped ("<small>%s</small>",
1266
gtk_label_set_markup (GTK_LABEL (window->priv->message_primary),
1268
gtk_label_set_markup (GTK_LABEL (window->priv->message_secondary),
1271
g_free (primary_markup);
1272
g_free (secondary_markup);
1276
message_area_response_cb (GtkInfoBar *message_area,
1277
int response_id, gpointer user_data)
1279
LogviewWindow *window = user_data;
1281
gtk_widget_hide (GTK_WIDGET (message_area));
1283
g_signal_handlers_disconnect_by_func (message_area,
1284
message_area_response_cb,
1289
logview_window_finalize (GObject *object)
1291
LogviewWindow *logview = LOGVIEW_WINDOW (object);
1293
g_object_unref (logview->priv->ui_manager);
1294
G_OBJECT_CLASS (logview_window_parent_class)->finalize (object);
1298
logview_window_init (LogviewWindow *logview)
1301
GtkActionGroup *action_group;
1302
GtkAccelGroup *accel_group;
1303
GError *error = NULL;
1304
GtkWidget *hpaned, *main_view, *scrolled, *vbox, *w;
1305
PangoContext *context;
1306
PangoFontDescription *fontdesc;
1307
gchar *monospace_font_name;
1308
LogviewWindowPrivate *priv;
1312
priv = logview->priv = GET_PRIVATE (logview);
1313
priv->prefs = logview_prefs_get ();
1314
priv->manager = logview_manager_get ();
1315
priv->monitor_id = 0;
1317
logview_prefs_get_stored_window_size (priv->prefs, &width, &height);
1318
gtk_window_set_default_size (GTK_WINDOW (logview), width, height);
1320
vbox = gtk_vbox_new (FALSE, 0);
1321
gtk_container_add (GTK_CONTAINER (logview), vbox);
1324
action_group = gtk_action_group_new ("LogviewMenuActions");
1325
gtk_action_group_set_translation_domain (action_group, NULL);
1326
gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), logview);
1327
gtk_action_group_add_toggle_actions (action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), logview);
1328
priv->action_group = action_group;
1330
priv->ui_manager = gtk_ui_manager_new ();
1332
gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, 0);
1333
accel_group = gtk_ui_manager_get_accel_group (priv->ui_manager);
1334
gtk_window_add_accel_group (GTK_WINDOW (logview), accel_group);
1336
res = gtk_ui_manager_add_ui_from_file (priv->ui_manager,
1337
LOGVIEW_DATADIR "/logview-toolbar.xml",
1341
priv->ui_manager = NULL;
1342
g_critical ("Can't load the UI description: %s", error->message);
1343
g_error_free (error);
1347
gtk_ui_manager_set_add_tearoffs (priv->ui_manager,
1348
logview_prefs_get_have_tearoff (priv->prefs));
1350
w = gtk_ui_manager_get_widget (priv->ui_manager, "/LogviewMenu");
1351
gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
1352
gtk_widget_show (w);
1355
hpaned = gtk_hpaned_new ();
1356
gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
1357
priv->hpaned = hpaned;
1358
gtk_widget_show (hpaned);
1360
/* first pane : sidebar (list of logs) */
1361
priv->sidebar = gtk_vbox_new (FALSE, 0);
1362
gtk_widget_show (priv->sidebar);
1364
/* first pane: log list */
1365
w = gtk_scrolled_window_new (NULL, NULL);
1366
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w),
1367
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1368
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w),
1369
GTK_SHADOW_ETCHED_IN);
1371
priv->loglist = logview_loglist_new ();
1372
gtk_container_add (GTK_CONTAINER (w), priv->loglist);
1373
gtk_box_pack_start (GTK_BOX (priv->sidebar), w, TRUE, TRUE, 0);
1374
gtk_paned_pack1 (GTK_PANED (hpaned), priv->sidebar, FALSE, FALSE);
1375
gtk_widget_show (w);
1376
gtk_widget_show (priv->loglist);
1378
g_signal_connect (priv->loglist, "day_selected",
1379
G_CALLBACK (loglist_day_selected_cb), logview);
1380
g_signal_connect (priv->loglist, "day_cleared",
1381
G_CALLBACK (loglist_day_cleared_cb), logview);
1383
/* second pane: log */
1384
main_view = gtk_vbox_new (FALSE, 0);
1385
gtk_paned_pack2 (GTK_PANED (hpaned), main_view, TRUE, TRUE);
1387
/* second pane: error message area */
1388
priv->message_area = gtk_info_bar_new ();
1389
message_area_create_error_box (logview, priv->message_area);
1390
gtk_info_bar_add_button (GTK_INFO_BAR (priv->message_area),
1391
GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
1392
gtk_box_pack_start (GTK_BOX (main_view), priv->message_area, FALSE, FALSE, 0);
1394
/* second pane: text view */
1395
w = gtk_scrolled_window_new (NULL, NULL);
1396
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (w),
1397
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1398
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (w), GTK_SHADOW_IN);
1399
gtk_box_pack_start (GTK_BOX (main_view), w, TRUE, TRUE, 0);
1400
gtk_widget_show (w);
1402
priv->tag_table = gtk_text_tag_table_new ();
1403
populate_tag_table (priv->tag_table);
1404
priv->text_view = gtk_text_view_new ();
1405
g_object_set (priv->text_view, "editable", FALSE, NULL);
1407
gtk_container_add (GTK_CONTAINER (w), priv->text_view);
1408
gtk_widget_show (priv->text_view);
1410
/* use the desktop monospace font */
1411
monospace_font_name = logview_prefs_get_monospace_font_name (priv->prefs);
1412
logview_set_font (logview, monospace_font_name);
1413
g_free (monospace_font_name);
1415
/* remember the original font size */
1416
context = gtk_widget_get_pango_context (priv->text_view);
1417
fontdesc = pango_context_get_font_description (context);
1418
priv->original_fontsize = pango_font_description_get_size (fontdesc) / PANGO_SCALE;
1420
/* restore saved zoom */
1421
priv->fontsize = logview_prefs_get_stored_fontsize (priv->prefs);
1423
if (priv->fontsize <= 0) {
1424
/* restore the default */
1425
logview_normal_text (NULL, logview);
1427
logview_set_fontsize (logview, FALSE);
1430
/* version selector */
1431
priv->version_bar = gtk_hbox_new (FALSE, 0);
1432
gtk_container_set_border_width (GTK_CONTAINER (priv->version_bar), 3);
1433
priv->version_selector = gtk_combo_box_new_text ();
1434
g_signal_connect (priv->version_selector, "changed",
1435
G_CALLBACK (logview_version_selector_changed), logview);
1436
w = gtk_label_new (_("Version: "));
1438
gtk_box_pack_end (GTK_BOX (priv->version_bar), priv->version_selector, FALSE, FALSE, 0);
1439
gtk_box_pack_end (GTK_BOX (priv->version_bar), w, FALSE, FALSE, 0);
1440
gtk_box_pack_end (GTK_BOX (main_view), priv->version_bar, FALSE, FALSE, 0);
1442
priv->find_bar = logview_findbar_new ();
1443
gtk_box_pack_end (GTK_BOX (main_view), priv->find_bar, FALSE, FALSE, 0);
1445
g_signal_connect (priv->find_bar, "previous",
1446
G_CALLBACK (findbar_previous_cb), logview);
1447
g_signal_connect (priv->find_bar, "next",
1448
G_CALLBACK (findbar_next_cb), logview);
1449
g_signal_connect (priv->find_bar, "text_changed",
1450
G_CALLBACK (findbar_text_changed_cb), logview);
1451
g_signal_connect (priv->find_bar, "close",
1452
G_CALLBACK (findbar_close_cb), logview);
1455
* - first is used to remember/restore the window size on quit.
1457
g_signal_connect (logview, "configure_event",
1458
G_CALLBACK (window_size_changed_cb), logview);
1459
g_signal_connect (priv->prefs, "system-font-changed",
1460
G_CALLBACK (font_changed_cb), logview);
1461
g_signal_connect (priv->prefs, "have-tearoff-changed",
1462
G_CALLBACK (tearoff_changed_cb), logview);
1463
g_signal_connect (priv->manager, "active-changed",
1464
G_CALLBACK (active_log_changed_cb), logview);
1465
g_signal_connect (logview, "style-set",
1466
G_CALLBACK (style_set_cb), logview);
1467
g_signal_connect (logview, "key-press-event",
1468
G_CALLBACK (key_press_event_cb), logview);
1470
/* status area at bottom */
1471
priv->statusbar = gtk_statusbar_new ();
1472
gtk_box_pack_start (GTK_BOX (vbox), priv->statusbar, FALSE, FALSE, 0);
1473
gtk_widget_show (priv->statusbar);
1476
priv->filter_action_group = gtk_action_group_new ("ActionGroupFilter");
1477
gtk_ui_manager_insert_action_group (priv->ui_manager, priv->filter_action_group,
1479
priv->active_filters = NULL;
1480
update_filter_menu (logview);
1482
gtk_widget_show (vbox);
1483
gtk_widget_show (main_view);
1487
logview_window_class_init (LogviewWindowClass *klass)
1489
GObjectClass *object_class = (GObjectClass *) klass;
1491
object_class->finalize = logview_window_finalize;
1493
g_type_class_add_private (klass, sizeof (LogviewWindowPrivate));
1496
/* public methods */
1499
logview_window_new ()
1501
LogviewWindow *logview;
1503
logview = g_object_new (LOGVIEW_TYPE_WINDOW, NULL);
1505
if (logview->priv->ui_manager == NULL) {
1509
return GTK_WIDGET (logview);
1513
logview_window_add_error (LogviewWindow *window,
1514
const char *primary,
1515
const char *secondary)
1517
LogviewWindowPrivate *priv;
1519
g_assert (LOGVIEW_IS_WINDOW (window));
1520
priv = window->priv;
1522
message_area_set_labels (window,
1523
primary, secondary);
1525
gtk_widget_show (priv->message_area);
1527
g_signal_connect (priv->message_area, "response",
1528
G_CALLBACK (message_area_response_cb), window);
1532
logview_window_add_errors (LogviewWindow *window,
1535
char *primary, *secondary;
1540
g_assert (LOGVIEW_IS_WINDOW (window));
1541
g_assert (errors->len > 1);
1543
primary = g_strdup (_("Could not open the following files:"));
1544
str = g_string_new (NULL);
1546
for (i = 0; i < errors->len; i++) {
1547
err = (char **) g_ptr_array_index (errors, i);
1548
g_string_append (str, err[0]);
1549
g_string_append (str, ": ");
1550
g_string_append (str, err[1]);
1551
g_string_append (str, "\n");
1554
secondary = g_string_free (str, FALSE);
1556
message_area_set_labels (window, primary, secondary);
1558
gtk_widget_show (window->priv->message_area);
1560
g_signal_connect (window->priv->message_area, "response",
1561
G_CALLBACK (message_area_response_cb), window);