missing NULL terminator in set_config_x
[geda-gaf.git] / gschem / src / gschem_log_dockable.c
blobd756a9b23cda53a80fad32626d531e0dcfc22d2a
1 /* gEDA - GPL Electronic Design Automation
2 * gschem - gEDA Schematic Capture
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2020 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 /*!
21 * \file gschem_log_dockable.c
23 * \brief GType class and functions to support the gschem log window.
26 #include <config.h>
28 #include <stdio.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #ifdef HAVE_STDLIB_H
32 #include <stdlib.h>
33 #endif
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #ifdef HAVE_FCNTL_H
38 #include <fcntl.h>
39 #endif
40 #ifdef HAVE_STRING_H
41 #include <string.h>
42 #endif
44 #include "gschem.h"
46 #include "../include/gschem_log_dockable.h"
49 static gpointer parent_class = NULL;
51 static void
52 apply_tag_cb (GtkTextBuffer *buffer, GtkTextTag *tag,
53 GtkTextIter *start, GtkTextIter *end,
54 GschemLogDockable *dockable);
56 static void
57 class_init (GschemLogDockableClass *class);
59 static GtkTextBuffer*
60 create_text_buffer();
62 static GtkWidget *
63 create_widget (GschemDockable *parent);
65 static void
66 dispose (GObject *object);
68 static void
69 x_log_message (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message);
71 static void
72 log_message (GschemLogDockableClass *klass, const gchar *message, const gchar *style);
75 /*!
76 * \brief Get the Log class type
78 * \par Function Description
80 * On first call, registers the Log class with the GType dynamic type system.
81 * On subsequent calls, returns the saved value from first execution.
82 * \returns the type identifier for the Log class
84 GType
85 gschem_log_dockable_get_type ()
87 static GType type = 0;
89 if (type == 0) {
90 static const GTypeInfo info = {
91 sizeof(GschemLogDockableClass),
92 NULL, /* base_init */
93 NULL, /* base_finalize */
94 (GClassInitFunc) class_init,
95 NULL, /* class_finalize */
96 NULL, /* class_data */
97 sizeof(GschemLogDockable),
98 0, /* n_preallocs */
99 NULL, /* instance_init */
102 type = g_type_register_static (GSCHEM_TYPE_DOCKABLE,
103 "GschemLogDockable",
104 &info,
108 return type;
112 /*! \brief Add a message to the status log
114 * \param [in] log_domain
115 * \param [in] log_level The severity of the message
116 * \param [in] message The message to be displayed
118 static void
119 x_log_message (const gchar *log_domain, GLogLevelFlags log_level, const gchar *message)
121 GschemLogDockableClass *klass = GSCHEM_LOG_DOCKABLE_CLASS (g_type_class_peek_static (GSCHEM_TYPE_LOG_DOCKABLE));
122 gchar *style;
124 if (log_level & (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_ERROR)) {
125 style = "critical";
126 } else if (log_level & G_LOG_LEVEL_WARNING) {
127 style = "warning";
128 } else {
129 style = "message";
132 log_message (klass, message, style);
137 * \brief Add a message to the log window
139 * \par Function Description
140 * \param [in] log The log instance
141 * \param [in] message The message to be logged
142 * \param [in] style The style to use in the text rendering
144 static void
145 log_message (GschemLogDockableClass *klass, const gchar *message, const gchar *style)
147 GtkTextIter iter;
149 g_return_if_fail (klass != NULL);
150 g_return_if_fail (klass->buffer != NULL);
152 gtk_text_buffer_get_end_iter (klass->buffer, &iter);
153 /* Apply the "plain" tag before the level-specific tag in order to
154 * reset the formatting */
156 if (g_utf8_validate (message, -1, NULL)) {
157 gtk_text_buffer_insert_with_tags_by_name (klass->buffer, &iter, message, -1,
158 "plain", style, NULL);
159 } else {
160 /* If UTF-8 wasn't valid (due to a system locale encoded filename or
161 * other string being included by mistake), log a warning, and print
162 * the original message to stderr, where it may be partly intelligible */
163 gtk_text_buffer_insert_with_tags_by_name (klass->buffer, &iter,
164 _("** Invalid UTF-8 in log message. See stderr or gschem.log.\n"),
165 -1, "plain", style, NULL);
166 fprintf (stderr, "%s", message);
171 /*! \brief callback for tags being applied to the text buffer
173 * Applying tags to the buffer causes all text view widgets to scroll
174 * to the bottom. Additionally, for high priority tags, the log
175 * dockable is presented to the user.
177 * \param [in] buffer the text buffer triggering the event
178 * \param [in] tag the applied tag
179 * \param [in] start the start of the range the tag is applied to
180 * \param [in] end the end of the range the tag is applied to
181 * \param [in] dockable the dockable to scroll to the bottom
183 static void
184 apply_tag_cb (GtkTextBuffer *buffer, GtkTextTag *tag,
185 GtkTextIter *start, GtkTextIter *end,
186 GschemLogDockable *dockable)
188 gchar *tag_name;
190 g_return_if_fail (buffer != NULL);
191 g_return_if_fail (dockable != NULL);
192 g_return_if_fail (dockable->viewer != NULL);
194 g_object_get (tag, "name", &tag_name, NULL);
195 if ((strcmp (tag_name, "critical") == 0 ||
196 strcmp (tag_name, "warning") == 0))
197 gschem_dockable_present (GSCHEM_DOCKABLE (dockable));
198 g_free (tag_name);
200 if (gtk_widget_get_realized (GTK_WIDGET (dockable->viewer)))
201 gtk_text_view_scroll_to_iter (dockable->viewer, end, 0.0, TRUE, 0.0, 1.0);
205 /*! \brief initialize class
207 static void
208 class_init (GschemLogDockableClass *klass)
210 gchar *contents;
211 /* GObjectClass *gobject_class = G_OBJECT_CLASS (klass); */
213 klass->buffer = create_text_buffer ();
215 /* make it read the content of the current log file */
216 /* and add its contents to the dialog */
217 contents = s_log_read ();
219 /* s_log_read can return NULL if the log file cannot be written to */
220 if (contents != NULL) {
221 log_message (klass, contents, "old");
222 g_free (contents);
224 x_log_update_func = x_log_message;
227 GSCHEM_DOCKABLE_CLASS (klass)->create_widget = create_widget;
228 G_OBJECT_CLASS (klass)->dispose = dispose;
230 parent_class = g_type_class_peek_parent (klass);
234 /*! \brief create the text buffer for storing the status log contents
236 * \return a GtkTextBuffer for storing the status log
238 static GtkTextBuffer*
239 create_text_buffer()
241 GtkTextBuffer *buffer = gtk_text_buffer_new (NULL);
243 /* Add some tags for highlighting log messages to the buffer */
244 gtk_text_buffer_create_tag (buffer,
245 "plain",
246 "foreground", "black",
247 "foreground-set", TRUE,
248 "weight", PANGO_WEIGHT_NORMAL,
249 "weight-set", TRUE,
250 NULL);
252 /* The default "message" style is plain */
253 gtk_text_buffer_create_tag (buffer, "message", NULL);
255 /* "old" messages are in dark grey */
256 gtk_text_buffer_create_tag (buffer,
257 "old",
258 "foreground", "#404040",
259 "foreground-set", TRUE,
260 NULL);
262 /* "warning" messages are printed in red */
263 gtk_text_buffer_create_tag (buffer,
264 "warning",
265 "foreground", "red",
266 "foreground-set", TRUE,
267 NULL);
269 /* "critical" messages are bold red */
270 gtk_text_buffer_create_tag (buffer,
271 "critical",
272 "foreground", "red",
273 "foreground-set", TRUE,
274 "weight", PANGO_WEIGHT_BOLD,
275 "weight-set", TRUE,
276 NULL);
278 return buffer;
282 /*! \brief create widgets
284 * \param [in] parent an instance of the dockable
286 static GtkWidget *
287 create_widget (GschemDockable *parent)
289 GschemLogDockable *dockable = GSCHEM_LOG_DOCKABLE (parent);
290 GtkTextIter iter;
291 GschemLogDockableClass *klass = GSCHEM_LOG_DOCKABLE_GET_CLASS (dockable);
292 GtkWidget *scrolled;
294 g_return_val_if_fail (klass != NULL, NULL);
295 g_return_val_if_fail (klass->buffer != NULL, NULL);
296 g_return_val_if_fail (dockable != NULL, NULL);
298 scrolled = gtk_scrolled_window_new (NULL, NULL);
300 dockable->viewer = GTK_TEXT_VIEW (g_object_new (GTK_TYPE_TEXT_VIEW,
301 /* GtkTextView */
302 "buffer", klass->buffer,
303 "editable", FALSE,
304 NULL));
306 gtk_container_add (GTK_CONTAINER (scrolled), GTK_WIDGET (dockable->viewer));
308 g_signal_connect (klass->buffer,
309 "apply-tag",
310 G_CALLBACK (&apply_tag_cb),
311 dockable);
313 gtk_text_buffer_get_end_iter (klass->buffer, &iter);
315 gtk_widget_show_all (scrolled);
316 return scrolled;
320 static void
321 dispose (GObject *object)
323 g_signal_handlers_disconnect_by_data (
324 GSCHEM_LOG_DOCKABLE_GET_CLASS (object)->buffer, object);
326 G_OBJECT_CLASS (parent_class)->dispose (object);