diff --git a/Makefile.am b/Makefile.am
index e10be9d..96749ac 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -18,25 +18,15 @@ distuninstallcheck:
distcleancheck_listfiles = find . -type f -print | grep -v 'omf\.out' | grep -v 'legal.xml'
-if BUILD_GFLOPPY
-gfloppy = gfloppy
-endif
-
always_built_SUBDIRS = \
po \
- logview \
- gsearchtool \
- gnome-dictionary \
- gnome-screenshot \
- baobab
+ logview
SUBDIRS = \
- $(always_built_SUBDIRS) \
- $(gfloppy)
+ $(always_built_SUBDIRS)
DIST_SUBDIRS = \
- $(always_built_SUBDIRS) \
- gfloppy
+ $(always_built_SUBDIRS)
EXTRA_DIST = \
gnome-utils.spec.in \
diff --git a/configure.ac b/configure.ac
index 70547af..f9bc205 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,6 +85,7 @@ GNOMEVFS_REQUIRED=2.8.4
LIBPANEL_APPLET_REQUIRED=2.13.4
LIBGTOP_REQUIRED=2.12.0
GNOMECANVAS_REQUIRED=2.10.2
+GMODULE_REQUIRED=2.10.2
dnl *****************************************
dnl libgnome, libgnomeui needed for all utils
@@ -149,29 +150,6 @@ PKG_CHECK_MODULES(SCREENSHOT, gio-2.0 >= $GLIB_REQUIRED dnl
AC_SUBST(SCREENSHOT_CFLAGS)
AC_SUBST(SCREENSHOT_LIBS)
-dnl ****************************************
-dnl HAL for floppy detection in gfloppy
-dnl ****************************************
-AC_ARG_ENABLE(hal,
- AC_HELP_STRING([--enable-hal], [use HAL if available]), [
- case "${enableval}" in
- yes) ENABLE_HAL=yes ;;
- no) ENABLE_HAL=no ;;
- *) AC_MSG_ERROR(bad value ${enableval} for --enable-hal) ;;
- esac],
- [ENABLE_HAL=yes]) dnl Default value
-
-if test "x$ENABLE_HAL" = "xyes"; then
- PKG_CHECK_MODULES(HAL, hal >= 0.5.0,
- AC_DEFINE(USE_HAL, 1, [defined if using libhal]),
- [ USE_HAL=""])
-else
- USE_HAL=""
-fi
-
-AC_SUBST(HAL_CFLAGS)
-AC_SUBST(HAL_LIBS)
-
dnl *********************************************
dnl gnome-vfs/mime-data is need for gsearchtool
dnl *********************************************
@@ -424,6 +402,9 @@ AC_SUBST(GREP_COMMAND)
dnl ********************
dnl logview checks
dnl ********************
+PKG_CHECK_MODULES(GMODULE, gmodule-2.0 >= $GMODULE_REQUIRED)
+AC_SUBST(GMODULE_CFLAGS)
+AC_SUBST(GMODULE_LIBS)
dnl This is where the binary actually resides,
dnl not the console helper link
@@ -434,7 +415,8 @@ else
fi
EXPANDED_LOGVIEWDIR=`eval echo $LOGVIEWDIR_TMP`
AC_SUBST(EXPANDED_LOGVIEWDIR)
-
+PLUGIN_LIBTOOL_FLAGS="-module -avoid-version"
+AC_SUBST(PLUGIN_LIBTOOL_FLAGS)
dnl ********************
dnl scrollkeeper checks
@@ -469,34 +451,13 @@ AC_OUTPUT([
Makefile
gnome-utils.spec
po/Makefile.in
-baobab/Makefile
-baobab/data/Makefile
-baobab/pixmaps/Makefile
-baobab/pixmaps/24x24/Makefile
-baobab/pixmaps/scalable/Makefile
-baobab/src/Makefile
-baobab/help/Makefile
logview/Makefile
logview/gnome-system-log-security
logview/help/Makefile
-gsearchtool/Makefile
-gsearchtool/data/Makefile
-gsearchtool/help/Makefile
-gnome-dictionary/Makefile
-gnome-dictionary/libgdict/Makefile
-gnome-dictionary/libgdict/gdict-version.h
-gnome-dictionary/libgdict/gdict-1.0.pc
-gnome-dictionary/data/Makefile
-gnome-dictionary/docs/Makefile
-gnome-dictionary/docs/reference/Makefile
-gnome-dictionary/docs/reference/gdict/Makefile
-gnome-dictionary/docs/reference/gdict/version.xml
-gnome-dictionary/help/Makefile
-gnome-dictionary/src/Makefile
-gfloppy/Makefile
-gfloppy/doc/Makefile
-gfloppy/src/Makefile
-gnome-screenshot/Makefile
+logview/plugins/Makefile
+logview/docs/Makefile
+logview/docs/reference/Makefile
+logview/docs/reference/logview/Makefile
])
dnl <= Configuration summary =>
diff --git a/logview/Makefile.am b/logview/Makefile.am
index d693568..e4a6706 100644
--- a/logview/Makefile.am
+++ b/logview/Makefile.am
@@ -1,6 +1,17 @@
# Process this file with automake to produce Makefile.in
-SUBDIRS = help
+SUBDIRS = . plugins help docs
+
+gnome_system_log_includedir = $(includedir)/gnome-system-log
+gnome_system_log_include_HEADERS = \
+ logview-log.h \
+ logview-plugin.h \
+ logview-iface.h \
+ logview-iface-io.h \
+ logview-iface-collector.h \
+ logview-iface-view.h \
+ logview-debug.h \
+ $(NULL)
Utilitiesdir = $(datadir)/applications
additionaldir = $(datadir)/gnome-system-log
@@ -10,7 +21,8 @@ INCLUDES = \
-DG_LOG_DOMAIN=\"gnome-system-log\" \
-DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
-DDATADIR=\""$(datadir)"\" \
- -DLOGVIEWINSTALLPREFIX=\""$(prefix)/\"" \
+ -DLOGVIEWINSTALLPREFIX=\""$(prefix)/"\" \
+ -DLOGVIEWPLUGINDIR=\""$(libdir)/gnome-system-log/plugins"\" \
$(SUN_OS) \
$(NULL)
@@ -24,12 +36,8 @@ gnome_system_log_SOURCES = \
calendar.h \
log_repaint.c \
log_repaint.h \
- logrtns.c \
- logrtns.h \
logview.c \
logview.h \
- misc.c \
- misc.h \
monitor.c \
monitor.h \
userprefs.c \
@@ -37,12 +45,44 @@ gnome_system_log_SOURCES = \
logview-findbar.c \
logview-findbar.h \
loglist.c \
- loglist.h
+ loglist.h \
+ logview-module.c \
+ logview-module.h \
+ logview-plugin-list.c \
+ logview-plugin-list.h \
+ logview-plugin.c \
+ logview-plugin.h \
+ logview-plugin-manager.c \
+ logview-plugin-manager.h \
+ $(NULL)
gnome_system_log_LDADD = \
- $(GNOME_UTILS_LIBS)
+ $(GNOME_UTILS_LIBS) \
+ $(GMODULE_LIBS) \
+ libgnome-system-log.la
-man_MANS = gnome-system-log.1
+noinst_LTLIBRARIES = libgnome-system-log.la
+libgnome_system_log_la_SOURCES = \
+ logrtns.c \
+ logrtns.h \
+ misc.c \
+ misc.h \
+ logview-iface.c \
+ logview-iface.h \
+ logview-iface-io.c \
+ logview-iface-io.h \
+ logview-iface-collector.c \
+ logview-iface-collector.h \
+ logview-iface-view.c \
+ logview-iface-view.h \
+ logview-debug.c \
+ logview-debug.h \
+ logview-log.h \
+ $(NULL)
+
+libgnome_system_log_la_LIBADD = \
+ $(GNOME_UTILS_LIBS) \
+ $(GMODULE_LIBS)
Utilities_in_files = gnome-system-log.desktop.in
Utilities_DATA = $(Utilities_in_files:.desktop.in=.desktop)
@@ -98,3 +138,4 @@ CLEANFILES = \
dist-hook:
cd $(distdir) ; rm -f $(CLEANFILES)
+
diff --git a/logview/calendar.c b/logview/calendar.c
index b6ad451..b20cd5c 100644
--- a/logview/calendar.c
+++ b/logview/calendar.c
@@ -64,7 +64,7 @@ calendar_init_data (Calendar *calendar, LogviewWindow *logview)
g_return_if_fail (IS_CALENDAR (calendar));
g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
- g_object_get (G_OBJECT (logview), "days", &(calendar->priv->days), NULL);
+ g_object_get (G_OBJECT (logview->curlog), "days", &(calendar->priv->days), NULL);
calendar->priv->first_pass = TRUE;
calendar_mark_dates (calendar);
@@ -77,23 +77,6 @@ calendar_month_changed (GtkWidget *widget, gpointer data)
calendar_mark_dates (CALENDAR (widget));
}
-static Day *
-log_find_day (Log *log, int d, int m, int y)
-{
- GDate *date;
- GSList *days;
- Day *day, *found_day = NULL;
-
- date = g_date_new_dmy (d, m+1, y);
- for (days = log->days; days!=NULL; days=g_slist_next(days)) {
- day = days->data;
- if (g_date_compare (day->date, date) == 0) {
- found_day = day;
- }
- }
- return found_day;
-}
-
static void
calendar_day_selected (GtkWidget *widget, LogviewWindow *logview)
{
@@ -101,6 +84,9 @@ calendar_day_selected (GtkWidget *widget, LogviewWindow *logview)
guint day, month, year;
Day *found_day;
GtkTreePath *path;
+ GList *selected_paths;
+ GtkTreePath *select_first;
+ GDate *date;
calendar = CALENDAR (widget);
@@ -113,11 +99,20 @@ calendar_day_selected (GtkWidget *widget, LogviewWindow *logview)
}
gtk_calendar_get_date (GTK_CALENDAR (calendar), &year, &month, &day);
- found_day = log_find_day (logview->curlog, day, month, year);
+
+ date = g_date_new_dmy (day, month+1, year);
+ found_day = log_find_day (logview->curlog, date);
+ g_date_free (date);
+
+ g_object_get (G_OBJECT (logview->curlog),
+ "selected-paths", &selected_paths,
+ NULL);
+ g_assert (selected_paths);
+ select_first = g_list_first (selected_paths)->data;
if (found_day != NULL) {
path = found_day->path;
- if ((gtk_tree_path_compare (path, logview->curlog->selected_range.first) != 0) &&
- (!gtk_tree_path_is_descendant (logview->curlog->selected_range.first, path)))
+ if ((gtk_tree_path_compare (path, select_first) != 0) &&
+ (!gtk_tree_path_is_descendant (select_first, path)))
gtk_tree_view_set_cursor (GTK_TREE_VIEW(logview->view), path, NULL, FALSE);
}
}
diff --git a/logview/docs/Makefile.am b/logview/docs/Makefile.am
new file mode 100644
index 0000000..86bb4ad
--- /dev/null
+++ b/logview/docs/Makefile.am
@@ -0,0 +1,3 @@
+# Process this file with automake to produce Makefile.in
+
+SUBDIRS = reference
diff --git a/logview/docs/reference/Makefile.am b/logview/docs/reference/Makefile.am
new file mode 100644
index 0000000..048bd8f
--- /dev/null
+++ b/logview/docs/reference/Makefile.am
@@ -0,0 +1,3 @@
+# Process this file with automake to produce Makefile.in
+
+SUBDIRS = logview
diff --git a/logview/docs/reference/logview/Makefile.am b/logview/docs/reference/logview/Makefile.am
new file mode 100644
index 0000000..ee2c82a
--- /dev/null
+++ b/logview/docs/reference/logview/Makefile.am
@@ -0,0 +1,84 @@
+## Process this file with automake to produce Makefile.in
+
+AUTOMAKE_OPTIONS = 1.6
+
+# The name of the module, e.g. 'glib'.
+DOC_MODULE=logview
+
+# The top-level SGML file. Change it if you want.
+DOC_MAIN_SGML_FILE=$(DOC_MODULE)-docs.sgml
+
+# The directory containing the source code. Relative to $(srcdir).
+# gtk-doc will search all .c & .h files beneath here for inline comments
+# documenting functions and macros.
+DOC_SOURCE_DIR=$(top_srcdir)/logview
+
+# Extra options to supply to gtkdoc-scan.
+SCAN_OPTIONS=
+
+# Extra options to pass to gtkdoc-scangobj
+SCANGOBJ_OPTIONS=
+
+# Extra options to supply to gtkdoc-mkdb.
+MKDB_OPTIONS=--sgml-mode --output-format=xml
+
+# Extra options to supply to gtkdoc-mktmpl
+# e.g. MKTMPL_OPTIONS=--only-section-tmpl
+MKTMPL_OPTIONS=
+
+# Extra options to supply to gtkdoc-fixref.
+FIXXREF_OPTIONS=
+
+# Used for dependencies.
+HFILE_GLOB=$(top_srcdir)/logview/*.h
+CFILE_GLOB=$(top_srcdir)/logview/*.c
+
+# Header files to ignore when scanning.
+IGNORE_HFILES = \
+ about.h \
+ calendar.h \
+ log_repaint.h \
+ logview.h \
+ monitor.h \
+ userprefs.h \
+ logview-findbar.h \
+ loglist.h \
+ logview-module.h \
+ logview-plugin.h \
+ logview-plugin-manager.h \
+ logview-plugin-list.h
+
+# Images to copy into HTML directory.
+HTML_IMAGES =
+
+# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
+content_files =
+
+# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
+# These files must be listed here *and* in content_files
+# e.g. expand_content_files=running.sgml
+expand_content_files=
+
+# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
+# Only needed if you are using gtkdoc-scangobj to dynamically query widget
+# signals and properties.
+# e.g. INCLUDES=-I$(top_srcdir) -I$(top_builddir) $(GTK_DEBUG_FLAGS)
+# e.g. GTKDOC_LIBS=$(top_builddir)/gtk/$(gtktargetlib)
+INCLUDES= \
+ $(CFLAGS) \
+ $(CPPFLAGS) \
+ $(GNOME_UTILS_CFLAGS) \
+ -I$(top_srcdir)/logview \
+ -I$(top_builddir)/logview
+
+GTKDOC_LIBS= \
+ $(LDFLAGS) \
+ $(GNOME_UTILS_LIBS) \
+ $(top_builddir)/logview/libgnome-system-log.la
+
+# This includes the standard gtk-doc make rules, copied by gtkdocize.
+include $(top_srcdir)/gtk-doc.make
+
+# Other files to distribute
+# e.g. EXTRA_DIST += version.xml.in
+EXTRA_DIST +=
diff --git a/logview/docs/reference/logview/logview-docs.sgml b/logview/docs/reference/logview/logview-docs.sgml
new file mode 100644
index 0000000..e6dc9be
--- /dev/null
+++ b/logview/docs/reference/logview/logview-docs.sgml
@@ -0,0 +1,44 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY index-Object-Tree SYSTEM "xml/tree_index.sgml">
+<!ENTITY LogviewLog SYSTEM "xml/logview-log.xml">
+<!ENTITY LogviewPlugin SYSTEM "xml/logview-plugin.xml">
+<!ENTITY LogviewIface SYSTEM "xml/logview-iface.xml">
+<!ENTITY LogviewIfaceIO SYSTEM "xml/logview-iface-io.xml">
+<!ENTITY LogviewIfaceView SYSTEM "xml/logview-iface-view.xml">
+<!ENTITY LogviewIfaceCollector SYSTEM "xml/logview-iface-collector.xml">
+<!ENTITY LogviewMisc SYSTEM "xml/misc.xml">
+]>
+
+<book id="logview">
+ <bookinfo>
+ <title>GNOME System Log Plugin Interfaces Reference Manual</title>
+ <abstract>
+ <para>This manual documents the Gnome System Log Plugin Interfaces.</para>
+ </abstract>
+ </bookinfo>
+
+ <preface>
+ <title>Introduction</title>
+ <para>The Gnome System Log Plugin Interfaces enable endusers to implement
+ plugins to display non-ASCII formatted log files.</para>
+ <para>It was created for the GNOME System Log application, but it has been
+ made available for each developer whom wishes to implement plugins for
+ fun.</para>
+ </preface>
+
+ <reference label="I">
+ <title>API reference</title>
+ &LogviewLog;
+ &LogviewIface;
+ &LogviewIfaceIO;
+ &LogviewIfaceView;
+ &LogviewIfaceCollector;
+ </reference>
+
+ <reference label="II">
+ <title>Miscellaneous Utility Functions</title>
+ &LogviewMisc;
+ </reference>
+</book>
diff --git a/logview/docs/reference/logview/logview.types b/logview/docs/reference/logview/logview.types
new file mode 100644
index 0000000..a303ce1
--- /dev/null
+++ b/logview/docs/reference/logview/logview.types
@@ -0,0 +1,5 @@
+logview_iface_collector_get_type
+logview_iface_view_get_type
+logview_iface_io_get_type
+logview_iface_get_type
+log_get_type
diff --git a/logview/gnome-system-log.desktop.in.in b/logview/gnome-system-log.desktop.in.in
index a06ba81..5a2be33 100644
--- a/logview/gnome-system-log.desktop.in.in
+++ b/logview/gnome-system-log.desktop.in.in
@@ -7,6 +7,7 @@ Terminal=false
Type=Application
StartupNotify=true
Categories=GTK;GNOME;System;Monitor;
+OnlyShowIn=GNOME;
NotShowIn=KDE;
X-GNOME-DocPath=gnome-system-log/gnome-system-log.xml
X-GNOME-Bugzilla-Bugzilla=GNOME
diff --git a/logview/log_repaint.c b/logview/log_repaint.c
index 24ceab0..2c777c2 100644
--- a/logview/log_repaint.c
+++ b/logview/log_repaint.c
@@ -31,38 +31,35 @@
#include "log_repaint.h"
#include "misc.h"
#include "calendar.h"
-
-enum {
- MESSAGE = 0,
- DAY_POINTER,
- LOG_LINE_WEIGHT,
- LOG_LINE_WEIGHT_SET
-};
+#include "logview-debug.h"
static gboolean busy_cursor = FALSE;
static gboolean
logview_show_busy_cursor (LogviewWindow *logview)
{
- GdkCursor *cursor;
- if (GTK_WIDGET_VISIBLE (logview->view) && logview->curlog->model == NULL) {
- cursor = gdk_cursor_new (GDK_WATCH);
- gdk_window_set_cursor (GTK_WIDGET (logview)->window, cursor);
- gdk_cursor_unref (cursor);
- gdk_display_flush (gtk_widget_get_display (GTK_WIDGET (logview)));
- busy_cursor = TRUE;
- }
- return (FALSE);
+ GdkCursor *cursor;
+ GObject *model;
+ g_assert (logview->curlog);
+ g_object_get (G_OBJECT (logview->curlog), "model", &model, NULL);
+ if (GTK_WIDGET_VISIBLE (logview->view) && model == NULL) {
+ cursor = gdk_cursor_new (GDK_WATCH);
+ gdk_window_set_cursor (GTK_WIDGET (logview)->window, cursor);
+ gdk_cursor_unref (cursor);
+ gdk_display_flush (gtk_widget_get_display (GTK_WIDGET (logview)));
+ busy_cursor = TRUE;
+ }
+ return (FALSE);
}
-static gboolean
+static void
logview_show_normal_cursor (LogviewWindow *logview)
{
- if (busy_cursor) {
- gdk_window_set_cursor (GTK_WIDGET (logview)->window, NULL);
- gdk_display_flush (gtk_widget_get_display (GTK_WIDGET (logview)));
- busy_cursor = FALSE;
- }
+ if (busy_cursor) {
+ gdk_window_set_cursor (GTK_WIDGET (logview)->window, NULL);
+ gdk_display_flush (gtk_widget_get_display (GTK_WIDGET (logview)));
+ busy_cursor = FALSE;
+ }
}
void
@@ -80,443 +77,296 @@ row_toggled_cb (GtkTreeView *treeview, GtkTreeIter *iter,
static int
tree_path_find_row (GtkTreeModel *model, GtkTreePath *path, gboolean has_date)
{
- int row = 0;
- int j;
- int *indices;
- GtkTreeIter iter;
- GtkTreePath *date_path;
-
- g_assert (GTK_IS_TREE_MODEL (model));
- g_assert (path);
+ int row = 0;
+ int j;
+ int *indices;
+ GtkTreeIter iter;
+
+ g_assert (GTK_IS_TREE_MODEL (model));
+ g_assert (path);
- indices = gtk_tree_path_get_indices (path);
+ indices = gtk_tree_path_get_indices (path);
- if (has_date) {
- for (j = 0; j < indices[0]; j++) {
- date_path = gtk_tree_path_new_from_indices (j, -1);
- gtk_tree_model_get_iter (model, &iter, date_path);
- row += gtk_tree_model_iter_n_children (model, &iter);
- }
- if (gtk_tree_path_get_depth (path) > 1)
- row += indices[1];
+ if (has_date) {
+ for (j = 0; j < indices[0]; j++) {
+ GtkTreePath *date_path;
+ date_path = gtk_tree_path_new_from_indices (j, -1);
+ gtk_tree_model_get_iter (model, &iter, date_path);
+ gtk_tree_path_free (date_path);
+ row += gtk_tree_model_iter_n_children (model, &iter);
+ }
+ if (gtk_tree_path_get_depth (path) > 1)
+ row += indices[1];
- } else
- row = indices[0];
+ } else
+ row = indices[0];
- return (row);
+ return (row);
}
void
selection_changed_cb (GtkTreeSelection *selection, gpointer data)
{
- int selected_first = -1, selected_last = -1;
- LogviewWindow *logview = data;
- GtkTreePath *selected_path;
- GList *selected_paths, *path;
- GtkTreeModel *model;
- gint row;
- Log *log;
+ LogviewWindow *logview = data;
+ GtkTreePath *selected_path;
+ GList *selected_paths;
+ GtkTreeModel *model;
+ gboolean groupable;
+ Log *log;
- g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
- g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
-
- log = logview->curlog;
- if (log == NULL)
- return;
-
- selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
+ g_return_if_fail (GTK_IS_TREE_SELECTION (selection));
+ g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
- if (selected_paths == NULL)
- return;
-
- for (path = selected_paths; path != NULL; path = g_list_next (path)) {
-
- selected_path = path->data;
-
- row = tree_path_find_row (model, selected_path, (log->days != NULL));
-
- if (selected_last == -1 || row > selected_last) {
- selected_last = row;
- }
- if (selected_first == -1 || row < selected_first) {
- selected_first = row;
- }
- }
-
- log->selected_range.first = gtk_tree_path_copy (g_list_first (selected_paths)->data);
- log->selected_range.last = gtk_tree_path_copy (g_list_last (selected_paths)->data);
- log->selected_line_first = selected_first;
- log->selected_line_last = selected_last;
-
- g_list_foreach (selected_paths, (GFunc) gtk_tree_path_free, NULL);
- g_list_free (selected_paths);
-
- if (log->days) {
- GtkTreeIter iter;
- Day *day;
+ log = logview->curlog;
+ if (log == NULL)
+ return;
+ g_object_get (G_OBJECT (log),
+ "groupable", &groupable,
+ NULL);
+ selected_paths = gtk_tree_selection_get_selected_rows (selection, &model);
+
+ if (selected_paths == NULL)
+ return;
+ g_object_set (G_OBJECT (log), "selected-paths", selected_paths, NULL);
+ selected_path = gtk_tree_path_copy (g_list_first (selected_paths)->data);
+
+ if (groupable) {
+ GtkTreeIter iter;
+ Day *day;
- selected_path = gtk_tree_path_copy (log->selected_range.first);
- if (gtk_tree_path_get_depth (selected_path) > 1)
- gtk_tree_path_up (selected_path);
- gtk_tree_model_get_iter (model, &iter, selected_path);
- gtk_tree_model_get (model, &iter, DAY_POINTER, &day, -1);
- calendar_select_date (CALENDAR (logview->calendar), day->date);
- gtk_tree_path_free (selected_path);
- }
+ if (gtk_tree_path_get_depth (selected_path) > 1)
+ gtk_tree_path_up (selected_path);
+ gtk_tree_model_get_iter (model, &iter, selected_path);
+ gtk_tree_model_get (model, &iter, DAY_POINTER, &day, -1);
+ calendar_select_date (CALENDAR (logview->calendar), day->date);
+ }
+ gtk_tree_path_free (selected_path);
}
static void
logview_update_statusbar (LogviewWindow *logview)
{
- char *statusbar_text;
- char *size, *modified, *index;
- Log *log;
+ char *statusbar_text;
+ char *size, *modified, *index;
+ time_t time;
+ guint64 log_size;
+ guint total_lines;
+ Log *log;
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
- log = logview->curlog;
+ log = logview->curlog;
- if (log == NULL) {
- gtk_statusbar_pop (GTK_STATUSBAR (logview->statusbar), 0);
- return;
- }
+ if (log == NULL) {
+ gtk_statusbar_pop (GTK_STATUSBAR (logview->statusbar), 0);
+ return;
+ }
- /* ctime returned string has "\n\0" causes statusbar display a invalid char */
- modified = ctime (&(log->stats->file_time));
- index = strrchr (modified, '\n');
- if (index && *index != '\0')
- *index = '\0';
-
- modified = g_strdup_printf (_("last update: %s"), modified);
- size = gnome_vfs_format_file_size_for_display (log->stats->file_size);
- statusbar_text = g_strdup_printf (_("%d lines (%s) - %s"),
- log->total_lines, size, modified);
-
- if (statusbar_text) {
- gtk_statusbar_pop (GTK_STATUSBAR(logview->statusbar), 0);
- gtk_statusbar_push (GTK_STATUSBAR(logview->statusbar), 0, statusbar_text);
- g_free (size);
- g_free (modified);
- g_free (statusbar_text);
- }
+ /* ctime returned string has "\n\0" causes statusbar display a invalid char */
+ g_object_get (G_OBJECT (log),
+ "size", &log_size,
+ "mtime", (glong *)&time,
+ "total-lines", &total_lines,
+ NULL);
+ modified = ctime (&time);
+ index = strrchr (modified, '\n');
+ if (index && *index != '\0')
+ *index = '\0';
+
+ modified = g_strdup_printf (_("last update: %s"), modified);
+ size = gnome_vfs_format_file_size_for_display (log_size);
+ statusbar_text = g_strdup_printf (_("%d lines (%s) - %s"),
+ total_lines, size, modified);
+ if (statusbar_text) {
+ gtk_statusbar_pop (GTK_STATUSBAR(logview->statusbar), 0);
+ gtk_statusbar_push (GTK_STATUSBAR(logview->statusbar), 0, statusbar_text);
+ g_free (size);
+ g_free (modified);
+ g_free (statusbar_text);
+ }
}
void
logview_update_version_bar (LogviewWindow *logview)
{
- Log *log;
- int i;
+ gint i, selected;
gchar *label;
-
- log = logview->curlog;
- if (log == NULL) {
- gtk_widget_hide (logview->version_bar);
- return;
- }
-
- if (log->versions > 0 || log->parent_log != NULL) {
- Log *recent;
-
- gtk_widget_show_all (logview->version_bar);
-
- if (log->current_version > 0)
- recent = log->parent_log;
- else
- recent = log;
-
- for (i=5; i>-1; i--)
- gtk_combo_box_remove_text (GTK_COMBO_BOX (logview->version_selector), i);
-
- gtk_combo_box_append_text (GTK_COMBO_BOX (logview->version_selector), _("Current"));
-
- for (i=0; i<(recent->versions); i++) {
- label = g_strdup_printf ("Archive %d", i+1);
- gtk_combo_box_append_text (GTK_COMBO_BOX (logview->version_selector),
- label);
- g_free (label);
+ Log *log;
+ Log **older_logs;
+ gint current_version;
+ gint versions;
+
+ /* recreate the list, and emit the set active item signal */
+ if (logview->curlog == NULL) {
+ gtk_widget_hide_all (logview->version_bar);
+ return;
+ }
+ g_assert (LOGVIEW_IS_LOG (logview->curlog));
+ /* get parent log. if only it hasn't parent log, update achive list. */
+ g_object_get (G_OBJECT (logview->curlog),
+ "parent", &log,
+ NULL);
+ /* log is always the parent */
+ if (log == NULL) {
+ log = logview->curlog;
+ /* retrieve children list */
+ g_object_get (G_OBJECT (log),
+ "archives", &older_logs,
+ "versions", &versions,
+ NULL);
+ gtk_widget_hide_all (logview->version_bar);
+
+ /* the maximum text items of the combo box togather with "Current"
+ is OLD_LOG_NUM */
+ for (i = OLD_LOG_NUM; i >= 0; i--)
+ gtk_combo_box_remove_text (
+ GTK_COMBO_BOX (logview->version_selector),
+ i);
+
+ gtk_combo_box_append_text (
+ GTK_COMBO_BOX (logview->version_selector),
+ _("Current"));
+
+ if (versions > 0) {
+ for (i=0; i<OLD_LOG_NUM; i++) {
+ gchar *n;
+ if (older_logs[i] == NULL)
+ continue;
+ g_object_get (G_OBJECT (older_logs[i]),
+ "path", &n,
+ NULL);
+ g_assert (n);
+ g_free (n);
+ label = g_strdup_printf ("Archive %d", i);
+ gtk_combo_box_append_text (
+ GTK_COMBO_BOX (logview->version_selector),
+ label);
+ g_free (label);
+ }
+ gtk_widget_show_all (logview->version_bar);
}
-
- gtk_combo_box_set_active (GTK_COMBO_BOX (logview->version_selector),
- log->current_version);
-
- } else {
- gtk_widget_hide (logview->version_bar);
}
+ g_object_get (G_OBJECT (log),
+ "current-version", &current_version, NULL);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (logview->version_selector),
+ current_version);
}
static void
-model_fill_date_iter (GtkTreeStore *model, GtkTreeIter *iter, Day *day)
-{
- gchar *utf8;
-
- g_assert (GTK_IS_TREE_STORE (model));
-
- utf8 = date_get_string (day->date);
- gtk_tree_store_set (model, iter, MESSAGE, utf8, DAY_POINTER, day, -1);
- g_free (utf8);
-}
-
-static gboolean
-logview_unbold_rows (Log *log)
-{
- LogviewWindow *logview;
- TreePathRange *bold_rows;
- GtkTreeIter iter;
- GtkTreePath *path;
-
- g_assert (log);
- logview = log->window;
-
- if (log->bold_rows_list == NULL)
- return FALSE;
-
- if (logview->curlog != log)
- return TRUE;
-
- bold_rows = g_list_first (log->bold_rows_list)->data;
- g_assert (bold_rows != NULL);
-
- for (path = bold_rows->first;
- gtk_tree_path_compare (path, bold_rows->last)<=0;
- gtk_tree_path_next (path)) {
- gtk_tree_model_get_iter (log->model, &iter, path);
- gtk_tree_store_set (GTK_TREE_STORE (log->model), &iter,
- LOG_LINE_WEIGHT, PANGO_WEIGHT_NORMAL,
- LOG_LINE_WEIGHT_SET, TRUE, -1);
- }
-
- gtk_tree_path_free (bold_rows->first);
- gtk_tree_path_free (bold_rows->last);
- log->bold_rows_list = g_list_remove (log->bold_rows_list, bold_rows);
- g_free (bold_rows);
-
- return FALSE;
-}
-
-static void
-log_add_new_log_lines (Log *log)
-{
- GtkTreeIter iter, child_iter, *iter_ptr;
- GtkTreePath *path;
- TreePathRange *bold_rows;
- Day *day;
- int i;
- gchar *line;
-
- g_assert (log);
-
- if (log_read_new_lines (log) == FALSE)
- return;
-
- /* Find the last expandable row */
- if (log->days) {
- day = g_slist_last (log->days)->data;
- gtk_tree_model_get_iter (log->model, &iter, day->path);
- iter_ptr = &iter;
- } else {
- iter_ptr = NULL;
- }
-
- for (i=log->displayed_lines; i<log->total_lines; i++) {
-
- line = log->lines[i];
-
- if (line != NULL) {
- gtk_tree_store_append (GTK_TREE_STORE (log->model), &child_iter, iter_ptr);
- gtk_tree_store_set (GTK_TREE_STORE (log->model), &child_iter,
- MESSAGE, line,
- DAY_POINTER, NULL,
- LOG_LINE_WEIGHT, PANGO_WEIGHT_BOLD,
- LOG_LINE_WEIGHT_SET, TRUE, -1);
- /* Remember the first and last bold lines in the model to
- unset them later */
- if (i==log->displayed_lines) {
- bold_rows = g_new0 (TreePathRange, 1);
- bold_rows->first = gtk_tree_model_get_path (log->model, &child_iter);
- }
- if (i == log->total_lines-1) {
- bold_rows->last = gtk_tree_model_get_path (log->model, &child_iter);
- }
- }
- }
- log->displayed_lines = log->total_lines;
- log->bold_rows_list = g_list_append (log->bold_rows_list, bold_rows);
-
- g_timeout_add (5000, (GSourceFunc) logview_unbold_rows, log);
-}
-
-static void
logview_scroll_and_focus_path (LogviewWindow *logview, Log *log)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
-
- if (log == NULL)
- return;
-
- if (log->selected_range.first != NULL) {
- GtkTreeSelection *selection;
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (logview->view));
- gtk_tree_selection_select_range (selection, log->selected_range.first,
- log->selected_range.last);
- }
-
- if (log->bold_rows_list != NULL) {
- TreePathRange *bold_rows;
- bold_rows = g_list_last (log->bold_rows_list)->data;
- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (logview->view),
- bold_rows->last,
- NULL, TRUE, 1.0, 1);
- } else {
- if (log->visible_first != NULL) {
- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (logview->view),
- log->visible_first,
- NULL, TRUE, 0.0, 1);
- }
- }
-}
+ LV_MARK;
+ GtkTreePath *last_bold_row;
+ GtkTreePath *visible_first;
+ GList *selected_paths, *idx;
+ GtkTreePath *selected_path;
-static void
-log_fill_model_no_date (Log *log, GtkTreeModel *model)
-{
- int i;
- gchar *line;
- GtkTreeIter iter;
+ g_assert (LOGVIEW_IS_WINDOW (logview));
- g_assert (log);
-
- for (i=log->total_lines-1; i>=0; i--) {
- line = log->lines[i];
- gtk_tree_store_prepend (GTK_TREE_STORE (model), &iter, NULL);
- gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
- MESSAGE, line, DAY_POINTER, NULL, -1);
- if (i == (log->total_lines-1)) {
- GtkTreePath *path;
- path = gtk_tree_model_get_path (model, &iter);
- log->selected_range.first = gtk_tree_path_copy (path);
- log->selected_range.last = gtk_tree_path_copy (path);
- log->visible_first = gtk_tree_path_copy (path);
- gtk_tree_path_free (path);
- }
- }
-}
-
-static void
-log_fill_day_iter (Log *log, GtkTreeModel *model, Day *day, GtkTreeIter *iter)
-{
- GtkTreeIter child_iter;
- int i;
-
- for (i = day->last_line; i >= day->first_line; i--) {
- gtk_tree_store_prepend (GTK_TREE_STORE (model), &child_iter, iter);
- gtk_tree_store_set (GTK_TREE_STORE (model), &child_iter,
- MESSAGE, log->lines[i], DAY_POINTER, NULL, -1);
- }
-}
-
-static void
-log_fill_model_with_date (Log *log, GtkTreeModel *model)
-{
- GtkTreeIter iter;
- GSList *days;
- Day *day;
- int i;
-
- g_assert (log->total_lines > 0);
-
- /* Cycle on the days in the log */
- /* It's not worth it to prepend instead of append */
-
- for (days = log->days; days != NULL; days = g_slist_next (days)) {
- day = days->data;
-
- gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL);
- model_fill_date_iter (GTK_TREE_STORE (model), &iter, day);
- day->path = gtk_tree_model_get_path (model, &iter);
-
- log_fill_day_iter (log, model, day, &iter);
- day->expand = FALSE;
-
- while (gtk_events_pending ())
- gtk_main_iteration ();
- }
-
- day->expand = TRUE;
- log->selected_range.first = gtk_tree_path_copy (day->path);
- log->selected_range.last = gtk_tree_path_copy (day->path);
- log->visible_first = gtk_tree_path_copy (day->path);
+ if (log == NULL)
+ return;
+
+ g_object_get (G_OBJECT (log),
+ "last-bold-row", &last_bold_row,
+ "visible-first", &visible_first,
+ "selected-paths", &selected_paths,
+ NULL);
+
+ if (selected_paths) {
+ GtkTreeSelection *selection;
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (logview->view));
+ for (idx = selected_paths; idx; idx = g_list_next (idx)) {
+ GtkTreePath *selected_path = idx->data;
+ gtk_tree_selection_select_path (selection, selected_path);
+ }
+ }
- log->displayed_lines = log->total_lines;
+ if (last_bold_row != NULL) {
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (logview->view),
+ last_bold_row,
+ NULL, TRUE, 1.0, 1);
+ } else {
+ if (visible_first != NULL) {
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (logview->view),
+ visible_first,
+ NULL, TRUE, 0.0, 1);
+ }
+ }
}
static void
-log_create_model (Log *log)
-{
- GtkTreeModel *model;
-
- g_assert (log != NULL);
- model = GTK_TREE_MODEL(gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER,
- G_TYPE_INT, G_TYPE_BOOLEAN));
- if (log->days != NULL)
- log_fill_model_with_date (log, model);
- else
- log_fill_model_no_date (log, model);
- log->model = model;
-}
-
-static void
logview_set_log_model (LogviewWindow *window, Log *log)
{
- GSList *days;
- Day *day;
-
- g_assert (LOGVIEW_IS_WINDOW (window));
- g_assert (log);
- g_assert (GTK_IS_TREE_MODEL (log->model));
-
- if (log->filter != NULL)
- gtk_tree_view_set_model (GTK_TREE_VIEW (window->view), GTK_TREE_MODEL (log->filter));
- else
- gtk_tree_view_set_model (GTK_TREE_VIEW (window->view), log->model);
-
- if (log->days != NULL) {
- for (days=log->days; days != NULL; days = g_slist_next(days)) {
- day = days->data;
- if (day->expand)
- gtk_tree_view_expand_row (GTK_TREE_VIEW (window->view),
- day->path, FALSE);
- }
- }
+ GSList *days, *idx;
+ Day *day;
+ GtkTreeModel *model;
+ GtkTreeModelFilter *filter;
+ gboolean groupable;
+
+ g_assert (LOGVIEW_IS_WINDOW (window));
+ g_assert (log);
+
+ logview_show_busy_cursor (window);
+ g_object_get (G_OBJECT (log),
+ "filter", &filter,
+ "model", &model,
+ "groupable", &groupable,
+ "days", &days,
+ NULL);
+
+ g_assert (GTK_IS_TREE_MODEL (model));
+
+ if (filter != NULL)
+ gtk_tree_view_set_model (GTK_TREE_VIEW (window->view),
+ GTK_TREE_MODEL (filter));
+ else
+ gtk_tree_view_set_model (GTK_TREE_VIEW (window->view),
+ model);
+
+ if (groupable) {
+ for (idx = days; idx != NULL; idx = g_slist_next(idx)) {
+ day = idx->data;
+ if (day->expand)
+ gtk_tree_view_expand_row (GTK_TREE_VIEW (window->view),
+ day->path, FALSE);
+ }
+ }
+ logview_show_normal_cursor (window);
}
void
logview_repaint (LogviewWindow *logview)
{
- Log *log;
- g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
+ /* if log has updated, get new lines and repaint the view */
+ Log *log;
+ GtkTreeModel *model;
+ gboolean monitoring;
+
+ g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
- log = logview->curlog;
+ log = logview->curlog;
+ if (log == NULL) {
+ gtk_tree_view_set_model (GTK_TREE_VIEW (logview->view), NULL);
+ return;
+ }
- logview_update_statusbar (logview);
- logview_set_window_title (logview);
-
- if (log == NULL) {
- gtk_tree_view_set_model (GTK_TREE_VIEW (logview->view), NULL);
- return;
- }
-
- if (log->model == NULL) {
- g_timeout_add (200, (GSourceFunc) logview_show_busy_cursor, logview);
- log_create_model (log);
- logview_show_normal_cursor (logview);
- }
-
- if (log->needs_refresh) {
- log_add_new_log_lines (log);
- log->needs_refresh = FALSE;
- }
-
- if (gtk_tree_view_get_model (GTK_TREE_VIEW (logview->view)) != log->model)
- logview_set_log_model (logview, log);
-
- logview_scroll_and_focus_path (logview, log);
+ g_assert (LOGVIEW_IS_LOG (log));
+ g_object_get (G_OBJECT (log),
+ "model", &model,
+ "monitoring", &monitoring,
+ NULL);
+ g_assert (model);
+
+ logview_set_window_title (logview);
+
+ if (monitoring && log_has_been_modified (log)) {
+ log_notify (log, TH_EVENT_UPDATE);
+ }
+
+ logview_update_statusbar (logview);
+
+ if (gtk_tree_view_get_model (GTK_TREE_VIEW (logview->view)) != model)
+ logview_set_log_model (logview, log);
+
+ logview_scroll_and_focus_path (logview, log);
}
diff --git a/logview/log_repaint.h b/logview/log_repaint.h
index 99e3d40..0136bfa 100644
--- a/logview/log_repaint.h
+++ b/logview/log_repaint.h
@@ -20,6 +20,15 @@
#ifndef __LOG_REPAINT_H__
#define __LOG_REPAINT_H__
+#include "logview.h"
+
+enum {
+ MESSAGE = 0,
+ DAY_POINTER,
+ LOG_LINE_WEIGHT,
+ LOG_LINE_WEIGHT_SET
+};
+
void logview_repaint (LogviewWindow *window);
void selection_changed_cb (GtkTreeSelection *selection, gpointer data);
void row_toggled_cb (GtkTreeView *treeview, GtkTreeIter *iter,
diff --git a/logview/loglist.c b/logview/loglist.c
index 572df35..6e8049f 100644
--- a/logview/loglist.c
+++ b/logview/loglist.c
@@ -23,14 +23,16 @@
#include "loglist.h"
#include "logrtns.h"
#include <libgnomevfs/gnome-vfs.h>
+#include <logview-debug.h>
-struct LogListPriv {
+#define BOLD_LOG_TIME 5000
+
+struct LogListPrv {
GtkTreeStore *model;
+ gpointer window;
+ guint unbold_event;
};
-static GObjectClass *parent_class;
-GType loglist_get_type (void);
-
enum {
LOG_NAME = 0,
LOG_POINTER,
@@ -38,6 +40,18 @@ enum {
LOG_WEIGHT_SET
};
+enum {
+ PROP_0 = 0,
+ PROP_WINDOW
+};
+
+static void loglist_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec);
+
+G_DEFINE_TYPE (LogList, loglist, GTK_TYPE_TREE_VIEW)
+
static GtkTreePath *
loglist_find_directory (LogList *list, gchar *dir)
{
@@ -48,14 +62,17 @@ loglist_find_directory (LogList *list, gchar *dir)
g_assert (LOG_IS_LIST (list));
- model = GTK_TREE_MODEL (list->priv->model);
+ model = GTK_TREE_MODEL (list->prv->model);
if (!gtk_tree_model_get_iter_first (model, &iter))
return NULL;
do {
gtk_tree_model_get (model, &iter, LOG_NAME, &iterdir, -1);
if (iterdir) {
- if (g_ascii_strncasecmp (iterdir, dir, -1) == 0) {
+ gint val;
+ val = g_ascii_strncasecmp (iterdir, dir, -1);
+ g_free (iterdir);
+ if (val == 0) {
path = gtk_tree_model_get_path (model, &iter);
break;
}
@@ -76,9 +93,10 @@ loglist_find_log (LogList *list, Log *log)
Log *iterlog;
g_assert (LOG_IS_LIST (list));
- g_assert (log != NULL);
+ g_assert (log != NULL);
+ LV_MARK;
- model = GTK_TREE_MODEL (list->priv->model);
+ model = GTK_TREE_MODEL (list->prv->model);
if (!gtk_tree_model_get_iter_first (model, &iter))
return NULL;
@@ -101,29 +119,34 @@ loglist_get_log_iter (LogList *list, Log *log, GtkTreeIter *logiter)
{
GtkTreeModel *model;
GtkTreePath *path = NULL;
+ LV_MARK;
path = loglist_find_log (list, log);
if (path) {
- model = GTK_TREE_MODEL (list->priv->model);
+ model = GTK_TREE_MODEL (list->prv->model);
gtk_tree_model_get_iter (model, logiter, path);
gtk_tree_path_free (path);
}
}
-void
-loglist_unbold_log (LogList *list, Log *log)
+static gboolean
+loglist_unbold (LogList *self)
{
- GtkTreeModel *model;
- GtkTreeIter iter;
+ LogviewWindow *logview = LOGVIEW_WINDOW(self->prv->window);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ LV_MARK;
- g_return_if_fail (LOG_IS_LIST (list));
- g_return_if_fail (log != NULL);
+ model = GTK_TREE_MODEL (self->prv->model);
- model = GTK_TREE_MODEL (list->priv->model);
+ loglist_get_log_iter (self, logview_get_active_log (logview),
+ &iter);
+ gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
+ LOG_WEIGHT_SET, FALSE, -1);
- loglist_get_log_iter (list, log, &iter);
- gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
- LOG_WEIGHT_SET, FALSE, -1);
+ self->prv->unbold_event = 0;
+ g_object_unref (self);
+ return FALSE;
}
void
@@ -131,11 +154,13 @@ loglist_bold_log (LogList *list, Log *log)
{
GtkTreeModel *model;
GtkTreeIter iter;
+ LogviewWindow *logview = LOGVIEW_WINDOW(list->prv->window);
+ LV_MARK;
g_return_if_fail (LOG_IS_LIST (list));
g_return_if_fail (log != NULL);
- model = GTK_TREE_MODEL (list->priv->model);
+ model = GTK_TREE_MODEL (list->prv->model);
loglist_get_log_iter (list, log, &iter);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
@@ -143,8 +168,10 @@ loglist_bold_log (LogList *list, Log *log)
LOG_WEIGHT_SET, TRUE, -1);
/* if the log is currently shown, put up a timer to unbold it */
- if (logview_get_active_log (log->window) == log)
- g_timeout_add (5000, log_unbold, log);
+ if (logview_get_active_log (logview) == log)
+ g_timeout_add (BOLD_LOG_TIME,
+ (GSourceFunc) loglist_unbold,
+ g_object_ref (list));
}
void
@@ -169,33 +196,36 @@ void
loglist_remove_log (LogList *list, Log *log)
{
GtkTreeIter iter, parent;
+ gchar *name;
- g_return_if_fail (LOG_IS_LIST (list));
- g_return_if_fail (log != NULL);
+ g_return_if_fail (LOG_IS_LIST (list));
+ g_return_if_fail (log != NULL);
- loglist_get_log_iter (list, log, &iter);
- gtk_tree_model_iter_parent (GTK_TREE_MODEL (list->priv->model), &parent, &iter);
+ g_object_get (G_OBJECT (log), "path", &name, NULL);
+ loglist_get_log_iter (list, log, &iter);
+ gtk_tree_model_iter_parent (GTK_TREE_MODEL (list->prv->model), &parent, &iter);
- if (gtk_tree_store_remove (list->priv->model, &iter)) {
- GtkTreeSelection *selection;
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
- gtk_tree_selection_select_iter (selection, &iter);
- } else {
- if (!gtk_tree_model_iter_has_child (GTK_TREE_MODEL (list->priv->model), &parent)) {
- if (gtk_tree_store_remove (list->priv->model, &parent)) {
- GtkTreeSelection *selection;
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
- gtk_tree_selection_select_iter (selection, &parent);
- }
- }
- }
+ if (gtk_tree_store_remove (list->prv->model, &iter)) {
+ GtkTreeSelection *selection;
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
+ gtk_tree_selection_select_iter (selection, &iter);
+ } else {
+ if (!gtk_tree_model_iter_has_child (GTK_TREE_MODEL (list->prv->model), &parent)) {
+ if (gtk_tree_store_remove (list->prv->model, &parent)) {
+ GtkTreeSelection *selection;
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
+ gtk_tree_selection_select_iter (selection, &parent);
+ }
+ }
+ }
+ g_free (name);
}
void
loglist_add_directory (LogList *list, gchar *dirname, GtkTreeIter *iter)
{
- gtk_tree_store_append (list->priv->model, iter, NULL);
- gtk_tree_store_set (list->priv->model, iter,
+ gtk_tree_store_append (list->prv->model, iter, NULL);
+ gtk_tree_store_set (list->prv->model, iter,
LOG_NAME, dirname, LOG_POINTER, NULL, -1);
}
@@ -209,17 +239,16 @@ loglist_add_log (LogList *list, Log *log)
g_return_if_fail (LOG_IS_LIST (list));
g_return_if_fail (log != NULL);
- dirname = log_extract_dirname (log);
+ log_extract_filepath (log, &dirname, &filename);
path = loglist_find_directory (list, dirname);
if (path) {
- gtk_tree_model_get_iter (GTK_TREE_MODEL (list->priv->model), &iter, path);
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (list->prv->model), &iter, path);
gtk_tree_path_free (path);
} else
loglist_add_directory (list, dirname, &iter);
- filename = log_extract_filename (log);
- gtk_tree_store_append (list->priv->model, &child_iter, &iter);
- gtk_tree_store_set (list->priv->model, &child_iter,
+ gtk_tree_store_append (list->prv->model, &child_iter, &iter);
+ gtk_tree_store_set (list->prv->model, &child_iter,
LOG_NAME, filename, LOG_POINTER, log, -1);
if (GTK_WIDGET_VISIBLE (GTK_WIDGET (list)))
@@ -230,121 +259,129 @@ loglist_add_log (LogList *list, Log *log)
}
static void
-loglist_selection_changed (GtkTreeSelection *selection, LogviewWindow *logview)
+loglist_selection_changed (GtkTreeSelection *selection, LogList *self)
{
- GtkTreeModel *model;
- GtkTreeIter iter;
- gboolean bold;
- gchar *name;
- Log *log;
-
- g_assert (LOGVIEW_IS_WINDOW (logview));
- g_assert (GTK_IS_TREE_SELECTION (selection));
-
- if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
- logview_select_log (logview, NULL);
- return;
- }
-
- gtk_tree_model_get (model, &iter,
- LOG_NAME, &name,
- LOG_POINTER, &log,
- LOG_WEIGHT_SET, &bold, -1);
- logview_select_log (logview, log);
- if (bold)
- g_timeout_add (5000, log_unbold, log);
-}
+ LogviewWindow *logview = LOGVIEW_WINDOW(self->prv->window);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean bold;
+ Log *log;
-void
-loglist_connect (LogList *list, LogviewWindow *logview)
-{
- GtkTreeSelection *selection;
+ LV_MARK;
+ g_assert (GTK_IS_TREE_SELECTION (selection));
- g_return_if_fail (LOG_IS_LIST (list));
- g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
+ if (!gtk_tree_selection_get_selected (selection, &model, &iter)) {
+ logview_select_log (logview, NULL);
+ return;
+ }
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
- g_signal_connect (G_OBJECT (selection), "changed",
- G_CALLBACK (loglist_selection_changed), logview);
+ gtk_tree_model_get (model, &iter,
+ LOG_POINTER, &log,
+ LOG_WEIGHT_SET, &bold, -1);
+ /* there is a differnt selection before,
+ check if there is a pending loglist_unbold */
+ if (logview_get_active_log (logview) != log) {
+ if (self->prv->unbold_event > 0) {
+ gboolean ret = FALSE;
+ ret = g_source_remove (self->prv->unbold_event);
+ g_assert (ret);
+ self->prv->unbold_event = 0;
+ }
+ }
+ logview_select_log (logview, log);
+ if (bold) {
+ self->prv->unbold_event =
+ g_timeout_add (BOLD_LOG_TIME,
+ (GSourceFunc) loglist_unbold,
+ g_object_ref (self));
+ }
}
static void
loglist_init (LogList *list)
{
- GtkTreeStore *model;
- GtkTreeViewColumn *column;
- GtkTreeSelection *selection;
- GtkCellRenderer *cell;
+ GtkTreeStore *model;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+ GtkCellRenderer *cell;
- list->priv = g_new0 (LogListPriv, 1);
+ list->prv = g_new0 (LogListPrv, 1);
- model = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_BOOLEAN);
- gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (model));
- list->priv->model = model;
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE);
- g_object_unref (G_OBJECT (model));
+ model = gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_INT, G_TYPE_BOOLEAN);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (list), GTK_TREE_MODEL (model));
+ list->prv->model = model;
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (list), FALSE);
+ g_object_unref (G_OBJECT (model));
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
- gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (list));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+ g_signal_connect (G_OBJECT (selection), "changed",
+ G_CALLBACK (loglist_selection_changed), list);
- cell = gtk_cell_renderer_text_new ();
- column = gtk_tree_view_column_new ();
- gtk_tree_view_column_pack_start (column, cell, TRUE);
- gtk_tree_view_column_set_attributes (column, cell,
- "text", LOG_NAME,
- "weight-set", LOG_WEIGHT_SET,
- "weight", LOG_WEIGHT,
- NULL);
-
- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(list->priv->model), 0, GTK_SORT_ASCENDING);
- gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
- gtk_tree_view_set_search_column (GTK_TREE_VIEW (list), -1);
+ cell = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_pack_start (column, cell, TRUE);
+ gtk_tree_view_column_set_attributes (column, cell,
+ "text", LOG_NAME,
+ "weight-set", LOG_WEIGHT_SET,
+ "weight", LOG_WEIGHT,
+ NULL);
+
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(list->prv->model), 0, GTK_SORT_ASCENDING);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (list), column);
+ gtk_tree_view_set_search_column (GTK_TREE_VIEW (list), -1);
}
static void
loglist_finalize (GObject *object)
{
LogList *list = LOG_LIST (object);
- g_free (list->priv);
- parent_class->finalize (object);
+ g_free (list->prv);
+ (*G_OBJECT_CLASS(loglist_parent_class)->finalize) (object);
}
static void
loglist_class_init (LogListClass *klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
- parent_class = g_type_class_peek_parent (klass);
+ GParamSpec *pspec;
+
object_class->finalize = loglist_finalize;
+ object_class->set_property = loglist_set_property;
+
+ pspec = g_param_spec_pointer ("window",
+ "LogviewWindow pointer",
+ "Set LogviewWindow pointer",
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class,
+ PROP_WINDOW,
+ pspec);
}
-GType
-loglist_get_type (void)
+static void
+loglist_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- static GType object_type = 0;
-
- if (!object_type) {
- static const GTypeInfo object_info = {
- sizeof (LogListClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) loglist_class_init,
- NULL,/* class_finalize */
- NULL, /* class_data */
- sizeof (LogList),
- 0, /* n_preallocs */
- (GInstanceInitFunc) loglist_init
- };
-
- object_type = g_type_register_static (GTK_TYPE_TREE_VIEW, "LogList", &object_info, 0);
+ LogList *self = LOG_LIST (object);
+
+ switch (property_id) {
+ case PROP_WINDOW:
+ self->prv->window = g_value_get_pointer (value);
+ g_assert (LOGVIEW_IS_WINDOW(self->prv->window));
+ break;
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
+ break;
}
-
- return object_type;
}
GtkWidget *
-loglist_new (void)
+loglist_new (gpointer window)
{
GtkWidget *widget;
- widget = g_object_new (LOG_LIST_TYPE, NULL);
+ widget = g_object_new (LOG_LIST_TYPE, "window", window, NULL);
return widget;
}
diff --git a/logview/loglist.h b/logview/loglist.h
index c7f766a..b3da652 100644
--- a/logview/loglist.h
+++ b/logview/loglist.h
@@ -17,6 +17,9 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+
+/* loglist is the left choice panel */
+
#ifndef __LOG_LIST_H__
#define __LOG_LIST_H__
@@ -27,11 +30,11 @@
#define LOG_IS_LIST_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), LOG_LIST_TYPE))
#define LOG_LIST_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), LOG_LIST_TYPE, LogListClass))
-typedef struct LogListPriv LogListPriv;
+typedef struct LogListPrv LogListPrv;
typedef struct LogList
{
- GtkTreeView parent_instance;
- LogListPriv *priv;
+ GtkTreeView parent_instance;
+ LogListPrv *prv;
}LogList;
typedef struct LogListClass
@@ -40,12 +43,10 @@ typedef struct LogListClass
}LogListClass;
GType loglist_get_type (void);
-GtkWidget *loglist_new (void);
-void loglist_connect (LogList *list, LogviewWindow *window);
+GtkWidget *loglist_new (gpointer window);
void loglist_add_log (LogList *list, Log *log);
void loglist_remove_log (LogList *list, Log *log);
void loglist_select_log (LogList *list, Log *log);
void loglist_bold_log (LogList *list, Log *log);
-void loglist_unbold_log (LogList *list, Log *log);
#endif /* __LOG_LIST_H__ */
diff --git a/logview/logrtns.c b/logview/logrtns.c
index 8300142..f61cf06 100644
--- a/logview/logrtns.c
+++ b/logview/logrtns.c
@@ -1,22 +1,22 @@
-/* ----------------------------------------------------------------------
+/* ----------------------------------------------------------------------
- Copyright (C) 1998 Cesar Miquel (miquel@df.uba.ar)
+ Copyright (C) 1998 Cesar Miquel (miquel@df.uba.ar)
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ---------------------------------------------------------------------- */
+ ---------------------------------------------------------------------- */
#ifdef __CYGWIN__
#define timezonevar
@@ -26,594 +26,1262 @@
#endif
#include <gtk/gtk.h>
#include <glib/gi18n.h>
-#include <string.h>
+#include <strings.h>
#include <stdlib.h>
-#include "logview.h"
-#include "logrtns.h"
#include <libgnomevfs/gnome-vfs-mime-utils.h>
+#include "logview-log.h"
+#include "logrtns.h"
+#include "log_repaint.h"
#include "misc.h"
#include "math.h"
+#include "logview-iface-io.h"
+#include "logview-iface-view.h"
+#include "logview-plugin-manager.h"
+#include "logview-debug.h"
+
+#define LINES_INIT_ALLOC 128
+#define LINES_STEP_ALLOC_MUTI_FACTOR 2
+#define BOLD_ROWS_TIME 5000
+#define WRITE_LINES 20
+#define DATA_LOCK(log) g_mutex_lock(log->prv->data_mutex)
+#define DATA_UNLOCK(log) g_mutex_unlock(log->prv->data_mutex)
+
+#define LOG_IS_VALID(log) g_assert (log); \
+ g_assert (LOGVIEW_IS_LOG (log)); \
+ g_assert (log->prv->dispose_has_run == FALSE)
+
+static void log_dispose (Log *log);
+static void log_finalize (Log *log);
+static void log_thread_idle (Log *self);
+static guint log_thread_main_loop (Log *self);
+static ThreadEvent log_thread_pop_event (Log *self);
+static void log_create_model (Log *log);
+static void log_thread_fill_content (Log *log);
+static void log_fill_model_with_date (Log *log, GSList *days);
+static void log_fill_model_no_date (Log *log, guint start, guint end);
+static gboolean log_unbold_rows (Log *log);
+
+static GObjectClass *parent_class = NULL;
+
+enum {
+ PROP_0 = 0,
+ PROP_NAME,
+ PROP_PROTOCOL,
+ PROP_MODEL,
+ PROP_FILTER,
+ PROP_DISPLAY_NAME,
+ PROP_TOTAL_LINES,
+ PROP_IS_MONITORED,
+ PROP_PARENT,
+ PROP_VERSIONS,
+ PROP_CURRENT_VERSION,
+ PROP_ARCHIVES,
+ PROP_DAYS,
+ PROP_VIEW,
+ PROP_VISIBLE_FIRST,
+ PROP_BOLD_FIRST,
+ PROP_BOLD_LAST,
+ PROP_SELECTED_PATHS,
+ PROP_SIZE,
+ PROP_MTIME,
+ PROP_MONITORABLE,
+ PROP_MONITORING,
+ PROP_MONITOR_HANDLE,
+ PROP_GROUPABLE
+};
+
+struct _LogPrivate {
+ gboolean dispose_has_run;
+
+ /* event related */
+ volatile ThreadEvent th_event;
+ GMutex* thread_lock;
+ GMutex* data_mutex;
+ GMutex* event_mutex;
+ GCond* event_cond;
+
+ gchar *log_path;
+ LogProtocol protocol;
+
+ /* content information */
+ GSList *need_free;
+ gchar **lines;
+ guint total_lines; /* current recorded lines in the file */
+ guint alloc_lines; /* capability of max lines in the file */
+
+ /* isolated calendar */
+ GList *selected_paths;
+
+ /* isolateed repaint */
+ GtkTreePath *first_bold_row;
+ GtkTreePath *last_bold_row;
+ GtkTreeModel *model;
+ GtkWidget *view; /* pointer to the only logview treeview */
+ gint current_version;
+ GtkTreeModelFilter *filter;
+ GSList *days;
+ /* isolated logview */
+ gchar *display_name;
+ gint versions;
+ Log *parent_log;
+ GtkTreePath *visible_first;
+
+ Log **older_logs;
+
+ /* Monitor info */
+ gboolean monitored;
+ GnomeVFSMonitorHandle *mon_handle;
+
+ /* plugin */
+ LogviewPlugin* ext_data[LOG_PF_NUM];
+
+ /* write pointer */
+ GtkTreeIter *date_iter;
+ GtkTreeIter *line_iter;
+
+ /* status */
+ gboolean update_status;
+};
-char *error_main = N_("One file or more could not be opened");
-
-static LogStats *log_stats_new (char *filename, gboolean show_error);
-
-/* File checking */
+static void
+log_instance_init (GTypeInstance *instance, gpointer g_class_data)
+{
+ Log* self = (Log*) instance;
+ self->prv = g_new0(LogPrivate, 1);
+ self->prv->dispose_has_run = FALSE;
+
+ /* thread related */
+ self->prv->thread_lock = g_mutex_new ();
+ g_assert (self->prv->thread_lock);
+ self->prv->data_mutex = g_mutex_new ();
+ g_assert (self->prv->data_mutex);
+ self->prv->event_mutex = g_mutex_new ();
+ g_assert (self->prv->event_mutex);
+ self->prv->event_cond = g_cond_new ();
+ g_assert (self->prv->event_cond);
+ self->prv->th_event = TH_EVENT_EMPTY;
+
+ self->prv->alloc_lines = LINES_INIT_ALLOC;
+ self->prv->lines = g_malloc0 (LINES_INIT_ALLOC * sizeof (gchar *));
+ g_assert (self->prv->lines);
+ self->prv->older_logs = g_malloc0 (OLD_LOG_NUM * sizeof (Log *));
+ g_assert (self->prv->older_logs);
+ self->prv->lines[0] = NULL;
+ self->prv->line_iter = g_new0 (GtkTreeIter,1);
+}
-static gboolean
-file_exist (char *filename, gboolean show_error)
-{
- GnomeVFSHandle *handle;
- GnomeVFSResult result;
- char *secondary = NULL;
-
- if (filename == NULL)
- return FALSE;
-
- result = gnome_vfs_open (&handle, filename, GNOME_VFS_OPEN_READ);
- if (result != GNOME_VFS_OK) {
- if (show_error) {
- switch (result) {
- case GNOME_VFS_ERROR_ACCESS_DENIED:
- case GNOME_VFS_ERROR_NOT_PERMITTED:
- secondary = g_strdup_printf (_("%s is not user readable. "
- "Either run the program as root or ask the sysadmin to "
- "change the permissions on the file.\n"), filename);
- break;
- case GNOME_VFS_ERROR_TOO_BIG:
- secondary = g_strdup_printf (_("%s is too big."), filename);
- break;
- default:
- secondary = g_strdup_printf (_("%s could not be opened."), filename);
- break;
- }
- error_dialog_show (NULL, error_main, secondary);
- g_free (secondary);
- }
- return FALSE;
- }
-
- gnome_vfs_close (handle);
- return TRUE;
+static void
+log_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ Log *self = LOGVIEW_LOG (object);
+
+ LOG_IS_VALID(self);
+
+ DATA_LOCK (self);
+ switch (property_id) {
+ case PROP_NAME:
+ g_free (self->prv->log_path);
+ self->prv->log_path = g_value_dup_string (value);
+ g_assert (self->prv->log_path);
+ g_assert (self->prv->log_path[0] != '\0');
+ LV_INFO ("log.path: %s",self->prv->log_path);
+ break;
+ case PROP_PROTOCOL:
+ self->prv->protocol = g_value_get_ulong (value);
+ LV_INFO ("log.protocol: %d",self->prv->protocol);
+ break;
+ case PROP_CURRENT_VERSION:
+ self->prv->current_version = g_value_get_int (value);
+ break;
+ case PROP_VERSIONS:
+ self->prv->versions = g_value_get_int (value);
+ LV_INFO ("log.versions: %d",self->prv->versions);
+ break;
+ case PROP_VISIBLE_FIRST:
+ if (self->prv->visible_first)
+ gtk_tree_path_free (self->prv->visible_first);
+ self->prv->visible_first = g_value_get_pointer (value);
+ break;
+ case PROP_SELECTED_PATHS: {
+ GList *paths;
+ paths = g_value_get_pointer (value);
+ g_assert (paths);
+ if (self->prv->selected_paths != paths) {
+ g_list_foreach (self->prv->selected_paths, (GFunc) gtk_tree_path_free, NULL);
+ g_list_free (self->prv->selected_paths);
+ self->prv->selected_paths = paths;
+ }
+ }
+ break;
+ case PROP_VIEW:
+ /* can be set only once */
+ g_assert (self->prv->view == NULL);
+ self->prv->view = g_value_get_pointer (value);
+ if (self->prv->view)
+ g_assert (GTK_IS_TREE_VIEW(self->prv->view));
+ break;
+ case PROP_MONITOR_HANDLE:
+ self->prv->mon_handle = g_value_get_pointer (value);
+ break;
+ case PROP_MONITORING:
+ self->prv->monitored = g_value_get_boolean (value);
+ break;
+ case PROP_FILTER:
+ self->prv->filter = g_value_get_pointer (value);
+ break;
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
+ break;
+ }
+ DATA_UNLOCK (self);
}
-static gboolean
-file_is_zipped (char *filename)
+static void
+log_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- char *mime_type;
+ Log *self = LOGVIEW_LOG (object);
+
+ LOG_IS_VALID(self);
+
+ DATA_LOCK (self);
+ switch (property_id) {
+ case PROP_NAME:
+ g_value_set_static_string (value, self->prv->log_path);
+ break;
+ case PROP_PROTOCOL:
+ g_value_set_ulong (value, self->prv->protocol);
+ break;
+ case PROP_MODEL:
+ g_value_set_pointer (value, self->prv->model);
+ break;
+ case PROP_PARENT:
+ g_value_set_object (value, self->prv->parent_log);
+ break;
+ case PROP_FILTER:
+ g_value_set_pointer (value, self->prv->filter);
+ break;
+ case PROP_DISPLAY_NAME:
+ g_value_set_string (value, self->prv->display_name);
+ break;
+ case PROP_TOTAL_LINES:
+ g_value_set_uint (value, self->prv->total_lines);
+ break;
+ case PROP_MONITORABLE:
+ g_value_set_boolean (value, logi_can_monitor(LOGVIEW_IFACE_IO(log_io(self))));
+ break;
+ case PROP_MONITORING:
+ g_value_set_boolean (value, self->prv->monitored);
+ break;
+ case PROP_GROUPABLE: {
+ gboolean ret;
+ ret = self->prv->days != NULL;
+ g_value_set_boolean (value, ret);
+ }
+ break;
+ case PROP_VISIBLE_FIRST:
+ g_value_set_pointer (value, self->prv->visible_first);
+ break;
+ case PROP_BOLD_FIRST:
+ g_value_set_pointer (value, self->prv->first_bold_row);
+ break;
+ case PROP_BOLD_LAST:
+ g_value_set_pointer (value, self->prv->last_bold_row);
+ break;
+ case PROP_VERSIONS:
+ g_value_set_int (value, self->prv->versions);
+ break;
+ case PROP_ARCHIVES:
+ g_value_set_pointer (value, self->prv->older_logs);
+ break;
+ case PROP_CURRENT_VERSION:
+ g_value_set_int (value, self->prv->current_version);
+ break;
+ case PROP_DAYS:
+ g_value_set_pointer (value, self->prv->days);
+ break;
+ case PROP_VIEW:
+ g_value_set_pointer (value, self->prv->view);
+ break;
+ case PROP_SELECTED_PATHS:
+ g_value_set_pointer (value, self->prv->selected_paths);
+ break;
+ case PROP_SIZE: {
+ guint64 size = (guint64) logi_get_size (LOGVIEW_IFACE_IO(log_io(self)));
+ g_value_set_uint64 (value, size);
+ break;
+ }
+ case PROP_MTIME: {
+ time_t time = logi_get_modified_time(LOGVIEW_IFACE_IO(log_io(self)));
+ g_value_set_long (value, time);
+ break;
+ }
+ case PROP_MONITOR_HANDLE:
+ g_value_set_pointer (value, self->prv->mon_handle);
+ break;
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object,property_id,pspec);
+ break;
+ }
+ DATA_UNLOCK (self);
+}
- if (filename == NULL)
- return FALSE;
+static void
+log_class_init (gpointer g_class, gpointer g_class_data)
+{
+ GObjectClass *object_class;
+ LogClass *self;
+ GParamSpec *pspec;
+
+ LV_MARK;
+
+ object_class = G_OBJECT_CLASS (g_class);
+ self = LOGVIEW_LOG_CLASS (g_class);
+ parent_class = g_type_class_peek_parent (g_class);
+
+ object_class->set_property = log_set_property;
+ object_class->get_property = log_get_property;
+ object_class->dispose = (void (*) (GObject*)) log_dispose;
+ object_class->finalize = (void (*) (GObject*)) log_finalize;
+
+ pspec = g_param_spec_string ("path",
+ "Log arbitrary path",
+ "Set or get log path",
+ "" /* default value */,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ pspec);
+
+ pspec = g_param_spec_string ("display-name",
+ "Log display name",
+ "Set or get log display name",
+ NULL /* default value */,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class,
+ PROP_DISPLAY_NAME,
+ pspec);
+
+ pspec = g_param_spec_ulong ("protocol",
+ "Log protocol",
+ "Set or get log protocol",
+ 0,
+ G_TYPE_ULONG,
+ UNKNOWN_LOG /* default value */,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+ g_object_class_install_property (object_class,
+ PROP_PROTOCOL,
+ pspec);
+
+ pspec = g_param_spec_int ("current-version",
+ "Currently displaying log",
+ "Set or get current version",
+ 0,
+ OLD_LOG_NUM,
+ 0 /* default value */,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class,
+ PROP_CURRENT_VERSION,
+ pspec);
+
+ pspec = g_param_spec_int ("versions",
+ "Log archive numbers",
+ "Get log archive numbers",
+ 0,
+ OLD_LOG_NUM,
+ 0 /* default value */,
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_VERSIONS,
+ pspec);
+
+ pspec = g_param_spec_pointer ("archives",
+ "elder logs pointer",
+ "Get elder logs pointer",
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_ARCHIVES,
+ pspec);
+
+ pspec = g_param_spec_uint64 ("size",
+ "Log file size",
+ "Get log size",
+ 0,
+ G_MAXUINT64,
+ 0 /* default value */,
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_SIZE,
+ pspec);
+
+ pspec = g_param_spec_uint ("total-lines",
+ "Log current read lines",
+ "Get current read lines",
+ 0,
+ G_MAXUINT,
+ 0 /* default value */,
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_TOTAL_LINES,
+ pspec);
+
+ pspec = g_param_spec_long ("mtime",
+ "Log modified time",
+ "Get modified time",
+ 0,
+ G_MAXLONG,
+ 0 /* default value */,
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_MTIME,
+ pspec);
+
+ pspec = g_param_spec_boolean ("monitorable",
+ "Log monitor capable",
+ "Get or set monitor capable",
+ FALSE,
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_MONITORABLE,
+ pspec);
+
+ pspec = g_param_spec_boolean ("monitoring",
+ "Is monitor the log",
+ "Get monitor status",
+ FALSE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class,
+ PROP_MONITORING,
+ pspec);
+
+ pspec = g_param_spec_boolean ("groupable",
+ "Log group capable",
+ "Get group capable",
+ FALSE,
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_GROUPABLE,
+ pspec);
+
+ pspec = g_param_spec_pointer ("model",
+ "Log tree model",
+ "Get log model",
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_MODEL,
+ pspec);
+
+ pspec = g_param_spec_pointer ("filter",
+ "Log tree filter",
+ "Get log filter",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class,
+ PROP_FILTER,
+ pspec);
+
+ pspec = g_param_spec_object ("parent",
+ "The parent log of the current log",
+ "Get parent log",
+ LOGVIEW_TYPE_LOG,
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_PARENT,
+ pspec);
+
+ pspec = g_param_spec_pointer ("days",
+ "The day list of a log",
+ "Get log days",
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_DAYS,
+ pspec);
+
+ pspec = g_param_spec_pointer ("view",
+ "Point to the only treeview of the main window",
+ "Get and set window",
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT);
+ g_object_class_install_property (object_class,
+ PROP_VIEW,
+ pspec);
+
+ pspec = g_param_spec_pointer ("visible-first",
+ "Log visible first",
+ "Set or get first visible line",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class,
+ PROP_VISIBLE_FIRST,
+ pspec);
+
+ pspec = g_param_spec_pointer ("first-bold-row",
+ "first bold row",
+ "Get first bold row",
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_BOLD_FIRST,
+ pspec);
+
+ pspec = g_param_spec_pointer ("last-bold-row",
+ "last bold row",
+ "Get last bold row",
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class,
+ PROP_BOLD_LAST,
+ pspec);
+
+ pspec = g_param_spec_pointer ("selected-paths",
+ "Log last selected lines",
+ "Set or get last selected lines",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class,
+ PROP_SELECTED_PATHS,
+ pspec);
+
+
+ pspec = g_param_spec_pointer ("monitor-handle",
+ "GnomeVFSMonitorHandle used for monitoring this log",
+ "Set or get last selected line",
+ G_PARAM_READWRITE);
+ g_object_class_install_property (object_class,
+ PROP_MONITOR_HANDLE,
+ pspec);
- mime_type = gnome_vfs_get_mime_type (filename);
- if (mime_type == NULL)
- return FALSE;
+}
- if (strcmp (mime_type, "application/x-gzip")==0 ||
- strcmp (mime_type, "application/x-zip")==0 ||
- strcmp (mime_type, "application/zip")==0) {
- g_free (mime_type);
- return TRUE;
- } else {
- g_free (mime_type);
- return FALSE;
- }
+GType
+log_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (LogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ log_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (Log),
+ 0, /* n_preallocs */
+ log_instance_init /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "LogviewLogType",
+ &info, 0);
+ }
+ return type;
}
-gboolean
-file_is_log (char *filename, gboolean show_error)
+static void
+log_append_garbage (Log *self, gchar *mass)
{
- LogStats *stats;
+ LOG_IS_VALID(self);
- if (filename == NULL)
- return FALSE;
+ self->prv->need_free = g_slist_append (self->prv->need_free, mass);
+}
- stats = log_stats_new (filename, show_error);
- if (stats==NULL)
- return FALSE;
- else {
- g_free (stats);
- return TRUE;
- }
+static void
+log_append_lines (Log *self, gchar **lines, gint len)
+{
+ guint i;
+
+ LOG_IS_VALID(self);
+
+ if (self->prv->total_lines + len >= (self->prv->alloc_lines -1)) {
+ self->prv->alloc_lines *= LINES_STEP_ALLOC_MUTI_FACTOR;
+ self->prv->lines = g_realloc (self->prv->lines,
+ self->prv->alloc_lines * sizeof (gchar *));
+ g_assert (self->prv->lines);
+ }
+ for (i = 0; i < len; i++) {
+ g_assert (lines[i]);
+ self->prv->lines[self->prv->total_lines++] = lines[i];
+ }
+ self->prv->lines[self->prv->total_lines] = NULL;
+}
+
+static void
+cleanup_binary_chars_in_log (gchar* buffer, gssize read_size)
+{
+ int i;
+ for ( i = 0; i < read_size; i++ ) {
+ if ( buffer[i] == '\0' ) {
+ buffer[i] = '?';
+ }
+ }
}
/* log functions */
+Day *
+log_find_day (Log *self, const GDate* date)
+{
+ GSList *days;
+ Day *day, *found_day = NULL;
+
+ LOG_IS_VALID(self);
+
+ DATA_LOCK (self);
+ for (days = self->prv->days; days!=NULL; days=g_slist_next(days)) {
+ day = days->data;
+ if (g_date_compare (day->date, date) == 0) {
+ found_day = day;
+ }
+ }
+ DATA_UNLOCK (self);
+ return found_day;
+}
-gint
-days_compare (gconstpointer a, gconstpointer b)
+/* return start index of lines */
+static guint
+log_build_list_index_from_mass (Log *self, const gchar* buffer)
{
- const Day *day1 = a, *day2 = b;
- return (g_date_compare (day1->date, day2->date));
+ gchar *fore_idx, *rear_idx;
+ guint ret = self->prv->total_lines;
+ gchar *cache[LINES_INIT_ALLOC];
+ gint i = 0;
+
+ LV_MARK;
+ LOG_IS_VALID(self);
+ g_assert (buffer);
+
+ DATA_LOCK (self);
+ log_append_garbage (self, (gchar *) buffer);
+ for (rear_idx = fore_idx = (gchar *) buffer; *fore_idx != '\0'; fore_idx++) {
+ /* do not skip empty lines */
+ while (*fore_idx == '\n') {
+ *fore_idx = '\0';
+ if (rear_idx != fore_idx) {
+ cache[i++] = rear_idx;
+ if (i == LINES_INIT_ALLOC) {
+ log_append_lines (self, cache, i);
+ i = 0;
+ DATA_UNLOCK (self);
+ log_thread_idle (self);
+ DATA_LOCK (self);
+ }
+ }
+ rear_idx = fore_idx + 1;
+ }
+ }
+ if (i > 0)
+ log_append_lines (self, cache, i);
+ DATA_UNLOCK (self);
+ return ret;
}
+/**
+ * log_read:
+ * @self: a #Log instance.
+ *
+ * If read end of line or zero chars or meats error, return NULL.
+ *
+ * Returns: the pointer of buffer.
+ */
gchar *
-string_get_date_string (gchar *line)
+log_read (Log *self)
{
- gchar **split, *date_string;
- gchar *month=NULL, *day=NULL;
- int i=0;
-
- if (line == NULL || line[0] == 0)
- return NULL;
-
- split = g_strsplit (line, " ", 4);
- if (split == NULL)
- return NULL;
-
- while ((day == NULL || month == NULL) && split[i]!=NULL && i<4) {
- if (g_str_equal (split[i], "")) {
- i++;
- continue;
+ gchar *buffer;
+ off_t len, read_size, fp;
+
+ LV_MARK;
+ LOG_IS_VALID(self);
+
+ g_assert (LOGVIEW_IS_IFACE_IO(log_io (self)));
+ g_assert (LOGVIEW_IS_IFACE_VIEW(log_view (self)));
+ DATA_LOCK (self);
+
+ fp = logi_tell (log_io(self));
+ logi_seek (log_io(self), 0, SEEK_END);
+ len = logi_tell (log_io(self)) - fp;
+ buffer = g_malloc (len * sizeof(gchar) +1);
+ logi_seek (log_io(self), fp, SEEK_SET);
+ read_size = logi_read (log_io(self), buffer, len);
+ if (read_size > 0) {
+ logi_update (log_io(self));
+ buffer [read_size] = '\0';
+ buffer = logi_to_utf8 (log_view (self), buffer, read_size);
+ cleanup_binary_chars_in_log (buffer, read_size);
}
+ else {
+ /* read_size == 0 || -1, reading finished or error? */
+ g_free (buffer);
+ buffer = NULL;
+ }
+ DATA_UNLOCK (self);
+ return buffer;
+}
- if (month == NULL) {
- month = split[i++];
- /* If the first field begins by a number, the date
- is given in yyyy-mm-dd format */
- if (!g_ascii_isalpha (month[0]))
- break;
- continue;
- }
+static guint
+log_thread_main_loop (Log *self)
+{
+ ThreadEvent te;
+
+ LOG_IS_VALID(self);
+
+ /* lock thread, prevent free instance before exist from thread */
+ g_mutex_lock (self->prv->thread_lock);
+ while ((te = log_thread_pop_event (self))) {
+ switch (te) {
+ case TH_EVENT_INIT_READ:
+ self->prv->update_status = FALSE;
+ LV_INFO ("%s begin building log lines...",
+ self->prv->log_path);
+ log_thread_fill_content (self);
+ LV_INFO ("%s finished building log lines,"
+ "found %ld new lines",
+ self->prv->log_path,
+ self->prv->total_lines);
+ break;
+ case TH_EVENT_UPDATE:
+ self->prv->update_status = TRUE;
+ log_thread_fill_content (self);
+ break;
+ case TH_EVENT_EXIT:
+ goto thread_exit;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ }
+thread_exit:
+ g_mutex_unlock (self->prv->thread_lock);
+ return 0;
+}
- if (day == NULL)
- day = split[i];
- i++;
- }
-
- if (i==3)
- date_string = g_strconcat (month, " ", day, NULL);
- else
- date_string = g_strconcat (month, " ", day, NULL);
- g_strfreev (split);
- return (date_string);
-}
-
-/* log_read_dates
- Read all dates which have a log entry to create calendar.
- All dates are given with respect to the 1/1/1970
- and are then corrected to the correct year once we
- reach the end.
-*/
-GSList *
-log_read_dates (gchar **buffer_lines, time_t current)
-{
- int offsetyear = 0, current_year;
- GSList *days = NULL, *days_copy;
- GDate *date, *newdate;
- struct tm *tmptm;
- gchar *date_string;
- Day *day;
- gboolean done = FALSE;
- int i, n, rangemin, rangemax;
-
- if (buffer_lines == NULL)
- return NULL;
-
- n = g_strv_length (buffer_lines);
-
- tmptm = localtime (&current);
- current_year = tmptm->tm_year + 1900;
-
- for (i=0; buffer_lines[i]==NULL; i++);
-
- /* Start building the list */
- /* Scanning each line to see if the date changed is too slow, so we proceed
- in a recursive fashion */
-
- date = string_get_date (buffer_lines[i]);
- if ((date==NULL)|| !g_date_valid (date))
- return NULL;
-
- g_date_set_year (date, current_year);
- day = g_new (Day, 1);
- days = g_slist_append (days, day);
-
- day->date = date;
- day->first_line = i;
- day->last_line = -1;
- date_string = string_get_date_string (buffer_lines[i]);
-
- rangemin = 0;
- rangemax = n-1;
-
- while (!done) {
-
- i = n-1;
- while (day->last_line < 0) {
-
- if (g_str_has_prefix (buffer_lines[i], date_string)) {
- if (i == (n-1)) {
- day->last_line = i;
- done = TRUE;
- break;
- } else {
- if (!g_str_has_prefix (buffer_lines[i+1], date_string)) {
- day->last_line = i;
- break;
- } else {
- rangemin = i;
- i = floor ( ((float) i + (float) rangemax)/2.);
- }
- }
- } else {
- rangemax = i;
- i = floor (((float) rangemin + (float) i)/2.);
- }
-
- }
-
- g_free (date_string);
-
- if (!done) {
- /* We need to find the first line now that has a date
- Logs can have some messages without dates ... */
- newdate = NULL;
- while (newdate == NULL && !done) {
- i++;
- date_string = string_get_date_string (buffer_lines[i]);
- if (date_string == NULL)
- if (i==n-1) {
- done = TRUE;
- break;
- } else
- continue;
- newdate = string_get_date (buffer_lines[i]);
-
- if (newdate == NULL && i==n-1)
- done = TRUE;
- }
-
- day->last_line = i-1;
-
- /* Append a day to the list */
- if (newdate) {
- g_date_set_year (newdate, current_year + offsetyear);
- if (g_date_compare (newdate, date) < 1) {
- offsetyear++; /* newdate is next year */
- g_date_add_years (newdate, 1);
- }
-
- date = newdate;
- day = g_new (Day, 1);
- days = g_slist_append (days, day);
-
- day->date = date;
- day->first_line = i;
- day->last_line = -1;
- rangemin = i;
- rangemax = n;
- }
- }
- }
-
- /* Correct years now. We assume that the last date on the log
- is the date last accessed */
-
- for (days_copy = days; days_copy != NULL; days_copy = g_slist_next (days_copy)) {
- day = days_copy -> data;
- g_date_subtract_years (day->date, offsetyear);
- }
-
- /* Sort the days in chronological order */
- days = g_slist_sort (days, days_compare);
-
- return (days);
-}
-
-/*
- log_stats_new
- Read the log and get some statistics from it.
- Returns NULL if the file is not a log.
-*/
-
-static LogStats *
-log_stats_new (char *filename, gboolean show_error)
-{
- GnomeVFSResult result;
- GnomeVFSFileInfo *info;
- GnomeVFSHandle *handle;
- GnomeVFSFileSize size;
- LogStats *stats;
- char buff[1024];
- char *found_space;
-
- if (filename == NULL)
- return NULL;
-
- /* Read first line and check that it is text */
- result = gnome_vfs_open (&handle, filename, GNOME_VFS_OPEN_READ);
- if (result != GNOME_VFS_OK) {
- return NULL;
- }
-
- info = gnome_vfs_file_info_new ();
- result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_FOLLOW_LINKS);
- if (result != GNOME_VFS_OK || info->type != GNOME_VFS_FILE_TYPE_REGULAR) {
- gnome_vfs_file_info_unref (info);
- gnome_vfs_close (handle);
- return NULL;
- }
-
- result = gnome_vfs_read (handle, buff, sizeof(buff), &size);
- gnome_vfs_close (handle);
- if (result != GNOME_VFS_OK) {
- gnome_vfs_file_info_unref (info);
- return NULL;
- }
-
- found_space = g_strstr_len (buff, 1024, " ");
- if (found_space == NULL) {
- gnome_vfs_file_info_unref (info);
- return NULL;
- }
-
- stats = g_new (LogStats, 1);
- stats->file_time = info->mtime;
- stats->file_size = info->size;
- gnome_vfs_file_info_unref (info);
-
- return (stats);
-}
-
-Log *
-log_open (char *filename, gboolean show_error)
-{
- char *buffer, *zipped_name= NULL, *error_message;
- GnomeVFSResult result;
- LogStats *stats;
- gboolean opened = TRUE;
- int i, size;
- GList *days;
- Log *log;
-
- stats = log_stats_new (filename, show_error);
- if (stats == NULL) {
- if (file_is_zipped (filename)) {
- zipped_name = g_strdup_printf ("%s#gzip:", filename);
- stats = log_stats_new (filename, show_error);
- if (stats == NULL) {
- opened = FALSE;
- }
- } else
- opened = FALSE;
- }
-
- if (opened == FALSE) {
- error_message = g_strdup_printf (_("%s is not a log file."), filename);
- goto error;
- }
-
- log = g_new0 (Log, 1);
- if (log == NULL) {
- error_message = g_strdup (_("Not enough memory."));
- goto error;
- }
-
- if (!zipped_name) {
- log->name = g_strdup (filename);
- } else {
- log->name = zipped_name;
- log->display_name = g_strdup (filename);
- }
-
- result = gnome_vfs_read_entire_file (log->name, &size, &buffer);
- buffer[size-1] = 0;
- if (result != GNOME_VFS_OK) {
- error_message = g_strdup_printf (_("%s cannot be opened."), log->name);
- goto error;
- }
-
- if (g_get_charset (NULL) == FALSE) {
- char *buffer2;
- buffer2 = locale_to_utf8 (buffer);
- g_free (buffer);
- buffer = buffer2;
- }
-
- log->lines = g_strsplit (buffer, "\n", -1);
- g_free (buffer);
-
- log->total_lines = g_strv_length (log->lines);
- log->displayed_lines = log->total_lines;
- log->first_time = TRUE;
- log->stats = stats;
- log->model = NULL;
- log->filter = NULL;
- log->mon_offset = 0;
- log->bold_rows_list = NULL;
-
- /* A log without dates will return NULL */
- log->days = log_read_dates (log->lines, log->stats->file_time);
-
- /* Check for older versions of the log */
- log->versions = 0;
- log->current_version = 0;
- log->parent_log = NULL;
- for (i=1; i<5; i++) {
- gchar *older_name;
- older_name = g_strdup_printf ("%s.%d", log->name, i);
- log->older_logs[i] = log_open (older_name, FALSE);
- g_free (older_name);
- if (log->older_logs[i] != NULL) {
- log->older_logs[i]->parent_log = log;
- log->older_logs[i]->current_version = i;
- log->versions++;
- }
- else
- break;
- }
-
- return log;
-
-error:
- if (error_message && show_error) {
- error_dialog_show (NULL, error_main, error_message);
- }
-
- g_free (error_message);
-
- return NULL;
+gboolean
+log_run (Log *self)
+{
+ /* this function should only be ran once */
+ LOG_IS_VALID(self);
+ g_assert (self->prv->model == NULL);
+
+ log_create_model (self);
+ LV_INFO ("[[Log thread run]] %s", self->prv->log_path);
+ if (g_thread_create ((GThreadFunc) log_thread_main_loop, self, TRUE, NULL))
+ return TRUE;
+ else {
+ LV_INFO ("create thread failed", NULL);
+ return FALSE;
+ }
}
static void
-log_add_lines (Log *log, gchar *buffer)
+log_dispose (Log *self)
{
- char *old_buffer, *new_buffer;
+ LV_MARK;
+ if (self->prv->dispose_has_run) {
+ /* If dispose did already run, return. */
+ return;
+ }
+ self->prv->dispose_has_run = TRUE;
+ G_OBJECT_CLASS (parent_class)->dispose (G_OBJECT (self));
+}
- g_assert (log != NULL);
- g_assert (buffer != NULL);
+static void
+log_finalize (Log *self)
+{
+ gint i;
+ GSList *idx;
+ Day *day;
+ GSList *days;
+
+ LV_MARK;
+ LV_INFO ("[[ log remove ]] %s", self->prv->log_path);
+
+ log_notify (self, TH_EVENT_EXIT);
+ /* make sure thread existed */
+ g_mutex_lock (self->prv->thread_lock);
+ g_mutex_unlock (self->prv->thread_lock);
+ g_mutex_free (self->prv->thread_lock);
+ self->prv->thread_lock = NULL;
+ /* free other locks */
+ g_assert (LOGVIEW_IS_LOG (self));
+ g_cond_free (self->prv->event_cond);
+ self->prv->event_cond = NULL;
+ g_mutex_free (self->prv->event_mutex);
+ self->prv->event_mutex = NULL;
+ g_mutex_free (self->prv->data_mutex);
+ self->prv->data_mutex = NULL;
+ /* Close archive logs if there's some */
+ for (i = 0; i < self->prv->versions; i++)
+ if (self->prv->older_logs[i])
+ g_object_unref (self->prv->older_logs[i]);
+ g_free (self->prv->older_logs);
+
+ if (self->prv->mon_handle != NULL) {
+ gnome_vfs_monitor_cancel (self->prv->mon_handle);
+ self->prv->mon_handle = NULL;
+ }
+
+ if (self->prv->model) {
+ gtk_tree_store_clear (GTK_TREE_STORE (self->prv->model));
+ g_object_unref (self->prv->model);
+ }
+
+ if (self->prv->days != NULL) {
+ for (days = self->prv->days; days != NULL; days = g_slist_next (days)) {
+ day = days->data;
+ g_date_free (day->date);
+ gtk_tree_path_free (day->path);
+ g_free (day);
+ }
+ g_slist_free (self->prv->days);
+ self->prv->days = NULL;
+ }
+
+ if (self->prv->date_iter)
+ gtk_tree_iter_free (self->prv->date_iter);
+ if (self->prv->line_iter)
+ gtk_tree_iter_free (self->prv->line_iter);
+ if (self->prv->visible_first)
+ gtk_tree_path_free (self->prv->visible_first);
+
+ if (self->prv->first_bold_row)
+ gtk_tree_path_free (self->prv->first_bold_row);
+ if (self->prv->last_bold_row)
+ gtk_tree_path_free (self->prv->last_bold_row);
+
+ for (i = 0; i < LOG_PF_NUM; i++) {
+ if (self->prv->ext_data[i] != NULL) {
+ g_object_unref (G_OBJECT (self->prv->ext_data[i]));
+ }
+ }
+
+ for (idx = self->prv->need_free; idx; idx = g_slist_next(idx)) {
+ gchar *mass = (gchar *)idx->data;
+ g_free (mass);
+ }
+
+ g_free (self->prv->lines);
+ self->prv->lines = NULL;
+
+ if (self->prv->display_name)
+ g_free (self->prv->display_name);
+ if (self->prv->log_path)
+ g_free (self->prv->log_path);
+ g_free (self->prv);
+ self->prv = NULL;
+ parent_class->finalize (G_OBJECT (self));
+}
- old_buffer = g_strjoinv ("\n", log->lines);
- new_buffer = g_strconcat (old_buffer, "\n", buffer, NULL);
- g_free (old_buffer);
-
- g_strfreev (log->lines);
- log->lines = g_strsplit (new_buffer, "\n", -1);
- g_free (new_buffer);
+void
+log_extract_filepath (Log* self, gchar** dirname, gchar** filename)
+{
+ LOG_IS_VALID(self);
+ g_assert (LOGVIEW_IS_IFACE_IO(log_io(self)));
- log->total_lines = g_strv_length (log->lines);
+ logi_extract_filepath(LOGVIEW_IFACE_IO(log_io(self)), dirname, filename);
}
-void log_stats_reload (Log *log)
+gboolean
+log_has_been_modified (Log *self)
{
- g_free (log->stats);
- log->stats = log_stats_new (log->name, TRUE);
+ LOG_IS_VALID(self);
+ g_assert (LOGVIEW_IS_IFACE_IO(log_io(self)));
+
+ return logi_has_updated(LOGVIEW_IFACE_IO(log_io(self)));
}
-/* log_read_new_lines */
+gboolean
+log_test_func (Log *self, PluginFunc pf)
+{
+ LOG_IS_VALID(self);
+
+ return self->prv->ext_data[pf] != NULL;
+}
-gboolean
-log_read_new_lines (Log *log)
+void
+log_set_func (Log *self, PluginFunc pf, LogviewPlugin *plugin)
{
- GnomeVFSResult result;
- gchar *buffer;
- GnomeVFSFileSize newfilesize, read;
- guint64 size, newsize;
-
- g_return_val_if_fail (log!=NULL, FALSE);
-
- result = gnome_vfs_seek (log->mon_file_handle, GNOME_VFS_SEEK_END, 0L);
- result = gnome_vfs_tell (log->mon_file_handle, &newfilesize);
- size = log->mon_offset;
- newsize = newfilesize;
-
- if (newsize > size) {
- buffer = g_malloc (newsize - size);
- if (!buffer)
- return FALSE;
+ LOG_IS_VALID(self);
+ g_assert (plugin != NULL);
- result = gnome_vfs_seek (log->mon_file_handle, GNOME_VFS_SEEK_START, size);
- if (result != GNOME_VFS_OK)
- return FALSE;
+ self->prv->ext_data[pf] = plugin;
+}
- result = gnome_vfs_read (log->mon_file_handle, buffer, newsize-size, &read);
- if (result != GNOME_VFS_OK)
- return FALSE;
+void
+log_set_child (Log *self, gint index, Log *child)
+{
+ LOG_IS_VALID(self);
+ g_assert (index >=0 && index < OLD_LOG_NUM);
+ g_assert (child && LOGVIEW_IS_LOG (child));
+ g_assert (self->prv->older_logs[index] == NULL);
+
+ self->prv->older_logs[index] = child;
+ self->prv->versions++;
+ child->prv->parent_log = self;
+}
- buffer [newsize-size-1] = 0;
- log->mon_offset = newsize;
- log_add_lines (log, buffer);
- g_free (buffer);
-
- log_stats_reload (log);
- return TRUE;
- }
- return FALSE;
+Log*
+log_get_child (Log *self, gint index)
+{
+ LOG_IS_VALID(self);
+ g_assert (index >=0 && index < OLD_LOG_NUM);
+
+ return self->prv->older_logs[index];
}
-/*
- log_unbold is called by a g_timeout
- set in loglist_bold_log
-*/
+void
+log_notify (Log *self, ThreadEvent te)
+{
+ g_mutex_lock (self->prv->event_mutex);
+ self->prv->th_event |= te;
+ g_cond_signal (self->prv->event_cond);
+ g_mutex_unlock (self->prv->event_mutex);
+}
-gboolean
-log_unbold (gpointer data)
+static ThreadEvent
+log_thread_pop_event (Log *self)
{
- LogviewWindow *logview;
- LogList *list;
- Log *log = data;
+ ThreadEvent te;
+ LOG_IS_VALID(self);
+
+ g_mutex_lock (self->prv->event_mutex);
+ while (self->prv->th_event == TH_EVENT_EMPTY)
+ g_cond_wait (self->prv->event_cond, self->prv->event_mutex);
+ if (self->prv->th_event & TH_EVENT_EXIT)
+ te = TH_EVENT_EXIT;
+ else if (self->prv->th_event & TH_EVENT_INIT_READ)
+ te = TH_EVENT_INIT_READ;
+ else if (self->prv->th_event & TH_EVENT_UPDATE)
+ te = TH_EVENT_UPDATE;
+ else
+ g_assert_not_reached ();
+ self->prv->th_event ^= te;
+ g_mutex_unlock (self->prv->event_mutex);
+ return te;
+}
- g_return_val_if_fail (log != NULL, FALSE);
+static void
+log_thread_idle (Log *self)
+{
+ g_assert (self);
+ g_assert (LOGVIEW_IS_LOG (self));
+
+ g_usleep (1);
+ g_mutex_lock (self->prv->event_mutex);
+ if (self->prv->th_event & TH_EVENT_EXIT) {
+ g_mutex_unlock (self->prv->event_mutex);
+ g_mutex_unlock (self->prv->thread_lock);
+ g_thread_exit (0);
+ }
+ g_mutex_unlock (self->prv->event_mutex);
+}
- logview = log->window;
+static void
+log_create_model (Log *self)
+{
+ LOG_IS_VALID(self);
+ self->prv->model = GTK_TREE_MODEL(
+ gtk_tree_store_new (4, G_TYPE_STRING, G_TYPE_POINTER,
+ G_TYPE_INT, G_TYPE_BOOLEAN)
+ );
+}
- /* If the log to unbold is not displayed, still wait */
- if (logview_get_active_log (logview) != log)
- return TRUE;
+static void
+log_thread_fill_content (Log *self)
+{
+ GSList *days, *idx;
+ GtkTreePath *path = NULL;
+ gchar *buffer;
+ guint start, end;
+ LV_MARK;
+
+ LOG_IS_VALID(self);
+ g_assert (self);
+
+ if (self->prv->update_status) {
+ if (log_has_been_modified (self) == FALSE)
+ return;
+ }
+
+ if ((buffer = log_read (self)) == NULL)
+ return;
+ g_assert (buffer && buffer[0] != '\0');
+
+ start = log_build_list_index_from_mass (self, buffer);
+ g_assert (start <= self->prv->total_lines);
+
+ days = logi_group_lines (log_view (self),
+ (const gchar **) (self->prv->lines + start));
+ end = self->prv->total_lines;
+
+ if (days) {
+ log_fill_model_with_date (self, days);
+ path = gtk_tree_model_get_path (self->prv->model,
+ self->prv->date_iter);
+ DATA_LOCK (self);
+ self->prv->days = g_slist_concat (self->prv->days, days);
+ DATA_UNLOCK (self);
+ }
+ else {
+ GtkTreeIter iter;
+ log_write_lines_range (self, self->prv->lines, start, end);
+ path = gtk_tree_model_get_path (self->prv->model,
+ self->prv->line_iter);
+ }
+
+ DATA_LOCK (self);
+ if (self->prv->update_status) {
+ /* update */
+ /* Remember the last bold lines in the model to
+ unset them later */
+ if (self->prv->last_bold_row)
+ gtk_tree_path_free (self->prv->last_bold_row);
+ self->prv->last_bold_row =
+ gtk_tree_model_get_path (self->prv->model,
+ self->prv->line_iter);
+ g_timeout_add (BOLD_ROWS_TIME,
+ (GSourceFunc) log_unbold_rows,
+ g_object_ref (self));
+ }
+ else {
+ /* initial, remember the first visible line
+ and selected lines */
+ self->prv->selected_paths =
+ g_list_append (self->prv->selected_paths,
+ gtk_tree_path_copy (path));
+ if (self->prv->visible_first)
+ gtk_tree_path_free (self->prv->visible_first);
+ self->prv->visible_first = gtk_tree_path_copy (path);
+ }
+ DATA_UNLOCK (self);
+ gtk_tree_path_free (path);
+}
+
+static void
+log_fill_model_with_date (Log *self, GSList *days)
+{
+ gint i;
+ GSList *iter;
+ Day *day = NULL;
+
+ LOG_IS_VALID(self);
+ g_assert (days);
+
+ for (iter = days; iter; iter = g_slist_next (iter)) {
+ day = (Day *)iter->data;
+
+ log_write_day (self, day);
+ day->path = gtk_tree_model_get_path (self->prv->model, self->prv->date_iter);
+ log_write_lines_range (self, self->prv->lines,
+ day->first_line,
+ day->last_line + 1);
+ day->expand = FALSE;
+ }
+ day->expand = TRUE;
+}
- list = logview_get_loglist (logview);
- loglist_unbold_log (list, log);
- return FALSE;
+void
+log_write_day (Log *self, Day *day)
+{
+ gchar *old_date_str = NULL;
+ gchar *new_date_str = NULL;
+ gint old_date_len;
+ gint new_date_len;
+ GDate *date;
+
+ LOG_IS_VALID(self);
+ g_assert (day);
+ g_assert (day->date);
+ g_assert (self->prv->model);
+
+ date = day->date;
+
+ g_assert (g_date_valid (date));
+
+ new_date_str = date_to_string (date); /* convert to utf8 */
+ g_assert (new_date_str);
+
+ if (self->prv->date_iter == NULL) {
+ self->prv->date_iter = g_new0 (GtkTreeIter,1);
+ goto log_write_date_first_run;
+ }
+
+ gtk_tree_model_get (self->prv->model,
+ self->prv->date_iter,
+ MESSAGE, &old_date_str,
+ -1);
+ old_date_len = (gint) g_utf8_strlen (old_date_str, -1);
+ new_date_len = (gint) g_utf8_strlen (new_date_str, -1);
+ if ((old_date_len != new_date_len)
+ || (old_date_len >= new_date_len ?
+ g_ascii_strncasecmp (old_date_str, new_date_str, new_date_len)
+ : g_ascii_strncasecmp (old_date_str, new_date_str, old_date_len)) != 0) {
+ /* new date */
+log_write_date_first_run:
+ gtk_tree_store_append (GTK_TREE_STORE (self->prv->model),
+ self->prv->date_iter,
+ NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (self->prv->model),
+ self->prv->date_iter,
+ MESSAGE, new_date_str,
+ DAY_POINTER, day,
+ -1);
+ }
+ g_free (new_date_str);
+ g_free (old_date_str);
+ log_thread_idle (self);
}
void
-log_close (Log *log)
-{
- gint i;
- Day *day;
- GSList *days;
-
- g_return_if_fail (log);
-
- /* Close archive logs if there's some */
- for (i = 0; i < log->versions; i++)
- log_close (log->older_logs[i]);
-
- /* Close file - this should not be needed */
- if (log->mon_file_handle != NULL) {
- gnome_vfs_close (log->mon_file_handle);
- log->mon_file_handle = NULL;
- }
-
- g_object_unref (log->model);
- g_strfreev (log->lines);
-
- if (log->days != NULL) {
- for (days = log->days; days != NULL; days = g_slist_next (days)) {
- day = days->data;
- g_date_free (day->date);
- gtk_tree_path_free (day->path);
- g_free (day);
- }
- g_slist_free (log->days);
- log->days = NULL;
- }
-
- g_free (log->stats);
-
- if (log->selected_range.first)
- gtk_tree_path_free (log->selected_range.first);
- if (log->selected_range.last)
- gtk_tree_path_free (log->selected_range.last);
- if (log->visible_first)
- gtk_tree_path_free (log->visible_first);
-
- g_free (log);
- return;
+log_write_date (Log *self, GDate *date)
+{
+ gchar *old_date_str = NULL;
+ gchar *new_date_str = NULL;
+ gint old_date_len;
+ gint new_date_len;
+
+ LOG_IS_VALID(self);
+ g_assert (date);
+ g_assert (self->prv->model);
+ g_assert (g_date_valid (date));
+
+ new_date_str = date_to_string (date); /* convert to utf8 */
+ g_assert (new_date_str);
+
+ if (self->prv->date_iter == NULL) {
+ self->prv->date_iter = g_new0 (GtkTreeIter,1);
+ goto log_write_date_first_run;
+ }
+
+ gtk_tree_model_get (self->prv->model,
+ self->prv->date_iter,
+ MESSAGE, &old_date_str,
+ -1);
+ old_date_len = (gint) g_utf8_strlen (old_date_str, -1);
+ new_date_len = (gint) g_utf8_strlen (new_date_str, -1);
+ if ((old_date_len != new_date_len)
+ || (old_date_len >= new_date_len ?
+ g_ascii_strncasecmp (old_date_str, new_date_str, new_date_len)
+ : g_ascii_strncasecmp (old_date_str, new_date_str, old_date_len)) != 0) {
+ /* new date */
+log_write_date_first_run:
+ gtk_tree_store_append (GTK_TREE_STORE (self->prv->model),
+ self->prv->date_iter,
+ NULL);
+ gtk_tree_store_set (GTK_TREE_STORE (self->prv->model),
+ self->prv->date_iter,
+ MESSAGE, new_date_str,
+ DAY_POINTER, date,
+ -1);
+ }
+ g_free (new_date_str);
+ g_free (old_date_str);
+ log_thread_idle (self);
}
-gchar *
-log_extract_filename (Log *log)
+void
+log_write_lines_range (Log *self, gchar **lines, gint start, gint end)
{
- GnomeVFSURI *uri;
- gchar *filename;
+ gint i, n;
+ g_assert (end > start);
+ n = (end-start)/WRITE_LINES;
+ for (i = 0; i < n; i ++) {
+ log_write_lines (self,
+ lines + start + i*WRITE_LINES,
+ WRITE_LINES);
+ }
+ log_write_lines (self, lines + start + n*WRITE_LINES,
+ (end-start)%WRITE_LINES);
+}
- uri = gnome_vfs_uri_new (log->name);
- filename = gnome_vfs_uri_extract_short_name (uri);
- gnome_vfs_uri_unref (uri);
+void
+log_write_lines (Log *self, gchar **lines, gint num)
+{
+ gint i;
+ for (i = 0; i < num; i ++)
+ log_write_line (self, lines[i]);
+ log_thread_idle (self);
+}
- return filename;
+void
+log_write_line (Log *self, gchar *line)
+{
+ LOG_IS_VALID(self);
+ g_assert (line);
+ g_assert (self->prv->model);
+ g_assert (self->prv->line_iter);
+
+ gtk_tree_store_append (GTK_TREE_STORE (self->prv->model),
+ self->prv->line_iter,
+ self->prv->date_iter);
+ if (!self->prv->update_status) {
+ /* normal */
+ gtk_tree_store_set (GTK_TREE_STORE (self->prv->model),
+ self->prv->line_iter,
+ MESSAGE, line,
+ DAY_POINTER, NULL,
+ -1);
+ } else {
+ /* bold */
+ gtk_tree_store_set (GTK_TREE_STORE (self->prv->model),
+ self->prv->line_iter,
+ MESSAGE, line,
+ DAY_POINTER, NULL,
+ LOG_LINE_WEIGHT, PANGO_WEIGHT_BOLD,
+ LOG_LINE_WEIGHT_SET, TRUE,
+ -1);
+ /* Remember the first bold lines in the model to unset them later */
+ if (self->prv->first_bold_row == NULL)
+ self->prv->first_bold_row = gtk_tree_model_get_path (self->prv->model, self->prv->line_iter);
+
+ }
+ log_thread_idle (self);
}
-gchar *
-log_extract_dirname (Log *log)
+static gboolean
+log_unbold_rows (Log *self)
{
- GnomeVFSURI *uri;
- gchar *dirname;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkTreePath *path;
- uri = gnome_vfs_uri_new (log->name);
- dirname = gnome_vfs_uri_extract_dirname (uri);
- gnome_vfs_uri_unref (uri);
+ LOG_IS_VALID(self);
- return dirname;
+ g_assert (self->prv->view);
+ if (self->prv->model !=
+ gtk_tree_view_get_model (GTK_TREE_VIEW(self->prv->view))) {
+ g_object_unref (self);
+ return TRUE;
+ }
+
+ DATA_LOCK (self);
+ if (self->prv->first_bold_row != NULL &&
+ self->prv->last_bold_row != NULL) {
+ for (path = self->prv->first_bold_row;
+ gtk_tree_path_compare (path, self->prv->last_bold_row)<=0;
+ gtk_tree_path_next (path)) {
+ gtk_tree_model_get_iter (self->prv->model, &iter, path);
+ gtk_tree_store_set (GTK_TREE_STORE (self->prv->model), &iter,
+ LOG_LINE_WEIGHT, PANGO_WEIGHT_NORMAL,
+ LOG_LINE_WEIGHT_SET, TRUE,
+ -1);
+ }
+
+ gtk_tree_path_free (self->prv->first_bold_row);
+ gtk_tree_path_free (self->prv->last_bold_row);
+ self->prv->first_bold_row = NULL;
+ self->prv->last_bold_row = NULL;
+ }
+ DATA_UNLOCK (self);
+ g_object_unref (self);
+ return FALSE;
}
+
+void log_lock (Log *self)
+{
+ DATA_LOCK (self);
+}
+
+void log_unlock (Log *self)
+{
+ DATA_UNLOCK (self);
+}
+
diff --git a/logview/logrtns.h b/logview/logrtns.h
index 891869a..20106f5 100644
--- a/logview/logrtns.h
+++ b/logview/logrtns.h
@@ -21,72 +21,19 @@
#ifndef __LOGRTNS_H__
#define __LOGRTNS_H__
-#include <time.h>
#include <libgnomevfs/gnome-vfs.h>
+#include "logview-log.h"
-typedef struct
-{
- GDate *date;
- long first_line, last_line; /* First and last line for this day in the log */
- gboolean expand;
- GtkTreePath *path;
-} Day;
+G_BEGIN_DECLS
-typedef struct
-{
- time_t file_time;
- GnomeVFSFileSize file_size;
-} LogStats;
+/* call by log_repaint */
+Day * log_find_day (Log *self, const GDate* date);
-typedef struct TreePathRange
-{
- GtkTreePath *first;
- GtkTreePath *last;
-}TreePathRange;
+/* log utilities base on the plugin interfaces */
+void log_extract_filepath (Log* self, gchar** dirname, gchar** filename);
+gboolean log_has_been_modified (Log* self);
+gboolean log_run (Log* self);
-typedef struct _log Log;
-struct _log
-{
- char *name;
- char *display_name;
- LogStats *stats;
-
- GSList *days;
- gchar **lines;
- gint selected_line_first;
- gint selected_line_last;
- gint total_lines; /* no of lines in the file */
- gint displayed_lines; /* no of lines displayed now */
-
- /* Monitor info */
- GnomeVFSFileSize mon_offset;
- GnomeVFSMonitorHandle *mon_handle;
- GnomeVFSHandle *mon_file_handle;
- gboolean monitored;
- gboolean needs_refresh;
-
- gboolean first_time;
- GtkTreeModel *model;
- GtkTreeModelFilter *filter;
- GList *bold_rows_list;
- TreePathRange selected_range;
- GtkTreePath *visible_first;
-
- int versions;
- int current_version;
- /* older_logs[0] should not be used */
- Log *older_logs[5];
- Log *parent_log;
-
- gpointer window;
-};
-
-gboolean file_is_log (char *filename, gboolean show_error);
-Log *log_open (char *filename, gboolean show_error);
-gboolean log_read_new_lines (Log *log);
-gboolean log_unbold (gpointer data);
-void log_close (Log * log);
-gchar *log_extract_filename (Log *log);
-gchar *log_extract_dirname (Log *log);
+G_END_DECLS
#endif /* __LOGRTNS_H__ */
diff --git a/logview/logview-debug.c b/logview/logview-debug.c
new file mode 100644
index 0000000..d3c602b
--- /dev/null
+++ b/logview/logview-debug.c
@@ -0,0 +1,74 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <glib.h>
+#include <glib/gstdio.h>
+#include "misc.h"
+#include "logview-debug.h"
+
+#define LOGVIEW_USER_PATH_SUFFIX LOGVIEW_HOME_SUFFIX "/gnome-system-log.log"
+static LogviewLevelFlags debug = LOGVIEW_INFO;
+static FILE *logf;
+
+void
+lv_debug (LogviewLevelFlags level,
+ const gchar *file,
+ gint line,
+ const gchar *function)
+{
+ g_return_if_fail (file && function && line >= 0);
+ if (debug & level) {
+ g_fprintf (logf, "\"%s\" %s:%d\n", file, function, line);
+ fflush (stdout);
+ }
+}
+
+void
+lv_debug_message (LogviewLevelFlags level,
+ const gchar *file,
+ gint line,
+ const gchar *function,
+ const gchar *format, ...)
+{
+ if (debug & level) {
+ va_list ap;
+ g_return_if_fail (file && function && line >= 0);
+
+ if (debug & LOGVIEW_VERBOSE) {
+ g_fprintf (logf, "\"%s\" %s:%d ", file, function, line);
+ fflush (stdout);
+ }
+
+ va_start (ap, format);
+ g_vfprintf (logf, format, ap);
+ g_fprintf (logf, "\n");
+ va_end (ap);
+ fflush (stdout);
+ }
+}
+
+void
+logview_debug_init ()
+{
+ gchar *f = g_build_path (G_DIR_SEPARATOR_S, (gchar*)g_get_home_dir (),
+ LOGVIEW_USER_PATH_SUFFIX, NULL);
+ logf = g_fopen (f, "wb");
+ g_free (f);
+
+ if (g_getenv ("LOGVIEW_DEBUG") != NULL) {
+ debug |= LOGVIEW_ERR | LOGVIEW_VERBOSE;
+ }
+ if (g_getenv ("LOGVIEW_VERBOSE") != NULL) {
+ debug |= LOGVIEW_VERBOSE;
+ }
+}
+
+void
+logview_debug_destroy ()
+{
+ fclose (logf);
+ logf = NULL;
+}
+
diff --git a/logview/logview-debug.h b/logview/logview-debug.h
new file mode 100644
index 0000000..f02a1db
--- /dev/null
+++ b/logview/logview-debug.h
@@ -0,0 +1,87 @@
+#ifndef __LOGVIEW_DEBUG_H__
+#define __LOGVIEW_DEBUG_H__
+#include <glib.h>
+
+/**
+ * LogviewLevelFlags:
+ * @LOGVIEW_INFO: Normal information will be displayed in this level.
+ * @LOGVIEW_VERBOSE: Like %LOGVIEW_INFO, more information like file name,
+ * function name and line number will be displayed in this level.
+ * @LOGVIEW_ERR: Cover all above levels, displays verbose information
+ * for debugging usage.
+ *
+ * Used to specify the level of the log of gnome-system-log.
+ **/
+typedef enum {
+ LOGVIEW_INFO = 1 << 0,
+ LOGVIEW_VERBOSE = 1 << 1,
+ LOGVIEW_ERR = 1 << 2
+} LogviewLevelFlags;
+
+void logview_debug_init ();
+void logview_debug_destroy ();
+void lv_debug (LogviewLevelFlags level,
+ const gchar *file,
+ gint line,
+ const gchar *function);
+void lv_debug_message (LogviewLevelFlags level,
+ const gchar *file,
+ gint line,
+ const gchar *function,
+ const gchar *format, ...);
+
+#ifdef ON_SUN_OS
+#define FUNC __func__
+#else
+#define FUNC G_STRFUNC
+#endif
+
+/**
+ * LV_MARK:
+ *
+ * Dump out information in the %LOGVIEW_ERR level.
+ **/
+#define LV_MARK \
+ lv_debug (LOGVIEW_ERR, __FILE__, __LINE__, FUNC)
+
+/**
+ * LV_INFO:
+ * @FORMAT: a formatted string.
+ * @Varargs:
+ *
+ * Dump out information in the %LOGVIEW_VERBOSE and %LOGVIEW_INFO level.
+ **/
+#define LV_INFO(FORMAT, ...) \
+ lv_debug_message (LOGVIEW_INFO, __FILE__, __LINE__, FUNC, "[II] " FORMAT, __VA_ARGS__)
+
+/**
+ * LV_INFO_WW:
+ * @FORMAT: a formatted string.
+ * @Varargs:
+ *
+ * Like LV_INFO(), dump out warnning information.
+ **/
+#define LV_INFO_WW(FORMAT, ...) \
+ lv_debug_message (LOGVIEW_INFO, __FILE__, __LINE__, FUNC, "[WW] " FORMAT, __VA_ARGS__)
+
+/**
+ * LV_INFO_EE:
+ * @FORMAT: a formatted string.
+ * @Varargs:
+ *
+ * Like LV_INFO(), dump out error information.
+ **/
+#define LV_INFO_EE(FORMAT, ...) \
+ lv_debug_message (LOGVIEW_INFO, __FILE__, __LINE__, FUNC, "[EE] " FORMAT, __VA_ARGS__)
+
+/**
+ * LV_ERR:
+ * @FORMAT: a formatted string.
+ * @Varargs:
+ *
+ * Dump out information in the %LOGVIEW_ERR level.
+ **/
+#define LV_ERR(FORMAT, ...) \
+ lv_debug_message (LOGVIEW_ERR, __FILE__, __LINE__, FUNC, FORMAT, __VA_ARGS__)
+
+#endif
diff --git a/logview/logview-findbar.c b/logview/logview-findbar.c
index c70ff16..8c6477b 100644
--- a/logview/logview-findbar.c
+++ b/logview/logview-findbar.c
@@ -22,6 +22,7 @@
#include <glib/gi18n.h>
#include "logview.h"
#include "logview-findbar.h"
+#include "log_repaint.h"
struct LogviewFindBarPriv
{
@@ -55,9 +56,15 @@ logview_findbar_clear (GtkWidget *widget, gpointer data)
{
LogviewFindBar *findbar = LOGVIEW_FINDBAR (data);
LogviewWindow *logview = LOGVIEW_WINDOW (findbar->priv->logview);
+ GtkTreeModelFilter *filter;
Log *log = logview->curlog;
- if (log==NULL || log->filter == NULL)
+ if (log==NULL)
+ return;
+ g_object_get (G_OBJECT (log),
+ "filter", &filter,
+ NULL);
+ if (filter == NULL)
return;
gtk_entry_set_text (GTK_ENTRY (findbar->priv->entry), "");
@@ -70,21 +77,28 @@ logview_findbar_entry_timeout (gpointer data)
LogviewFindBar *findbar = LOGVIEW_FINDBAR (data);
LogviewWindow *logview = LOGVIEW_WINDOW (findbar->priv->logview);
Log *log = logview->curlog;
+ GtkTreeModel *model;
+ GtkTreeModelFilter *filter;
GdkCursor *cursor;
+ g_object_get (G_OBJECT (log),
+ "model", &model,
+ "filter", &filter,
+ NULL);
cursor = gdk_cursor_new (GDK_WATCH);
gdk_window_set_cursor (GTK_WIDGET (logview)->window, cursor);
gdk_cursor_unref (cursor);
gdk_display_flush (gtk_widget_get_display (GTK_WIDGET (logview)));
- if (log->filter == NULL) {
+ if (filter == NULL) {
- log->filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (log->model, NULL));
- gtk_tree_model_filter_set_visible_func (log->filter, iter_is_visible, findbar, NULL);
- gtk_tree_view_set_model (GTK_TREE_VIEW (logview->view), GTK_TREE_MODEL (log->filter));
+ filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (model, NULL));
+ gtk_tree_model_filter_set_visible_func (filter, iter_is_visible, findbar, NULL);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (logview->view), GTK_TREE_MODEL (filter));
+ g_object_set (G_OBJECT (log), "filter", filter, NULL);
} else {
- gtk_tree_model_filter_refilter (log->filter);
+ gtk_tree_model_filter_refilter (filter);
}
gtk_tree_view_expand_all (GTK_TREE_VIEW (logview->view));
@@ -103,13 +117,19 @@ logview_findbar_entry_changed_cb (GtkEditable *editable,
LogviewFindBar *findbar = LOGVIEW_FINDBAR (data);
LogviewWindow *logview = LOGVIEW_WINDOW (findbar->priv->logview);
Log *log = logview->curlog;
+ GtkTreeModelFilter *filter;
gchar *search_string;
search_string = g_strdup (gtk_entry_get_text (GTK_ENTRY (findbar->priv->entry)));
+ g_object_get (G_OBJECT (log),
+ "filter", &filter,
+ NULL);
- if (strlen (search_string) == 0 && log->filter != NULL) {
- g_object_unref (log->filter);
- log->filter = NULL;
+ if (strlen (search_string) == 0 && filter != NULL) {
+ g_object_unref (filter);
+ g_object_set (G_OBJECT (log),
+ "filter", NULL,
+ NULL);
logview_repaint (logview);
return;
}
@@ -143,7 +163,7 @@ logview_findbar_connect (LogviewFindBar *findbar, LogviewWindow *logview)
static void
logview_findbar_init (LogviewFindBar *findbar)
{
- GtkWidget *label, *button;
+ GtkWidget *label;
findbar->priv = g_new0 (LogviewFindBarPriv, 1);
diff --git a/logview/logview-iface-collector.c b/logview/logview-iface-collector.c
new file mode 100644
index 0000000..3d97d6f
--- /dev/null
+++ b/logview/logview-iface-collector.c
@@ -0,0 +1,99 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#include "logview-iface.h"
+#include "logview-iface-collector.h"
+#include "logview-debug.h"
+
+static void
+logview_iface_base_init (gpointer gclass)
+{
+ static gboolean initialized = FALSE;
+ if (!initialized) {
+ initialized = TRUE;
+ }
+}
+
+static void
+logview_iface_class_init (gpointer g_class, gpointer g_class_data)
+{
+ LogviewIFaceCollector *self = (LogviewIFaceCollector *)g_class;
+ self->config_log = NULL;
+ self->config_log_from_path = NULL;
+ self->config_log = NULL;
+}
+
+GType
+logview_iface_collector_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (LogviewIFaceCollector),
+ logview_iface_base_init, /* base_init */
+ NULL, /* base_finalize */
+ logview_iface_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_INTERFACE,
+ g_intern_static_string ("LogviewIFaceCollectorType"),
+ &info, 0);
+ g_type_interface_add_prerequisite (type, LOGVIEW_TYPE_IFACE);
+ }
+ return type;
+}
+
+/**
+ * logi_get_logs:
+ * @self: a #LogviewICollector instance.
+ *
+ * Gnome System Log get logs by invoking this routine.
+ *
+ * Returns: a single list, each element is a string represents a log name.
+ **/
+GSList*
+logi_get_logs (LogviewICollector *self)
+{
+ LV_MARK;
+ return LOGVIEW_GET_COLLECTOR_INTERFACE (self)->get_logs(self);
+}
+
+/**
+ * logi_config_log_from_path:
+ * @self: a #LogviewICollector instance.
+ * @log_name: log name which is obtained from logi_get_logs().
+ *
+ * Gnome System Log tries to config a log instance by passing the log name to this routine.
+ *
+ * Returns: On successful completion, returns a #Log instance; else returns NULL.
+ **/
+Log*
+logi_config_log_from_path (LogviewICollector *self, const gchar *log_name)
+{
+ LV_MARK;
+ return LOGVIEW_GET_COLLECTOR_INTERFACE (self)->config_log_from_path (self, log_name);
+}
+
+/**
+ * logi_config_log:
+ * @self: a #LogviewICollector instance.
+ * @log: a #Log instance.
+ *
+ * Gnome System Log tries to config a log instance by passing the @log to this routine.
+ *
+ * Returns: On successful completion, returns TRUE; else returns FALSE.
+ **/
+gboolean
+logi_config_log (LogviewICollector *self, Log *log)
+{
+ LV_MARK;
+ return LOGVIEW_GET_COLLECTOR_INTERFACE (self)->config_log (self, log);
+}
+
diff --git a/logview/logview-iface-collector.h b/logview/logview-iface-collector.h
new file mode 100644
index 0000000..495301a
--- /dev/null
+++ b/logview/logview-iface-collector.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifndef __LOGVIEW_IFACE_COLLECTOR_H__
+#define __LOGVIEW_IFACE_COLLECTOR_H__
+
+#include <glib-object.h>
+#include "logview-log.h"
+
+G_BEGIN_DECLS
+
+#define LOGVIEW_TYPE_IFACE_COLLECTOR \
+ (logview_iface_collector_get_type ())
+#define LOGVIEW_IFACE_COLLECTOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), LOGVIEW_TYPE_IFACE_COLLECTOR, \
+ LogviewICollector))
+#define LOGVIEW_IS_IFACE_COLLECTOR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), LOGVIEW_TYPE_IFACE_COLLECTOR))
+#define LOGVIEW_GET_COLLECTOR_INTERFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE((obj), LOGVIEW_TYPE_IFACE_COLLECTOR, \
+ LogviewIFaceCollector))
+
+typedef struct _LogviewICollector LogviewICollector; /* dummy object */
+typedef struct _LogviewIFaceCollector LogviewIFaceCollector;
+
+struct _LogviewIFaceCollector {
+ GTypeInterface parent;
+
+ /* Generate a new list of log names, need be freed */
+ GSList* (*get_logs) (LogviewICollector *self);
+
+ /* Create a log instance from path name, returns NULL if fails. */
+ Log* (*config_log_from_path) (LogviewICollector *self,
+ const gchar *log_name);
+
+ /* configure a log instance */
+ gboolean (*config_log) (LogviewICollector *self, Log *log);
+};
+
+extern GType logview_iface_collector_get_type (void) G_GNUC_CONST;
+
+/* for logview application internal usage */
+extern GSList* logi_get_logs (LogviewICollector *self);
+extern Log* logi_config_log_from_path (LogviewICollector *self,
+ const gchar *log_name);
+extern gboolean logi_config_log (LogviewICollector *self, Log *log);
+
+G_END_DECLS
+
+#endif /* __LOGVIEW_IFACE_COLLECTOR_H__ */
diff --git a/logview/logview-iface-io.c b/logview/logview-iface-io.c
new file mode 100644
index 0000000..ddfd532
--- /dev/null
+++ b/logview/logview-iface-io.c
@@ -0,0 +1,212 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#include "logview-iface.h"
+#include "logview-iface-io.h"
+#include "logview-debug.h"
+
+static void
+logview_iface_base_init (gpointer gclass)
+{
+ static gboolean initialized = FALSE;
+ if (!initialized) {
+ initialized = TRUE;
+ }
+}
+
+static void
+logview_iface_class_init (gpointer g_class, gpointer g_class_data)
+{
+ LogviewIFaceIO *self = (LogviewIFaceIO *)g_class;
+ self->can_monitor = NULL;
+ self->extract_filepath = NULL;
+ self->has_updated = NULL;
+ self->update = NULL;
+ self->read = NULL;
+ self->seek = NULL;
+ self->tell = NULL;
+ self->get_size = NULL;
+ self->get_modified_time = NULL;
+}
+
+GType
+logview_iface_io_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (LogviewIFaceIO),
+ logview_iface_base_init, /* base_init */
+ NULL, /* base_finalize */
+ logview_iface_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_INTERFACE,
+ g_intern_static_string ("LogviewIFaceIOType"),
+ &info, 0);
+ g_type_interface_add_prerequisite (type, LOGVIEW_TYPE_IFACE);
+ }
+ return type;
+}
+
+/**
+ * logi_can_monitor:
+ * @self: a #LogviewIIO instance.
+ *
+ * Check whether @self can be monitored.
+ *
+ * Returns: Return TRUE, if it can.
+ **/
+gboolean
+logi_can_monitor (LogviewIIO *self)
+{
+ LogviewIFaceIO *iface = LOGVIEW_GET_IO_INTERFACE (self);
+ LV_MARK;
+ return iface->can_monitor(self);
+}
+
+/**
+ * logi_has_updated:
+ * @self: a #LogviewIIO instance.
+ *
+ * Check if @self has changed since last reading happens.
+ *
+ * Returns: Return TRUE, if it can.
+ * */
+gboolean
+logi_has_updated (LogviewIIO *self)
+{
+ LV_MARK;
+ return LOGVIEW_GET_IO_INTERFACE (self)->has_updated(self);
+}
+
+/**
+ * logi_has_updated:
+ * @self: a #LogviewIIO instance.
+ *
+ * Update @self to a new state, do not report True
+ * if call logi_has_updated() any more except a new change is made to @self.
+ */
+void
+logi_update (LogviewIIO *self)
+{
+ LV_MARK;
+ LOGVIEW_GET_IO_INTERFACE (self)->update(self);
+}
+
+/**
+ * logi_read:
+ * @self: a #LogviewIIO instance.
+ * @buffer: a buffer.
+ * @size: the length of the @buffer.
+ *
+ * read, seek, tell are similiar to Standard C read, fseek, ftell.
+ * whence := SEEK_SET | SEEK_CUR | SEEK_END
+ * returns -1 if met error.
+ * but no errno currently.
+ *
+ * Returns: Upon successful completion, logi_read() returns the size of
+ * successfully read. If @size is equal to 0, logi_read() returns 0 and
+ * the contents of the @buffer remain unchanged. Otherwise, if a read error
+ * occurs, returns -1.
+ */
+size_t
+logi_read (LogviewIIO *self, void* buffer, size_t size)
+{
+ LV_MARK;
+ return LOGVIEW_GET_IO_INTERFACE (self)->read(self, buffer, size);
+}
+
+/**
+ * logi_seek:
+ * @self: a #LogviewIIO instance.
+ * @offset: a offset.
+ * @whence: like fseek, accept SEEK_SET | SEEK_CUR | SEEK_END.
+ *
+ * read, seek, tell are similiar to Standard C read, fseek, ftell.
+ * but no errno currently.
+ *
+ * Returns: -1 if met error.
+ */
+off_t
+logi_seek (LogviewIIO *self, off_t offset, int whence)
+{
+ LV_MARK;
+ return LOGVIEW_GET_IO_INTERFACE (self)->seek(self, offset, whence);
+}
+
+/**
+ * logi_tell:
+ * @self: a #LogviewIIO instance.
+ *
+ * read, seek, tell are similiar to Standard C read, fseek, ftell.
+ * but no errno currently.
+ *
+ * Returns: On successful completion, returns the current offset
+ * opposite to the log head; returns -1 if met error.
+ */
+off_t
+logi_tell (LogviewIIO *self)
+{
+ LV_MARK;
+ return LOGVIEW_GET_IO_INTERFACE (self)->tell(self);
+}
+
+/**
+ * logi_get_size:
+ * @self: a #LogviewIIO instance.
+ *
+ * Depends on logi_update(), report the size in one state of @self.
+ *
+ * Returns: On successful completion, returns the current size of @self,
+ * else returns 0.
+ **/
+off_t
+logi_get_size (LogviewIIO* self)
+{
+ LV_MARK;
+ return LOGVIEW_GET_IO_INTERFACE (self)->get_size(self);
+}
+
+/**
+ * logi_get_modified_time:
+ * @self: a #LogviewIIO instance.
+ *
+ * Depends on logi_update(), report the modified time in one state of @self.
+ *
+ * Returns: On successful completion, returns the current size of @self,
+ * else returns 0.
+ **/
+time_t
+logi_get_modified_time (LogviewIIO* self)
+{
+ LV_MARK;
+ return LOGVIEW_GET_IO_INTERFACE (self)->get_modified_time(self);
+}
+
+/**
+ * logi_extract_filepath:
+ * @self: a #LogviewIIO instance.
+ * @dirname: returns a pointer points to the new alloc buffer
+ * contains the path name of @self.
+ * If passes NULL, the plugin should ignore this argument.
+ * @filename: returns a pointer points to the new alloc buffer
+ * contains the file name of @self.
+ * If passes NULL, the plugin should ignore this argument.
+ *
+ * Extract the path name and the file name from $self, which will be displayed on
+ * Gnome System Log left tree pane.
+ **/
+void
+logi_extract_filepath (LogviewIIO *self, gchar** dirname, gchar** filename)
+{
+ LV_MARK;
+ LOGVIEW_GET_IO_INTERFACE (self)->extract_filepath(self, dirname, filename);
+}
diff --git a/logview/logview-iface-io.h b/logview/logview-iface-io.h
new file mode 100644
index 0000000..1ae5526
--- /dev/null
+++ b/logview/logview-iface-io.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifndef __LOGVIEW_IFACE_IO_H__
+#define __LOGVIEW_IFACE_IO_H__
+
+#include <sys/types.h>
+#include <glib-object.h>
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define LOGVIEW_TYPE_IFACE_IO \
+ (logview_iface_io_get_type ())
+#define LOGVIEW_IFACE_IO(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_IFACE_IO, \
+ LogviewIIO))
+#define LOGVIEW_IS_IFACE_IO(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_IFACE_IO))
+#define LOGVIEW_GET_IO_INTERFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE ((obj), LOGVIEW_TYPE_IFACE_IO, \
+ LogviewIFaceIO))
+
+typedef struct _LogviewIIO LogviewIIO; /* dummy object */
+typedef struct _LogviewIFaceIO LogviewIFaceIO;
+
+struct _LogviewIFaceIO {
+ GTypeInterface parent;
+
+ gboolean (*can_monitor) (LogviewIIO *self);
+ void (*extract_filepath) (LogviewIIO *self,
+ gchar** dirname, gchar** filename);
+ gboolean (*has_updated) (LogviewIIO *self);
+ void (*update) (LogviewIIO *self);
+ size_t (*read) (LogviewIIO *self, void* buffer, size_t size);
+ off_t (*seek) (LogviewIIO *self, off_t offset, int whence);
+ off_t (*tell) (LogviewIIO *self);
+ off_t (*get_size) (LogviewIIO* self);
+ time_t (*get_modified_time) (LogviewIIO* self);
+
+};
+
+extern GType logview_iface_io_get_type (void) G_GNUC_CONST;
+
+/* for logview application internal usage */
+extern gboolean logi_can_monitor (LogviewIIO *self);
+extern void logi_extract_filepath (LogviewIIO *self,
+ gchar** dirname, gchar** filename);
+extern gboolean logi_has_updated (LogviewIIO *self);
+extern void logi_update (LogviewIIO *self);
+extern size_t logi_read (LogviewIIO *self, void* buffer, size_t size);
+extern off_t logi_seek (LogviewIIO *self, off_t offset, int whence);
+extern off_t logi_tell (LogviewIIO *self);
+extern off_t logi_get_size (LogviewIIO* self);
+extern time_t logi_get_modified_time (LogviewIIO* self);
+
+G_END_DECLS
+
+#endif /* __LOGVIEW_IFACE_H__ */
diff --git a/logview/logview-iface-view.c b/logview/logview-iface-view.c
new file mode 100644
index 0000000..5e3b55c
--- /dev/null
+++ b/logview/logview-iface-view.c
@@ -0,0 +1,87 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#include "logview-iface.h"
+#include "logview-iface-view.h"
+#include "logview-debug.h"
+
+static void
+logview_iface_base_init (gpointer gclass)
+{
+ static gboolean initialized = FALSE;
+ if (!initialized) {
+ initialized = TRUE;
+ }
+}
+
+static void
+logview_iface_class_init (gpointer g_class, gpointer g_class_data)
+{
+ LogviewIFaceView *self = (LogviewIFaceView *)g_class;
+ self->group_lines = NULL;
+ self->to_utf8 = NULL;
+}
+
+GType
+logview_iface_view_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (LogviewIFaceView),
+ logview_iface_base_init, /* base_init */
+ NULL, /* base_finalize */
+ logview_iface_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_INTERFACE,
+ g_intern_static_string ("LogviewIFaceViewType"),
+ &info, 0);
+ g_type_interface_add_prerequisite (type, LOGVIEW_TYPE_IFACE);
+ }
+ return type;
+}
+
+/**
+ * logi_group_lines:
+ * @self: a #LogviewIView instance.
+ * @lines: an array of strings, terminates in NULL.
+ *
+ * Passes an array of strings to logi_group_lines(),
+ * the plugin should try to group these strings by date.
+ *
+ * Returns: a single list with each element is a #Day object.
+ **/
+GSList*
+logi_group_lines (LogviewIView *self, const gchar **lines)
+{
+ LV_MARK;
+ return LOGVIEW_GET_VIEW_INTERFACE (self)->group_lines(self, lines);
+}
+
+/**
+ * logi_to_utf8:
+ * @self: a #LogviewIView instance.
+ * @str: a string.
+ * @size: the length of @str.
+ *
+ * Gnome System Log will call this routine before displays the string on the screen.
+ *
+ * Returns: a converted string, which will be freed by Gnome System Log.
+ **/
+gchar*
+logi_to_utf8 (LogviewIView *self, gchar *str, gssize size)
+{
+ LogviewIFaceView *iface = LOGVIEW_GET_VIEW_INTERFACE (self);
+ LV_MARK;
+ if (iface->to_utf8)
+ return iface->to_utf8 (self, str, size);
+ return str;
+}
diff --git a/logview/logview-iface-view.h b/logview/logview-iface-view.h
new file mode 100644
index 0000000..b32330b
--- /dev/null
+++ b/logview/logview-iface-view.h
@@ -0,0 +1,54 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifndef __LOGVIEW_IFACE_VIEW_H__
+#define __LOGVIEW_IFACE_VIEW_H__
+
+#include <glib-object.h>
+#include "logview-log.h"
+
+G_BEGIN_DECLS
+
+#define LOGVIEW_TYPE_IFACE_VIEW \
+ (logview_iface_view_get_type ())
+#define LOGVIEW_IFACE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), LOGVIEW_TYPE_IFACE_VIEW, \
+ LogviewIView))
+#define LOGVIEW_IS_IFACE_VIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), LOGVIEW_TYPE_IFACE_VIEW))
+#define LOGVIEW_GET_VIEW_INTERFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE((obj), LOGVIEW_TYPE_IFACE_VIEW, \
+ LogviewIFaceView))
+
+typedef struct _LogviewIView LogviewIView;
+typedef struct _LogviewIFaceView LogviewIFaceView;
+
+struct _LogviewIFaceView {
+ GTypeInterface parent;
+
+ /*
+ Create a list, each element is a group entry,
+ each group entry has a log list, do not free mass.
+ returns NULL if failed.
+ */
+ GSList* (*group_lines) (LogviewIView *self, const gchar **lines);
+
+ /*
+ If possible, convert a string to utf8, free the original
+ string, return the new one.
+ */
+ gchar* (*to_utf8) (LogviewIView *self, gchar *str, gssize size);
+};
+
+extern GType logview_iface_view_get_type (void) G_GNUC_CONST;
+
+/* for logview application internal usage */
+extern GSList* logi_group_lines (LogviewIView *self, const gchar **lines);
+extern gchar* logi_to_utf8 (LogviewIView *self, gchar *str, gssize size);
+
+G_END_DECLS
+
+#endif /* __LOGVIEW_IFACE_VIEW_H__ */
+
diff --git a/logview/logview-iface.c b/logview/logview-iface.c
new file mode 100644
index 0000000..865073a
--- /dev/null
+++ b/logview/logview-iface.c
@@ -0,0 +1,69 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+
+#include "logview-iface.h"
+#include "logview-debug.h"
+
+static void
+logview_iface_base_init (gpointer gclass)
+{
+ static gboolean initialized = FALSE;
+ if (!initialized) {
+ initialized = TRUE;
+ }
+}
+
+static void
+logview_iface_class_init (gpointer g_class, gpointer g_class_data)
+{
+ LogviewInterface *self = (LogviewInterface *)g_class;
+ self->can_handle = NULL;
+}
+
+GType
+logview_iface_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (LogviewInterface),
+ logview_iface_base_init, /* base_init */
+ NULL, /* base_finalize */
+ logview_iface_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ 0,
+ 0, /* n_preallocs */
+ NULL /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_INTERFACE,
+ g_intern_static_string ("LogviewInterfaceType"),
+ &info, 0);
+ }
+ return type;
+}
+
+/**
+ * logi_can_handle:
+ * @self: a #LogviewIFace instance.
+ * @log: a #Log instance.
+ *
+ * Check whether the @log can be handled.
+ *
+ * Returns: If this interface is not overwritten,
+ * it default returns TRUE means the @log can be recognized.
+ **/
+gboolean
+logi_can_handle (LogviewIFace *self, struct _Log* log)
+{
+ LogviewInterface *iface = LOGVIEW_GET_INTERFACE (self);
+ //LV_MARK;
+ if (iface->can_handle)
+ return (iface)->can_handle(self, log);
+ return TRUE;
+}
+
diff --git a/logview/logview-iface.h b/logview/logview-iface.h
new file mode 100644
index 0000000..cb8b2b8
--- /dev/null
+++ b/logview/logview-iface.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifndef __LOGVIEW_IFACE_H__
+#define __LOGVIEW_IFACE_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define LOGVIEW_TYPE_IFACE \
+ (logview_iface_get_type ())
+#define LOGVIEW_IFACE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), LOGVIEW_TYPE_IFACE, \
+ LogviewIFace))
+#define LOGVIEW_IS_IFACE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), LOGVIEW_TYPE_IFACE))
+#define LOGVIEW_GET_INTERFACE(obj) \
+ (G_TYPE_INSTANCE_GET_INTERFACE((obj), LOGVIEW_TYPE_IFACE, \
+ LogviewInterface))
+
+struct _Log;
+
+typedef struct _LogviewIFace LogviewIFace; /* dummy object */
+typedef struct _LogviewInterface LogviewInterface;
+
+struct _LogviewInterface {
+ GTypeInterface parent;
+
+ gboolean (*can_handle) (LogviewIFace *self, struct _Log* log);
+};
+
+GType logview_iface_get_type (void);
+
+/* for logview application internal usage */
+gboolean logi_can_handle (LogviewIFace *self, struct _Log* log);
+
+G_END_DECLS
+
+#endif /* __LOGVIEW_IFACE_H__ */
+
diff --git a/logview/logview-log.h b/logview/logview-log.h
new file mode 100644
index 0000000..cadd1e8
--- /dev/null
+++ b/logview/logview-log.h
@@ -0,0 +1,207 @@
+/* ----------------------------------------------------------------------
+
+ Copyright (C) 1998 Cesar Miquel (miquel@df.uba.ar)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ---------------------------------------------------------------------- */
+
+#ifndef __LOGVIEW_LOG_H__
+#define __LOGVIEW_LOG_H__
+
+#include <time.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+#include "logview-plugin.h"
+#include "logview-iface.h"
+
+G_BEGIN_DECLS
+
+#define LOGVIEW_TYPE_LOG (log_get_type ())
+#define LOGVIEW_LOG(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), LOGVIEW_TYPE_LOG, Log))
+#define LOGVIEW_LOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), LOGVIEW_TYPE_LOG, LogClass))
+#define LOGVIEW_IS_LOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), LOGVIEW_TYPE_LOG))
+#define LOGVIEW_IS_LOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), LOGVIEW_TYPE_LOG))
+#define LOGVIEW_LOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), LOGVIEW_TYPE_LOG, LogClass))
+
+typedef struct _Log Log;
+typedef struct _LogClass LogClass;
+typedef struct _LogPrivate LogPrivate;
+
+struct _Log
+{
+ GObject parent;
+ /*< private >*/
+ LogPrivate *prv;
+};
+
+struct _LogClass {
+ GObjectClass parent;
+};
+
+/**
+ * LogProtocol:
+ * @UNKNOWN_LOG: represents the log can't be recognized.
+ * But still has the opportunity to be handled by other plugins.
+ * @BAD_LOG: represents the log is not a log or a bad log.
+ * If in one time a log is marked with this, it's permanently
+ * ignored and removed from the log name list.
+ * @PLAIN_LOG: a ASCII log.
+ * @GZIP_LOG: a zipped or gzipped log.
+ * @PIPE_LOG: a log can be open by other command.
+ * @USER_DEFINED_LOG: a plugin can define a log protocol for itself,
+ * e.g. %USER_DEFINED_LOG + 1.
+ */
+typedef enum {
+ UNKNOWN_LOG=0,
+ BAD_LOG,
+ PLAIN_LOG,
+ GZIP_LOG,
+ PIPE_LOG,
+ USER_DEFINED_LOG
+} LogProtocol;
+
+typedef enum {
+ TH_EVENT_EMPTY = 0,
+ TH_EVENT_INIT_READ = 1<<1,
+ TH_EVENT_UPDATE = 1<<2,
+ TH_EVENT_EXIT = 1<<8
+} ThreadEvent;
+
+/**
+ * Day:
+ * @date: a date, without time value.
+ * @first_line: First line for this day in the log.
+ * @last_line: Last line for this day in the log.
+ * @expand: Collapse all the logs in this @date if %FALSE, else expand all.
+ * @path: Gtk tree path of the day item display in main view of the log.
+ *
+ * A structure used for grouping and recording the logs by date.
+ */
+typedef struct _Day
+{
+ GDate *date;
+ long first_line, last_line;
+ gboolean expand;
+ GtkTreePath *path;
+} Day;
+
+#define OLD_LOG_NUM 5
+
+/**
+ * log_io:
+ * @log: a #Log instance.
+ *
+ * Returns: the %PF_LOG_IO type plugin.
+ */
+#define log_io(log) (LOGVIEW_IFACE_IO (log->prv->ext_data [PF_LOG_IO]))
+
+/**
+ * log_view:
+ * @log: a #Log instance.
+ *
+ * Returns: the %PF_LOG_VIEW type plugin.
+ */
+#define log_view(log) (LOGVIEW_IFACE_VIEW (log->prv->ext_data [PF_LOG_VIEW]))
+
+/**
+ * log_name:
+ * @self: a #Log instance.
+ *
+ * Get the log name.
+ *
+ * Returns: a constant string which should not be free.
+ */
+
+/**
+ * log_get_protocol:
+ * @self: a #Log instance.
+ *
+ * Get the #LogProtocol value of self's.
+ *
+ * Returns: the #LogProtocol value.
+ */
+
+/**
+ * log_set_protocol:
+ * @self: a #Log instance.
+ * @protocol: a #LogProtocol value.
+ *
+ * Set the #LogProtocol value of self's.
+ */
+
+/**
+ * is_log:
+ * @log: a #Log instance.
+ *
+ * Determining whether @log is a #Log instance.
+ *
+ * Returns: TRUE if it is.
+ */
+
+
+/**
+ * log_set_child:
+ * @self: a #Log instance.
+ * @index: the child log id. it should be no less than zero and less #OLD_LOG_NUM
+ * @child: a #Log instance.
+ *
+ * Access child log instances.
+ */
+void log_set_child (Log *self, gint index, Log *child);
+
+/**
+ * log_get_child:
+ * @self: a #Log instance.
+ * @index: the child log id. it should be no less than zero and less #OLD_LOG_NUM
+ *
+ * Access child log instances.
+ *
+ * Returns: the child #Log instance.
+ */
+Log* log_get_child (Log *self, gint index);
+
+/**
+ * log_test_func:
+ * @self: a #Log instance.
+ * @pf: a #PluginFunc index.
+ *
+ * Returns: if a #pf type plugin is assigned to #self, returns TRUE.
+ */
+gboolean log_test_func (Log *self, PluginFunc pf);
+
+/**
+ * log_set_func:
+ * @self: a #Log instance.
+ * @pf: a #PluginFunc index.
+ * @plugin: a #LogviewPlugin instance.
+ *
+ * Assign a #pf type plugin to #self.
+ */
+void log_set_func (Log *self, PluginFunc pf, LogviewPlugin *plugin);
+
+void log_notify (Log *self, ThreadEvent te);
+gchar *log_read (Log *self);
+void log_write_line (Log *self, gchar *line);
+void log_write_lines (Log *self, gchar **lines, gint num);
+void log_write_lines_range (Log *self, gchar **lines, gint start, gint end);
+void log_write_date (Log *self, GDate *date);
+void log_write_day (Log *self, Day *day);
+
+extern GType log_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __LOGVIEW_LOG_H__ */
diff --git a/logview/logview-module.c b/logview/logview-module.c
new file mode 100644
index 0000000..a231ec0
--- /dev/null
+++ b/logview/logview-module.c
@@ -0,0 +1,160 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+
+#include "logview-module.h"
+#include "logview-debug.h"
+
+/* default routines for implement the plugin interfaces */
+static gboolean logview_module_load (LogviewModule* self);
+static void logview_module_unload (LogviewModule* self);
+static void logview_module_class_init (gpointer g_class, gpointer g_class_data);
+static void logview_module_instance_init (GTypeInstance *instance, gpointer g_class);
+
+static GObjectClass *parent_class = NULL;
+
+struct _LogviewModulePrivate {
+ GModule *handle;
+ GType type;
+ LogviewPluginInfo *info;
+};
+
+static void
+module_finalize (LogviewModule* self)
+{
+ g_free (self->prv);
+ parent_class->finalize (G_OBJECT (self));
+}
+
+static void
+logview_module_class_init (gpointer g_class, gpointer g_class_data)
+{
+ GObjectClass *object_class;
+ GTypeModuleClass *self;
+
+ object_class = G_OBJECT_CLASS (g_class);
+ self = G_TYPE_MODULE_CLASS (g_class);
+ parent_class = g_type_class_peek_parent (g_class);
+ object_class->finalize = (void (*)(GObject*)) module_finalize;
+
+ self->load = (gboolean (*)(GTypeModule*)) logview_module_load;
+ self->unload = (void (*)(GTypeModule*)) logview_module_unload;
+}
+
+static void
+logview_module_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+ LogviewModule *self = LOGVIEW_MODULE (instance);
+ self->prv = g_new0 (LogviewModulePrivate, 1);
+}
+
+GType
+logview_module_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (LogviewModuleClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ logview_module_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (LogviewModule),
+ 0, /* n_preallocs */
+ logview_module_instance_init /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_TYPE_MODULE, "LogviewModuleType", &info, 0);
+ }
+ return type;
+}
+
+LogviewModule*
+logview_new_module (const gchar* module_path)
+{
+ LogviewModule* new_module = NULL;
+
+ LV_MARK;
+ g_assert (module_path != NULL);
+ new_module = g_object_new (LOGVIEW_TYPE_MODULE, NULL);
+ g_type_module_set_name (G_TYPE_MODULE (new_module), module_path);
+ return new_module;
+}
+
+LogviewPlugin*
+logview_module_new_plugin (const LogviewModule* self)
+{
+ LogviewPlugin *plugin;
+ LV_MARK;
+ g_assert (self->prv->type != 0);
+ plugin = g_object_new (self->prv->type, NULL);
+ g_assert (LOGVIEW_IS_PLUGIN(plugin));
+ return LOGVIEW_PLUGIN (plugin);
+}
+
+static gboolean
+logview_module_load (LogviewModule* self)
+{
+ GType (*register_logview_plugin)(GTypeModule*);
+ LogviewPluginInfo *(*logview_plugin_info)();
+
+ LV_MARK;
+
+ self->prv->handle = g_module_open (logview_module_name (self), G_MODULE_BIND_LOCAL);
+ if (self->prv->handle !=NULL) {
+ gboolean hit;
+ hit = g_module_symbol (self->prv->handle, "register_logview_plugin", (gpointer*)(&register_logview_plugin));
+ g_return_val_if_fail (hit != FALSE, FALSE);
+ hit = g_module_symbol (self->prv->handle, "logview_plugin_info", (gpointer*)(&logview_plugin_info));
+ g_return_val_if_fail (hit != FALSE, FALSE);
+
+ self->prv->type = (*register_logview_plugin) ((GTypeModule*) self);
+ self->prv->info = (*logview_plugin_info) ();
+
+ g_return_val_if_fail (self->prv->type != 0, FALSE);
+ g_return_val_if_fail (self->prv->info != NULL, FALSE);
+ return TRUE;
+ }
+ else {
+ LV_ERR ("logview_module_load error: %s", g_module_error());
+ }
+ return FALSE;
+}
+
+static void
+logview_module_unload (LogviewModule* self)
+{
+ LV_MARK;
+ g_module_close (self->prv->handle);
+ self->prv->handle = NULL;
+ self->prv->type = 0;
+ self->prv->info = NULL;
+}
+
+const gchar*
+logview_module_name (LogviewModule *self)
+{
+ g_assert (G_IS_TYPE_MODULE (self));
+ return G_TYPE_MODULE (self)->name;
+}
+
+GType
+logview_module_type (LogviewModule *self)
+{
+ return self->prv->type;
+}
+
+PluginPrio
+logview_module_priority (LogviewModule *self)
+{
+ return self->prv->info->prio;
+}
+
+const gchar*
+logview_module_desc (LogviewModule *self)
+{
+ return self->prv->info->desc;
+}
diff --git a/logview/logview-module.h b/logview/logview-module.h
new file mode 100644
index 0000000..52fe388
--- /dev/null
+++ b/logview/logview-module.h
@@ -0,0 +1,50 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifndef __LOGVIEW_MODULE_H__
+#define __LOGVIEW_MODULE_H__
+
+#include <glib-object.h>
+#include <gmodule.h>
+#include "logview-plugin.h"
+
+#define LOGVIEW_TYPE_MODULE (logview_module_get_type ())
+#define LOGVIEW_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_MODULE, LogviewModule))
+#define LOGVIEW_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_MODULE, LogviewModuleClass))
+#define LOGVIEW_IS_MODULE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_MODULE))
+#define LOGVIEW_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_MODULE))
+#define LOGVIEW_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_MODULE, LogviewModuleClass))
+
+typedef struct _LogviewModule LogviewModule;
+typedef struct _LogviewModuleClass LogviewModuleClass;
+typedef struct _LogviewModulePrivate LogviewModulePrivate;
+
+struct _LogviewModule{
+ GTypeModule parent;
+ /* instance members */
+/* private */
+ LogviewModulePrivate *prv;
+};
+
+struct _LogviewModuleClass {
+ GTypeModuleClass parent;
+ /* class members */
+};
+
+
+/* For the core application which should implemete the level to call plugins */
+GType logview_module_get_type (void);
+/* return the name of the module, should not be freed */
+const gchar* logview_module_name (LogviewModule *self);
+GType logview_module_type (LogviewModule *self);
+PluginPrio logview_module_priority (LogviewModule *self);
+const gchar* logview_module_desc (LogviewModule *self);
+/* return a new module */
+LogviewModule* logview_new_module (const gchar* module_path);
+/* return a new plugin */
+LogviewPlugin* logview_module_new_plugin (const LogviewModule* self);
+
+#endif /* __LOGVIEW_MODULE_H__ */
+
diff --git a/logview/logview-plugin-list.c b/logview/logview-plugin-list.c
new file mode 100644
index 0000000..3b79b02
--- /dev/null
+++ b/logview/logview-plugin-list.c
@@ -0,0 +1,280 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <glib/gi18n.h>
+#include "logview-plugin-list.h"
+#include "logview-plugin-manager.h"
+#include "logview-module.h"
+#include "misc.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+static void logview_plugin_list_init (LogviewPluginList *plugin_list);
+
+#define GLADE_HOOKUP_OBJECT(component,widget,name) \
+ g_object_set_data_full (G_OBJECT (component), name, \
+ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref)
+
+#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
+ g_object_set_data (G_OBJECT (component), name, widget)
+
+enum {
+ NAME_COL,
+ PRI_COL,
+ DESC_COL,
+ PATH_COL,
+ N_COLS
+};
+
+static void
+logview_plugin_list_sync_cb (const LogviewModule *module, gpointer data)
+{
+ GtkTreeIter iter;
+ gchar *name, *desc, *path;
+ gint pri;
+ LogviewPluginList *self = (LogviewPluginList*)data;
+
+ path = logview_module_name (module);
+ pri = logview_module_priority (module);
+ desc = logview_module_desc (module);
+ name = log_extract_filename (path);
+
+ gtk_tree_store_append (self->list, &iter, NULL);
+ gtk_tree_store_set (self->list, &iter,
+ NAME_COL, name,
+ PRI_COL, pri,
+ DESC_COL, desc,
+ PATH_COL, path,
+ -1);
+ g_free (name);
+}
+
+static void
+logview_plugin_list_sync (LogviewPluginList *self)
+{
+ gtk_widget_hide_all (self->scrolledwindow);
+ gtk_widget_hide_all (self->label);
+ gtk_tree_store_clear (self->list);
+ if (pluginmgr_plugin_amount () > 0) {
+ pluginmgr_modules_iterate (logview_plugin_list_sync_cb, self);
+ gtk_widget_show_all (self->scrolledwindow);
+ }
+ else
+ gtk_widget_show_all (self->label);
+
+}
+
+void
+logview_plugin_list_show (LogviewPluginList *self, GtkWidget *window)
+{
+ g_return_if_fail (GTK_IS_WINDOW (window));
+ gtk_widget_show_all (self->dialog);
+ logview_plugin_list_sync (self);
+}
+
+static gint
+logview_plugin_list_cmp (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ gint col_id = GPOINTER_TO_INT(user_data);
+ gint ret;
+
+ switch (col_id) {
+ case PATH_COL:
+ case NAME_COL: {
+ gchar *stra, *strb;
+ gtk_tree_model_get (model, a, (gint)user_data, &stra, -1);
+ gtk_tree_model_get (model, b, (gint)user_data, &strb, -1);
+ ret = g_ascii_strcasecmp (stra, strb);
+ g_free (stra);
+ g_free (strb);
+ }
+ break;
+ case PRI_COL: {
+ gint ia, ib;
+ gtk_tree_model_get (model, a, (gint)user_data, &ia, -1);
+ gtk_tree_model_get (model, b, (gint)user_data, &ib, -1);
+ ret = ia - ib;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ return ret;
+}
+
+static void
+logview_plugin_list_init (LogviewPluginList *self)
+{
+ GtkWidget *dialog_vbox3;
+ GtkWidget *dialog_action_area3;
+ GtkWidget *exist_button;
+ GtkTreeViewColumn *name_col, *pri_col, *path_col, *desc_col;
+ GtkCellRenderer *text_renderer;
+ GtkWidget *view;
+
+ self->list = gtk_tree_store_new (N_COLS,
+ G_TYPE_STRING,
+ G_TYPE_INT,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+ text_renderer = gtk_cell_renderer_text_new ();
+
+ view = g_object_new (GTK_TYPE_TREE_VIEW,
+ "model", self->list,
+ "rules-hint", TRUE,
+ "headers-clickable", TRUE,
+ "reorderable", TRUE,
+ NULL);
+
+ name_col = gtk_tree_view_column_new_with_attributes (_("Plugin Name"),
+ text_renderer,
+ "text", NAME_COL,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id (name_col, NAME_COL);
+
+ g_object_set (name_col,
+ "resizable", TRUE,
+ "clickable", TRUE,
+ "sort-indicator", TRUE,
+ "reorderable", TRUE,
+ NULL);
+ pri_col = gtk_tree_view_column_new_with_attributes (_("Priority"),
+ text_renderer,
+ "text", PRI_COL,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id (pri_col, PRI_COL);
+
+ g_object_set (pri_col,
+ "resizable", TRUE,
+ "clickable", TRUE,
+ "sort-indicator", TRUE,
+ "reorderable", TRUE,
+ NULL);
+ desc_col = gtk_tree_view_column_new_with_attributes (_("Description"),
+ text_renderer,
+ "text", DESC_COL,
+ NULL);
+ g_object_set (desc_col,
+ "resizable", TRUE,
+ "reorderable", TRUE,
+ NULL);
+
+ path_col = gtk_tree_view_column_new_with_attributes (_("Path"),
+ text_renderer,
+ "text", PATH_COL,
+ NULL);
+ g_object_set (path_col,
+ "resizable", TRUE,
+ "clickable", TRUE,
+ "sort-indicator", TRUE,
+ "reorderable", TRUE,
+ NULL);
+ gtk_tree_view_column_set_sort_column_id (path_col, PATH_COL);
+
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(self->list),
+ NAME_COL,
+ (GtkTreeIterCompareFunc) logview_plugin_list_cmp,
+ GINT_TO_POINTER(NAME_COL),
+ NULL);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(self->list),
+ PATH_COL,
+ (GtkTreeIterCompareFunc) logview_plugin_list_cmp,
+ GINT_TO_POINTER(PATH_COL),
+ NULL);
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE(self->list),
+ PRI_COL,
+ (GtkTreeIterCompareFunc) logview_plugin_list_cmp,
+ GINT_TO_POINTER(PRI_COL),
+ NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE(self->list), NAME_COL, GTK_SORT_ASCENDING);
+
+ gtk_tree_view_append_column (view, name_col);
+ gtk_tree_view_append_column (view, pri_col);
+ gtk_tree_view_append_column (view, desc_col);
+ gtk_tree_view_append_column (view, path_col);
+
+ self->dialog = gtk_dialog_new ();
+ gtk_dialog_set_has_separator (GTK_DIALOG (self->dialog), FALSE);
+ gtk_widget_set_size_request (self->dialog, 800, 400);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (self->dialog), TRUE);
+ gtk_window_set_title (GTK_WINDOW (self->dialog), _("Log Viewer Plugins"));
+ gtk_window_set_position (GTK_WINDOW (self->dialog),
+ GTK_WIN_POS_CENTER_ON_PARENT);
+ gtk_window_set_modal (GTK_WINDOW (self->dialog), TRUE);
+ gtk_window_set_resizable (GTK_WINDOW (self->dialog), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (self->dialog),
+ GDK_WINDOW_TYPE_HINT_DIALOG);
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (self->dialog), TRUE);
+
+ dialog_vbox3 = GTK_DIALOG (self->dialog)->vbox;
+
+ self->label = gtk_label_new (_("No plugins installed!"));
+ gtk_widget_show (self->label);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox3), self->label, TRUE, TRUE, 0);
+
+ self->scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox3), self->scrolledwindow,
+ TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (self->scrolledwindow),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (self->scrolledwindow),
+ GTK_SHADOW_NONE);
+ gtk_container_add (GTK_CONTAINER (self->scrolledwindow), view);
+
+ dialog_action_area3 = GTK_DIALOG (self->dialog)->action_area;
+ gtk_container_set_border_width (GTK_CONTAINER (self->scrolledwindow), 12);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area3),
+ GTK_BUTTONBOX_END);
+
+ exist_button = gtk_button_new_from_stock ("gtk-close");
+ gtk_dialog_add_action_widget (GTK_DIALOG (self->dialog),
+ exist_button, GTK_RESPONSE_CLOSE);
+ GTK_WIDGET_SET_FLAGS (exist_button, GTK_CAN_DEFAULT);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (self->dialog, dialog_vbox3, "dialog_vbox3");
+ GLADE_HOOKUP_OBJECT (self->dialog, self->scrolledwindow, "scrolledwindow");
+ GLADE_HOOKUP_OBJECT (self->dialog, view, "treeview1");
+ GLADE_HOOKUP_OBJECT_NO_REF (self->dialog, dialog_action_area3, "dialog_action_area3");
+ GLADE_HOOKUP_OBJECT (self->dialog, exist_button, "exist_button");
+ GLADE_HOOKUP_OBJECT (self->dialog, self->label, "label1");
+
+ g_signal_connect_swapped (exist_button, "clicked",
+ G_CALLBACK(gtk_widget_hide_all),
+ self->dialog);
+ g_signal_connect_swapped (self->dialog, "delete-event",
+ G_CALLBACK(gtk_widget_hide_on_delete),
+ self->dialog);
+
+}
+
+LogviewPluginList *
+logview_plugin_list_new (void)
+{
+ LogviewPluginList * list;
+ list = g_new0 (LogviewPluginList, 1);
+ logview_plugin_list_init (list);
+ return list;
+}
+
+void
+logview_plugin_list_delete (LogviewPluginList * list)
+{
+ g_free (list);
+}
diff --git a/logview/logview-plugin-list.h b/logview/logview-plugin-list.h
new file mode 100644
index 0000000..64a0d98
--- /dev/null
+++ b/logview/logview-plugin-list.h
@@ -0,0 +1,23 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifndef __LOGVIEW_PLUGIN_LIST_H__
+#define __LOGVIEW_PLUGIN_LIST_H__
+
+#include <gtk/gtk.h>
+
+typedef struct _LogviewPluginList LogviewPluginList;
+struct _LogviewPluginList {
+ GtkTreeStore *list;
+ GtkWidget *scrolledwindow;
+ GtkWidget *label;
+ GtkWidget *dialog;
+};
+
+void logview_plugin_list_show (LogviewPluginList *self, GtkWidget *window);
+LogviewPluginList *logview_plugin_list_new (void);
+void logview_plugin_list_delete (LogviewPluginList *);
+
+#endif /* __LOGVIEW_PLUGIN_LIST_H__ */
diff --git a/logview/logview-plugin-manager.c b/logview/logview-plugin-manager.c
new file mode 100644
index 0000000..58cf886
--- /dev/null
+++ b/logview/logview-plugin-manager.c
@@ -0,0 +1,529 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/utsname.h>
+#include "logview-module.h"
+#include "logview-plugin-manager.h"
+#include "logview-iface-io.h"
+#include "logview-iface-view.h"
+#include "logview-iface-collector.h"
+#include "logview-debug.h"
+#include "misc.h"
+
+#define LOGVIEW_TYPE_PLUGINMGR (logview_pluginmgr_get_type ())
+#define LOGVIEW_PLUGINMGR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), LOGVIEW_TYPE_PLUGINMGR, LogviewPluginMgr))
+#define LOGVIEW_PLUGINMGR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), LOGVIEW_TYPE_PLUGINMGR, LogviewPluginMgrClass))
+#define LOGVIEW_IS_PLUGINMGR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), LOGVIEW_TYPE_PLUGINMGR))
+#define LOGVIEW_IS_PLUGINMGR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), LOGVIEW_TYPE_PLUGINMGR))
+#define LOGVIEW_PLUGINMGR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), LOGVIEW_TYPE_PLUGINMGR, LogviewPluginMgrClass))
+
+static GType logview_pluginmgr_get_type (void);
+static void pluginmgr_class_init (gpointer g_class, gpointer g_class_data);
+static void pluginmgr_instance_init (GTypeInstance *instance, gpointer g_class);
+
+static gboolean load_module(LogviewPluginMgr *self, const gchar* module_path);
+static void unload_module (LogviewPluginMgr *self, LogviewModule* plugin_info);
+static gboolean load_modules (LogviewPluginMgr *self);
+static void unload_modules (LogviewPluginMgr *self);
+
+static gboolean register_module (LogviewPluginMgr *self, LogviewModule* plugin_info);
+static gboolean is_plugin_file (const gchar* filepath);
+static Log* pluginmgr_new_log (Log *log);
+/*-------------------------------------------------------------------------------*/
+static gint module_prio_cmpfunc (gconstpointer a, gconstpointer b, gpointer user_data);
+static gint module_cmpfunc (gconstpointer a, gconstpointer b);
+
+static GObjectClass *parent_class = NULL;
+static LogviewPluginMgr *pluginmgr_instance = NULL;
+
+struct _LogviewPluginMgrPrivate {
+ GType typehash[MGR_PF_NUM];
+ GSList *all_modules;
+ GSList *modules[MGR_PF_NUM];
+ GSList *plugin_full_paths;
+};
+
+static GType
+logview_pluginmgr_get_type (void)
+{
+ static GType type = 0;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (LogviewPluginMgrClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ pluginmgr_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (LogviewPluginMgr),
+ 0, /* n_preallocs */
+ pluginmgr_instance_init /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "LogviewPluginMgrType",
+ &info, 0);
+ }
+ return type;
+}
+
+static void
+pluginmgr_instance_init (GTypeInstance *instance, gpointer g_class)
+{
+ LogviewPluginMgr *self = LOGVIEW_PLUGINMGR (instance);
+ self->prv = g_new0 (LogviewPluginMgrPrivate,1);
+ self->prv->typehash[PF_LOG_IO] = LOGVIEW_TYPE_IFACE_IO;
+ self->prv->typehash[PF_LOG_VIEW] = LOGVIEW_TYPE_IFACE_VIEW;
+ self->prv->typehash[PF_LOG_COLLECTOR] = LOGVIEW_TYPE_IFACE_COLLECTOR;
+}
+
+static void
+pluginmgr_finalize (LogviewPluginMgr *self)
+{
+ GSList *idx;
+
+ LV_MARK;
+
+ LOGVIEW_PLUGINMGR_GET_CLASS (self)->unload_modules (self);
+
+ if (self->prv->plugin_full_paths) {
+ for (idx = self->prv->plugin_full_paths; idx; idx = g_slist_next(idx)) {
+ gchar *path = (gchar *)idx->data;
+ g_free (path);
+ }
+ g_slist_free (self->prv->plugin_full_paths);
+ }
+
+ g_free (self->prv);
+ parent_class->finalize (G_OBJECT (self));
+}
+
+static gboolean
+load_modules (LogviewPluginMgr *self)
+{
+ LogviewPluginMgrClass* klass;
+ GSList* plugin_paths;
+ GSList* idx;
+
+ LV_MARK;
+ if (!g_module_supported())
+ return FALSE;
+
+ klass = LOGVIEW_PLUGINMGR_GET_CLASS(self);
+ plugin_paths = get_plugin_paths();
+
+ g_return_val_if_fail (plugin_paths != NULL, FALSE);
+
+ for (idx = plugin_paths; idx; idx = idx->next) {
+ /* load plugins */
+ GDir *dir;
+ gchar* plugin_full_path;
+ gchar* search_path = idx->data;
+
+ dir = g_dir_open (search_path, 0, NULL);
+ if (dir != NULL) {
+ while ((plugin_full_path = (gchar *) g_dir_read_name (dir)) != NULL) {
+ plugin_full_path = g_build_filename (search_path, plugin_full_path, NULL);
+ if (klass->load_module (self, plugin_full_path)) {
+ LV_INFO ("module %s loaded successfully",
+ plugin_full_path);
+ }
+ g_free (plugin_full_path);
+ }
+ g_dir_close (dir);
+ }
+ else
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/* load all modules in the paths */
+static gboolean
+load_module (LogviewPluginMgr *self, const gchar* module_path)
+{
+ LogviewModule* module = NULL;
+
+ LV_MARK;
+ if (!is_plugin_file (module_path)) {
+ return FALSE;
+ }
+
+ module = logview_new_module (module_path);
+ g_assert (module != NULL);
+
+ if (!g_type_module_use ((GTypeModule*) module)) {
+ LV_INFO ("module %s loaded failed: %s",
+ logview_module_name (module), g_module_error ());
+ g_object_unref (module);
+ return FALSE;
+ }
+
+ if (register_module (self, module))
+ return TRUE;
+ else {
+ g_type_module_unuse ((GTypeModule*) module);
+ return FALSE;
+ }
+}
+
+/* destroy all modules in the paths
+ * must be called after destroy all plugin instances
+ */
+static void
+unload_modules(LogviewPluginMgr *self)
+{
+ PluginFunc i;
+ GSList* idx;
+ LV_MARK;
+
+ for (idx = self->prv->all_modules; idx != NULL; idx = idx->next) {
+ LogviewModule *module = LOGVIEW_MODULE (idx->data);
+ g_assert (module != NULL);
+ LV_INFO ("unload|module: %s", logview_module_name (module));
+ g_type_module_unuse ((GTypeModule*) module);
+ }
+ g_slist_free (self->prv->all_modules);
+ self->prv->all_modules = NULL;
+
+ for (i = 0; i < MGR_PF_NUM; i++) {
+ if (self->prv->modules[i]) {
+ g_slist_free (self->prv->modules[i]);
+ self->prv->modules[i] = NULL;
+ }
+ }
+}
+
+static gboolean
+register_module (LogviewPluginMgr *self, LogviewModule* module)
+{
+ GType mt = logview_module_type (module);
+ PluginFunc i;
+ gboolean ret = FALSE;
+
+ LV_MARK;
+ for (i = 0; i < MGR_PF_NUM; i++) {
+ if (g_type_is_a (mt, self->prv->typehash[i])) {
+ LV_INFO ("module %s, derived from type %s",
+ logview_module_name (module),
+ g_type_name (self->prv->typehash[i]));
+
+ if (g_slist_find_custom (self->prv->modules[i],
+ module, module_cmpfunc) == NULL) {
+ self->prv->modules[i] =
+ g_slist_insert_sorted_with_data (
+ self->prv->modules[i],
+ module, module_prio_cmpfunc, NULL);
+ ret = TRUE;
+ }
+ }
+ }
+ if (ret) {
+ self->prv->all_modules = g_slist_append (self->prv->all_modules, module);
+ }
+ return ret;
+}
+
+static void
+unload_module (LogviewPluginMgr *self, LogviewModule* module)
+{
+ GType mt = logview_module_type (module);
+ PluginFunc i;
+ GSList* idx = NULL;
+ LV_MARK;
+
+ for (i = 0; i < MGR_PF_NUM; i++) {
+ if (g_type_is_a (mt, self->prv->typehash[i])) {
+ idx = g_slist_find (self->prv->modules[i], module);
+ g_assert (idx != NULL);
+ self->prv->modules[i] =
+ g_slist_delete_link (self->prv->modules[i], idx);
+ }
+ }
+ idx = g_slist_find (self->prv->all_modules, module);
+ g_assert (idx != NULL);
+ self->prv->all_modules = g_slist_delete_link (self->prv->all_modules, idx);
+ g_type_module_unuse ((GTypeModule*) module);
+}
+
+static gint
+module_cmpfunc (gconstpointer a, gconstpointer b)
+{
+ return g_ascii_strcasecmp (logview_module_name (LOGVIEW_MODULE(a)),
+ logview_module_name (LOGVIEW_MODULE(b)));
+}
+
+static gint
+module_prio_cmpfunc (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ PluginPrio ap = logview_module_priority (LOGVIEW_MODULE (a));
+ PluginPrio bp = logview_module_priority (LOGVIEW_MODULE (b));
+ /* from high priory to low */
+ return ap > bp ? -1 : (ap == bp ? 0 : 1);
+}
+
+static gboolean
+is_plugin_file (const gchar* filepath)
+{
+ gchar* suffix[] = {
+ G_MODULE_SUFFIX,
+ NULL};
+ gchar ext[32];
+ gint i;
+ for (i = 0; suffix[i] != NULL; i++) {
+ g_sprintf (ext, ".%s", suffix[i]);
+ if (g_str_has_suffix (filepath, ext)) {
+ if (g_access (filepath, R_OK) == 0) {
+ return TRUE;
+ }
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+void
+iterate (LogviewPluginMgr *self, ModuleHandleCB cb, gpointer data)
+{
+ GSList *idx;
+ for (idx = self->prv->all_modules; idx; idx = g_slist_next(idx)) {
+ cb (LOGVIEW_MODULE (idx->data), data);
+ }
+}
+
+static void
+pluginmgr_class_init (gpointer g_class, gpointer g_class_data)
+{
+ GObjectClass *object_class;
+ LogviewPluginMgrClass *self = LOGVIEW_PLUGINMGR_CLASS (g_class);
+
+ object_class = G_OBJECT_CLASS (g_class);
+ parent_class = g_type_class_peek_parent (g_class);
+ object_class->finalize = (void(*)(GObject*)) pluginmgr_finalize;
+
+ self->load_module = load_module;
+ self->unload_module = unload_module;
+ self->load_modules = load_modules;
+ self->unload_modules = unload_modules;
+ self->iterate = iterate;
+
+}
+
+GSList *
+pluginmgr_get_all_logs ()
+{
+ GSList *all_logs = NULL;
+ GSList *idx = NULL;
+
+ LV_MARK;
+
+ for (idx = pluginmgr_instance->prv->modules[PF_LOG_COLLECTOR];
+ idx != NULL; idx = idx->next) {
+ GSList *logs, *i;
+ LogviewPlugin *plugin;
+ g_assert (LOGVIEW_IS_MODULE (idx->data));
+ plugin = logview_module_new_plugin (LOGVIEW_MODULE (idx->data));
+ g_assert (LOGVIEW_IS_IFACE_COLLECTOR (plugin));
+ logs = logi_get_logs (LOGVIEW_IFACE_COLLECTOR (plugin));
+ g_object_unref (plugin);
+ if (logs) {
+ for (i = logs; i; i = g_slist_next(i)) {
+ if (g_slist_find_custom (all_logs, i->data,
+ (GCompareFunc) g_ascii_strcasecmp)== NULL) {
+ all_logs = g_slist_append (all_logs, i->data);
+ LV_INFO ("all logs: %s", i->data);
+ }
+ else
+ g_free (i->data);
+ }
+ g_slist_free (logs);
+ }
+ }
+
+ return all_logs;
+}
+
+static void
+pluginmgr_handle_derived_log (const Log* parent, PluginFunc pf, LogviewModule *module)
+{
+ int i;
+ int versions;
+ Log **older_logs;
+
+ LV_MARK;
+ g_object_get (G_OBJECT (parent),
+ "versions", &versions,
+ "archives", &older_logs,
+ NULL);
+ if (versions > 0) {
+ for (i=0; i<OLD_LOG_NUM; i++) {
+ if (older_logs[i]) {
+ LogviewPlugin *plugin;
+ plugin = logview_module_new_plugin (module);
+ if (logi_can_handle (LOGVIEW_IFACE (plugin),
+ older_logs[i])) {
+ if (logview_plugin_init (plugin)) {
+ log_set_func (older_logs[i],pf,plugin);
+ }
+ }
+ }
+ }
+ }
+}
+
+/* try each plugin to find one which can handle the log */
+static LogviewPlugin*
+pluginmgr_probe_plugin (const Log* log, PluginFunc pf)
+{
+ /* do not check dependency right now */
+ GSList *idx;
+ LogviewPlugin *plugin;
+
+ LV_MARK;
+
+ if (pluginmgr_instance->prv->modules[pf] != NULL) {
+ for (idx = pluginmgr_instance->prv->modules[pf]; idx != NULL; idx=idx->next) {
+ LogviewModule *module;
+ module = LOGVIEW_MODULE (idx->data);
+ LV_ERR ("probing module %s", logview_module_name (module));
+ plugin = logview_module_new_plugin (module);
+ g_return_val_if_fail (plugin != NULL, NULL);
+ g_return_val_if_fail (LOGVIEW_IS_PLUGIN (plugin), NULL);
+ g_return_val_if_fail (LOGVIEW_IS_IFACE (plugin), NULL);
+ if (logi_can_handle (LOGVIEW_IFACE (plugin), (struct _Log *) log)) {
+ if (logview_plugin_init (plugin)) {
+ pluginmgr_handle_derived_log (log, pf, module);
+ return plugin;
+ }
+ }
+ g_object_unref (plugin);
+ }
+ }
+ return NULL;
+}
+
+gboolean pluginmgr_load_modules ()
+{
+ return LOGVIEW_PLUGINMGR_GET_CLASS (pluginmgr_instance)->load_modules (pluginmgr_instance);
+}
+
+void pluginmgr_unload_modules ()
+{
+ LOGVIEW_PLUGINMGR_GET_CLASS (pluginmgr_instance)->unload_modules (pluginmgr_instance);
+}
+
+Log*
+pluginmgr_new_log_from_path (const gchar* log_path)
+{
+ Log *log = NULL;
+ GSList *idx = NULL;
+ LV_MARK;
+ log_error_init (log_path);
+ for (idx = pluginmgr_instance->prv->modules[PF_LOG_COLLECTOR];
+ idx != NULL; idx = idx->next) {
+ LogviewPlugin *plugin;
+ g_assert (LOGVIEW_IS_MODULE (idx->data));
+ plugin = logview_module_new_plugin (LOGVIEW_MODULE (idx->data));
+ g_assert (LOGVIEW_IS_IFACE_COLLECTOR (plugin));
+ if (logi_can_handle (LOGVIEW_IFACE (plugin), log)) {
+ log = logi_config_log_from_path (
+ LOGVIEW_IFACE_COLLECTOR (plugin), log_path);
+ }
+ g_object_unref (plugin);
+ if (log != NULL)
+ return pluginmgr_new_log (log);
+ }
+ return NULL;
+}
+
+static Log*
+pluginmgr_new_log (Log *log)
+{
+ LogviewPlugin *plugin;
+ Log **older_logs;
+ int i;
+
+ LV_MARK;
+
+ g_assert (log);
+ g_object_get (G_OBJECT (log),
+ "archives", &older_logs,
+ NULL);
+ if (! log_test_func (log, PF_LOG_IO)) {
+ plugin = pluginmgr_probe_plugin (log, PF_LOG_IO);
+ if (plugin != NULL) {
+ log_set_func (log,PF_LOG_IO,plugin);
+ }
+ else {
+ g_object_unref (log);
+ return NULL;
+ }
+ }
+
+ for (i = PF_LOG_IO + 1; i < LOG_PF_NUM; i++) {
+ if (! log_test_func (log, i)) {
+ plugin = pluginmgr_probe_plugin (log, i);
+ if (plugin != NULL) {
+ log_set_func (log,i,plugin);
+ }
+ }
+ }
+
+ /* Check for older versions of the log */
+ for (i=0; i<OLD_LOG_NUM; i++) {
+ if (older_logs[i] &&
+ LOGVIEW_IS_LOG(older_logs[i]))
+ pluginmgr_new_log (older_logs[i]);
+ }
+ g_assert (LOGVIEW_IS_LOG (log));
+ log_run (log);
+ log_notify (log, TH_EVENT_INIT_READ);
+ return log;
+}
+
+
+/* global functions */
+
+void
+pluginmgr_destroy ()
+{
+ LV_MARK;
+ if (pluginmgr_instance != NULL) {
+ g_object_unref (pluginmgr_instance);
+ pluginmgr_instance = NULL;
+ }
+}
+
+void
+pluginmgr_init()
+{
+ LV_MARK;
+ if (pluginmgr_instance == NULL) {
+ pluginmgr_instance = g_object_new (LOGVIEW_TYPE_PLUGINMGR, NULL);
+ }
+}
+
+void
+pluginmgr_modules_iterate (ModuleHandleCB cb, gpointer data)
+{
+ LOGVIEW_PLUGINMGR_GET_CLASS (pluginmgr_instance)->iterate (pluginmgr_instance,
+ cb, data);
+}
+
+gint
+pluginmgr_plugin_amount ()
+{
+ gint i, n;
+ for (i = 0, n = 0; i < MGR_PF_NUM; i++) {
+ n += g_slist_length (pluginmgr_instance->prv->modules[i]);
+ }
+ return n;
+}
diff --git a/logview/logview-plugin-manager.h b/logview/logview-plugin-manager.h
new file mode 100644
index 0000000..52d9fda
--- /dev/null
+++ b/logview/logview-plugin-manager.h
@@ -0,0 +1,66 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+
+#ifndef __LOGVIEW_PLUGINMGR_H__
+#define __LOGVIEW_PLUGINMGR_H__
+#include <glib-object.h>
+#include <glib.h>
+#include "logview-module.h"
+#include "logrtns.h"
+
+typedef struct _LogviewPluginMgr LogviewPluginMgr;
+typedef struct _LogviewPluginMgrClass LogviewPluginMgrClass;
+typedef struct _LogviewPluginMgrPrivate LogviewPluginMgrPrivate;
+
+typedef void (*ModuleHandleCB) (const LogviewModule *module, gpointer data);
+
+struct _LogviewPluginMgr {
+ GObject parent;
+ /* instance members */
+/* private */
+ LogviewPluginMgrPrivate *prv;
+};
+
+struct _LogviewPluginMgrClass {
+ GObjectClass parent;
+
+ /* class members */
+
+ /* handle one module */
+ gboolean (*load_module) (LogviewPluginMgr *self, const gchar *module_path);
+ void (*unload_module) (LogviewPluginMgr *self, LogviewModule *module);
+
+ /* handle all module in paths */
+ gboolean (*load_modules)(LogviewPluginMgr *self);
+ void (*unload_modules)(LogviewPluginMgr *self);
+
+ /* collect all the path names in Plugin paths.
+ return a list, do not try to free it.
+ */
+ GSList* (*compose_search_plugin_paths)(LogviewPluginMgr *self);
+
+ void (*iterate)(LogviewPluginMgr *self, ModuleHandleCB cb, gpointer data);
+};
+
+/* For the core application which should implemete the level to call plugins */
+
+//void logview_plugins_detect (const gchar* plugin_patchs);
+
+
+extern void pluginmgr_init ();
+extern void pluginmgr_destroy ();
+extern gboolean pluginmgr_load_modules ();
+extern void pluginmgr_unload_modules ();
+extern gint pluginmgr_plugin_amount();
+
+extern GSList* pluginmgr_get_all_logs ();
+extern Log* pluginmgr_new_log_from_path (const gchar* log_path);
+extern void pluginmgr_modules_iterate (ModuleHandleCB cb, gpointer data);
+
+/* routines provided for internal usage */
+
+#endif /* __LOGVIEW_PLUGINMGR_H__ */
+
diff --git a/logview/logview-plugin.c b/logview/logview-plugin.c
new file mode 100644
index 0000000..6a3beed
--- /dev/null
+++ b/logview/logview-plugin.c
@@ -0,0 +1,105 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+
+#include "logview-plugin.h"
+#include "logview-debug.h"
+
+static GObjectClass *parent_class = NULL;
+static void logview_plugin_finalize (GObject *object);
+
+static void
+logview_plugin_instance_init (LogviewPlugin *self, gpointer g_class_data)
+{
+ LV_MARK;
+}
+
+static void
+logview_plugin_class_init (gpointer g_class, gpointer g_class_data)
+{
+ GObjectClass *object_class;
+ LogviewPluginClass *self;
+
+ LV_MARK;
+
+ object_class = G_OBJECT_CLASS (g_class);
+ self = LOGVIEW_PLUGIN_CLASS (g_class);
+ parent_class = g_type_class_peek_parent (g_class);
+ self->plugin_init = NULL;
+ self->plugin_destroy = NULL;
+ object_class->finalize = logview_plugin_finalize;
+}
+
+GType
+logview_plugin_get_type (void)
+{
+ static GType type = 0;
+ LV_MARK;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (LogviewPluginClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ logview_plugin_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (LogviewPlugin),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) logview_plugin_instance_init /* instance_init */
+ };
+ type = g_type_register_static (G_TYPE_OBJECT,
+ "LogviewPluginType",
+ &info, 0);
+ }
+ return type;
+}
+
+static void
+logview_plugin_finalize (GObject *object)
+{
+ LV_MARK;
+ if (LOGVIEW_PLUGIN_GET_CLASS (object)->plugin_destroy)
+ LOGVIEW_PLUGIN_GET_CLASS (object)->plugin_destroy (LOGVIEW_PLUGIN (object));
+ parent_class->finalize (object);
+}
+
+/**
+ * logview_plugin_init:
+ * @self: a #LogviewPlugin instance.
+ *
+ * plugin_init default returns TRUE if it is not overriden.
+ * If it returns FALSE, the plugin will be skipped.
+ *
+ * This method will be called by manager after interface can_handle
+ * is called. The plugin should be initialized at this time.
+ * If returns TRUE, this plugin will be assigned to log.
+ *
+ * Returns: Upon a successful completion or it is not be overloaded, returns TRUE.
+ */
+gboolean
+logview_plugin_init (LogviewPlugin* self)
+{
+ LV_MARK;
+ if (LOGVIEW_PLUGIN_GET_CLASS(self)->plugin_init)
+ return LOGVIEW_PLUGIN_GET_CLASS(self)->plugin_init (self);
+ return TRUE;
+}
+
+/**
+ * logview_plugin_destroy:
+ * @self: a #LogviewPlugin instance.
+ *
+ * Log instance will automatically destroy all plugins it has.
+ * This method will be automatically called when it's unrefed.
+ */
+void
+logview_plugin_destroy (LogviewPlugin* self)
+{
+ LV_MARK;
+ if (LOGVIEW_PLUGIN_GET_CLASS(self)->plugin_destroy)
+ LOGVIEW_PLUGIN_GET_CLASS(self)->plugin_destroy (self);
+}
+
diff --git a/logview/logview-plugin.h b/logview/logview-plugin.h
new file mode 100644
index 0000000..16fca0b
--- /dev/null
+++ b/logview/logview-plugin.h
@@ -0,0 +1,125 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifndef __LOGVIEW_PLUGIN_H__
+#define __LOGVIEW_PLUGIN_H__
+
+#include <glib-object.h>
+#include <gmodule.h>
+#include "logview-iface.h"
+
+G_BEGIN_DECLS
+
+#define LOGVIEW_TYPE_PLUGIN (logview_plugin_get_type ())
+#define LOGVIEW_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), LOGVIEW_TYPE_PLUGIN, LogviewPlugin))
+#define LOGVIEW_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), LOGVIEW_TYPE_PLUGIN, LogviewPluginClass))
+#define LOGVIEW_IS_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), LOGVIEW_TYPE_PLUGIN))
+#define LOGVIEW_IS_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), LOGVIEW_TYPE_PLUGIN))
+#define LOGVIEW_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), LOGVIEW_TYPE_PLUGIN, LogviewPluginClass))
+
+typedef struct _LogviewPluginInfo LogviewPluginInfo;
+typedef struct _LogviewPlugin LogviewPlugin;
+typedef struct _LogviewPluginClass LogviewPluginClass;
+
+/**
+ * PluginPrio:
+ * @PLUG_PRIO_BASE: the base priority. if a plugin is explicited defined
+ * a priority by redefine #PLUGIN_PRIO, it will be assigned to %PLUG_PRIO_USER.
+ * @PLUG_PRIO_USER: the base line of priority which user should use,
+ * e.g. %PLUG_PRIO_USER + 1
+ *
+ * A plugin with a high priority will be used first.
+ */
+typedef enum {
+ PLUG_PRIO_BASE=0,
+ PLUG_PRIO_USER=10
+} PluginPrio;
+
+/*< private >*/
+typedef enum {
+ PF_LOG_IO=0,
+ PF_LOG_VIEW,
+ PF_LOG_COLLECTOR,
+ PF_LOG_NUM
+} PluginFunc;
+
+/*< private >*/
+#define LOG_PF_NUM PF_LOG_COLLECTOR
+/*< private >*/
+#define MGR_PF_NUM PF_LOG_NUM
+
+/*< private >*/
+struct _LogviewPluginInfo {
+ PluginPrio prio;
+ gchar *desc;
+};
+
+/*< public >*/
+struct _LogviewPlugin {
+ /*< private >*/
+ GObject parent;
+};
+
+struct _LogviewPluginClass {
+ GObjectClass parent;
+
+/* virtual public */
+ gboolean (*plugin_init) (LogviewPlugin* self);
+ void (*plugin_destroy) (LogviewPlugin* self);
+};
+
+GType logview_plugin_get_type (void);
+gboolean logview_plugin_init (LogviewPlugin* self);
+void logview_plugin_destroy (LogviewPlugin* self);
+
+/**
+ * PLUGIN_PRIO:
+ *
+ * Define plugin priority, can be redefined by users.
+ *
+ * PLUGIN_PRIO should be defined great or equal to PLUG_PRIO_USER,
+ * so that your plugin can be probed first.
+ *
+ * e.g. %PLUG_PRIO_USER + 1
+ */
+#define PLUGIN_PRIO PLUG_PRIO_USER
+
+/**
+ * PLUGIN_DESC:
+ *
+ * A brief description for the plugin is needed
+ * for displaying the plugin information in GUI.
+ *
+ * e.g. PLUGIN_DESC "For ..."
+ */
+#define PLUGIN_DESC "Unknown plugin."
+
+/**
+ * LOGVIEW_INIT_PLUGIN:
+ * @PluginTypeFunc: a function reports the #GType of the plugin.
+ *
+ * A macro exports some useful functions. Therefor core application
+ * can get some useful information to load the plugin.
+ */
+#define LOGVIEW_INIT_PLUGIN(PluginTypeFunc) \
+G_MODULE_EXPORT LogviewPluginInfo* logview_plugin_info (void); \
+G_MODULE_EXPORT LogviewPluginInfo* logview_plugin_info (void) \
+{ \
+ static LogviewPluginInfo __plugin_info; \
+ __plugin_info.prio = PLUGIN_PRIO; \
+ __plugin_info.desc = PLUGIN_DESC; \
+ return &__plugin_info; \
+} \
+G_MODULE_EXPORT GType register_logview_plugin (GTypeModule* module); \
+G_MODULE_EXPORT GType register_logview_plugin (GTypeModule* module) \
+{ \
+ return PluginTypeFunc (module); \
+}
+
+
+G_END_DECLS
+
+#endif /* __LOGVIEW_PLUGIN_H__ */
+
diff --git a/logview/logview.c b/logview/logview.c
index d1bdbaa..91ce390 100644
--- a/logview/logview.c
+++ b/logview/logview.c
@@ -1,22 +1,22 @@
/* ----------------------------------------------------------------------
- Copyright (C) 1998 Cesar Miquel (miquel@df.uba.ar)
+Copyright (C) 1998 Cesar Miquel (miquel@df.uba.ar)
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ---------------------------------------------------------------------- */
+---------------------------------------------------------------------- */
#include <config.h>
#include <stdlib.h>
@@ -33,19 +33,21 @@
#include "logview-findbar.h"
#include "userprefs.h"
#include "calendar.h"
+#include "logview-debug.h"
+#include "logview-plugin-manager.h"
#define APP_NAME _("System Log Viewer")
enum {
- PROP_0,
- PROP_DAYS,
+ PROP_0,
+ PROP_DAYS,
};
enum {
- LOG_LINE_TEXT = 0,
- LOG_LINE_POINTER,
- LOG_LINE_WEIGHT,
- LOG_LINE_WEIGHT_SET
+ LOG_LINE_TEXT = 0,
+ LOG_LINE_POINTER,
+ LOG_LINE_WEIGHT1,
+ LOG_LINE_WEIGHT_SET1
};
static GObjectClass *parent_class;
@@ -76,8 +78,7 @@ static void logview_help (GtkAction *action, GtkWidget *parent_window);
static void logview_copy (GtkAction *action, LogviewWindow *logview);
static void logview_select_all (GtkAction *action, LogviewWindow *logview);
static Log *logview_find_log_from_name (LogviewWindow *logview, gchar *name);
-
-static void logview_window_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec);
+static void logview_plugin_dialog_show (GtkAction *action, LogviewWindow *logview);
/* Menus */
@@ -115,14 +116,16 @@ static GtkActionEntry entries[] = {
G_CALLBACK (logview_help) },
{ "AboutAction", GTK_STOCK_ABOUT, N_("_About"), NULL, N_("Show the about dialog for the log viewer"),
G_CALLBACK (logview_about) },
+ { "PluginList", NULL, N_("_Plugins"), NULL, N_("Show the information of the loaded plugins"),
+ G_CALLBACK (logview_plugin_dialog_show) },
};
static GtkToggleActionEntry toggle_entries[] = {
- { "ShowStatusBar", NULL, N_("_Statusbar"), NULL, N_("Show Status Bar"),
- G_CALLBACK (logview_toggle_statusbar), TRUE },
+ { "ShowStatusBar", NULL, N_("_Statusbar"), NULL, N_("Show Status Bar"),
+ G_CALLBACK (logview_toggle_statusbar), TRUE },
{ "ShowSidebar", NULL, N_("Side _Pane"), "F9", N_("Show Side Pane"),
- G_CALLBACK (logview_toggle_sidebar), TRUE },
+ G_CALLBACK (logview_toggle_sidebar), TRUE },
{ "MonitorLogs", NULL, N_("_Monitor"), "<control>M", N_("Monitor Current Log"),
G_CALLBACK (logview_toggle_monitor), TRUE },
{"ShowCalendar", NULL, N_("Ca_lendar"), "<control>L", N_("Show Calendar Log"),
@@ -130,202 +133,240 @@ static GtkToggleActionEntry toggle_entries[] = {
};
static const char *ui_description =
- "<ui>"
- " <menubar name='LogviewMenu'>"
- " <menu action='FileMenu'>"
- " <menuitem action='OpenLog'/>"
- " <menuitem action='CloseLog'/>"
- " <menuitem action='Quit'/>"
- " </menu>"
- " <menu action='EditMenu'>"
- " <menuitem action='Copy'/>"
- " <menuitem action='SelectAll'/>"
- " </menu>"
- " <menu action='ViewMenu'>"
- " <menuitem action='MonitorLogs'/>"
- " <separator/>"
- " <menuitem action='ShowStatusBar'/>"
- " <menuitem action='ShowSidebar'/>"
- " <menuitem action='ShowCalendar'/>"
- " <separator/>"
- " <menuitem action='Search'/>"
- " <menuitem action='CollapseAll'/>"
- " <separator/>"
- " <menuitem action='ViewZoomIn'/>"
- " <menuitem action='ViewZoomOut'/>"
- " <menuitem action='ViewZoom100'/>"
- " </menu>"
- " <menu action='HelpMenu'>"
- " <menuitem action='HelpContents'/>"
- " <menuitem action='AboutAction'/>"
- " </menu>"
- " </menubar>"
- "</ui>";
+"<ui>"
+" <menubar name='LogviewMenu'>"
+" <menu action='FileMenu'>"
+" <menuitem action='OpenLog'/>"
+" <menuitem action='CloseLog'/>"
+" <menuitem action='Quit'/>"
+" </menu>"
+" <menu action='EditMenu'>"
+" <menuitem action='Copy'/>"
+" <menuitem action='SelectAll'/>"
+" </menu>"
+" <menu action='ViewMenu'>"
+" <menuitem action='MonitorLogs'/>"
+" <separator/>"
+" <menuitem action='ShowStatusBar'/>"
+" <menuitem action='ShowSidebar'/>"
+" <menuitem action='ShowCalendar'/>"
+" <separator/>"
+" <menuitem action='Search'/>"
+" <menuitem action='CollapseAll'/>"
+" <separator/>"
+" <menuitem action='ViewZoomIn'/>"
+" <menuitem action='ViewZoomOut'/>"
+" <menuitem action='ViewZoom100'/>"
+" <separator/>"
+" <menuitem action='PluginList'/>"
+" </menu>"
+" <menu action='HelpMenu'>"
+" <menuitem action='HelpContents'/>"
+" <menuitem action='AboutAction'/>"
+" </menu>"
+" </menubar>"
+"</ui>";
/* public interface */
Log *
logview_get_active_log (LogviewWindow *logview)
{
- g_return_val_if_fail (LOGVIEW_IS_WINDOW (logview), NULL);
- return logview->curlog;
+ g_return_val_if_fail (LOGVIEW_IS_WINDOW (logview), NULL);
+ return logview->curlog;
}
LogList *
logview_get_loglist (LogviewWindow *logview)
{
- g_return_val_if_fail (LOGVIEW_IS_WINDOW (logview), NULL);
- return LOG_LIST (logview->loglist);
+ g_return_val_if_fail (LOGVIEW_IS_WINDOW (logview), NULL);
+ return LOG_LIST (logview->loglist);
}
int
logview_count_logs (LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
- return g_slist_length (logview->logs);
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+ return g_slist_length (logview->logs);
}
static void
logview_store_visible_range (LogviewWindow *logview)
{
- GtkTreePath *first, *last;
- Log *log = logview->curlog;
- if (log == NULL)
- return;
+ GtkTreePath *first = NULL;
+ Log *log = logview->curlog;
+ if (log == NULL)
+ return;
- if (log->visible_first)
- gtk_tree_path_free (log->visible_first);
+ if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (logview->view),
+ &first, NULL))
+ g_object_set (G_OBJECT (log), "visible-first", first, NULL);
+}
- if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (logview->view),
- &first, NULL))
- log->visible_first = first;
+static void
+logview_update_other_components (LogviewWindow *logview)
+{
+ logview_set_window_title (logview);
+ logview_menus_set_state (logview);
+ logview_calendar_set_state (logview);
+ logview_repaint (logview);
+ logview_update_findbar_visibility (logview);
}
void
logview_select_log (LogviewWindow *logview, Log *log)
{
- g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
+ LV_MARK;
+ g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
+ if (!GTK_WIDGET_VISIBLE (GTK_WIDGET (logview->view)))
+ return;
- logview_store_visible_range (logview);
-
- logview->curlog = log;
- logview_menus_set_state (logview);
- logview_calendar_set_state (logview);
- logview_repaint (logview);
- logview_update_findbar_visibility (logview);
-
- logview_update_version_bar (logview);
- logview_save_prefs (logview);
- gtk_widget_grab_focus (logview->view);
-}
+ logview_store_visible_range (logview);
+
+ logview->curlog = log;
+ /*
+ update version bar first, because the user may choose a child log
+ of logview->curlog, so to avoid update other components multi times
+ give the update responsibility to the change signal of version bar.
+
+ Note that if choose a log path, then blank out all the Gui.
+ */
+ logview_update_version_bar (logview);
+ if (logview->curlog == NULL) {
+ logview_update_other_components (logview);
+ }
+ gtk_widget_grab_focus (logview->view);
+}
void
logview_add_log_from_name (LogviewWindow *logview, gchar *file)
{
Log *log;
- g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
- g_return_if_fail (file);
+ g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
+ g_return_if_fail (file);
- log = log_open (file, TRUE);
- if (log != NULL)
- logview_add_log (logview, log);
+ log = pluginmgr_new_log_from_path (file);
+ if (log != NULL)
+ logview_add_log (logview, log);
+ else
+ error_dialog_show (NULL, _("Add log error."), log_error());
}
void
logview_add_logs_from_names (LogviewWindow *logview, GSList *lognames, gchar *selected)
{
- GSList *list;
- Log *log, *curlog = NULL;
+ GSList *list;
+ Log *log, *curlog = NULL;
+ gchar *log_name;
- g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
-
- if (lognames == NULL)
- return;
-
- for (list = lognames; list != NULL; list = g_slist_next (list)) {
- log = log_open (list->data, FALSE);
- if (log != NULL) {
- logview_add_log (logview, log);
- if (selected!=NULL && g_strncasecmp (log->name, selected, -1)==0)
- curlog = log;
- }
- }
+ g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
+
+ if (lognames == NULL)
+ return;
+
+ /* remove log_open, open by pluginmgr_get_all_logs or loglist? */
+ for (list = lognames; list != NULL; list = g_slist_next (list)) {
+ log = pluginmgr_new_log_from_path ((gchar*)list->data);
+ if (log != NULL) {
+ logview_add_log (logview, log);
+ g_object_get (G_OBJECT (log), "path", &log_name, NULL);
+ if (selected!=NULL &&
+ (g_strncasecmp (log_name, selected, -1) == 0))
+ curlog = log;
+ g_free (log_name);
+ }
+ else
+ error_dialog_show (NULL, _("Add log error."), log_error());
+ }
- if (curlog)
- loglist_select_log (LOG_LIST (logview->loglist), curlog);
+ if (curlog)
+ loglist_select_log (LOG_LIST (logview->loglist), curlog);
- gtk_tree_view_expand_all (GTK_TREE_VIEW (logview->loglist));
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (logview->loglist));
}
void
logview_menus_set_state (LogviewWindow *logview)
{
- Log *log;
- gboolean calendar_active = FALSE, monitor_active = FALSE;
- GtkWidget *widget;
-
- g_assert (LOGVIEW_IS_WINDOW (logview));
- log = logview->curlog;
-
- if (log) {
- monitor_active = (log->display_name == NULL);
- calendar_active = (log->days != NULL);
- logview_menu_item_toggle_set_active (logview, "/LogviewMenu/ViewMenu/MonitorLogs", logview->curlog->monitored);
- }
+ Log *log;
+ gboolean monitorable;
+ gboolean monitoring;
+ gboolean groupable;
+ gboolean calendar_active = FALSE, monitor_active = FALSE;
+
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+ log = logview->curlog;
+ if (log) {
+ g_assert (LOGVIEW_IS_LOG (log));
+ g_object_get (G_OBJECT (log),
+ "monitorable", &monitorable,
+ "monitoring", &monitoring,
+ "groupable", &groupable,
+ NULL);
+
+ monitor_active = monitorable;
+ calendar_active = groupable;
+ logview_menu_item_toggle_set_active (logview,
+ "/LogviewMenu/ViewMenu/MonitorLogs",
+ monitoring);
+ }
- logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/MonitorLogs", monitor_active);
- logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/ShowCalendar", calendar_active);
- logview_menu_item_set_state (logview, "/LogviewMenu/FileMenu/CloseLog", (log != NULL));
- logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/CollapseAll", calendar_active);
- logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/Search", (log != NULL));
- logview_menu_item_set_state (logview, "/LogviewMenu/EditMenu/Copy", (log != NULL));
- logview_menu_item_set_state (logview, "/LogviewMenu/EditMenu/SelectAll", (log != NULL));
+ logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/MonitorLogs", monitor_active);
+ logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/ShowCalendar", calendar_active);
+ logview_menu_item_set_state (logview, "/LogviewMenu/FileMenu/CloseLog", (log != NULL));
+ logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/CollapseAll", calendar_active);
+ logview_menu_item_set_state (logview, "/LogviewMenu/ViewMenu/Search", (log != NULL));
+ logview_menu_item_set_state (logview, "/LogviewMenu/EditMenu/Copy", (log != NULL));
+ logview_menu_item_set_state (logview, "/LogviewMenu/EditMenu/SelectAll", (log != NULL));
}
void
logview_set_window_title (LogviewWindow *logview)
{
- gchar *window_title;
- gchar *logname;
- Log *log;
-
- g_assert (LOGVIEW_IS_WINDOW (logview));
-
- log = logview->curlog;
- if (log == NULL)
- return;
-
- if (log->name != NULL) {
-
- if (log->display_name != NULL)
- logname = log->display_name;
- else
- logname = log->name;
-
- if (log->monitored)
- window_title = g_strdup_printf (_("%s (monitored) - %s"), logname, APP_NAME);
- else
- window_title = g_strdup_printf ("%s - %s", logname, APP_NAME);
-
- }
- else
- window_title = g_strdup_printf (APP_NAME);
-
- gtk_window_set_title (GTK_WINDOW (logview), window_title);
- g_free (window_title);
+ gchar *window_title;
+ gchar *logname;
+ gboolean monitoring;
+ Log *log;
+
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+
+ log = logview->curlog;
+ logname = NULL;
+
+ if (log != NULL) {
+ g_object_get (G_OBJECT (log),
+ "display-name", &logname,
+ "monitoring", &monitoring,
+ NULL);
+ if (logname == NULL) {
+ g_object_get (G_OBJECT (log),
+ "path", &logname,
+ NULL);
+ }
+ if (monitoring)
+ window_title = g_strdup_printf (_("%s (monitored) - %s"), logname, APP_NAME);
+ else
+ window_title = g_strdup_printf (_("%s - %s"), logname, APP_NAME);
+ }
+ else
+ window_title = g_strdup_printf (APP_NAME);
+
+ gtk_window_set_title (GTK_WINDOW (logview), window_title);
+ g_free (window_title);
+ g_free (logname);
}
void
logview_show_main_content (LogviewWindow *logview)
{
- g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
- gtk_widget_show (logview->calendar);
- gtk_widget_show (logview->loglist);
- gtk_widget_show (logview->sidebar);
- gtk_widget_show (logview->view);
- gtk_widget_show (logview->hpaned);
- gtk_widget_show (logview->statusbar);
+ g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
+ gtk_widget_show (logview->calendar);
+ gtk_widget_show (logview->loglist);
+ gtk_widget_show (logview->sidebar);
+ gtk_widget_show (logview->view);
+ gtk_widget_show (logview->hpaned);
+ gtk_widget_show (logview->statusbar);
}
/* private functions */
@@ -334,12 +375,18 @@ static void
logview_update_findbar_visibility (LogviewWindow *logview)
{
Log *log = logview->curlog;
- if (log == NULL) {
- gtk_widget_hide (logview->find_bar);
- return;
- }
+ GtkTreeModelFilter *filter;
+
+ if (log == NULL) {
+ gtk_widget_hide (logview->find_bar);
+ return;
+ }
+
+ g_object_get (G_OBJECT (log),
+ "filter", &filter,
+ NULL);
- if (log->filter != NULL)
+ if (filter != NULL)
gtk_widget_show (logview->find_bar);
else
gtk_widget_hide (logview->find_bar);
@@ -348,208 +395,279 @@ logview_update_findbar_visibility (LogviewWindow *logview)
static void
logview_save_prefs (LogviewWindow *logview)
{
- GSList *list;
- Log *log;
+ GSList *list;
+ Log *log, *parent;
- g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
+ LV_MARK;
+ g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
- if (GTK_WIDGET_VISIBLE (GTK_WIDGET (logview->loglist))) {
- prefs_free_loglist();
- for (list = logview->logs; list != NULL; list = g_slist_next (list)) {
- log = list->data;
- prefs_store_log (log->name);
- }
+ if (GTK_WIDGET_VISIBLE (GTK_WIDGET (logview->loglist))) {
+ prefs_free_loglist();
+ for (list = logview->logs; list != NULL; list = g_slist_next (list)) {
+ gchar *name = NULL;
+ g_assert (LOGVIEW_IS_LOG (list->data));
+ log = LOGVIEW_LOG (list->data);
+ g_object_get (G_OBJECT (log), "path", &name, NULL);
+ prefs_store_log (name);
+ g_free (name);
+ }
- if (logview->curlog) {
- if (logview->curlog->parent_log)
- prefs_store_active_log (logview->curlog->parent_log->name);
- else
- prefs_store_active_log (logview->curlog->name);
+ if (logview->curlog) {
+ gchar *log_name, *parent_name;
+ log_name = parent_name = NULL;
+ g_assert (LOGVIEW_IS_LOG (logview->curlog));
+ g_object_get (G_OBJECT (logview->curlog),
+ "path", &log_name,
+ "parent", &parent,
+ NULL);
+ if (parent) {
+ g_assert (LOGVIEW_IS_LOG (parent));
+ g_object_get (G_OBJECT (parent),
+ "path", &parent_name,
+ NULL);
+ prefs_store_active_log (parent_name);
+ g_free (parent_name);
+ }
+ else {
+ prefs_store_active_log (log_name);
+ }
+ g_free (log_name);
+ }
+ prefs_store_fontsize (logview->fontsize);
+ prefs_save ();
}
- prefs_store_fontsize (logview->fontsize);
- prefs_save ();
- }
}
static void
logview_destroy (GObject *object, LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
-
- if (logview->curlog) {
- if (logview->curlog->monitored)
- monitor_stop (logview->curlog);
- }
+ GSList* idx;
+ gboolean monitoring;
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+ LV_MARK;
+
+ if (logview->curlog) {
+ g_object_get (G_OBJECT (logview->curlog), "monitoring", &monitoring, NULL);
+ if (monitoring)
+ monitor_stop (logview->curlog);
+ }
- logview_save_prefs (logview);
- prefs_free_loglist ();
+ logview_save_prefs (logview);
+ prefs_free_loglist();
+
+ logview_select_log (logview, NULL);
+ for (idx = logview->logs; idx != NULL; idx = idx->next) {
+ Log *log;
+ g_assert (LOGVIEW_IS_LOG (idx->data));
+ log = LOGVIEW_LOG (idx->data);
+ g_object_get (G_OBJECT (log), "monitoring", &monitoring, NULL);
+ if (monitoring)
+ monitor_stop (log);
+ }
+ g_slist_foreach (logview->logs, (GFunc) g_object_unref, NULL);
+ g_slist_free (logview->logs);
- if (gtk_main_level() > 0)
- gtk_main_quit ();
- else
- exit (0);
+ if (gtk_main_level() > 0)
+ gtk_main_quit ();
+ else {
+ pluginmgr_destroy ();
+ logview_debug_destroy ();
+ exit (0);
+ }
}
static void
logview_add_log (LogviewWindow *logview, Log *log)
{
- g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
- g_return_if_fail (log);
+ g_return_if_fail (LOGVIEW_IS_WINDOW (logview));
+ g_return_if_fail (log);
- logview->logs = g_slist_append (logview->logs, log);
- loglist_add_log (LOG_LIST(logview->loglist), log);
- log->window = logview;
- monitor_start (log);
+ logview->logs = g_slist_append (logview->logs, log);
+ loglist_add_log (LOG_LIST(logview->loglist), log);
+ g_object_set (G_OBJECT (log), "view", logview->view, NULL);
+ monitor_start (log);
+ logview_select_log (logview, log);
}
static Log *
logview_find_log_from_name (LogviewWindow *logview, gchar *name)
{
- GSList *list;
- Log *log;
-
- if (logview == NULL || name == NULL)
- return NULL;
-
- for (list = logview->logs; list != NULL; list = g_slist_next (list)) {
- log = list->data;
- if (g_ascii_strncasecmp (log->name, name, 255) == 0) {
- return log;
- }
- }
- return NULL;
+ GSList *list;
+ Log *log;
+
+ if (logview == NULL || name == NULL)
+ return NULL;
+
+ for (list = logview->logs; list != NULL; list = g_slist_next (list)) {
+ gchar *log_name;
+ log = list->data;
+ g_object_get (G_OBJECT (log), "path", &log_name, NULL);
+ if (g_ascii_strncasecmp (log_name , name, 255) == 0) {
+ g_free (log_name);
+ return log;
+ }
+ g_free (log_name);
+ }
+ return NULL;
}
static void
logview_version_selector_changed (GtkComboBox *version_selector, gpointer user_data)
{
LogviewWindow *logview = user_data;
- Log *log = logview->curlog;
- int selected;
+ Log *log, **old_logs;
+ int selected, archive_id, current_version, versions;
+ gchar *archive_n = NULL;
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+ if (logview->curlog == NULL)
+ return;
+ g_assert (LOGVIEW_IS_LOG (logview->curlog));
+ /* first, get the parent log */
+ g_object_get (G_OBJECT (logview->curlog),
+ "parent", &log,
+ NULL);
+ if (log == NULL)
+ log = logview->curlog;
+ g_object_get (G_OBJECT (log),
+ "archives", &old_logs,
+ "current-version", &current_version,
+ NULL);
selected = gtk_combo_box_get_active (version_selector);
-
- if (selected == log->current_version)
- return;
+ /* return if already selected and
+ recorded pointer is equal to the current log or child log */
+ if (selected > 0) {
+ archive_n = gtk_combo_box_get_active_text (version_selector);
+ sscanf (archive_n, "%*s%d", &archive_id);
+ g_free (archive_n);
+ }
/* select a new version */
- if (selected == 0) {
- logview_select_log (logview, log->parent_log);
+ if (selected >= 0)
+ g_object_set (G_OBJECT (log),
+ "current-version", selected,
+ NULL);
+ if (selected <= 0) {
+ logview->curlog = log;
} else {
- Log *new;
- if (log->parent_log) {
- new = log->parent_log->older_logs[selected];
- } else {
- new = log->older_logs[selected];
- }
-
- logview_select_log (logview, new);
+ logview->curlog = old_logs[archive_id];
}
+ /* must update the gui due to currently log is switched */
+ logview_update_other_components (logview);
}
static void
logview_close_log (GtkAction *action, LogviewWindow *logview)
{
- Log *log;
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ Log *log;
+ gboolean monitoring;
+ LV_MARK;
+ g_assert (LOGVIEW_IS_WINDOW (logview));
- if (logview->curlog == NULL)
- return;
+ if (logview->curlog == NULL)
+ return;
- if (logview->curlog->monitored) {
- GtkAction *action = gtk_ui_manager_get_action (logview->ui_manager, "/LogviewMenu/ViewMenu/MonitorLogs");
- gtk_action_activate (action);
- }
+ g_object_get (G_OBJECT (logview->curlog), "monitoring", &monitoring, NULL);
+ if (monitoring) {
+ GtkAction *action = gtk_ui_manager_get_action (logview->ui_manager, "/LogviewMenu/ViewMenu/MonitorLogs");
+ gtk_action_activate (action);
+ }
- gtk_widget_hide (logview->find_bar);
+ gtk_widget_hide (logview->find_bar);
- log = logview->curlog;
- logview->curlog = NULL;
+ /* loglist can only remove parent log */
+ g_object_get (G_OBJECT (logview->curlog), "parent", &log, NULL);
+ if (log == NULL)
+ log = logview->curlog;
+ logview->curlog = NULL;
- logview->logs = g_slist_remove (logview->logs, log);
- log_close (log);
- loglist_remove_log (LOG_LIST (logview->loglist), log);
+ logview->logs = g_slist_remove (logview->logs, log);
+ loglist_remove_log (LOG_LIST (logview->loglist), log);
+ g_object_unref (log);
}
static void
logview_file_selected_cb (GtkWidget *chooser, gint response, LogviewWindow *logview)
{
- char *f;
+ char *f;
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
- gtk_widget_hide (GTK_WIDGET (chooser));
- if (response != GTK_RESPONSE_OK)
- return;
-
- f = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
-
- if (f != NULL) {
- /* Check if the log is not already opened */
- GSList *list;
- Log *log, *tl;
- for (list = logview->logs; list != NULL; list = g_slist_next (list)) {
- log = list->data;
- if (g_ascii_strncasecmp (log->name, f, 255) == 0) {
- loglist_select_log (LOG_LIST (logview->loglist), log);
- return;
- }
- }
-
- if ((tl = log_open (f, TRUE)) != NULL)
- logview_add_log (logview, tl);
- }
+ gtk_widget_hide (GTK_WIDGET (chooser));
+ if (response != GTK_RESPONSE_OK)
+ return;
- g_free (f);
+ f = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser));
+
+ if (f != NULL) {
+ /* Check if the log is not already opened */
+ GSList *list;
+ Log *log, *tl;
+ for (list = logview->logs; list != NULL; list = g_slist_next (list)) {
+ gchar *log_name;
+ log = list->data;
+ g_object_get (G_OBJECT (log), "path", &log_name, NULL);
+ if (g_ascii_strncasecmp (log_name, f, 255) == 0) {
+ loglist_select_log (LOG_LIST (logview->loglist), log);
+ g_free (log_name);
+ return;
+ }
+ g_free (log_name);
+ }
+ if ((tl = pluginmgr_new_log_from_path (f)) != NULL)
+ logview_add_log (logview, tl);
+ else
+ error_dialog_show (NULL, _("Add log error."), log_error());
+ }
+ g_free (f);
}
static void
logview_open_log (GtkAction *action, LogviewWindow *logview)
{
- static GtkWidget *chooser = NULL;
+ static GtkWidget *chooser = NULL;
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
- if (chooser == NULL) {
- chooser = gtk_file_chooser_dialog_new (_("Open Log"),
- GTK_WINDOW (logview),
- GTK_FILE_CHOOSER_ACTION_OPEN,
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OPEN, GTK_RESPONSE_OK,
- NULL);
- gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
- gtk_window_set_modal (GTK_WINDOW (chooser), TRUE);
- g_signal_connect (G_OBJECT (chooser), "response",
- G_CALLBACK (logview_file_selected_cb), logview);
- g_signal_connect (G_OBJECT (chooser), "destroy",
- G_CALLBACK (gtk_widget_destroyed), &chooser);
- if (prefs_get_active_log () != NULL)
- gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser),
- prefs_get_active_log ());
- }
-
- gtk_window_present (GTK_WINDOW (chooser));
+ if (chooser == NULL) {
+ chooser = gtk_file_chooser_dialog_new (_("Open Log"),
+ GTK_WINDOW (logview),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_OK,
+ NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (chooser), GTK_RESPONSE_OK);
+ gtk_window_set_modal (GTK_WINDOW (chooser), TRUE);
+ g_signal_connect (G_OBJECT (chooser), "response",
+ G_CALLBACK (logview_file_selected_cb), logview);
+ g_signal_connect (G_OBJECT (chooser), "destroy",
+ G_CALLBACK (gtk_widget_destroyed), &chooser);
+ if (prefs_get_active_log () != NULL)
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (chooser),
+ prefs_get_active_log ());
+ }
+
+ gtk_window_present (GTK_WINDOW (chooser));
}
static void
logview_toggle_statusbar (GtkAction *action, LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
- if (GTK_WIDGET_VISIBLE (logview->statusbar))
- gtk_widget_hide (logview->statusbar);
- else
- gtk_widget_show (logview->statusbar);
+ if (GTK_WIDGET_VISIBLE (logview->statusbar))
+ gtk_widget_hide (logview->statusbar);
+ else
+ gtk_widget_show (logview->statusbar);
}
static void
logview_toggle_sidebar (GtkAction *action, LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
if (GTK_WIDGET_VISIBLE (logview->sidebar))
gtk_widget_hide (logview->sidebar);
@@ -560,7 +678,7 @@ logview_toggle_sidebar (GtkAction *action, LogviewWindow *logview)
static void
logview_toggle_calendar (GtkAction *action, LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
if (GTK_WIDGET_VISIBLE (logview->calendar))
gtk_widget_hide (logview->calendar);
@@ -576,37 +694,46 @@ logview_toggle_calendar (GtkAction *action, LogviewWindow *logview)
static void
logview_collapse_rows (GtkAction *action, LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
- gtk_tree_view_collapse_all (GTK_TREE_VIEW (logview->view));
+ gtk_tree_view_collapse_all (GTK_TREE_VIEW (logview->view));
}
static void
logview_toggle_monitor (GtkAction *action, LogviewWindow *logview)
{
- Log *log;
-
- g_assert (LOGVIEW_IS_WINDOW (logview));
-
- log = logview->curlog;
- if ((log == NULL) || (log->display_name))
- return;
+ Log *log;
+ gchar *display_name;
+ gboolean monitoring;
+
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+
+ log = logview->curlog;
+ g_object_get (G_OBJECT (log),
+ "display-name", &display_name,
+ "monitoring", &monitoring,
+ NULL);
+ if ((log == NULL) || display_name) {
+ g_free (display_name);
+ return;
+ }
+ g_free (display_name);
- if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) &&
- (log->monitored))
- return;
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action)) &&
+ monitoring)
+ return;
- if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))==FALSE &&
- (!log->monitored))
- return;
+ if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action))==FALSE &&
+ !monitoring)
+ return;
- if (log->monitored)
- monitor_stop (log);
- else
- monitor_start (log);
+ if (monitoring)
+ monitor_stop (log);
+ else
+ monitor_start (log);
- logview_set_window_title (logview);
- logview_menus_set_state (logview);
+ logview_set_window_title (logview);
+ logview_menus_set_state (logview);
}
#define DEFAULT_LOGVIEW_FONT "Monospace 10"
@@ -635,7 +762,7 @@ logview_set_fontsize (LogviewWindow *logview)
PangoFontDescription *fontdesc;
PangoContext *context;
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
context = gtk_widget_get_pango_context (logview->view);
fontdesc = pango_context_get_font_description (context);
@@ -647,7 +774,7 @@ logview_set_fontsize (LogviewWindow *logview)
static void
logview_bigger_text (GtkAction *action, LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
logview->fontsize = MIN (logview->fontsize + 1, 24);
logview_set_fontsize (logview);
@@ -656,7 +783,7 @@ logview_bigger_text (GtkAction *action, LogviewWindow *logview)
static void
logview_smaller_text (GtkAction *action, LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
logview->fontsize = MAX (logview->fontsize-1, 6);
logview_set_fontsize (logview);
@@ -665,7 +792,7 @@ logview_smaller_text (GtkAction *action, LogviewWindow *logview)
static void
logview_normal_text (GtkAction *action, LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
logview->fontsize = logview->original_fontsize;
logview_set_fontsize (logview);
@@ -674,47 +801,56 @@ logview_normal_text (GtkAction *action, LogviewWindow *logview)
static void
logview_search (GtkAction *action, LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
- gtk_widget_show_all (logview->find_bar);
- logview_findbar_grab_focus (LOGVIEW_FINDBAR (logview->find_bar));
+ gtk_widget_show_all (logview->find_bar);
+ logview_findbar_grab_focus (LOGVIEW_FINDBAR (logview->find_bar));
}
static void
logview_copy (GtkAction *action, LogviewWindow *logview)
{
gchar *text, **lines;
- int nline, i, l1, l2;
- gchar *line;
- Log *log;
- GtkClipboard *clipboard;
-
- g_assert (LOGVIEW_IS_WINDOW (logview));
-
- log = logview->curlog;
- if (log == NULL)
- return;
-
- l1 = log->selected_line_first;
- l2 = log->selected_line_last;
- if (l1 == -1 || l2 == -1)
- return;
-
- nline = l2 - l1 + 1;
- lines = g_new0(gchar *, (nline + 1));
- for (i=0; i<=nline; i++) {
- line = log->lines[l1+i];
- lines[i] = g_strdup (line);
- }
- lines[nline] = NULL;
- text = g_strjoinv ("\n", lines);
-
- clipboard = gtk_widget_get_clipboard (GTK_WIDGET (logview->view),
- GDK_SELECTION_CLIPBOARD);
- gtk_clipboard_set_text (clipboard, text, -1);
-
- g_free (text);
- g_strfreev (lines);
+ int nline, i;
+ gchar *line;
+ GtkTreeIter iter;
+ GtkTreePath *selected_path;
+ Log *log;
+ GtkClipboard *clipboard;
+ GList *selected_paths, *idx;
+ GtkTreeModel *model;
+
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+
+ log = logview->curlog;
+ g_assert (LOGVIEW_IS_LOG (log));
+
+ g_object_get (G_OBJECT (log),
+ "selected-paths", &selected_paths,
+ "model", &model,
+ NULL);
+
+ if (selected_paths == NULL)
+ return;
+
+ nline = g_list_length (selected_paths);
+ lines = g_new0(gchar *, (nline + 1));
+ lines[nline] = NULL;
+ for (i = 0, idx = selected_paths; idx != NULL; idx = g_list_next (idx), i++) {
+ selected_path = idx->data;
+ gtk_tree_model_get_iter (model, &iter, selected_path);
+ gtk_tree_model_get (model,
+ &iter,
+ MESSAGE, &lines[i],
+ -1);
+ }
+ text = g_strjoinv ("\n", lines);
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (logview->view),
+ GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_text (clipboard, text, -1);
+
+ g_free (text);
+ g_strfreev (lines);
}
static void
@@ -722,7 +858,7 @@ logview_select_all (GtkAction *action, LogviewWindow *logview)
{
GtkTreeSelection *selection;
- g_assert (LOGVIEW_IS_WINDOW (logview));
+ g_assert (LOGVIEW_IS_WINDOW (logview));
selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (logview->view));
gtk_tree_selection_select_all (selection);
@@ -731,12 +867,12 @@ logview_select_all (GtkAction *action, LogviewWindow *logview)
static void
logview_menu_item_toggle_set_active (LogviewWindow *logview, char *path, gboolean state)
{
- GtkToggleAction *action;
+ GtkToggleAction *action;
- g_assert (path);
+ g_assert (path);
- action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (logview->ui_manager, path));
- gtk_toggle_action_set_active (action, state);
+ action = GTK_TOGGLE_ACTION (gtk_ui_manager_get_action (logview->ui_manager, path));
+ gtk_toggle_action_set_active (action, state);
}
static void
@@ -753,22 +889,26 @@ logview_menu_item_set_state (LogviewWindow *logview, char *path, gboolean state)
static void
logview_calendar_set_state (LogviewWindow *logview)
{
- g_assert (LOGVIEW_IS_WINDOW (logview));
-
- if (logview->curlog) {
- if (logview->curlog->days != NULL)
- calendar_init_data (CALENDAR (logview->calendar), logview);
- gtk_widget_set_sensitive (logview->calendar, (logview->curlog->days != NULL));
- } else
- gtk_widget_set_sensitive (logview->calendar, FALSE);
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+ gboolean groupable;
+
+ if (logview->curlog) {
+ g_object_get (G_OBJECT (logview->curlog),
+ "groupable", &groupable,
+ NULL);
+ if (groupable)
+ calendar_init_data (CALENDAR (logview->calendar), logview);
+ gtk_widget_set_sensitive (logview->calendar, groupable);
+ } else
+ gtk_widget_set_sensitive (logview->calendar, FALSE);
}
static void
logview_help (GtkAction *action, GtkWidget *parent_window)
{
- GError *error = NULL;
- gnome_help_display_desktop_on_screen (NULL, "gnome-system-log", "gnome-system-log", NULL,
- gtk_widget_get_screen (GTK_WIDGET(parent_window)), &error);
+ GError *error = NULL;
+ gnome_help_display_desktop_on_screen (NULL, "gnome-system-log", "gnome-system-log", NULL,
+ gtk_widget_get_screen (GTK_WIDGET(parent_window)), &error);
if (error) {
error_dialog_show (GTK_WIDGET(parent_window), _("There was an error displaying help."), error->message);
g_error_free (error);
@@ -777,188 +917,175 @@ logview_help (GtkAction *action, GtkWidget *parent_window)
static gboolean
window_size_changed_cb (GtkWidget *widget, GdkEventConfigure *event,
- gpointer data)
+ gpointer data)
{
- LogviewWindow *logview = LOGVIEW_WINDOW (data);
+ LogviewWindow *logview = LOGVIEW_WINDOW (data);
- g_assert (LOGVIEW_IS_WINDOW (logview));
- prefs_store_window_size (GTK_WIDGET(logview));
- return FALSE;
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+ prefs_store_window_size (GTK_WIDGET(logview));
+ return FALSE;
}
static void
logview_window_finalize (GObject *object)
{
- LogviewWindow *logview = LOGVIEW_WINDOW(object);
+ LogviewWindow *logview = LOGVIEW_WINDOW(object);
+
+ logview_plugin_list_delete (logview->plugin_list);
- g_object_unref (logview->ui_manager);
- parent_class->finalize (object);
+ g_object_unref (logview->ui_manager);
+ parent_class->finalize (object);
}
static void
logview_init (LogviewWindow *logview)
{
- GtkWidget *vbox;
- GtkTreeStore *tree_store;
- GtkTreeSelection *selection;
- GtkTreeViewColumn *column;
- GtkCellRenderer *renderer;
- gint i;
- GtkActionGroup *action_group;
- GtkAccelGroup *accel_group;
- GError *error = NULL;
- GtkWidget *menubar;
- GtkWidget *hpaned;
- GtkWidget *label;
- GtkWidget *main_view;
- GtkWidget *loglist_scrolled, *scrolled;
- PangoContext *context;
- PangoFontDescription *fontdesc;
- gchar *monospace_font_name;
-
- gtk_window_set_default_size (GTK_WINDOW (logview), prefs_get_width (), prefs_get_height ());
-
- vbox = gtk_vbox_new (FALSE, 0);
- gtk_container_add (GTK_CONTAINER (logview), vbox);
-
- /* Create menus */
- action_group = gtk_action_group_new ("LogviewMenuActions");
- gtk_action_group_set_translation_domain (action_group, NULL);
- gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), logview);
- gtk_action_group_add_toggle_actions(action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), logview);
-
- logview->ui_manager = gtk_ui_manager_new ();
-
- gtk_ui_manager_insert_action_group (logview->ui_manager, action_group, 0);
+ GtkWidget *vbox;
+ GtkTreeSelection *selection;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkActionGroup *action_group;
+ GtkAccelGroup *accel_group;
+ GError *error = NULL;
+ GtkWidget *menubar;
+ GtkWidget *hpaned;
+ GtkWidget *label;
+ GtkWidget *main_view;
+ GtkWidget *loglist_scrolled, *scrolled;
+ PangoContext *context;
+ PangoFontDescription *fontdesc;
+ gchar *monospace_font_name;
+
+ gtk_window_set_default_size (GTK_WINDOW (logview), prefs_get_width (), prefs_get_height ());
+
+ vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (logview), vbox);
+
+ /* Create menus */
+ action_group = gtk_action_group_new ("LogviewMenuActions");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ gtk_action_group_add_actions (action_group, entries, G_N_ELEMENTS (entries), logview);
+ gtk_action_group_add_toggle_actions(action_group, toggle_entries, G_N_ELEMENTS (toggle_entries), logview);
+
+ logview->ui_manager = gtk_ui_manager_new ();
+
+ gtk_ui_manager_insert_action_group (logview->ui_manager, action_group, 0);
- accel_group = gtk_ui_manager_get_accel_group (logview->ui_manager);
- gtk_window_add_accel_group (GTK_WINDOW (logview), accel_group);
+ accel_group = gtk_ui_manager_get_accel_group (logview->ui_manager);
+ gtk_window_add_accel_group (GTK_WINDOW (logview), accel_group);
- if (!gtk_ui_manager_add_ui_from_string (logview->ui_manager, ui_description, -1, &error)) {
- logview->ui_manager = NULL;
- return;
- }
+ if (!gtk_ui_manager_add_ui_from_string (logview->ui_manager, ui_description, -1, &error)) {
+ logview->ui_manager = NULL;
+ return;
+ }
- menubar = gtk_ui_manager_get_widget (logview->ui_manager, "/LogviewMenu");
- gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
+ menubar = gtk_ui_manager_get_widget (logview->ui_manager, "/LogviewMenu");
+ gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
- /* panes */
- hpaned = gtk_hpaned_new ();
- gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
+ /* panes */
+ hpaned = gtk_hpaned_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), hpaned, TRUE, TRUE, 0);
- /* First pane : sidebar (list of logs + calendar) */
- logview->sidebar = gtk_vbox_new (FALSE, 0);
-
- logview->calendar = calendar_new ();
- calendar_connect (CALENDAR (logview->calendar), logview);
- gtk_box_pack_end (GTK_BOX (logview->sidebar), GTK_WIDGET(logview->calendar), FALSE, FALSE, 0);
+ /* First pane : sidebar (list of logs + calendar) */
+ logview->sidebar = gtk_vbox_new (FALSE, 0);
- /* log list */
- loglist_scrolled = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (loglist_scrolled),
- GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (loglist_scrolled),
- GTK_SHADOW_ETCHED_IN);
- logview->loglist = loglist_new ();
- gtk_container_add (GTK_CONTAINER (loglist_scrolled), logview->loglist);
- gtk_box_pack_start (GTK_BOX (logview->sidebar), loglist_scrolled, TRUE, TRUE, 0);
- gtk_paned_pack1 (GTK_PANED (hpaned), logview->sidebar, FALSE, FALSE);
- loglist_connect (LOG_LIST(logview->loglist), logview);
-
- /* Second pane : log */
- main_view = gtk_vbox_new (FALSE, 0);
- gtk_paned_pack2 (GTK_PANED (hpaned), GTK_WIDGET (main_view), TRUE, TRUE);
-
- /* Scrolled window for the main view */
- scrolled = gtk_scrolled_window_new (NULL, NULL);
- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
- GTK_POLICY_AUTOMATIC,
- GTK_POLICY_AUTOMATIC);
- gtk_box_pack_start (GTK_BOX(main_view), scrolled, TRUE, TRUE, 0);
-
- /* Main Tree View */
- logview->view = gtk_tree_view_new ();
- gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (logview->view), FALSE);
- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (logview->view), FALSE);
-
- /* Use the desktop monospace font */
- monospace_font_name = prefs_get_monospace ();
- logview_set_font (logview, monospace_font_name);
- g_free (monospace_font_name);
-
- renderer = gtk_cell_renderer_text_new ();
- column = gtk_tree_view_column_new ();
- gtk_tree_view_column_pack_start (column, renderer, TRUE);
- gtk_tree_view_column_set_attributes (column, renderer,
- "text", LOG_LINE_TEXT,
- "weight", LOG_LINE_WEIGHT,
- "weight-set", LOG_LINE_WEIGHT_SET,
- NULL);
- //gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
- gtk_tree_view_append_column (GTK_TREE_VIEW (logview->view), column);
-
- /* Version selector */
- logview->version_bar = gtk_hbox_new (FALSE, 0);
- gtk_container_set_border_width (GTK_CONTAINER (logview->version_bar), 3);
- logview->version_selector = gtk_combo_box_new_text ();
- g_signal_connect (G_OBJECT (logview->version_selector), "changed",
- G_CALLBACK (logview_version_selector_changed), logview);
- label = gtk_label_new (_("Version: "));
+ logview->calendar = calendar_new ();
+ calendar_connect (CALENDAR (logview->calendar), logview);
+ gtk_box_pack_end (GTK_BOX (logview->sidebar), GTK_WIDGET(logview->calendar), FALSE, FALSE, 0);
- gtk_box_pack_end (GTK_BOX(logview->version_bar), logview->version_selector, FALSE, FALSE, 0);
- gtk_box_pack_end (GTK_BOX(logview->version_bar), label, FALSE, FALSE, 0);
- gtk_box_pack_end (GTK_BOX(main_view), logview->version_bar, FALSE, FALSE, 0);
+ /* log list */
+ loglist_scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (loglist_scrolled),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (loglist_scrolled),
+ GTK_SHADOW_ETCHED_IN);
+ logview->loglist = loglist_new ((gpointer)logview);
+ gtk_container_add (GTK_CONTAINER (loglist_scrolled), logview->loglist);
+ gtk_box_pack_start (GTK_BOX (logview->sidebar), loglist_scrolled, TRUE, TRUE, 0);
+ gtk_paned_pack1 (GTK_PANED (hpaned), logview->sidebar, FALSE, FALSE);
+
+ /* Second pane : log */
+ main_view = gtk_vbox_new (FALSE, 0);
+ gtk_paned_pack2 (GTK_PANED (hpaned), GTK_WIDGET (main_view), TRUE, TRUE);
+
+ /* Scrolled window for the main view */
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
+ GTK_POLICY_AUTOMATIC,
+ GTK_POLICY_AUTOMATIC);
+ gtk_box_pack_start (GTK_BOX(main_view), scrolled, TRUE, TRUE, 0);
+
+ /* Main Tree View */
+ logview->view = gtk_tree_view_new ();
+ gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (logview->view), FALSE);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (logview->view), FALSE);
+
+ /* Use the desktop monospace font */
+ monospace_font_name = prefs_get_monospace ();
+ logview_set_font (logview, monospace_font_name);
+ g_free (monospace_font_name);
+
+ renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new ();
+ gtk_tree_view_column_pack_start (column, renderer, TRUE);
+ gtk_tree_view_column_set_attributes (column, renderer,
+ "text", LOG_LINE_TEXT,
+ "weight", LOG_LINE_WEIGHT1,
+ "weight-set", LOG_LINE_WEIGHT_SET1,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (logview->view), column);
+
+ /* Version selector */
+ logview->version_bar = gtk_hbox_new (FALSE, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (logview->version_bar), 3);
+ logview->version_selector = gtk_combo_box_new_text ();
+ g_signal_connect (G_OBJECT (logview->version_selector), "changed",
+ G_CALLBACK (logview_version_selector_changed), logview);
+ label = gtk_label_new (_("Version: "));
- logview->find_bar = logview_findbar_new ();
- gtk_box_pack_end (GTK_BOX (main_view), logview->find_bar, FALSE, FALSE, 0);
- logview_findbar_connect (LOGVIEW_FINDBAR (logview->find_bar), logview);
-
- /* Remember the original font size */
- context = gtk_widget_get_pango_context (logview->view);
- fontdesc = pango_context_get_font_description (context);
- logview->original_fontsize = pango_font_description_get_size (fontdesc) / PANGO_SCALE;
- logview->fontsize = logview->original_fontsize;
-
- gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (logview->view));
- gtk_widget_show_all (scrolled);
+ gtk_box_pack_end (GTK_BOX(logview->version_bar), logview->version_selector, FALSE, FALSE, 0);
+ gtk_box_pack_end (GTK_BOX(logview->version_bar), label, FALSE, FALSE, 0);
+ gtk_box_pack_end (GTK_BOX(main_view), logview->version_bar, FALSE, FALSE, 0);
- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (logview->view));
- gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
-
- /* Add signal handlers */
- g_signal_connect (G_OBJECT (selection), "changed",
- G_CALLBACK (selection_changed_cb), logview);
- g_signal_connect (G_OBJECT (logview->view), "row-expanded",
- G_CALLBACK (row_toggled_cb), logview);
- g_signal_connect (G_OBJECT (logview->view), "row-collapsed",
- G_CALLBACK (row_toggled_cb), logview);
- g_signal_connect (G_OBJECT (logview), "configure_event",
- G_CALLBACK (window_size_changed_cb), logview);
-
- /* Status area at bottom */
- logview->statusbar = gtk_statusbar_new ();
- gtk_box_pack_start (GTK_BOX (vbox), logview->statusbar, FALSE, FALSE, 0);
-
- gtk_widget_show (menubar);
- gtk_widget_show (loglist_scrolled);
- gtk_widget_show (main_view);
- gtk_widget_show (vbox);
- logview->hpaned = hpaned;
-}
+ logview->find_bar = logview_findbar_new ();
+ gtk_box_pack_end (GTK_BOX (main_view), logview->find_bar, FALSE, FALSE, 0);
+ logview_findbar_connect (LOGVIEW_FINDBAR (logview->find_bar), logview);
-static void
-logview_window_get_property (GObject *object, guint param_id, GValue *value, GParamSpec *pspec)
-{
- LogviewWindow *logview = LOGVIEW_WINDOW (object);
-
- switch (param_id) {
- case PROP_DAYS:
- g_value_set_pointer (value, logview->curlog->days);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- }
+ /* Remember the original font size */
+ context = gtk_widget_get_pango_context (logview->view);
+ fontdesc = pango_context_get_font_description (context);
+ logview->original_fontsize = pango_font_description_get_size (fontdesc) / PANGO_SCALE;
+ logview->fontsize = logview->original_fontsize;
+
+ gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (logview->view));
+ gtk_widget_show_all (scrolled);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (logview->view));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
+
+ /* Add signal handlers */
+ g_signal_connect (G_OBJECT (selection), "changed",
+ G_CALLBACK (selection_changed_cb), logview);
+ g_signal_connect (G_OBJECT (logview->view), "row-expanded",
+ G_CALLBACK (row_toggled_cb), logview);
+ g_signal_connect (G_OBJECT (logview->view), "row-collapsed",
+ G_CALLBACK (row_toggled_cb), logview);
+ g_signal_connect (G_OBJECT (logview), "configure_event",
+ G_CALLBACK (window_size_changed_cb), logview);
+
+ /* Status area at bottom */
+ logview->statusbar = gtk_statusbar_new ();
+ gtk_box_pack_start (GTK_BOX (vbox), logview->statusbar, FALSE, FALSE, 0);
+
+ gtk_widget_show (menubar);
+ gtk_widget_show (loglist_scrolled);
+ gtk_widget_show (main_view);
+ gtk_widget_show (vbox);
+ logview->hpaned = hpaned;
+ logview->plugin_list = logview_plugin_list_new ();
+
+ /* set logview pointer */
+ monitor_set_window ((gpointer)logview);
}
static void
@@ -967,14 +1094,7 @@ logview_window_class_init (LogviewWindowClass *klass)
GObjectClass *object_class = (GObjectClass *) klass;
object_class->finalize = logview_window_finalize;
- object_class->get_property = logview_window_get_property;
parent_class = g_type_class_peek_parent (klass);
-
- g_object_class_install_property (object_class, PROP_DAYS,
- g_param_spec_pointer ("days",
- _("Days"),
- _("Pointer towards a GSList of days for the current log."),
- (G_PARAM_READABLE)));
}
GType
@@ -1004,21 +1124,28 @@ logview_window_get_type (void)
GtkWidget *
logview_window_new ()
{
- LogviewWindow *logview;
- GtkWidget *window;
+ LogviewWindow *logview;
+ GtkWidget *window;
- window = g_object_new (LOGVIEW_TYPE_WINDOW, NULL);
- logview = LOGVIEW_WINDOW (window);
- if (logview->ui_manager == NULL)
- return NULL;
+ window = g_object_new (LOGVIEW_TYPE_WINDOW, NULL);
+ logview = LOGVIEW_WINDOW (window);
+ if (logview->ui_manager == NULL)
+ return NULL;
- logview->logs = NULL;
+ logview->logs = NULL;
- gtk_ui_manager_set_add_tearoffs (logview->ui_manager,
- prefs_get_have_tearoff ());
+ gtk_ui_manager_set_add_tearoffs (logview->ui_manager,
+ prefs_get_have_tearoff ());
- g_signal_connect (GTK_OBJECT (window), "destroy",
- G_CALLBACK (logview_destroy), logview);
+ g_signal_connect (GTK_OBJECT (window), "destroy",
+ G_CALLBACK (logview_destroy), logview);
- return window;
+ return window;
+}
+
+static void
+logview_plugin_dialog_show (GtkAction *action, LogviewWindow *logview)
+{
+ g_assert (LOGVIEW_IS_WINDOW (logview));
+ logview_plugin_list_show (logview->plugin_list, GTK_WIDGET (logview));
}
diff --git a/logview/logview.h b/logview/logview.h
index dacfa2e..1e826d6 100644
--- a/logview/logview.h
+++ b/logview/logview.h
@@ -23,6 +23,7 @@
#define __LOGVIEW_H__
#include "logrtns.h"
+#include "logview-plugin-list.h"
#define MAX_VERSIONS 5
@@ -39,19 +40,20 @@ typedef struct _LogviewWindowClass LogviewWindowClass;
struct _LogviewWindow {
GtkWindow parent_instance;
- GtkWidget *view;
+ GtkWidget *view;
GtkWidget *statusbar;
GtkUIManager *ui_manager;
GtkWidget *calendar;
GtkWidget *find_bar;
GtkWidget *loglist;
- GtkWidget *sidebar;
+ GtkWidget *sidebar;
GtkWidget *version_bar;
GtkWidget *version_selector;
- GtkWidget *hpaned;
-
- GSList *logs;
+ GtkWidget *hpaned;
+ LogviewPluginList *plugin_list;
+
+ GSList *logs;
Log *curlog;
int original_fontsize, fontsize;
diff --git a/logview/main.c b/logview/main.c
index 37242b8..05e17af 100644
--- a/logview/main.c
+++ b/logview/main.c
@@ -36,6 +36,8 @@
#include "logview.h"
#include "misc.h"
#include "userprefs.h"
+#include "logview-plugin-manager.h"
+#include "logview-debug.h"
static gboolean show_version = FALSE;
@@ -86,7 +88,6 @@ save_session_cb (GnomeClient *gnome_client,
gchar **argv;
gint numlogs;
GSList *logs;
- Log *log;
gint i = 0;
g_assert (LOGVIEW_IS_WINDOW (logview));
@@ -98,12 +99,11 @@ save_session_cb (GnomeClient *gnome_client,
argv = g_new0 (gchar *, numlogs + 2);
argv[i++] = g_get_prgname();
- for (logs = logview->logs; logs != NULL; logs = logs->next) {
+ for (i = 1, logs = logview->logs; logs != NULL; logs = logs->next) {
Log *log = (Log *) logs->data;
g_assert (log != NULL);
-
- argv[i++] = g_strdup (log->name);
+ g_object_get (G_OBJECT (log), "path", &argv[i++], NULL);
}
argv[i] = NULL;
@@ -120,7 +120,6 @@ int
main (int argc, char *argv[])
{
GnomeClient *gnome_client;
- GError *error;
GnomeProgram *program;
GOptionContext *context;
LogviewWindow *logview;
@@ -129,10 +128,6 @@ main (int argc, char *argv[])
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
textdomain (GETTEXT_PACKAGE);
- error_dialog_queue (TRUE);
-
- gnome_vfs_init ();
- prefs_init ();
context = logview_init_options ();
program = gnome_program_init ("gnome-system-log", VERSION,
@@ -140,20 +135,42 @@ main (int argc, char *argv[])
argc, argv,
GNOME_PARAM_APP_DATADIR, DATADIR,
GNOME_PARAM_GOPTION_CONTEXT, context,
- NULL);
+ GNOME_PARAM_NONE);
g_set_application_name (_("Log Viewer"));
if (show_version)
logview_show_version_and_quit ();
-
+
+ error_dialog_queue (TRUE);
+
+ g_type_init ();
+ if (! g_thread_supported ())
+ g_thread_init (NULL);
+
+ if (!create_home_dir ()) {
+ g_printf (_("Fatal error! Can't open $HOME/%s.\n"),
+ LOGVIEW_HOME_SUFFIX);
+ exit (1);
+ }
+
+ gnome_vfs_init ();
+ logview_debug_init ();
+ pluginmgr_init ();
+ if (!pluginmgr_load_modules ()) {
+ error_dialog_show (NULL,
+ _("Unable to load modules."),
+ NULL);
+ exit (1);
+ }
+ prefs_init ();
+
/* Open regular logs and add each log passed as a parameter */
logview = LOGVIEW_WINDOW (logview_window_new ());
if (!logview) {
error_dialog_show (NULL,
_("Unable to create user interface."),
NULL);
-
exit (0);
}
@@ -174,7 +191,7 @@ main (int argc, char *argv[])
} else {
gint i;
- for (i = 1; i < argc; i++)
+ for (i = 1; i < argc; i++)
logview_add_log_from_name (logview, argv[i]);
}
@@ -191,6 +208,10 @@ main (int argc, char *argv[])
}
gtk_main ();
-
+
+ pluginmgr_destroy ();
+ logview_debug_destroy ();
+ gnome_vfs_shutdown ();
return EXIT_SUCCESS;
}
+
diff --git a/logview/misc.c b/logview/misc.c
index 09db2c7..57cf343 100644
--- a/logview/misc.c
+++ b/logview/misc.c
@@ -18,24 +18,45 @@
---------------------------------------------------------------------- */
+#define _XOPEN_SOURCE 500
+
#ifdef __CYGWIN__
#define timezonevar
#endif
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
-#define _XOPEN_SOURCE
+
#include <time.h>
#include <string.h>
#include <stdlib.h>
+#include <unistd.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
+#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-mime-utils.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include "logrtns.h"
+#include "logview-plugin-manager.h"
+#include "logview-debug.h"
+#include "misc.h"
+
+#define LOGVIEW_DATA_PLUGIN_PATH LOGVIEWPLUGINDIR
+#define LOGVIEW_USER_PLUGIN_PATH_SUFFIX LOGVIEW_HOME_SUFFIX"/plugins"
+char *error_main = N_("One file or more could not be opened");
static gboolean queue_err_messages = FALSE;
static GSList *msg_queue_main = NULL, *msg_queue_sec = NULL;
const char *month[12] =
@@ -44,7 +65,7 @@ const char *month[12] =
N_("November"), N_("December")};
static void
-error_dialog_run (GtkWidget *window, const char *main, char *secondary)
+error_dialog_run (GtkWidget *window, const char *main, const char *secondary)
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW (window),
@@ -60,13 +81,13 @@ error_dialog_run (GtkWidget *window, const char *main, char *secondary)
}
void
-error_dialog_show (GtkWidget *window, char *main, char *secondary)
+error_dialog_show (GtkWidget *window, const char *main, const char *secondary)
{
- if (queue_err_messages) {
- msg_queue_main = g_slist_append (msg_queue_main, g_strdup (main));
- msg_queue_sec = g_slist_append (msg_queue_sec, g_strdup (secondary));
- } else
- error_dialog_run (window, main, secondary);
+ if (queue_err_messages) {
+ msg_queue_main = g_slist_append (msg_queue_main, g_strdup (main));
+ msg_queue_sec = g_slist_append (msg_queue_sec, g_strdup (secondary));
+ } else
+ error_dialog_run (window, main, secondary);
}
void
@@ -116,63 +137,599 @@ error_dialog_show_queued (void)
}
}
+char*
+error_system_string (void)
+{
+ return strerror (errno);
+}
+
char *
locale_to_utf8 (const char *in)
{
- char *out;
+ char *out;
- if (g_utf8_validate (in, -1, NULL))
- out = g_strdup (in);
- else {
- out = g_locale_to_utf8 (in, -1, NULL, NULL, NULL);
- if (out == NULL)
- out = g_strdup ("?");
- }
+ if (g_utf8_validate (in, -1, NULL))
+ out = g_strdup (in);
+ else {
+ out = g_locale_to_utf8 (in, -1, NULL, NULL, NULL);
+ if (out == NULL)
+ out = g_strdup ("?");
+ }
- return out;
+ return out;
}
GDate *
string_get_date (char *line)
{
- GDate *date;
- struct tm tp;
- char *cp;
-
- if (line == NULL || line[0] == 0)
- return NULL;
-
- cp = strptime (line, "%b %d", &tp);
- if (cp == NULL) {
- cp = strptime (line, "%F", &tp);
- if (cp == NULL) {
- return NULL;
- }
- }
+ GDate *date;
+ struct tm tp;
+ char *cp;
+ char *tm_locale = NULL;
+
+ if (line == NULL || line[0] == '\0')
+ return NULL;
+
+ if (tm_locale != NULL) {
+change_locale:
+ tm_locale = setlocale (LC_TIME, NULL);
+ setlocale (LC_TIME, "C");
+ }
- date = g_date_new_dmy (tp.tm_mday, tp.tm_mon+1, 70);
- return date;
+ if ((cp = strptime (line, "%b %d", &tp)) == NULL)
+ if ((cp = strptime (line, "%a %b %d", &tp)) == NULL)
+ if ((cp = strptime (line, "%F", &tp)) == NULL) {
+ if (tm_locale == NULL)
+ goto change_locale;
+ else {
+ setlocale (LC_TIME, tm_locale);
+ return NULL;
+ }
+ }
+
+ if (tm_locale != NULL) {
+ setlocale (LC_TIME, tm_locale);
+ }
+
+ date = g_date_new_dmy (tp.tm_mday, tp.tm_mon+1, 70);
+ return date;
}
char *
-date_get_string (GDate *date)
+date_to_string (GDate *date)
{
- char buf[512];
- char *utf8;
+ char buf[512];
+ char *utf8;
- if (date == NULL || !g_date_valid (date)) {
- utf8 = g_strdup(_("Invalid date"));
- return utf8;
- }
+ if (date == NULL || !g_date_valid (date)) {
+ utf8 = g_strdup(_("Invalid date"));
+ return utf8;
+ }
- /* Translators: Only date format, time will be bogus */
- if (g_date_strftime (buf, sizeof (buf), _("%x"), date) == 0) {
- int m = g_date_get_month (date);
- int d = g_date_get_day (date);
- /* If we fail just use the US format */
- utf8 = g_strdup_printf ("%s %d", _(month[(int) m-1]), d);
- } else
- utf8 = locale_to_utf8 (buf);
+ /* Translators: Only date format, time will be bogus */
+ if (g_date_strftime (buf, sizeof (buf), _("%x"), date) == 0) {
+ int m = g_date_get_month (date);
+ int d = g_date_get_day (date);
+ /* If we fail just use the US format */
+ utf8 = g_strdup_printf ("%s %d", _(month[(int) m-1]), d);
+ } else
+ utf8 = locale_to_utf8 (buf);
- return utf8;
+ return utf8;
}
+
+/* File checking */
+
+gboolean
+try_to_open (const gchar *filename, gboolean show_error)
+{
+ GnomeVFSHandle *handle;
+ GnomeVFSResult result;
+ char *secondary = NULL;
+
+ if (filename == NULL)
+ return FALSE;
+
+ result = gnome_vfs_open (&handle, filename, GNOME_VFS_OPEN_READ);
+ if (result != GNOME_VFS_OK) {
+ if (show_error) {
+ switch (result) {
+ case GNOME_VFS_ERROR_ACCESS_DENIED:
+ case GNOME_VFS_ERROR_NOT_PERMITTED:
+ secondary = g_strdup_printf (_("%s is not user readable. "
+ "Either run the program as root or ask the sysadmin to "
+ "change the permissions on the file.\n"), filename);
+ break;
+ case GNOME_VFS_ERROR_TOO_BIG:
+ secondary = g_strdup_printf (_("%s is too big."), filename);
+ break;
+ default:
+ secondary = g_strdup_printf (_("%s could not be opened."), filename);
+ break;
+ }
+ error_dialog_show (NULL, error_main, secondary);
+ g_free (secondary);
+ }
+ return FALSE;
+ }
+
+ gnome_vfs_close (handle);
+ return TRUE;
+}
+
+gchar *
+log_extract_dirname (const gchar *logname)
+{
+ GnomeVFSURI *uri;
+ gchar *dirname;
+
+ uri = gnome_vfs_uri_new (logname);
+ dirname = gnome_vfs_uri_extract_dirname (uri);
+ gnome_vfs_uri_unref (uri);
+
+ return dirname;
+}
+
+gchar *
+log_extract_filename (const gchar *logname)
+{
+ GnomeVFSURI *uri;
+ gchar *filename;
+
+ uri = gnome_vfs_uri_new (logname);
+ filename = gnome_vfs_uri_extract_short_name (uri);
+ gnome_vfs_uri_unref (uri);
+
+ return filename;
+}
+
+void
+extract_filepath (const gchar *logname, gchar** dirname, gchar** filename)
+{
+ GnomeVFSURI *uri;
+
+ uri = gnome_vfs_uri_new (logname);
+ if (dirname != NULL) *dirname = gnome_vfs_uri_extract_dirname (uri);
+ if (filename != NULL) *filename = gnome_vfs_uri_extract_short_name (uri);
+ gnome_vfs_uri_unref (uri);
+}
+
+gchar *
+get_date_string (gchar *line)
+{
+ gchar **split, *date_string;
+ gchar *month=NULL, *day=NULL;
+ int i=0;
+
+ if (line == NULL || line[0] == 0)
+ return NULL;
+
+ split = g_strsplit (line, " ", 4);
+ if (split == NULL)
+ return NULL;
+
+ while ((day == NULL || month == NULL) && split[i]!=NULL && i<4) {
+ if (g_str_equal (split[i], "")) {
+ i++;
+ continue;
+ }
+
+ if (month == NULL) {
+ month = split[i++];
+ /* If the first field begins by a number, the date
+ is given in yyyy-mm-dd format */
+ if (!g_ascii_isalpha (month[0]))
+ break;
+ continue;
+ }
+
+ if (day == NULL)
+ day = split[i];
+ i++;
+ }
+
+ if (i==3)
+ date_string = g_strconcat (month, " ", day, NULL);
+ else
+ date_string = g_strconcat (month, " ", day, NULL);
+ g_strfreev (split);
+ return (date_string);
+}
+
+LogProtocol
+file_protocol (const char *filename)
+{
+ LogProtocol protocol;
+
+ LV_MARK;
+ g_assert (filename);
+ g_assert (filename[0] != '\0');
+
+ if (local_file_exist (filename)) {
+ char *mime_type = gnome_vfs_get_mime_type (filename);
+ LV_INFO ("[protocol] %s detected mime: %s",
+ filename,
+ mime_type != NULL ? mime_type : "(nil)");
+ if (mime_type == NULL) {
+ protocol = UNKNOWN_LOG;
+ } else if (g_str_has_prefix (mime_type, "text/")) {
+ protocol = PLAIN_LOG;
+ } else if (strcmp (mime_type, "application/octet-stream")==0) {
+ protocol = PIPE_LOG;
+ } else if (strcmp (mime_type, "application/x-gzip")==0 ||
+ strcmp (mime_type, "application/x-zip")==0 ||
+ strcmp (mime_type, "application/zip")==0) {
+ protocol = GZIP_LOG;
+ } else if (g_str_has_prefix (mime_type, "x-directory/") ||
+ g_str_has_prefix (mime_type, "application/x-executable")) {
+ protocol = BAD_LOG;
+ } else {
+ protocol = UNKNOWN_LOG;
+ }
+ g_free (mime_type);
+ } else {
+ protocol = UNKNOWN_LOG;
+ }
+ LV_INFO ("[protocol] %s assigned protocol: %d", filename, protocol);
+ return protocol;
+}
+
+gboolean
+local_file_can_executed (const gchar *filename)
+{
+ struct stat buf;
+ if (stat (filename, &buf) == 0) {
+ return buf.st_uid == getuid() || buf.st_uid == 0;
+ }
+}
+
+gboolean
+local_file_exist (const gchar *filename)
+{
+ struct stat buf;
+ if (stat (filename, &buf) == 0) {
+ return S_ISBLK (buf.st_mode) ||
+ S_ISCHR (buf.st_mode) ||
+ S_ISDIR (buf.st_mode) ||
+ S_ISFIFO (buf.st_mode) ||
+ S_ISREG (buf.st_mode) ||
+ S_ISSOCK (buf.st_mode);
+ }
+ return FALSE;
+}
+
+gchar *
+processor_arch (void)
+{
+ static gchar cpu_arch[BUFSIZ] = {0};
+ /* get system ARCH for Solaris*/
+ if (*cpu_arch == 0) {
+#ifdef ON_SUN_OS
+#include <sys/systeminfo.h>
+ if (sysinfo(SI_ARCHITECTURE, cpu_arch, sizeof (cpu_arch)) == -1) {
+ LV_INFO_EE ("get sysinfo failed: %s", error_system_string ());
+ }
+#else
+#include <sys/utsname.h>
+ struct utsname buf;
+ if (uname(&buf) == -1) {
+ LV_INFO_EE ("get sysinfo failed: %s", error_system_string ());
+ }
+ strcpy(cpu_arch, buf.machine);
+#endif
+ }
+ LV_ERR ("ARCH = %s", cpu_arch);
+ return cpu_arch;
+}
+
+G_CONST_RETURN GSList*
+get_plugin_paths()
+{
+ static GSList *plugin_paths = NULL;
+ struct stat buf;
+ gchar* user_plugin_path = NULL;
+
+ if (plugin_paths)
+ return plugin_paths;
+
+ /* get user plugin path */
+ user_plugin_path = g_build_path (G_DIR_SEPARATOR_S,
+ (gchar*)g_get_home_dir (),
+ LOGVIEW_USER_PLUGIN_PATH_SUFFIX,
+ processor_arch (),
+ NULL);
+ if (stat (user_plugin_path, &buf) == 0) {
+ if (S_ISDIR (buf.st_mode)) {
+ plugin_paths = g_slist_append (plugin_paths,
+ user_plugin_path);
+ } else {
+ g_free (user_plugin_path);
+ }
+ }
+ else if (errno == ENOENT &&
+ g_mkdir_with_parents (user_plugin_path, get_umask()) == 0) {
+ plugin_paths = g_slist_append (plugin_paths,
+ user_plugin_path);
+ }
+ else {
+ LV_ERR ("err|create user plugin path: %s", user_plugin_path);
+ g_free (user_plugin_path);
+ return NULL;
+ }
+
+ /* get default plugin path */
+ if (stat (LOGVIEW_DATA_PLUGIN_PATH, &buf) == 0) {
+ if (S_ISDIR (buf.st_mode)) {
+ plugin_paths = g_slist_append(plugin_paths,
+ (gpointer*)g_strdup (LOGVIEW_DATA_PLUGIN_PATH));
+ }
+ }
+ return plugin_paths;
+}
+
+/*
+ * Alternative popen due to the security issue
+ */
+
+typedef struct {
+ int fd;
+ pid_t pid;
+} pf_node; /* pair of pipe and file description */
+
+static GSList *pf_list = NULL;
+static void
+pf_insert (int fd, pid_t pid)
+{
+ pf_node *node = g_new0 (pf_node, 1);
+ g_assert (node);
+ node->fd = fd;
+ node->pid = pid;
+ pf_list = g_slist_prepend (pf_list, node);
+}
+
+static pid_t
+pf_delete (int fd)
+{
+ GSList *idx = NULL;
+ pid_t pid = -1;
+ for (idx = pf_list; idx; idx=g_slist_next (idx)) {
+ if (((pf_node *)idx->data)->fd == fd) {
+ pid = ((pf_node *)idx->data)->pid;
+ g_free (idx->data);
+ pf_list = g_slist_delete_link (pf_list, idx);
+ break;
+ }
+ }
+ return pid;
+}
+
+static GStaticMutex pipe_mutex = G_STATIC_MUTEX_INIT;
+#define PIPE_MUTEX_LOCK() (g_static_mutex_lock (&pipe_mutex))
+#define PIPE_MUTEX_UNLOCK() (g_static_mutex_unlock (&pipe_mutex))
+/**
+ * _security_popen_raw:
+ * @cmd:
+ * @argv: directly pass to execve, so should be NULL terminated.
+ * @envp: directly pass to execve.
+ *
+ * Only support read.
+ *
+ * Note that, the path is restricted in "/usr/bin:/usr/sbin".
+ *
+ * RETURNS: the pointer of the file stream structure.
+ */
+static FILE*
+_security_popen (const char *path, char *const argv[], char *const envp[])
+{
+ int p[2];
+ pid_t pid;
+ FILE* iop;
+
+ if (path == NULL || argv == NULL)
+ return NULL;
+
+ if (pipe (p) < 0)
+ return NULL;
+
+ if ((iop = fdopen (p[0], "r")) == NULL) {
+ close (p[0]);
+ close (p[1]);
+ return NULL;
+ }
+
+ PIPE_MUTEX_LOCK();
+
+ if ((pid = vfork()) == 0) {
+ /* child */
+ GSList *idx = NULL;
+ int error;
+ close (p[0]);
+ if (p[1] != STDOUT_FILENO) {
+ if (dup2 (p[1], STDOUT_FILENO) == -1){
+ perror ("dup2(3C)");
+ exit (errno);
+ }
+ close (p[1]);
+ }
+
+ /* close all fds */
+ for (idx = pf_list; idx; idx = g_slist_next (idx)) {
+ close (((pf_node *)idx->data)->fd);
+ g_free (idx->data);
+ }
+ g_slist_free (pf_list);
+
+ error = execve (path, argv, envp);
+ if ( error == -1) {
+ perror ("execve(2)");
+ exit (errno);
+ }
+ exit (127);
+ }
+ else if (pid < 0) {
+ PIPE_MUTEX_UNLOCK();
+ close (p[0]);
+ close (p[1]);
+ fclose (iop);
+ return NULL;
+ }
+ /* parent */
+ PIPE_MUTEX_UNLOCK();
+ close (p[1]);
+ pf_insert (p[0], pid);
+ return iop;
+}
+
+/**
+ * security_pclose:
+ * @fp:
+ *
+ */
+int
+security_pclose (FILE *fp)
+{
+#ifdef ON_SUN_OS
+ pid_t pid;
+ int status;
+
+ if (fp == NULL)
+ return -1;
+
+ pid = pf_delete (fileno (fp));
+
+ fclose (fp);
+ if (pid == -1)
+ return -1;
+ while (waitpid(pid, &status, 0) < 0) {
+ if (errno != EINTR) {
+ status = -1;
+ break;
+ }
+ }
+ return status;
+#else
+ return pclose (fp);
+#endif
+}
+
+/**
+ * security_popen:
+ * @command: the command need be executed.
+ * @mode: for compatible usage in Linux, this function will call popen().
+ * In Solaris, it's useless.
+ *
+ * Only support read.
+ *
+ * Note that, the path is restricted in "/bin:/sbin:/usr/bin:/usr/sbin".
+ *
+ * RETURNS: the pointer of the file stream structure.
+ */
+FILE*
+security_popen (const char *command, const char *mode)
+{
+#ifdef ON_SUN_OS
+ static char *const res_path[] = {"PATH=/bin:/sbin:/usr/bin:/usr/sbin", NULL};
+ static const char *shellenv = "SHELL";
+ static const char *pfsh_path = "/bin/pfsh";
+ static const char *pfsh = "pfsh";
+ static const char *pfcsh_path = "/bin/pfcsh";
+ static const char *pfcsh = "pfcsh";
+ static const char *pfksh_path = "/bin/pfksh";
+ static const char *pfksh = "pfksh";
+ static const char *sh_opt = "-c";
+ char *argve[4];
+ char *shpath = NULL;
+ char *shell = NULL;
+
+ shpath = (char*) pfsh_path;
+ shell = (char*) pfsh;
+ argve[0] = (char *) shell;
+ argve[1] = (char *) sh_opt;
+ argve[2] = (char *) command;
+ argve[3] = NULL;
+ return _security_popen (shpath, (char* const*)argve, res_path);
+#else
+ return popen (command, mode);
+#endif
+}
+
+static gchar *err_msg = NULL;
+G_CONST_RETURN gchar *
+log_error (void)
+{
+ return err_msg;
+}
+
+void
+log_error_init (const gchar *log_path)
+{
+ if (err_msg)
+ g_free (err_msg);
+ err_msg = g_strdup_printf ("%s :\n", log_path);
+}
+
+void
+log_error_append (const gchar *msg)
+{
+ gchar *tmp;
+ g_assert (msg);
+ tmp = g_strdup_printf ("%s\t%s\n", err_msg, msg);
+ g_free (err_msg);
+ err_msg = tmp;
+}
+
+void
+log_error_appendv (const gchar *format, ...)
+{
+ gchar *tmp, *err;
+ va_list ap;
+
+ g_assert (format);
+
+ va_start (ap, format);
+ err= g_strdup_vprintf (format, ap);
+ va_end (ap);
+
+ tmp = g_strdup_printf ("%s\t%s\n", err_msg, err);
+
+ g_free (err);
+ g_free (err_msg);
+ err_msg = tmp;
+}
+
+gint
+get_umask ()
+{
+ static gint current_umask=0;
+ if (current_umask == 0) {
+ mode_t umode = 0;
+ umode = umask (umode);
+ umask (umode);
+ current_umask = umode ^ 0777;
+ }
+ return current_umask;
+}
+
+gboolean
+create_home_dir (void)
+{
+ struct stat buf;
+ gboolean ret = FALSE;
+ gchar* logview_home = NULL;
+
+ /* get user plugin path */
+ logview_home = g_build_path (G_DIR_SEPARATOR_S,
+ (gchar*)g_get_home_dir (),
+ LOGVIEW_HOME_SUFFIX,
+ NULL);
+ if (stat (logview_home, &buf) == 0) {
+ if (S_ISDIR (buf.st_mode) && (S_IRWXU & buf.st_mode)) {
+ ret = TRUE;
+ }
+ } else if (errno == ENOENT &&
+ g_mkdir_with_parents (logview_home, get_umask()) == 0) {
+ ret = TRUE;
+ }
+ return ret;
+}
+
diff --git a/logview/misc.h b/logview/misc.h
index c0eb5ee..37d4e01 100644
--- a/logview/misc.h
+++ b/logview/misc.h
@@ -20,14 +20,41 @@
#ifndef __LOG_MISC_H__
#define __LOG_MISC_H__
-void error_dialog_show (GtkWidget *window, char *main, char *secondary);
+#include "logview-log.h"
+
+#define LOGVIEW_HOME_SUFFIX ".gnome2/gnome-system-log"
+
+void error_dialog_show (GtkWidget *window, const char *main, const char *secondary);
void error_dialog_queue (gboolean do_queue);
void error_dialog_show_queued (void);
+char* error_system_string (void);
char *locale_to_utf8 (const char *in);
GDate *string_get_date (char *line);
int string_get_month (const char *str);
-char *date_get_string (GDate *date);
+char *date_to_string (GDate *date);
+
+gboolean file_is_log (char *filename, gboolean show_error);
+gchar *log_extract_dirname (const gchar *logname);
+gchar *log_extract_filename (const gchar *logname);
+
+void extract_filepath (const gchar *logname, gchar** dirname, gchar** filename);
+LogProtocol file_protocol (const char *filename);
+gboolean try_to_open (const gchar *filename, gboolean show_error);
+gboolean local_file_exist (const gchar *filename);
+gboolean local_file_can_executed (const gchar *filename);
+
+gchar * get_date_string (gchar *line);
+gchar * processor_arch (void);
+G_CONST_RETURN GSList* get_plugin_paths();
+FILE* security_popen (const char *cmd, const char *mode);
+int security_pclose (FILE *fp);
+
+G_CONST_RETURN gchar *log_error (void);
+void log_error_append (const gchar *msg);
+void log_error_init (const gchar *log_path);
+gint get_umask ();
+gboolean create_home_dir (void);
#endif /* __LOG_MISC_H__ */
diff --git a/logview/monitor.c b/logview/monitor.c
index a156033..ff03b48 100644
--- a/logview/monitor.c
+++ b/logview/monitor.c
@@ -1,98 +1,163 @@
-/* ----------------------------------------------------------------------
+/* ----------------------------------------------------------------------
- Copyright (C) 1998 Cesar Miquel (miquel@df.uba.ar)
+Copyright (C) 1998 Cesar Miquel (miquel@df.uba.ar)
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- ---------------------------------------------------------------------- */
+---------------------------------------------------------------------- */
#include <gtk/gtk.h>
#include <glib/gi18n.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
#include "logview.h"
#include "logrtns.h"
+#include "log_repaint.h"
#include "monitor.h"
-#include <libgnomevfs/gnome-vfs-ops.h>
+#include "misc.h"
+#include "logview-debug.h"
+
+#define CHECK_FILE_PERIOD 10000
+
+static gpointer window = NULL;
void
monitor_stop (Log *log)
{
- g_return_if_fail (log);
-
- if (log->mon_handle != NULL) {
- gnome_vfs_monitor_cancel (log->mon_handle);
- log->mon_handle = NULL;
- log->mon_offset = 0;
-
- gnome_vfs_close (log->mon_file_handle);
- log->mon_file_handle = NULL;
-
- log->monitored = FALSE;
- }
+ GnomeVFSMonitorHandle *mon_handle;
+ LV_MARK;
+ g_assert (LOGVIEW_IS_LOG (log));
+
+ g_object_get (G_OBJECT (log),
+ "monitor-handle", &mon_handle, NULL);
+ if (mon_handle != NULL) {
+ gnome_vfs_monitor_cancel (mon_handle);
+ g_object_set (G_OBJECT (log),
+ "monitor-handle", NULL, NULL);
+ }
+ g_object_set (G_OBJECT (log),
+ "monitoring", FALSE, NULL);
+ g_object_unref (log);
}
static void
monitor_callback (GnomeVFSMonitorHandle *handle, const gchar *monitor_uri,
- const gchar *info_uri, GnomeVFSMonitorEventType event_type,
- gpointer data)
+ const gchar *info_uri, GnomeVFSMonitorEventType event_type,
+ gpointer data)
+{
+ LogviewWindow *logview = LOGVIEW_WINDOW(window);
+ Log *log = data;
+
+ LV_MARK;
+ g_assert (LOGVIEW_IS_LOG (log));
+
+ loglist_bold_log (LOG_LIST (logview->loglist), log);
+ if (logview->curlog == log)
+ logview_repaint (logview);
+}
+
+/* ----------------------------------------------------------------------
+NAME: monitor_log_was_modified
+DESCRIPTION: Returns true if modified flag in log changed. It also
+changes the modified flag. This function is called in unexpected time,
+so the passed in log must be referenced. And only unreferenced when timer
+is invalid.
+---------------------------------------------------------------------- */
+
+static gboolean
+monitor_log_was_modified (Log *log)
{
- LogviewWindow *logview;
- Log *log = data;
-
- g_assert (log);
-
- logview = LOGVIEW_WINDOW (log->window);
- loglist_bold_log (LOG_LIST (logview->loglist), log);
- log->needs_refresh = TRUE;
- if (logview->curlog == log)
- logview_repaint (logview);
+ gboolean monitoring;
+ LV_MARK;
+ g_assert (LOGVIEW_IS_LOG (log));
+ g_object_get (G_OBJECT (log), "monitoring", &monitoring, NULL);
+ if (! monitoring) {
+ g_object_unref (log);
+ return FALSE;
+ }
+ if (log_has_been_modified (log)) {
+ monitor_callback(NULL, NULL, NULL, 0, log);
+ }
+ g_object_unref (log);
+ return TRUE;
}
void
monitor_start (Log *log)
{
- GnomeVFSResult result;
- GnomeVFSFileSize size;
- gchar *main = NULL, *second = NULL;
-
- g_return_if_fail (log);
-
- result = gnome_vfs_open (&(log->mon_file_handle), log->name,
- GNOME_VFS_OPEN_READ);
- result = gnome_vfs_seek (log->mon_file_handle, GNOME_VFS_SEEK_END, 0L);
- result = gnome_vfs_tell (log->mon_file_handle, &size);
- log->mon_offset = size;
-
- result = gnome_vfs_monitor_add (&(log->mon_handle), log->name,
- GNOME_VFS_MONITOR_FILE, monitor_callback,
- log);
-
- if (result != GNOME_VFS_OK) {
- main = g_strdup (_("This file cannot be monitored."));
- switch (result) {
- case GNOME_VFS_ERROR_NOT_SUPPORTED :
- second = g_strdup (_("File monitoring is not supported on this file system.\n"));
- default:
- second = g_strdup (_("Gnome-VFS Error.\n"));
- }
- error_dialog_show (NULL, main, second);
- g_free (main);
- g_free (second);
- gnome_vfs_close (log->mon_file_handle);
- return;
- }
-
- log->monitored = TRUE;
+ GnomeVFSResult result;
+ gchar *first = NULL, *second = NULL;
+ gboolean monitorable;
+ gchar *name;
+ GnomeVFSMonitorHandle *mon_handle;
+
+ LV_MARK;
+ g_assert (LOGVIEW_IS_LOG (log));
+
+ g_object_ref (log);
+ g_object_get (G_OBJECT (log),
+ "monitorable", &monitorable,
+ "monitor-handle", &mon_handle,
+ "path", &name,
+ NULL);
+ if (!monitorable) {
+ g_free (name);
+ g_object_unref (log);
+ return;
+ }
+
+ result = gnome_vfs_monitor_add (&mon_handle, name,
+ GNOME_VFS_MONITOR_FILE,
+ monitor_callback, log);
+ if (result != GNOME_VFS_OK) {
+ if (result == GNOME_VFS_ERROR_NOT_SUPPORTED) {
+ mon_handle = NULL;
+ g_timeout_add (CHECK_FILE_PERIOD,
+ (GSourceFunc) monitor_log_was_modified,
+ g_object_ref(log));
+ }
+ else {
+ goto gnome_vfs_err;
+ }
+ }
+ if (mon_handle != NULL) {
+ g_object_set (G_OBJECT (log),
+ "monitor-handle", mon_handle, NULL);
+ }
+
+ g_object_set (G_OBJECT (log),
+ "monitoring", TRUE, NULL);
+ g_free (name);
+ return;
+
+gnome_vfs_err:
+ first = g_strdup (_("Gnome-VFS error."));
+ second = g_strdup_printf ("%s, (%d): %s",
+ name,
+ result,
+ gnome_vfs_result_to_string (result));
+ error_dialog_show (NULL, first, second);
+ g_free (first);
+ g_free (second);
+ g_free (name);
+ g_object_unref (log);
+}
+
+void
+monitor_set_window (gpointer win)
+{
+ g_assert (window == NULL);
+ window = win;
}
diff --git a/logview/monitor.h b/logview/monitor.h
index 30f9360..76fd3a0 100644
--- a/logview/monitor.h
+++ b/logview/monitor.h
@@ -20,6 +20,7 @@
#ifndef __LOG_MONITOR_H__
#define __LOG_MONITOR_H__
+void monitor_set_window (gpointer win);
void monitor_start (Log *log);
void monitor_stop (Log *log);
diff --git a/logview/plugins/Makefile.am b/logview/plugins/Makefile.am
new file mode 100644
index 0000000..26a821b
--- /dev/null
+++ b/logview/plugins/Makefile.am
@@ -0,0 +1,63 @@
+plugindir = $(libdir)/gnome-system-log/plugins
+
+NULL =
+
+if FALSE
+libtest_la_LDFLAGS = \
+ $(PLUGIN_LIBTOOL_FLAGS) $(GNOME_UTILS_LIBS) $(GMODULE_LIBS)
+plugin_LTLIBRARIES = libtest.la
+libtest_la_SOURCES = test.c
+endif
+
+libgrablogs_la_LDFLAGS = \
+ $(PLUGIN_LIBTOOL_FLAGS) $(GNOME_UTILS_LIBS) $(GMODULE_LIBS)
+libplainlog_la_LDFLAGS = \
+ $(PLUGIN_LIBTOOL_FLAGS) $(GNOME_UTILS_LIBS) $(GMODULE_LIBS)
+libpipelog_la_LDFLAGS = \
+ $(PLUGIN_LIBTOOL_FLAGS) $(GNOME_UTILS_LIBS) $(GMODULE_LIBS)
+libbaseview_la_LDFLAGS = \
+ $(PLUGIN_LIBTOOL_FLAGS) $(GNOME_UTILS_LIBS) $(GMODULE_LIBS)
+
+plugin_LTLIBRARIES = \
+ libgrablogs.la \
+ libplainlog.la \
+ libpipelog.la \
+ libbaseview.la
+
+libgrablogs_la_SOURCES = grablogs.c
+libplainlog_la_SOURCES = plainlog.c
+libpipelog_la_SOURCES = pipelog.c
+libbaseview_la_SOURCES = baseview.c
+
+.PHONY: always
+
+additionaldir = $(plugindir)
+additional_DATA = \
+ grablogs.conf \
+ pipelog.conf
+
+EXTRA_DIST = \
+ $(additional_DATA)
+
+#
+# This part allows people to build their own plugins in here.
+# Yes, it's a mess.
+#
+SUFFIXES: .c .so
+.c.so:
+ $(LIBTOOL) --mode=compile $(CC) -DHAVE_CONFIG_H -I$(top_srcdir) $(AM_CPPFLAGS) $(CFLAGS) -c $< -o tmp$@.lo $(GNOME_UTILS_CFLAGS)
+ $(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o libtmp$@.la -rpath $(plugindir) tmp$@.lo $(LIBS) $(LDFLAGS) -module -avoid-version $(GNOME_UTILS_LIBS)
+ @rm -f tmp$@.lo tmp$@.o libtmp$@.la
+ @cp .libs/libtmp$@.so* $@
+ @rm -f .libs/libtmp$@.*
+
+
+AM_CPPFLAGS = \
+ -DDATADIR=\"$(datadir)\" \
+ -I$(top_builddir)/logview \
+ -I$(top_srcdir)/logview \
+ $(GNOME_UTILS_CFLAGS) \
+ $(SUN_OS) \
+ $(NULL)
+
+
diff --git a/logview/plugins/baseview.c b/logview/plugins/baseview.c
new file mode 100644
index 0000000..c1abfc4
--- /dev/null
+++ b/logview/plugins/baseview.c
@@ -0,0 +1,289 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#include <glib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <glib.h>
+#include "logview-plugin.h"
+#include "logview-iface-view.h"
+#include "logview-debug.h"
+#include "logview-log.h"
+#include "misc.h"
+
+
+#define PLUGIN_BASEVIEW(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUGIN_TYPE_BASEVIEW, Baseview))
+#define PLUGIN_BASEVIEW_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), PLUGIN_TYPE_BASEVIEW, BaseviewClass))
+#define BASEVIEW_IS_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUGIN_TYPE_BASEVIEW))
+#define BASEVIEW_IS_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUGIN_TYPE_BASEVIEW))
+#define PLUGIN_BASEVIEW_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUGIN_TYPE_BASEVIEW, BaseviewClass))
+
+#undef PLUGIN_PRIO
+#define PLUGIN_PRIO PLUG_PRIO_BASE
+#undef PLUGIN_DESC
+#define PLUGIN_DESC "Group by date and try to convert to UTF-8"
+
+typedef struct _Baseview Baseview;
+typedef struct _BaseviewClass BaseviewClass;
+
+struct _Baseview {
+ LogviewPlugin parent;
+};
+
+struct _BaseviewClass {
+ LogviewPluginClass parent;
+};
+
+
+/* class implement */
+static void iface_init (gpointer g_iface, gpointer iface_data);
+static void view_init (gpointer g_iface, gpointer iface_data);
+
+static void
+baseview_class_init (gpointer g_class, gpointer g_class_data)
+{
+ LV_MARK;
+}
+
+static void
+baseview_instance_init (GTypeInstance *instance, gpointer g_class_data)
+{
+ LV_MARK;
+}
+
+static GType
+baseview_get_type (GTypeModule* module)
+{
+ static GType type = 0;
+ LV_MARK;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (BaseviewClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ baseview_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (Baseview),
+ 0, /* n_preallocs */
+ baseview_instance_init /* instance_init */
+ };
+ static const GInterfaceInfo iface_info = {
+ iface_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+ static const GInterfaceInfo view_info = {
+ view_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+ type = g_type_module_register_type (module,
+ LOGVIEW_TYPE_PLUGIN,
+ "BaseviewType",
+ &info,
+ 0);
+ g_type_module_add_interface (module, type, LOGVIEW_TYPE_IFACE,
+ &iface_info);
+ g_type_module_add_interface (module, type, LOGVIEW_TYPE_IFACE_VIEW,
+ &view_info);
+ }
+ return type;
+}
+
+/* interfaces */
+static gboolean
+can_handle(Baseview *self, Log *log)
+{
+ LV_MARK;
+ return TRUE;
+}
+
+static gint
+days_compare (gconstpointer a, gconstpointer b)
+{
+ const Day *day1 = a, *day2 = b;
+ return (g_date_compare (day1->date, day2->date));
+}
+
+/* log_read_dates
+ Read all dates which have a log entry to create calendar.
+ All dates are given with respect to the 1/1/1970
+ and are then corrected to the correct year once we
+ reach the end.
+*/
+
+static GSList *
+baseview_read_dates (LogviewIView *self, gchar **buffer_lines, time_t current)
+{
+ int offsetyear = 0, current_year;
+ GSList *days = NULL, *days_copy;
+ GDate *date, *newdate;
+ struct tm *tmptm;
+ gchar *date_string;
+ Day *day;
+ gboolean done = FALSE;
+ int i, n, rangemin, rangemax;
+
+ if (buffer_lines == NULL)
+ return NULL;
+
+ n = g_strv_length (buffer_lines);
+ for (i=0; buffer_lines[i] == NULL && i < n; i++);
+ if (i == n)
+ return NULL;
+
+ tmptm = localtime (&current);
+ current_year = tmptm->tm_year + 1900;
+
+ /* Start building the list */
+ /* Scanning each line to see if the date changed is too slow,
+ so we proceed in a recursive fashion */
+
+ date = string_get_date (buffer_lines[i]);
+ if ((date==NULL)|| !g_date_valid (date)) {
+ return NULL;
+ }
+
+ g_date_set_year (date, current_year);
+ day = g_new0 (Day, 1);
+ days = g_slist_append (days, day);
+
+ day->date = date;
+ day->first_line = i;
+ day->last_line = -1;
+ date_string = get_date_string (buffer_lines[i]);
+
+ rangemin = 0;
+ rangemax = n-1;
+
+ while (!done) {
+
+ i = n-1;
+ while (day->last_line < 0) {
+
+ if (g_str_has_prefix (buffer_lines[i], date_string)) {
+ if (i == (n-1)) {
+ day->last_line = i;
+ done = TRUE;
+ break;
+ } else {
+ if (!g_str_has_prefix (buffer_lines[i+1], date_string)) {
+ day->last_line = i;
+ break;
+ } else {
+ rangemin = i;
+ i = (int) ( ((float) i + (float) rangemax)/2.);
+ }
+ }
+ } else {
+ rangemax = i;
+ i = (int) (((float) rangemin + (float) i)/2.);
+ }
+
+ }
+
+ g_free (date_string);
+
+ if (!done) {
+ /* We need to find the first line now that has a date
+ Logs can have some messages without dates ... */
+ newdate = NULL;
+ while (newdate == NULL && !done && i < n) {
+ i++;
+ date_string = get_date_string (buffer_lines[i]);
+ if (date_string == NULL)
+ continue;
+ g_assert (newdate == NULL);
+ newdate = string_get_date (buffer_lines[i]);
+
+ if (newdate == NULL && i==n-1)
+ done = TRUE;
+ }
+
+ day->last_line = i-1;
+
+ /* Append a day to the list */
+ if (newdate) {
+ g_date_set_year (newdate, current_year + offsetyear);
+ if (g_date_compare (newdate, date) < 1) {
+ offsetyear++; /* newdate is next year */
+ g_date_add_years (newdate, 1);
+ }
+
+ date = newdate;
+ day = g_new0 (Day, 1);
+ days = g_slist_append (days, day);
+
+ day->date = date;
+ day->first_line = i;
+ day->last_line = -1;
+ rangemin = i;
+ rangemax = n;
+ }
+ }
+ }
+
+ /* Correct years now. We assume that the last date on the log
+ is the date last accessed */
+
+ for (days_copy = days; days_copy != NULL; days_copy = g_slist_next (days_copy)) {
+ day = days_copy -> data;
+ g_date_subtract_years (day->date, offsetyear);
+ }
+
+ /* Sort the days in chronological order */
+ days = g_slist_sort (days, days_compare);
+
+ return (days);
+}
+
+static GSList*
+group_lines (LogviewIView *self, const gchar **lines)
+{
+ LV_MARK;
+ return baseview_read_dates (self, (gchar **)lines, time (NULL));
+}
+
+static void
+iface_init (gpointer g_iface, gpointer iface_data)
+{
+ LogviewInterface *iface = (LogviewInterface*)g_iface;
+ LV_MARK;
+ iface->can_handle = (gboolean (*) (LogviewIFace*, Log*)) can_handle;
+}
+
+static gchar*
+to_utf8 (LogviewIView *self, gchar *str)
+{
+ char *out;
+ if (g_utf8_validate (str, -1, NULL))
+ out = str;
+ else {
+ if ((out = g_locale_to_utf8 (str, -1, NULL, NULL, NULL)) != NULL)
+ g_free (str);
+ else
+ out = str;
+ }
+ return out;
+}
+
+static void
+view_init (gpointer g_iface, gpointer iface_data)
+{
+ LogviewIFaceView *self = (LogviewIFaceView*)g_iface;
+ LV_MARK;
+ self->group_lines = (GSList* (*) (LogviewIView*, const gchar**)) group_lines;
+ self->to_utf8 = (gchar* (*) (LogviewIView*, gchar*, gssize)) to_utf8;
+}
+
+LOGVIEW_INIT_PLUGIN (baseview_get_type)
+
diff --git a/logview/plugins/grablogs.c b/logview/plugins/grablogs.c
new file mode 100644
index 0000000..efcf1d6
--- /dev/null
+++ b/logview/plugins/grablogs.c
@@ -0,0 +1,496 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <glib.h>
+#include <stdio.h>
+#include <signal.h>
+#include <glib.h>
+#include <locale.h>
+#include "logview-plugin.h"
+#include "logview-iface-collector.h"
+#include "logview-debug.h"
+#include "logview-log.h"
+#include "misc.h"
+
+#define PLUGIN_GRABLOGS(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), PLUGIN_TYPE_GRABLOGS, PluginGrabLogs))
+#define PLUGIN_GRABLOGS_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), PLUGIN_TYPE_GRABLOGS, PluginGrabLogsClass))
+#define GRABLOGS_IS_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PLUGIN_TYPE_GRABLOGS))
+#define GRABLOGS_IS_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), PLUGIN_TYPE_GRABLOGS))
+#define PLUGIN_GRABLOGS_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), PLUGIN_TYPE_GRABLOGS, PluginGrabLogsClass))
+
+#undef PLUGIN_PRIO
+#define PLUGIN_PRIO PLUG_PRIO_BASE
+#undef PLUGIN_DESC
+#define PLUGIN_DESC "For colloct log files from shell commands"
+
+#ifdef ON_SUN_OS
+#define FILE_CMD "file"
+#else
+#define FILE_CMD "file"
+#endif
+#define GRABLOGS_CONF "grablogs.conf"
+#define CAT_CMD "[commands]"
+#define CAT_LOG "[logs]"
+#define CAT_CONF "[configs]"
+
+
+typedef GSList* (*Parse_All) (FILE*);
+typedef GSList* (*Parse_Line) (FILE*, Parse_All);
+typedef struct _PluginGrabLogs PluginGrabLogs;
+typedef struct _PluginGrabLogsClass PluginGrabLogsClass;
+
+struct _PluginGrabLogs {
+ LogviewPlugin parent;
+};
+
+struct _PluginGrabLogsClass {
+ LogviewPluginClass parent;
+};
+
+/* class implement */
+static void iface_init (gpointer g_iface, gpointer iface_data);
+static void collector_init (gpointer g_iface, gpointer iface_data);
+
+static struct sigaction old_sa;
+static gchar* category;
+
+static void
+grablogs_class_init (gpointer g_class, gpointer g_class_data)
+{
+ LV_MARK;
+}
+
+static void
+grablogs_instance_init (GTypeInstance *instance, gpointer g_class_data)
+{
+ LV_MARK;
+}
+
+static GType
+grablogs_get_type (GTypeModule* module)
+{
+ static GType type = 0;
+ LV_MARK;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (PluginGrabLogsClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ grablogs_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (PluginGrabLogs),
+ 0, /* n_preallocs */
+ grablogs_instance_init /* instance_init */
+ };
+ static const GInterfaceInfo iface_info = {
+ iface_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+ static const GInterfaceInfo collector_info = {
+ collector_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+ type = g_type_module_register_type (module,
+ LOGVIEW_TYPE_PLUGIN,
+ "GrablogsType",
+ &info,
+ 0);
+ g_type_module_add_interface (module, type, LOGVIEW_TYPE_IFACE,
+ &iface_info);
+ g_type_module_add_interface (module, type, LOGVIEW_TYPE_IFACE_COLLECTOR,
+ &collector_info);
+ }
+ return type;
+}
+
+static GSList*
+get_logs (const gchar* logcfg, Parse_All cp)
+{
+ GSList* loglist = NULL;
+ FILE* handle;
+ int (*lclose) (FILE*) = NULL;
+
+ LV_MARK;
+ /*
+ * lines in [command] will be run in popen
+ */
+ if (category && g_ascii_strcasecmp(g_strstrip(category),
+ CAT_CMD) == 0) {
+ LV_INFO ("[grablogs-PIPE-open] %s", logcfg);
+ handle = security_popen (logcfg, "r");
+ lclose = security_pclose;
+ }
+ else if (local_file_exist (logcfg)
+ && local_file_can_executed (logcfg)) {
+ LV_INFO ("[grablogs-FILE-open] %s", logcfg);
+ handle = fopen (logcfg, "r");
+ lclose = fclose;
+ }
+ else
+ goto get_logs_err;
+
+ if (handle != NULL) {
+ LV_INFO ("[grablogs-open] %s", logcfg);
+ loglist = cp (handle);
+ if (lclose (handle) == -1)
+ goto get_logs_err;
+ LV_INFO ("[grablogs-close] %s", logcfg);
+ }
+ else {
+get_logs_err:
+ LV_INFO_EE ("[grablogs handles]: \"%s\", msg: %s",
+ logcfg, error_system_string ());
+ return NULL;
+ }
+ return loglist;
+}
+
+static gchar*
+get_line (FILE *handle)
+{
+ glong inc = BUFSIZ, size = inc;
+ glong p = -1;
+ gchar *buf = (gchar *) g_malloc (size * sizeof (gchar));
+ g_assert (handle);
+ g_assert (buf);
+ do {
+ g_assert (p < size);
+ if (++p == size) {
+ size += inc;
+ buf = (gchar *) g_realloc (buf, size * sizeof(gchar));
+ g_assert (buf);
+ }
+ buf[p] = (gchar)getc (handle);
+ } while (buf[p] != '\n' && buf[p] != EOF);
+ if (buf[p] != EOF) {
+ buf[p] = '\0';
+ } else if (feof (handle) == 0 && p > 0) {
+ buf[p] = '\0';
+ } else if (feof (handle) != 0) {
+ LV_INFO_EE ("get_line error: %s", error_system_string());
+ g_free (buf);
+ buf = NULL;
+ } else {
+ g_free (buf);
+ buf = NULL;
+ }
+ LV_ERR ("get_line %s", buf? buf:"EOFed");
+ return buf;
+}
+
+/* one log per line */
+static GSList*
+cp_logline (FILE *handle)
+{
+ gchar *buf;
+ GSList *logfiles = NULL;
+ LV_MARK;
+ while ((buf = get_line(handle)) != NULL) {
+ if (g_str_has_prefix (g_strchug (buf), "#")) {
+ g_free (buf);
+ continue;
+ }
+ if (g_str_has_prefix(g_strstrip(buf), "[")) {
+ g_free (category);
+ category = buf;
+ break;
+ }
+ if (strlen (buf) != 0)
+ logfiles = g_slist_append (logfiles, g_strdup (buf));
+ g_free (buf);
+ }
+ return logfiles;
+}
+
+
+static GSList*
+cp_logconf (FILE *handle)
+{
+ gchar *buf, *p;
+ GSList *logfiles = NULL;
+ LV_MARK;
+ while ((buf = get_line(handle)) != NULL) {
+ gchar **list;
+ gint i;
+ for (p = buf; g_ascii_isspace(*p); ++p);
+ if (*p == '\0' || *p == '#' || *p == '\n') {
+ g_free (buf);
+ continue;
+ }
+ list = g_strsplit_set (p, ", -\t()\n'`", 0);
+ for (i = 0; list[i]; ++i) {
+ if (*list[i] == '/' &&
+ g_slist_find_custom(logfiles, list[i],
+ (GCompareFunc)g_ascii_strcasecmp) == NULL) {
+ logfiles = g_slist_append (logfiles,
+ g_strdup(list[i]));
+ }
+ }
+ g_strfreev(list);
+ g_free (buf);
+ }
+ return logfiles;
+}
+
+/* one shell or command per line
+ * run each line
+ * one log per line of output
+ */
+static GSList*
+cp_shell_per_line (FILE *handle)
+{
+ gchar *buf = NULL;
+ GSList *all_logs = NULL;
+ LV_MARK;
+ while ((buf = get_line(handle)) != NULL) {
+ if (g_str_has_prefix (g_strchug (buf), "#")) {
+ g_free (buf);
+ continue;
+ }
+ if (g_str_has_prefix(g_strchug (buf), "[")) {
+ g_free (category);
+ category = buf;
+ break;
+ }
+ if (strlen (buf) != 0) {
+ GSList *idx;
+ GSList *logfiles = NULL;
+ logfiles = get_logs (buf, cp_logline);
+ for (idx = logfiles; idx; idx=g_slist_next(idx)) {
+ if (g_slist_find_custom (all_logs, idx->data,
+ (GCompareFunc)g_ascii_strcasecmp)
+ == NULL) {
+ all_logs = g_slist_append (all_logs,
+ idx->data);
+ }
+ else
+ g_free (idx->data);
+ }
+ if (logfiles)
+ g_slist_free (logfiles);
+ }
+ g_free (buf);
+ }
+ return all_logs;
+}
+
+static GSList*
+cp_conf_per_line (FILE *handle)
+{
+ gchar *buf = NULL;
+ GSList *all_logs = NULL;
+ LV_MARK;
+ while ((buf = get_line(handle)) != NULL) {
+ if (g_str_has_prefix (g_strchug (buf), "#")) {
+ g_free (buf);
+ continue;
+ }
+ if (g_str_has_prefix(g_strchug (buf), "[")) {
+ g_free (category);
+ category = buf;
+ break;
+ }
+ if (strlen (buf) != 0) {
+ GSList *idx;
+ GSList *logfiles = NULL;
+ logfiles = get_logs (buf, cp_logconf);
+ for (idx = logfiles; idx; idx=g_slist_next(idx)) {
+ if (g_slist_find_custom (all_logs, idx->data,
+ (GCompareFunc)g_ascii_strcasecmp)
+ == NULL) {
+ all_logs = g_slist_append (all_logs,
+ idx->data);
+ }
+ else
+ g_free (idx->data);
+ }
+ if (logfiles)
+ g_slist_free (logfiles);
+ }
+ g_free (buf);
+ }
+ return all_logs;
+}
+
+static GSList*
+cp_grab_conf (FILE *handle)
+{
+ GSList *all_logs = NULL;
+ LV_MARK;
+
+ /* A line without any categories will be skipped */
+ category = get_line(handle);
+ while (feof (handle) == 0) {
+ if (g_str_has_prefix (g_strchug (category), "#"))
+ goto next_line;
+ if (category) {
+ if (g_ascii_strcasecmp(g_strstrip(category),
+ CAT_CMD) == 0) {
+ LV_INFO ("grab category %s, enter", category);
+ all_logs = g_slist_concat (all_logs,
+ cp_shell_per_line (handle));
+ }
+ else if (g_ascii_strcasecmp(g_strstrip(category),
+ CAT_LOG) == 0) {
+ LV_INFO ("grab category %s, enter", category);
+ all_logs = g_slist_concat (all_logs,
+ cp_logline (handle));
+ }
+ else if (g_ascii_strcasecmp(g_strstrip(category),
+ CAT_CONF) == 0) {
+ LV_INFO ("grab category %s, enter", category);
+ all_logs = g_slist_concat (all_logs,
+ cp_conf_per_line (handle));
+ }
+ else
+ goto next_line;
+ }
+ else {
+next_line:
+ g_free (category);
+ category = get_line(handle);
+ }
+ }
+ g_free (category);
+ return all_logs;
+}
+
+static GSList*
+get_all_logs (PluginGrabLogs *self)
+{
+ GSList *plugin_paths, *i;
+ GSList *all_logs = NULL;
+ LV_MARK;
+
+ plugin_paths = (GSList *) get_plugin_paths ();
+ category = NULL;
+ for (i = plugin_paths; i; i=g_slist_next(i)) {
+ gchar* path = g_build_path (G_DIR_SEPARATOR_S,
+ i->data, GRABLOGS_CONF, NULL);
+ if (local_file_exist (path)
+ && local_file_can_executed (path)) {
+ GSList *logfiles, *idx;
+ logfiles = get_logs (path, cp_grab_conf);
+ for (idx = logfiles; idx; idx = g_slist_next(idx)) {
+ if (g_slist_find_custom (all_logs, idx->data,
+ (GCompareFunc)g_ascii_strcasecmp) == NULL) {
+ all_logs = g_slist_append (all_logs, idx->data);
+ LV_ERR ("add %s", idx->data);
+ }
+ else {
+ LV_ERR ("del %s", idx->data);
+ g_free (idx->data);
+ }
+ }
+ g_slist_free (logfiles);
+ /* break to search the sequent path of GRABLOGS_CONF */
+ g_free (path);
+ break;
+ } else {
+ g_free (path);
+ }
+ }
+ return all_logs;
+}
+
+static void
+config_child_log (Log *log)
+{
+ /* Check for older versions of the log */
+ gchar *log_name = NULL;
+ gint i;
+ g_object_get (G_OBJECT (log), "path", &log_name, NULL);
+ for (i=0; i<OLD_LOG_NUM; i++) {
+ gboolean flag = FALSE;
+ gchar *older_name;
+ Log *child;
+ older_name = g_strdup_printf ("%s.%d", log_name, i);
+ if (local_file_exist (older_name)) {
+ flag = TRUE;
+ } else {
+ g_free (older_name);
+ older_name = g_strdup_printf ("%s.%d.gz", log_name, i);
+ if (local_file_exist (older_name)) {
+ flag = TRUE;
+ }
+ }
+ if (flag) {
+ child = g_object_new (LOGVIEW_TYPE_LOG,
+ "path", older_name,
+ "protocol", file_protocol (older_name),
+ NULL);
+ log_set_child (log, i, child);
+ }
+ g_free (older_name);
+ }
+ g_free (log_name);
+}
+
+static Log*
+config_log_from_path (PluginGrabLogs *self, const gchar *log_path)
+{
+ Log *log;
+ LogProtocol protocol;
+ gchar *utf8_name = NULL;
+ gchar *name;
+ gchar *message;
+
+ protocol = file_protocol (log_path);
+ switch (protocol) {
+ case UNKNOWN_LOG:
+ case PLAIN_LOG:
+ case GZIP_LOG:
+ case PIPE_LOG:
+ log = g_object_new (LOGVIEW_TYPE_LOG,
+ "path", log_path,
+ "protocol", protocol,
+ NULL);
+ config_child_log (log);
+ return log;
+ default:;
+ }
+ utf8_name = locale_to_utf8 (log_path);
+ name = utf8_name ? utf8_name : log_path;
+ /* SUN_BRANDING */
+ message = g_strdup_printf (_("Unknown file type: %d"), protocol);
+ log_error_appendv ("grablogs - %s - %s", name, message);
+ g_free (message);
+ g_free (utf8_name);
+ return NULL;
+}
+
+static void
+iface_init (gpointer g_iface, gpointer iface_data)
+{
+ LogviewInterface *iface = (LogviewInterface*) g_iface;
+ LV_MARK;
+ iface->can_handle = NULL; /* dummy */
+}
+
+static void
+collector_init (gpointer g_iface, gpointer iface_data)
+{
+ LogviewIFaceCollector *iface = (LogviewIFaceCollector*) g_iface;
+ LV_MARK;
+ iface->get_logs = (GSList* (*) (LogviewICollector*)) get_all_logs;
+ iface->config_log_from_path = (Log* (*) (LogviewICollector*, const gchar*))config_log_from_path;
+}
+
+LOGVIEW_INIT_PLUGIN (grablogs_get_type)
+
diff --git a/logview/plugins/grablogs.conf b/logview/plugins/grablogs.conf
new file mode 100644
index 0000000..78841cc
--- /dev/null
+++ b/logview/plugins/grablogs.conf
@@ -0,0 +1,10 @@
+[commands]
+for i in `svcs -aH -o FMRI | grep -v lrc `; do svcprop -p restarter/logfile $i 2>/dev/null || svcprop -q -p restarter/alt_logfile $i 2>/dev/null ; done
+
+[logs]
+/var/adm/messages
+/var/adm/wtmpx
+/var/adm/utmpx
+/var/log/Xorg.0.log
+/var/log/syslog
+
diff --git a/logview/plugins/pipelog.c b/logview/plugins/pipelog.c
new file mode 100644
index 0000000..56de934
--- /dev/null
+++ b/logview/plugins/pipelog.c
@@ -0,0 +1,428 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include "logview-iface-io.h"
+#include "misc.h"
+#include "logview-debug.h"
+#include "logview-log.h"
+#include "logview-plugin.h"
+
+#define PLUGIN_PIPELOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), PLUGIN_TYPE_PIPELOG, PluginPipelog))
+#define PLUGIN_PIPELOG_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), PLUGIN_TYPE_PIPELOG, PluginPipelogClass))
+#define PIPELOG_IS_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), PLUGIN_TYPE_PIPELOG))
+#define PIPELOG_IS_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), PLUGIN_TYPE_PIPELOG))
+#define PLUGIN_PIPELOG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), PLUGIN_TYPE_PIPELOG, PluginPipelogClass))
+
+#undef PLUGIN_DESC
+#define PLUGIN_DESC "For non-ASCII formatted log files"
+#undef PLUGIN_PRIO
+#define PLUGIN_PRIO (PLUG_PRIO_BASE + 1)
+
+typedef struct _PluginPipelog PluginPipelog;
+typedef struct _PluginPipelogClass PluginPipelogClass;
+
+struct _PluginPipelog {
+ LogviewPlugin parent;
+
+ Log *log;
+
+ gchar *log_name;
+ LogProtocol protocol;
+
+ gchar *pipe;
+ time_t file_time;
+ GnomeVFSFileSize file_size;
+ FILE *file_handle;
+ gchar *pbuffer;
+ gssize psize;
+ gssize poffset;
+};
+
+struct _PluginPipelogClass {
+ LogviewPluginClass parent;
+};
+
+static GObjectClass *parent_class = NULL;
+
+/* default routines for implement the plugin interfaces */
+static void iface_init (gpointer g_iface, gpointer iface_data);
+static void io_init (gpointer g_iface, gpointer iface_data);
+static gboolean plugin_init (PluginPipelog* self);
+static void plugin_destroy (PluginPipelog* self);
+
+/* interfaces */
+static gboolean can_handle(PluginPipelog *self, Log *log);
+static gboolean can_monitor(PluginPipelog *self);
+static gboolean has_updated(PluginPipelog *self);
+static gboolean update(PluginPipelog *self);
+static void logf_extract_filepath (PluginPipelog *self, gchar** dirname, gchar** filename);
+static size_t logf_read (PluginPipelog *self, void* buffer, size_t size);
+static off_t logf_seek (PluginPipelog *self, off_t offset, int whence);
+static off_t logf_tell (PluginPipelog *self);
+static time_t get_modified_time (PluginPipelog* self);
+static off_t get_size (PluginPipelog* self);
+
+/* others */
+static gboolean seek_pipe_log (PluginPipelog* self, const gchar *filename);
+
+#define PIPELOG_CONF "pipelog.conf"
+
+/* class implement */
+static void
+pipelog_finalize (PluginPipelog *self)
+{
+ g_free (self->log_name);
+}
+
+static void
+pipelog_class_init (gpointer g_class, gpointer g_class_data)
+{
+ LV_MARK;
+ LogviewPluginClass *parent = LOGVIEW_PLUGIN_CLASS (g_class);
+ parent_class = g_type_class_peek_parent (g_class);
+ G_OBJECT_CLASS (g_class)->finalize = (void (*) (GObject*)) pipelog_finalize;
+
+ parent->plugin_init = (gboolean (*) (LogviewPlugin*)) plugin_init;
+ parent->plugin_destroy = (void (*) (LogviewPlugin*)) plugin_destroy;
+}
+
+static void
+pipelog_instance_init (GTypeInstance *instance, gpointer g_class_data)
+{
+ PluginPipelog *self;
+ LV_MARK;
+ self = (PluginPipelog*) instance;
+ self->pipe = NULL;
+ self->pbuffer = NULL;
+ self->psize = 0;
+ self->poffset = 0;
+ self->log_name = NULL;
+}
+
+static GType
+pipelog_get_type (GTypeModule* module)
+{
+ static GType type = 0;
+ LV_MARK;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (PluginPipelogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ pipelog_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (PluginPipelog),
+ 0, /* n_preallocs */
+ pipelog_instance_init /* instance_init */
+ };
+ static const GInterfaceInfo iface_info = {
+ iface_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+ static const GInterfaceInfo io_info = {
+ io_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+ type = g_type_module_register_type (module,
+ LOGVIEW_TYPE_PLUGIN,
+ "PipelogType",
+ &info,
+ 0);
+ g_type_module_add_interface (module, type, LOGVIEW_TYPE_IFACE,
+ &iface_info);
+ g_type_module_add_interface (module, type,
+ LOGVIEW_TYPE_IFACE_IO, &io_info);
+ }
+ return type;
+}
+
+static void load_file (PluginPipelog* self)
+{
+ gint inc = 5*BUFSIZ, p =0, size = 0;
+
+ LV_MARK;
+ self->pbuffer = malloc (inc * sizeof (gchar) + 1);
+ while ((size = fread(self->pbuffer + p,
+ sizeof (gchar),
+ inc,
+ self->file_handle)) == inc) {
+ p += inc;
+ self->pbuffer = realloc (self->pbuffer, p + inc + 1);
+ }
+ *(self->pbuffer + p + size) = '\0';
+ self->psize = p + size;
+}
+
+static gboolean
+plugin_init (PluginPipelog* self)
+{
+ gchar *utf8_name = NULL;
+ gchar *name;
+
+ LV_MARK;
+ self->file_handle = security_popen ((const char *)self->pipe, "r");
+ if (self->file_handle) {
+ load_file (self);
+ return update (self);
+ }
+
+ if (!self->log_name) {
+ /* SUN_BRANDING */
+ name = _("NULL Filename");
+ } else {
+ utf8_name = locale_to_utf8 (self->log_name);
+ name = utf8_name ? utf8_name : self->log_name;
+ }
+ /* SUN_BRANDING */
+ log_error_appendv ("pipelog - %s - %s", name, _("popen failed"));
+ g_free (utf8_name);
+ return FALSE;
+}
+
+static void
+plugin_destroy (PluginPipelog* self)
+{
+ LV_MARK;
+ if (self->file_handle != NULL) {
+ security_pclose (self->file_handle);
+ }
+ if (self->pipe)
+ g_free (self->pipe);
+ if (self->pbuffer)
+ g_free (self->pbuffer);
+}
+
+
+/* interfaces */
+static gboolean
+can_handle(PluginPipelog *self, Log *log)
+{
+ gchar *utf8_name = NULL;
+ gchar *name;
+ gchar *message = NULL;
+
+ LV_MARK;
+ g_object_get (G_OBJECT (log),
+ "path", &self->log_name,
+ "protocol", &self->protocol,
+ NULL);
+
+ if (self->log_name == NULL) {
+ /* SUN_BRANDING */
+ log_error_appendv ("pipelog - %s", _("NULL Filename"));
+ return FALSE;
+ }
+ switch (self->protocol) {
+ case UNKNOWN_LOG:
+ case PLAIN_LOG:
+ case PIPE_LOG:
+ if (seek_pipe_log (self, self->log_name)) {
+ self->log = log;
+ self->protocol = PIPE_LOG;
+ g_object_set (G_OBJECT (log),
+ "protocol", self->protocol,
+ NULL);
+ return TRUE;
+ } else {
+ utf8_name = locale_to_utf8 (self->log_name);
+ name = (utf8_name) ? (utf8_name) : self->log_name;
+ /* SUN_BRANDING */
+ log_error_appendv ("pipelog - %s - %s", name, _("Cannot open"));
+ g_free (utf8_name);
+ return FALSE;
+ }
+ default:;
+ }
+ utf8_name = locale_to_utf8 (self->log_name);
+ name = (utf8_name) ? (utf8_name) : self->log_name;
+ /* SUN_BRANDING */
+ message = g_strdup_printf (_("Unknown file type: %d"), self->protocol);
+ log_error_appendv ("pipelog - %s - %s", name, message);
+ g_free (message);
+ g_free (utf8_name);
+ return FALSE;
+}
+
+static gboolean
+can_monitor(PluginPipelog *self)
+{
+ LV_MARK;
+ return FALSE;
+}
+
+static gboolean
+has_updated(PluginPipelog *self)
+{
+ LV_MARK;
+ return FALSE;
+}
+
+static gboolean
+update(PluginPipelog *self)
+{
+ struct stat buf;
+ LV_MARK;
+ g_assert (self->log_name != NULL);
+ if (stat (self->log_name, &buf) == 0) {
+ self->file_time = buf.st_mtime;
+ self->file_size = buf.st_size;
+ }
+ else {
+ LV_INFO_EE ("%s stat: %s", self->log_name,
+ error_system_string());
+ self->file_time = 0;
+ self->file_size = 0;
+ }
+ return TRUE;
+}
+
+static size_t
+logf_read (PluginPipelog *self, void* buffer, size_t size)
+{
+ gssize lsize = 0;
+ LV_MARK;
+ g_assert (size >= 0 && buffer);
+ g_assert (self->psize >=0 && self->pbuffer);
+ g_assert (self->poffset >=0 && self->poffset <= self->psize);
+ lsize = self->psize - self->poffset;
+ if (size > lsize)
+ size = lsize;
+ bcopy (self->pbuffer, buffer, size * sizeof(gchar));
+ self->poffset += size;
+ return size;
+}
+
+static off_t
+logf_seek (PluginPipelog *self, off_t offset, int whence)
+{
+ g_assert (self->psize >=0 && self->pbuffer);
+ g_assert (self->poffset >=0 && self->poffset <= self->psize);
+ switch (whence) {
+ case SEEK_SET:
+ self->poffset = offset;
+ break;
+ case SEEK_CUR:
+ self->poffset += offset;
+ break;
+ case SEEK_END:
+ self->poffset = self->psize;
+ break;
+ default:
+ return -1;
+ }
+ return logf_tell(self);
+}
+
+static off_t
+logf_tell (PluginPipelog *self)
+{
+ g_assert (self->psize >=0 && self->pbuffer);
+ g_assert (self->poffset >=0 && self->poffset <= self->psize);
+ return (off_t)self->poffset;
+}
+
+static void
+logf_extract_filepath (PluginPipelog *self, gchar** dirname, gchar** filename)
+{
+ extract_filepath (self->log_name, dirname, filename);
+}
+
+static off_t
+get_size (PluginPipelog* self)
+{
+ return self->file_size;
+}
+
+static time_t
+get_modified_time (PluginPipelog* self)
+{
+ return self->file_time;
+}
+
+static void
+io_init (gpointer g_iface, gpointer iface_data)
+{
+ LogviewIFaceIO *iface = (LogviewIFaceIO*)g_iface;
+ LV_MARK;
+ iface->can_monitor = (gboolean (*) (LogviewIIO*)) can_monitor;
+ iface->extract_filepath = (void (*) (LogviewIIO*, gchar**, gchar**)) logf_extract_filepath;
+ iface->has_updated = (gboolean (*) (LogviewIIO*)) has_updated;
+ iface->update = (void (*) (LogviewIIO*)) update;
+ iface->read = (size_t (*) (LogviewIIO*, void*, size_t)) logf_read;
+ iface->seek = (off_t (*) (LogviewIIO*, off_t, int)) logf_seek;
+ iface->tell = (off_t (*) (LogviewIIO*)) logf_tell;
+ iface->get_size = (off_t (*) (LogviewIIO*)) get_size;
+ iface->get_modified_time = (time_t (*) (LogviewIIO*)) get_modified_time;
+}
+
+static void
+iface_init (gpointer g_iface, gpointer iface_data)
+{
+ LogviewInterface *iface = (LogviewInterface*)g_iface;
+ LV_MARK;
+ iface->can_handle = (gboolean (*) (LogviewIFace*, Log*)) can_handle;
+}
+
+static gboolean
+seek_pipe_log (PluginPipelog* self, const gchar *filename)
+{
+ GSList *plugin_paths, *i;
+ gboolean hint = FALSE;
+ gchar cbuf[BUFSIZ];
+ LV_MARK;
+
+ plugin_paths = (GSList *) get_plugin_paths ();
+
+ for (i = plugin_paths; !hint && i; i=g_slist_next(i)) {
+ gchar* path = g_build_path (G_DIR_SEPARATOR_S, i->data,
+ PIPELOG_CONF, NULL);
+ if (local_file_exist (path)
+ && local_file_can_executed (path)) {
+ FILE *handle = fopen (path, "r");
+ if (handle != NULL) {
+ while (!hint && fgets(cbuf, sizeof(cbuf), handle) != NULL) {
+ gchar *str, *fp;
+ g_strdelimit (cbuf, "\t\n", ' ');
+ str = g_strchug (cbuf);
+ if (g_str_has_prefix (str, "#"))
+ continue;
+ fp = g_strstr_len (str, strlen (str), filename);
+ if (fp != NULL) {
+ self->pipe = g_strdup_printf (
+ g_strstrip(fp + strlen (filename) + 1),
+ filename);
+ LV_INFO ("found pipe log : %s", self->pipe);
+ hint = TRUE;
+ }
+ }
+ fclose (handle);
+ }
+ }
+ g_free (path);
+ }
+ return hint;
+}
+
+LOGVIEW_INIT_PLUGIN (pipelog_get_type)
+
diff --git a/logview/plugins/pipelog.conf b/logview/plugins/pipelog.conf
new file mode 100644
index 0000000..fea6731
--- /dev/null
+++ b/logview/plugins/pipelog.conf
@@ -0,0 +1,2 @@
+/var/adm/wtmpx last -f %s
+/var/adm/utmpx last -f %s
diff --git a/logview/plugins/plainlog.c b/logview/plugins/plainlog.c
new file mode 100644
index 0000000..f8f1fec
--- /dev/null
+++ b/logview/plugins/plainlog.c
@@ -0,0 +1,413 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2006 Lin Ma <Lin.Ma@sun.com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <libgnomevfs/gnome-vfs.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-mime-utils.h>
+#include "logview-iface-io.h"
+#include "misc.h"
+#include "logview-debug.h"
+#include "logview-log.h"
+#include "logview-plugin.h"
+
+#define PLUGIN_PLAINLOG(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), PLUGIN_TYPE_PLAINLOG, PluginPlainlog))
+#define PLUGIN_PLAINLOG_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), PLUGIN_TYPE_PLAINLOG, PluginPlainlogClass))
+#define PLAINLOG_IS_PLUGIN(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), PLUGIN_TYPE_PLAINLOG))
+#define PLAINLOG_IS_PLUGIN_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), PLUGIN_TYPE_PLAINLOG))
+#define PLUGIN_PLAINLOG_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS((obj), PLUGIN_TYPE_PLAINLOG, PluginPlainlogClass))
+
+#undef PLUGIN_PRIO
+#define PLUGIN_PRIO PLUG_PRIO_BASE
+#undef PLUGIN_DESC
+#define PLUGIN_DESC "For ASCII formatted log files"
+
+typedef struct _PluginPlainLog PluginPlainLog;
+typedef struct _PluginPlainLogClass PluginPlainLogClass;
+
+struct _PluginPlainLog {
+ LogviewPlugin parent;
+
+ Log *log;
+
+ gchar *log_name;
+ LogProtocol protocol;
+
+ time_t file_time;
+ GnomeVFSFileSize file_size;
+ GnomeVFSHandle *file_handle;
+};
+
+struct _PluginPlainLogClass {
+ LogviewPluginClass parent;
+};
+
+static GObjectClass *parent_class = NULL;
+
+/* default routines for implement the plugin interfaces */
+static void iface_init (gpointer g_iface, gpointer iface_data);
+static void io_init (gpointer g_iface, gpointer iface_data);
+static gboolean plugin_init (PluginPlainLog* self);
+static void plugin_destroy (PluginPlainLog* self);
+
+/* interfaces */
+static gboolean can_handle(PluginPlainLog *self, Log *log);
+static gboolean can_monitor(PluginPlainLog *self);
+static gboolean has_updated(PluginPlainLog *self);
+static gboolean update(PluginPlainLog *self);
+static void logf_extract_filepath (PluginPlainLog *self, gchar** dirname, gchar** filename);
+static size_t logf_read (PluginPlainLog *self, void* buffer, size_t size);
+static off_t logf_seek (PluginPlainLog *self, off_t offset, int whence);
+static off_t logf_tell (PluginPlainLog *self);
+static time_t get_modified_time (PluginPlainLog* self);
+static off_t get_size (PluginPlainLog* self);
+
+/* others */
+static gboolean regular_open (PluginPlainLog *self);
+static void regular_close (PluginPlainLog *self);
+
+/* class implement */
+static void
+plainlog_finalize (PluginPlainLog *self)
+{
+ g_free (self->log_name);
+}
+
+static void
+plainlog_class_init (gpointer g_class, gpointer g_class_data)
+{
+ LV_MARK;
+ LogviewPluginClass *parent = LOGVIEW_PLUGIN_CLASS (g_class);
+ parent_class = g_type_class_peek_parent (g_class);
+ G_OBJECT_CLASS (g_class)->finalize = (void (*) (GObject*)) plainlog_finalize;
+
+ parent->plugin_init = (gboolean (*) (LogviewPlugin*)) plugin_init;
+ parent->plugin_destroy = (void (*) (LogviewPlugin*)) plugin_destroy;
+}
+
+static void
+plainlog_instance_init (GTypeInstance *instance, gpointer g_class_data)
+{
+ PluginPlainLog *self;
+ LV_MARK;
+ self = (PluginPlainLog*) instance;
+ self->log_name = NULL;
+}
+
+static GType
+plainlog_get_type (GTypeModule* module)
+{
+ static GType type = 0;
+ LV_MARK;
+ if (type == 0) {
+ static const GTypeInfo info = {
+ /* You fill this structure. */
+ sizeof (PluginPlainLogClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ plainlog_class_init, /* class_init */
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (PluginPlainLog),
+ 0, /* n_preallocs */
+ plainlog_instance_init /* instance_init */
+ };
+ static const GInterfaceInfo iface_info = {
+ iface_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+ static const GInterfaceInfo io_info = {
+ io_init, /* interface_init */
+ NULL, /* interface_finalize */
+ NULL /* interface_data */
+ };
+ type = g_type_module_register_type (module,
+ LOGVIEW_TYPE_PLUGIN,
+ "PlainlogType",
+ &info,
+ 0);
+ g_type_module_add_interface (module, type, LOGVIEW_TYPE_IFACE,
+ &iface_info);
+ g_type_module_add_interface (module, type, LOGVIEW_TYPE_IFACE_IO,
+ &io_info);
+ }
+ return type;
+}
+
+static gboolean
+plugin_init (PluginPlainLog* self)
+{
+ gchar *utf8_name = NULL;
+ gchar *name;
+
+ LV_MARK;
+ if (regular_open (self))
+ return update (self);
+ utf8_name = locale_to_utf8 (self->log_name);
+ name = utf8_name ? utf8_name : self->log_name;
+ /* SUN_BRANDING */
+ log_error_appendv ("plainlog - %s - %s", name, _("Cannot open"));
+ g_free (utf8_name);
+ return FALSE;
+}
+
+static void
+plugin_destroy (PluginPlainLog* self)
+{
+ LV_MARK;
+ if (self->file_handle != NULL) {
+ regular_close (self);
+ }
+}
+
+/* interfaces */
+static gboolean
+can_handle(PluginPlainLog *self, Log *log)
+{
+ gchar *utf8_name = NULL;
+ gchar *name;
+ gchar *message = NULL;
+
+ LV_MARK;
+
+ g_object_get (G_OBJECT (log),
+ "path", &self->log_name,
+ "protocol", &self->protocol,
+ NULL);
+ if (self->log_name == NULL) {
+ /* SUN_BRANDING */
+ log_error_appendv ("plainlog - %s", _("NULL Filename"));
+ return FALSE;
+ }
+ if (self->protocol == PLAIN_LOG ||
+ self->protocol == GZIP_LOG) {
+ self->log = log;
+ return TRUE;
+ } else if (self->protocol == UNKNOWN_LOG) {
+ /* try to open */
+ if (try_to_open (self->log_name, FALSE)) {
+ self->log = log;
+ self->protocol = PLAIN_LOG;
+ g_object_set (G_OBJECT (log),
+ "protocol", self->protocol,
+ NULL);
+ return TRUE;
+ }
+ else {
+ utf8_name = locale_to_utf8 (self->log_name);
+ name = utf8_name ? utf8_name : self->log_name;
+ /* SUN_BRANDING */
+ log_error_appendv ("plainlog - %s - %s", name, _("Cannot open"));
+ g_free (utf8_name);
+ return FALSE;
+ }
+ }
+ utf8_name = locale_to_utf8 (self->log_name);
+ name = utf8_name ? utf8_name : self->log_name;
+ /* SUN_BRANDING */
+ message = g_strdup_printf (_("Unknown file type: %d"), self->protocol);
+ log_error_appendv ("plainlog - %s - %s", name, message);
+ g_free (message);
+ g_free (utf8_name);
+ return FALSE;
+}
+
+static gboolean
+can_monitor(PluginPlainLog *self)
+{
+ LV_MARK;
+ switch (self->protocol) {
+ case PLAIN_LOG:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+static gboolean
+has_updated(PluginPlainLog *self)
+{
+ struct stat buf;
+ LV_MARK;
+
+ if (stat (self->log_name, &buf) == 0) {
+ if (buf.st_mtime != self->file_time) {
+ return TRUE;
+ }
+ } else {
+ LV_INFO_EE ("%s stat: %s", self->log_name,
+ error_system_string());
+ }
+ return FALSE;
+}
+
+static gboolean
+update(PluginPlainLog *self)
+{
+ struct stat buf;
+ LV_MARK;
+ g_assert (self->log_name != NULL);
+ if (stat (self->log_name, &buf) == 0) {
+ self->file_time = buf.st_mtime;
+ self->file_size = buf.st_size;
+ return TRUE;
+ } else {
+ LV_INFO_EE ("%s stat: %s", self->log_name,
+ error_system_string());
+ }
+ return FALSE;
+}
+
+static size_t
+logf_read (PluginPlainLog *self, void* buffer, size_t size)
+{
+ GnomeVFSResult result;
+ GnomeVFSFileSize read_size;
+
+ LV_MARK;
+ g_return_val_if_fail (self->file_handle !=NULL, -1);
+ result = gnome_vfs_read (self->file_handle,
+ buffer,
+ (GnomeVFSFileSize)size,
+ &read_size);
+ if ( result != GNOME_VFS_OK) {
+ LV_INFO_EE ("%s: (%d), %s",
+ self->log_name,
+ result, gnome_vfs_result_to_string (result));
+ return -1;
+ }
+ return (size_t)read_size;
+}
+
+static off_t
+logf_seek (PluginPlainLog *self, off_t offset, int whence)
+{
+ GnomeVFSSeekPosition sp;
+ switch (whence) {
+ case SEEK_SET:
+ sp = GNOME_VFS_SEEK_START;
+ break;
+ case SEEK_CUR:
+ sp = GNOME_VFS_SEEK_CURRENT;
+ break;
+ case SEEK_END:
+ sp = GNOME_VFS_SEEK_END;
+ break;
+ default:
+ return -1;
+ }
+ if (gnome_vfs_seek (self->file_handle, sp, (GnomeVFSFileOffset)offset) == GNOME_VFS_OK) {
+ return logf_tell(self);
+ }
+ else
+ return -1;
+}
+
+static off_t
+logf_tell (PluginPlainLog *self)
+{
+ GnomeVFSFileSize size;
+ if (gnome_vfs_tell (self->file_handle, &size) == GNOME_VFS_OK) {
+ return (off_t)size;
+ }
+ return -1;
+}
+
+static void
+logf_extract_filepath (PluginPlainLog *self, gchar** dirname, gchar** filename)
+{
+ extract_filepath (self->log_name, dirname, filename);
+}
+
+static off_t
+get_size (PluginPlainLog* self)
+{
+ return self->file_size;
+}
+
+static time_t
+get_modified_time (PluginPlainLog* self)
+{
+ return self->file_time;
+}
+
+static void
+io_init (gpointer g_iface, gpointer iface_data)
+{
+ LogviewIFaceIO *iface = (LogviewIFaceIO*) g_iface;
+ LV_MARK;
+ iface->can_monitor = (gboolean (*) (LogviewIIO*)) can_monitor;
+ iface->extract_filepath = (void (*) (LogviewIIO*, gchar**, gchar**)) logf_extract_filepath;
+ iface->has_updated = (gboolean (*) (LogviewIIO*)) has_updated;
+ iface->update = (void (*) (LogviewIIO*)) update;
+ iface->read = (size_t (*) (LogviewIIO*, void*, size_t)) logf_read;
+ iface->seek = (off_t (*) (LogviewIIO*, off_t, int)) logf_seek;
+ iface->tell = (off_t (*) (LogviewIIO*)) logf_tell;
+ iface->get_size = (off_t (*) (LogviewIIO*)) get_size;
+ iface->get_modified_time = (time_t (*) (LogviewIIO*)) get_modified_time;
+}
+
+static void
+iface_init (gpointer g_iface, gpointer iface_data)
+{
+ LogviewInterface *iface = (LogviewInterface*)g_iface;
+ LV_MARK;
+ iface->can_handle = (gboolean (*) (LogviewIFace*, Log*)) can_handle;
+}
+
+/* log functions */
+static gboolean
+regular_open (PluginPlainLog *self)
+{
+ char *file_name;
+ GnomeVFSResult result;
+
+ if (self->protocol == GZIP_LOG) {
+ file_name = g_strdup_printf ("%s#gzip:", self->log_name);
+ }
+ else {
+ file_name = g_strdup (self->log_name);
+ }
+ result = gnome_vfs_open (&self->file_handle,
+ file_name, GNOME_VFS_OPEN_READ);
+ g_free (file_name);
+ if (result != GNOME_VFS_OK) {
+ LV_INFO_EE ("%s: (%d), %s",
+ self->log_name,
+ result, gnome_vfs_result_to_string (result));
+ self->file_handle = NULL;
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static void
+regular_close (PluginPlainLog *self)
+{
+ GnomeVFSResult result;
+
+ result = gnome_vfs_close (self->file_handle);
+ if (result != GNOME_VFS_OK) {
+ LV_INFO_EE ("%s: (%d), %s",
+ self->log_name,
+ result, gnome_vfs_result_to_string (result));
+ }
+}
+
+LOGVIEW_INIT_PLUGIN (plainlog_get_type)
diff --git a/logview/userprefs.c b/logview/userprefs.c
index c205a6d..35419f5 100644
--- a/logview/userprefs.c
+++ b/logview/userprefs.c
@@ -27,9 +27,11 @@
#include <gtk/gtk.h>
#include <gconf/gconf-client.h>
#include <libgnomevfs/gnome-vfs.h>
-#include "userprefs.h"
#include <sys/stat.h>
+#include "userprefs.h"
#include "logview.h"
+#include "logview-plugin-manager.h"
+#include "logview-debug.h"
#define LOGVIEW_DEFAULT_HEIGHT 400
#define LOGVIEW_DEFAULT_WIDTH 600
@@ -49,94 +51,18 @@
static GConfClient *gconf_client = NULL;
static UserPrefs *prefs;
-static GSList*
-parse_syslog(gchar *syslog_file) {
-
- /* Most of this stolen from sysklogd sources */
-
- char *logfile = NULL;
- char cbuf[BUFSIZ];
- char *cline, *p;
- FILE *cf;
- GSList *logfiles = NULL;
- if ((cf = fopen(syslog_file, "r")) == NULL) {
- return NULL;
- }
- cline = cbuf;
- while (fgets(cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) {
- gchar **list;
- gint i;
- for (p = cline; g_ascii_isspace(*p); ++p);
- if (*p == '\0' || *p == '#' || *p == '\n')
- continue;
- list = g_strsplit_set (p, ", -\t()\n", 0);
- for (i = 0; list[i]; ++i) {
- if (*list[i] == '/' &&
- g_slist_find_custom(logfiles, list[i],
- (GCompareFunc)g_ascii_strcasecmp) == NULL) {
- logfiles = g_slist_insert (logfiles,
- g_strdup(list[i]), 0);
- }
- }
- g_strfreev(list);
- }
- fclose(cf);
- return logfiles;
-}
-
static void
prefs_create_defaults (UserPrefs *p)
{
- int i;
- gchar *logfiles[] = {
- "/var/log/sys.log",
-#ifndef ON_SUN_OS
- "/var/log/messages",
- "/var/log/secure",
- "/var/log/maillog",
- "/var/log/cron",
- "/var/log/Xorg.0.log",
- "/var/log/XFree86.0.log",
- "/var/log/auth.log",
- "/var/log/cups/error_log",
-#else
- "/var/adm/messages",
- "/var/adm/sulog",
- "/var/log/authlog",
- "/var/log/brlog",
- "/var/log/postrun.log",
- "/var/log/scrollkeeper.log",
- "/var/log/snmpd.log",
- "/var/log/sysidconfig.log",
- "/var/log/swupas/swupas.log",
- "/var/log/swupas/swupas.error.log",
-#endif
- NULL};
- struct stat filestat;
- GSList *logs = NULL;
- GnomeVFSResult result;
- GnomeVFSHandle *handle;
+ GSList* idx;
- g_assert (p != NULL);
-
- /* For first time running, try parsing various logfiles */
- /* Try to parse syslog.conf to get logfile names */
+ LV_MARK;
+ g_assert (p->logs == NULL);
+ p->logfile = NULL;
+ p->logs = pluginmgr_get_all_logs ();
- result = gnome_vfs_open (&handle, "/etc/syslog.conf", GNOME_VFS_OPEN_READ);
- if (result == GNOME_VFS_OK) {
- gnome_vfs_close (handle);
- logs = parse_syslog ("/etc/syslog.conf");
- }
-
- for (i=0; logfiles[i]; i++) {
- if (g_slist_find_custom(logs, logfiles[i], (GCompareFunc)g_ascii_strcasecmp) == NULL &&
- file_is_log (logfiles[i], FALSE))
- logs = g_slist_insert (logs, g_strdup(logfiles[i]), 0);
- }
-
- if (logs != NULL) {
- p->logs = logs;
- p->logfile = logs->data;
+ for (idx = p->logs; idx != NULL; idx = idx->next) {
+ LV_ERR ("add|log: %s", (gchar*) idx->data);
}
}
@@ -159,22 +85,23 @@ prefs_load (void)
&err);
if (p->logs == NULL)
prefs_create_defaults (p);
+ if (p->logs)
+ p->logfile = p->logs->data;
logfile = NULL;
logfile = gconf_client_get_string (gconf_client, GCONF_LOGFILE, NULL);
- if (logfile && logfile[0] != '\0' && file_is_log (logfile, FALSE)) {
- gboolean found;
+ if (logfile && logfile[0] != '\0') {
GSList *iter;
- p->logfile = g_strdup (logfile);
- g_free (logfile);
-
- for (found = FALSE, iter = p->logs;
- iter != NULL;
+ for (iter = p->logs; iter != NULL;
iter = g_slist_next (iter)) {
- if (g_ascii_strncasecmp (iter->data, p->logfile, 255) == 0)
- found = TRUE;
+ if (g_ascii_strncasecmp (iter->data,
+ logfile, 255) == 0) {
+ p->logfile = iter->data;
+ break;
+ }
}
+ g_free (logfile);
}
width = gconf_client_get_int (gconf_client, GCONF_WIDTH_KEY, NULL);
@@ -184,6 +111,7 @@ prefs_load (void)
p->width = (width == 0 ? LOGVIEW_DEFAULT_WIDTH : width);
p->height = (height == 0 ? LOGVIEW_DEFAULT_HEIGHT : height);
p->fontsize = fontsize;
+ p->logfile = g_strdup (p->logfile);
return p;
}
@@ -260,22 +188,38 @@ prefs_get_height (void)
void
prefs_free_loglist ()
{
- g_slist_free (prefs->logs);
- prefs->logs = NULL;
+ GSList *idx;
+ if (prefs->logs) {
+ for (idx = prefs->logs; idx; idx = g_slist_next(idx)) {
+ g_free ((gchar*)idx->data);
+ }
+ g_slist_free (prefs->logs);
+ prefs->logs = NULL;
+ }
+ if (prefs->logfile) {
+ g_free (prefs->logfile);
+ prefs->logfile = NULL;
+ }
}
void
-prefs_store_log (gchar *name)
+prefs_store_log (const gchar *name)
{
+ LV_INFO ("[Prefs Store] %s", name);
if (name && name[0] != '\0')
- prefs->logs = g_slist_append (prefs->logs, name);
+ prefs->logs = g_slist_append (prefs->logs, g_strdup (name));
}
void
-prefs_store_active_log (gchar *name)
+prefs_store_active_log (const gchar *name)
{
/* name can be NULL if no active log */
- prefs->logfile = name;
+ if (prefs->logfile)
+ g_free (prefs->logfile);
+ if (name)
+ prefs->logfile = g_strdup(name);
+ else
+ prefs->logfile = NULL;
}
void
@@ -287,8 +231,6 @@ prefs_store_fontsize (int fontsize)
void
prefs_save (void)
{
- GSList *logs;
-
g_assert (gconf_client != NULL);
if (prefs->logfile) {
diff --git a/logview/userprefs.h b/logview/userprefs.h
index 1cf10fb..174165e 100644
--- a/logview/userprefs.h
+++ b/logview/userprefs.h
@@ -33,8 +33,8 @@ gchar *prefs_get_active_log (void);
GSList *prefs_get_logs (void);
int prefs_get_width (void);
int prefs_get_height (void);
-void prefs_store_log (gchar *name);
-void prefs_store_active_log (gchar *name);
+void prefs_store_log (const gchar *name);
+void prefs_store_active_log (const gchar *name);
void prefs_store_fontsize (int fontsize);
void prefs_store_window_size (GtkWidget *window);
void prefs_save (void);