1 /*
2  * libgnumeric.c: global initialization and management code
3  *
4  * Copyright (C) 2000-2007 Jody Goldberg (jody@gnome.org)
5  * Copyright (C) 1997-1999 Miguel de Icaza (miguel@kernel.org)
6  * Copyright (C) 2006-2009 Morten Welinder (terra@gnome.org)
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of the
11  * License, or (at your option) version 3.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
21  * USA
22  */
23 #include <gnumeric-config.h>
24 #include <glib/gi18n-lib.h>
25 #include <gnumeric.h>
26 #include <libgnumeric.h>
27 #include <gutils.h>
28 
29 #include <application.h>
30 #include <stf.h>
31 #include <gnm-format.h>
32 #include <command-context.h>
33 #include <command-context-stderr.h>
34 #include <workbook.h>
35 #include <sheet-object.h>
36 #include <number-match.h>
37 #include <expr-name.h>
38 #include <func.h>
39 #include <print-info.h>
40 #include <style-font.h>
41 #include <mstyle.h>
42 #include <style-border.h>
43 #include <style-color.h>
44 #include <print.h>
45 #include <dependent.h>
46 #include <sheet-autofill.h>
47 #include <sheet-private.h>
48 #include <xml-sax.h>
49 #include <clipboard.h>
50 #include <gui-clipboard.h>
51 #include <value.h>
52 #include <expr.h>
53 #include <expr-deriv.h>
54 #include <parse-util.h>
55 #include <rendered-value.h>
56 #include <gnumeric-conf.h>
57 #include <gnm-plugin.h>
58 #include <mathfunc.h>
59 #include <hlink.h>
60 #include <wbc-gtk-impl.h>
61 #include <gnmresources.h>
62 #include <goffice/goffice.h>
63 
64 #ifdef HAVE_SYS_RESOURCE_H
65 #include <sys/resource.h>
66 #endif
67 #include <locale.h>
68 
69 #ifndef HAVE_GTK_ICON_THEME_ADD_RESOURCE_PATH
70 #define gtk_icon_theme_add_resource_path fake_gtk_icon_theme_add_resource_path
71 
72 
73 static void
walk_resource_path(const char * path,int level,int size)74 walk_resource_path (const char *path, int level, int size)
75 {
76 	char **children = g_resources_enumerate_children (path, 0, NULL);
77 	int i;
78 
79 	if (!children)
80 		return;
81 
82 	for (i = 0; children[i]; i++) {
83 		const char *child = children[i];
84 		char *subpath;
85 		GBytes *data;
86 
87 		if (level == 0) {
88 			size = atol (child);
89 			if (size <= 0)
90 				continue;
91 		}
92 
93 		subpath = g_build_path ("/", path, child, NULL);
94 
95 		data = g_resources_lookup_data (subpath, 0, NULL);
96 		if (data) {
97 			GdkPixbuf *pixbuf = gdk_pixbuf_new_from_resource (subpath, NULL);
98 			if (pixbuf && size > 0 && strchr (child, '.')) {
99 				char *iconname = g_strdup (child);
100 				strchr(iconname, '.')[0] = 0;
101 				if (gnm_debug_flag ("icons"))
102 					g_printerr ("Defining icon %s at size %d\n", iconname, size);
103 				gtk_icon_theme_add_builtin_icon (iconname,
104 								 size,
105 								 pixbuf);
106 
107 				g_object_unref (pixbuf);
108 				g_free (iconname);
109 			}
110 
111 			g_bytes_unref (data);
112 		} else
113 			walk_resource_path (subpath, level + 1, size);
114 		g_free (subpath);
115 	}
116 
117 	g_strfreev (children);
118 }
119 
120 static void
fake_gtk_icon_theme_add_resource_path(GtkIconTheme G_GNUC_UNUSED * theme,const char * path)121 fake_gtk_icon_theme_add_resource_path (GtkIconTheme G_GNUC_UNUSED *theme,
122 				       const char *path)
123 {
124 	walk_resource_path (path, 0, -1);
125 }
126 
127 #endif
128 
129 static gboolean param_show_version = FALSE;
130 static char *param_lib_dir  = NULL;
131 static char *param_data_dir = NULL;
132 
133 static GOptionEntry const libspreadsheet_options [] = {
134 	/*********************************
135 	 * Public Actions */
136 	{
137 		"version", 'v',
138 		0, G_OPTION_ARG_NONE, &param_show_version,
139 		N_("Display Gnumeric's version"),
140 		NULL
141 	},
142 
143 	/*********************************
144 	 * Public Variables */
145 	{
146 		"lib-dir", 'L',
147 		0, G_OPTION_ARG_FILENAME, &param_lib_dir,
148 		N_("Set the root library directory"),
149 		N_("DIR")
150 	},
151 	{
152 		"data-dir", 'D',
153 		0, G_OPTION_ARG_FILENAME, &param_data_dir,
154 		N_("Adjust the root data directory"),
155 		N_("DIR")
156 	},
157 
158 	/**************************************
159 	 * Hidden debugging flags */
160 
161 	{ NULL }
162 };
163 
164 static gboolean
cb_gnm_option_group_post_parse(GOptionContext * context,GOptionGroup * group,gpointer data,GError ** error)165 cb_gnm_option_group_post_parse (GOptionContext *context,
166 				GOptionGroup   *group,
167 				gpointer        data,
168 				GError        **error)
169 {
170 	if (param_show_version) {
171 		g_print (_("gnumeric version '%s'\ndatadir := '%s'\nlibdir := '%s'\n"),
172 			 GNM_VERSION_FULL, gnm_sys_data_dir (), gnm_sys_lib_dir ());
173 		exit (0);
174 	}
175 	return TRUE;
176 }
177 
178 /**
179  * gnm_get_option_group: (skip)
180  *
181  * Returns a #GOptionGroup for the commandline arguments recognized
182  * by libspreadsheet. You should add this group to your #GOptionContext with
183  * g_option_context_add_group(), if you are using g_option_context_parse() to
184  * parse your commandline arguments.
185  *
186  * Returns a #GOptionGroup for the commandline arguments recognized
187  *   by libspreadsheet
188  *
189  * Since: 1.8
190  **/
191 GOptionGroup *
gnm_get_option_group(void)192 gnm_get_option_group (void)
193 {
194 	GOptionGroup *group = g_option_group_new ("libspreadsheet",
195 		_("Gnumeric Options"), _("Show Gnumeric Options"), NULL, NULL);
196 	g_option_group_add_entries (group, libspreadsheet_options);
197 	g_option_group_set_translation_domain (group, GETTEXT_PACKAGE);
198 	g_option_group_set_parse_hooks (group, NULL,
199 		&cb_gnm_option_group_post_parse);
200 	return group;
201 }
202 
203 /**
204  * gnm_pre_parse_init:
205  * @argc:
206  * @argv:
207  *
208  * Initialization to be done before cmd line arguments are handled.
209  * Needs to be called first, before any other initialization.
210  *
211  * Returns: (transfer none): the arguments in UTF-8 encoding.
212  **/
213 gchar const **
gnm_pre_parse_init(int argc,gchar const ** argv)214 gnm_pre_parse_init (int argc, gchar const **argv)
215 {
216 /*
217  * NO CODE BEFORE THIS POINT, PLEASE!
218  *
219  * Using threads (by way of libraries) makes our stack too small in some
220  * circumstances.  It is hard to control directly, but setting the stack
221  * limit to something not unlimited seems to work.
222  *
223  * See http://bugzilla.gnome.org/show_bug.cgi?id=92131
224  */
225 #ifdef HAVE_SYS_RESOURCE_H
226 	struct rlimit rlim;
227 
228 	if (getrlimit (RLIMIT_STACK, &rlim) == 0) {
229 		rlim_t our_lim = 64 * 1024 * 1024;
230 		if (rlim.rlim_max != RLIM_INFINITY)
231 			our_lim = MIN (our_lim, rlim.rlim_max);
232 		if (rlim.rlim_cur != RLIM_INFINITY &&
233 		    rlim.rlim_cur < our_lim) {
234 			rlim.rlim_cur = our_lim;
235 			(void)setrlimit (RLIMIT_STACK, &rlim);
236 		}
237 	}
238 #endif
239 
240 	/* Default value is bogus, see 732184.  */
241 	if (!getenv ("G_ENABLE_DIAGNOSTIC")) {
242 #ifdef HAVE_SETENV
243 		setenv ("G_ENABLE_DIAGNOSTIC", "0", FALSE);
244 #elif defined(HAVE_PUTENV)
245 		putenv ("G_ENABLE_DIAGNOSTIC=0");
246 #else
247 		/* No big deal.  */
248 #endif
249 	}
250 
251 	/* On win32 argv contains 'ansi' encoded args.  We need to manually
252 	 * pull in the real versions and convert them to utf-8 */
253 	argv = go_shell_argv_to_glib_encoding (argc, argv);
254 
255 	g_set_prgname (argv[0]);
256 
257 	/* Make stdout line buffered - we only use it for debug info */
258 	setvbuf (stdout, NULL, _IOLBF, 0);
259 
260 	gutils_init ();
261 
262 	bindtextdomain (GETTEXT_PACKAGE, gnm_locale_dir ());
263 	bindtextdomain (GETTEXT_PACKAGE "-functions", gnm_locale_dir ());
264 	textdomain (GETTEXT_PACKAGE);
265 
266 	/* Force all of the locale segments to update from the environment.
267 	 * Unless we do this they will default to C
268 	 */
269 	setlocale (LC_ALL, "");
270 
271 	return argv;
272 }
273 
274 void
gnm_pre_parse_shutdown(void)275 gnm_pre_parse_shutdown (void)
276 {
277 	go_shell_argv_to_glib_encoding_free ();
278 }
279 
280 void
gnm_init(void)281 gnm_init (void)
282 {
283 	static gboolean inited = FALSE;
284 	if (inited)
285 		return;
286 	inited = TRUE;
287 
288 	// Might be duplicate call, but that's ok
289 	gutils_init ();
290 
291 	libgoffice_init ();
292 	_gnm_register_resource ();
293 	if (gdk_screen_get_default ()) {
294 		/* Only when we have a gui.  */
295 		gtk_icon_theme_add_resource_path (gtk_icon_theme_get_default (),
296 						  "/org/gnumeric/gnumeric/icons");
297 	}
298 
299 	gnm_plugins_service_init ();
300 
301 	g_object_new (GNM_APP_TYPE, NULL);
302 	mathfunc_init ();
303 
304 	gnm_style_init ();
305 	gnm_conf_init ();
306 	gnm_color_init ();
307 	gnm_font_init ();	/* requires config */
308 
309 	value_init ();
310 	parse_util_init ();
311 	gnm_expr_init_ ();
312 	gnm_sheet_cell_init ();
313 	clipboard_init ();
314 	gui_clipboard_init ();
315 	dependent_types_init ();
316 	gnm_rendered_value_init ();
317 	gnm_func_init_ ();
318 	print_init ();
319 	gnm_autofill_init ();
320 	sheet_objects_init ();
321 	gnm_hlink_init_ ();
322 
323 	/* The statically linked in file formats */
324 	gnm_xml_sax_read_init ();
325 	gnm_xml_sax_write_init ();
326 	stf_init ();
327 
328 	/* Make sure that images will be displayed with the correct
329 	 resolution, see #628472 */
330 	go_image_set_default_dpi (gnm_app_display_dpi_get (TRUE),
331 	                          gnm_app_display_dpi_get (FALSE));
332 }
333 
334 void
gnm_shutdown(void)335 gnm_shutdown (void)
336 {
337 	GSList *plugin_states;
338 
339 	gnm_app_clipboard_clear (TRUE);
340 
341 	plugin_states = go_plugins_shutdown ();
342 	if (NULL != plugin_states) {
343 		gnm_conf_set_plugins_file_states (plugin_states);
344 		g_slist_free_full (plugin_states, g_free);
345 	}
346 
347 	stf_shutdown ();
348 	gnm_xml_sax_write_shutdown ();
349 	gnm_xml_sax_read_shutdown ();
350 
351 	sheet_objects_shutdown ();
352 	gnm_autofill_shutdown ();
353 	print_shutdown ();
354 	gnm_func_shutdown_ ();
355 
356 	gnm_rendered_value_shutdown ();
357 	dependent_types_shutdown ();
358 	gui_clipboard_shutdown ();
359 	clipboard_shutdown ();
360 	gnm_sheet_cell_shutdown ();
361 	gnm_expr_deriv_shutdown_ ();
362 	gnm_expr_shutdown_ ();
363 	parse_util_shutdown ();
364 	value_shutdown ();
365 
366 	// The style leak printer may access font/border/color info so
367 	// shut styles down first.
368 	gnm_style_shutdown ();
369 	gnm_font_shutdown ();
370 	gnm_border_shutdown ();
371 	gnm_color_shutdown ();
372 
373 	gnm_conf_shutdown ();
374 
375 	_gnm_unregister_resource ();
376 	libgoffice_shutdown ();
377 	go_plugin_services_shutdown ();
378 	g_object_unref (gnm_app_get_app ());
379 	gutils_shutdown ();
380 }
381