1 /*
2  *      libmain.c - this file is part of Geany, a fast and lightweight IDE
3  *
4  *      Copyright 2005 The Geany contributors
5  *
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.
10  *
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.
15  *
16  *      You should have received a copy of the GNU General Public License along
17  *      with this program; if not, write to the Free Software Foundation, Inc.,
18  *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 /**
22  * @file: main.h
23  * Main program-related commands.
24  * Handles program initialization and cleanup.
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30 
31 #include "main.h"
32 
33 #include "app.h"
34 #include "build.h"
35 #include "callbacks.h"
36 #include "dialogs.h"
37 #include "document.h"
38 #include "encodingsprivate.h"
39 #include "filetypes.h"
40 #include "geanyobject.h"
41 #include "highlighting.h"
42 #include "keybindings.h"
43 #include "keyfile.h"
44 #include "log.h"
45 #include "msgwindow.h"
46 #include "navqueue.h"
47 #include "notebook.h"
48 #include "plugins.h"
49 #include "prefs.h"
50 #include "printing.h"
51 #include "sidebar.h"
52 #ifdef HAVE_SOCKET
53 # include "socket.h"
54 #endif
55 #include "support.h"
56 #include "symbols.h"
57 #include "templates.h"
58 #include "toolbar.h"
59 #include "tools.h"
60 #include "ui_utils.h"
61 #include "utils.h"
62 #include "vte.h"
63 #include "win32.h"
64 #include "osx.h"
65 
66 #include "gtkcompat.h"
67 
68 #include <signal.h>
69 #include <time.h>
70 #include <sys/types.h>
71 #include <sys/stat.h>
72 #include <errno.h>
73 #include <string.h>
74 #include <stdlib.h>
75 
76 #include <glib/gstdio.h>
77 
78 #ifdef G_OS_UNIX
79 # include <glib-unix.h>
80 #endif
81 
82 #ifdef HAVE_LOCALE_H
83 # include <locale.h>
84 #endif
85 
86 
87 GeanyApp	*app;
88 gboolean	ignore_callback;	/* hack workaround for GTK+ toggle button callback problem */
89 
90 GeanyStatus	 main_status;
91 CommandLineOptions cl_options;	/* fields initialised in parse_command_line_options */
92 
93 static gchar *original_cwd = NULL;
94 
95 static const gchar geany_lib_versions[] = "GTK %u.%u.%u, GLib %u.%u.%u";
96 
97 static gboolean want_plugins;
98 
99 /* command-line options */
100 static gboolean verbose_mode = FALSE;
101 static gboolean ignore_global_tags = FALSE;
102 static gboolean no_msgwin = FALSE;
103 static gboolean show_version = FALSE;
104 static gchar *alternate_config = NULL;
105 #ifdef HAVE_VTE
106 static gboolean no_vte = FALSE;
107 static gchar *lib_vte = NULL;
108 #endif
109 static gboolean generate_tags = FALSE;
110 static gboolean no_preprocessing = FALSE;
111 static gboolean ft_names = FALSE;
112 static gboolean print_prefix = FALSE;
113 #ifdef HAVE_PLUGINS
114 static gboolean no_plugins = FALSE;
115 #endif
116 static gboolean dummy = FALSE;
117 
118 /* in alphabetical order of short options */
119 static GOptionEntry entries[] =
120 {
121 	{ "column", 0, 0, G_OPTION_ARG_INT, &cl_options.goto_column, N_("Set initial column number to COLUMN for the first opened file (useful in conjunction with --line)"), N_("COLUMN") },
122 	{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &alternate_config, N_("Use alternate configuration directory DIR"), N_("DIR") },
123 	{ "ft-names", 0, 0, G_OPTION_ARG_NONE, &ft_names, N_("Print internal filetype names"), NULL },
124 	{ "generate-tags", 'g', 0, G_OPTION_ARG_NONE, &generate_tags, N_("Generate global tags file (see documentation)"), NULL },
125 	{ "no-preprocessing", 'P', 0, G_OPTION_ARG_NONE, &no_preprocessing, N_("Don't preprocess C/C++ files when generating tags file"), NULL },
126 #ifdef HAVE_SOCKET
127 	{ "new-instance", 'i', 0, G_OPTION_ARG_NONE, &cl_options.new_instance, N_("Don't open files in a running instance, force opening a new instance"), NULL },
128 	{ "socket-file", 0, 0, G_OPTION_ARG_FILENAME, &cl_options.socket_filename, N_("Use socket filename FILE for communication with a running Geany instance"), N_("FILE") },
129 	{ "list-documents", 0, 0, G_OPTION_ARG_NONE, &cl_options.list_documents, N_("Return a list of open documents in a running Geany instance"), NULL },
130 #endif
131 	{ "line", 'l', 0, G_OPTION_ARG_INT, &cl_options.goto_line, N_("Set initial line number to LINE for the first opened file"), N_("LINE") },
132 	{ "no-msgwin", 'm', 0, G_OPTION_ARG_NONE, &no_msgwin, N_("Don't show message window at startup"), NULL },
133 	{ "no-ctags", 'n', 0, G_OPTION_ARG_NONE, &ignore_global_tags, N_("Don't load auto completion data (see documentation)"), NULL },
134 #ifdef HAVE_PLUGINS
135 	{ "no-plugins", 'p', 0, G_OPTION_ARG_NONE, &no_plugins, N_("Don't load plugins"), NULL },
136 #endif
137 	{ "print-prefix", 0, 0, G_OPTION_ARG_NONE, &print_prefix, N_("Print Geany's installation prefix"), NULL },
138 	{ "read-only", 'r', 0, G_OPTION_ARG_NONE, &cl_options.readonly, N_("Open all FILES in read-only mode (see documentation)"), NULL },
139 	{ "no-session", 's', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &cl_options.load_session, N_("Don't load the previous session's files"), NULL },
140 #ifdef HAVE_VTE
141 	{ "no-terminal", 't', 0, G_OPTION_ARG_NONE, &no_vte, N_("Don't load terminal support"), NULL },
142 	{ "vte-lib", 0, 0, G_OPTION_ARG_FILENAME, &lib_vte, N_("Use FILE as the dynamically-linked VTE library"), N_("FILE") },
143 #endif
144 	{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose_mode, N_("Be verbose"), NULL },
145 	{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Show version and exit"), NULL },
146 	{ "dummy", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &dummy, NULL, NULL }, /* for +NNN line number arguments */
147 	{ NULL, 0, 0, 0, NULL, NULL, NULL }
148 };
149 
150 
setup_window_position(void)151 static void setup_window_position(void)
152 {
153 	/* interprets the saved window geometry */
154 	if (prefs.save_wingeom)
155 	{
156 		if (ui_prefs.geometry[2] != -1 && ui_prefs.geometry[3] != -1)
157 		{
158 			gtk_window_set_default_size(GTK_WINDOW(main_widgets.window),
159 				ui_prefs.geometry[2], ui_prefs.geometry[3]);
160 		}
161 	}
162 
163 	if (prefs.save_winpos)
164 	{
165 		if (ui_prefs.geometry[0] != -1 && ui_prefs.geometry[1] != -1)
166 		{
167 			gtk_window_move(GTK_WINDOW(main_widgets.window),
168 				ui_prefs.geometry[0], ui_prefs.geometry[1]);
169 		}
170 		if (ui_prefs.geometry[4] == 1)
171 		{
172 			gtk_window_maximize(GTK_WINDOW(main_widgets.window));
173 		}
174 	}
175 }
176 
177 
178 /* special things for the initial setup of the checkboxes and related stuff
179  * an action on a setting is only performed if the setting is not equal to the program default
180  * (all the following code is not perfect but it works for the moment) */
apply_settings(void)181 static void apply_settings(void)
182 {
183 	ui_update_fold_items();
184 
185 	/* toolbar, message window and sidebar are by default visible, so don't change it if it is true */
186 	toolbar_show_hide();
187 	if (! ui_prefs.msgwindow_visible)
188 	{
189 		ignore_callback = TRUE;
190 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_show_messages_window1")), FALSE);
191 		gtk_widget_hide(main_widgets.message_window_notebook);
192 		ignore_callback = FALSE;
193 	}
194 	if (! ui_prefs.sidebar_visible)
195 	{
196 		ignore_callback = TRUE;
197 		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_show_sidebar1")), FALSE);
198 		ignore_callback = FALSE;
199 	}
200 
201 	toolbar_apply_settings();
202 	toolbar_update_ui();
203 
204 	ui_update_view_editor_menu_items();
205 
206 	/* hide statusbar if desired */
207 	if (! interface_prefs.statusbar_visible)
208 	{
209 		gtk_widget_hide(ui_widgets.statusbar);
210 	}
211 
212 	/* set the tab placements of the notebooks */
213 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(main_widgets.notebook), interface_prefs.tab_pos_editor);
214 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(msgwindow.notebook), interface_prefs.tab_pos_msgwin);
215 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(main_widgets.sidebar_notebook), interface_prefs.tab_pos_sidebar);
216 
217 	/* whether to show notebook tabs or not */
218 	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(main_widgets.notebook), interface_prefs.show_notebook_tabs);
219 
220 #ifdef HAVE_VTE
221 	if (! vte_info.have_vte)
222 #endif
223 	{
224 		gtk_widget_set_sensitive(
225 			ui_lookup_widget(main_widgets.window, "send_selection_to_vte1"), FALSE);
226 	}
227 
228 	if (interface_prefs.sidebar_pos != GTK_POS_LEFT)
229 		ui_swap_sidebar_pos();
230 
231 	gtk_orientable_set_orientation(GTK_ORIENTABLE(ui_lookup_widget(main_widgets.window, "vpaned1")),
232 		interface_prefs.msgwin_orientation);
233 }
234 
235 
on_window_active_changed(GtkWindow * window,GParamSpec * pspec,gpointer data)236 static void on_window_active_changed(GtkWindow *window, GParamSpec *pspec, gpointer data)
237 {
238 	GeanyDocument *doc = document_get_current();
239 
240 	if (doc && gtk_window_is_active(window))
241 		document_check_disk_status(doc, TRUE);
242 }
243 
244 
main_init(void)245 static void main_init(void)
246 {
247 	/* add our icon path in case we aren't installed in the system prefix */
248 	gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), utils_resource_dir(RESOURCE_DIR_ICON));
249 
250 	/* inits */
251 	ui_init_stock_items();
252 
253 	ui_init_builder();
254 
255 	main_widgets.window				= NULL;
256 	app->project			= NULL;
257 	ui_widgets.open_fontsel		= NULL;
258 	ui_widgets.open_colorsel	= NULL;
259 	ui_widgets.prefs_dialog		= NULL;
260 	main_status.main_window_realized = FALSE;
261 	file_prefs.tab_order_ltr		= FALSE;
262 	file_prefs.tab_order_beside		= FALSE;
263 	main_status.quitting			= FALSE;
264 	ignore_callback	= FALSE;
265 	ui_prefs.recent_queue				= g_queue_new();
266 	ui_prefs.recent_projects_queue		= g_queue_new();
267 	main_status.opening_session_files	= FALSE;
268 
269 	main_widgets.window = create_window1();
270 	g_signal_connect(main_widgets.window, "notify::is-active", G_CALLBACK(on_window_active_changed), NULL);
271 
272 	/* add recent projects to the Project menu */
273 	ui_widgets.recent_projects_menuitem = ui_lookup_widget(main_widgets.window, "recent_projects1");
274 	ui_widgets.recent_projects_menu_menubar = gtk_menu_new();
275 	gtk_menu_item_set_submenu(GTK_MENU_ITEM(ui_widgets.recent_projects_menuitem),
276 							ui_widgets.recent_projects_menu_menubar);
277 
278 	/* store important pointers for later reference */
279 	main_widgets.toolbar = toolbar_init();
280 	main_widgets.sidebar_notebook = ui_lookup_widget(main_widgets.window, "notebook3");
281 	main_widgets.notebook = ui_lookup_widget(main_widgets.window, "notebook1");
282 	main_widgets.editor_menu = create_edit_menu1();
283 	main_widgets.tools_menu = ui_lookup_widget(main_widgets.window, "tools1_menu");
284 	main_widgets.message_window_notebook = ui_lookup_widget(main_widgets.window, "notebook_info");
285 	main_widgets.project_menu = ui_lookup_widget(main_widgets.window, "menu_project1_menu");
286 
287 	ui_widgets.toolbar_menu = create_toolbar_popup_menu1();
288 	ui_init();
289 #ifdef MAC_INTEGRATION
290 	osx_ui_init();
291 #endif
292 
293 	/* set widget names for matching with .gtkrc-2.0 */
294 	gtk_widget_set_name(main_widgets.window, "GeanyMainWindow");
295 	gtk_widget_set_name(ui_widgets.toolbar_menu, "GeanyToolbarMenu");
296 	gtk_widget_set_name(main_widgets.editor_menu, "GeanyEditMenu");
297 	gtk_widget_set_name(ui_lookup_widget(main_widgets.window, "menubar1"), "GeanyMenubar");
298 	gtk_widget_set_name(main_widgets.toolbar, "GeanyToolbar");
299 
300 	gtk_window_set_default_size(GTK_WINDOW(main_widgets.window),
301 		GEANY_WINDOW_DEFAULT_WIDTH, GEANY_WINDOW_DEFAULT_HEIGHT);
302 }
303 
304 
main_get_version_string(void)305 const gchar *main_get_version_string(void)
306 {
307 	static gchar full[] = VERSION " (git >= " REVISION ")";
308 
309 	if (utils_str_equal(REVISION, "-1"))
310 		return VERSION;
311 	else
312 		return full;
313 }
314 
315 
316 /* get the full file path of a command-line argument
317  * N.B. the result should be freed and may contain '/../' or '/./ ' */
main_get_argv_filename(const gchar * filename)318 gchar *main_get_argv_filename(const gchar *filename)
319 {
320 	gchar *result;
321 
322 	if (g_path_is_absolute(filename) || utils_is_uri(filename))
323 		result = g_strdup(filename);
324 	else
325 	{
326 		/* use current dir */
327 		gchar *cur_dir = NULL;
328 		if (original_cwd == NULL)
329 			cur_dir = g_get_current_dir();
330 		else
331 			cur_dir = g_strdup(original_cwd);
332 
333 		result = g_strjoin(
334 			G_DIR_SEPARATOR_S, cur_dir, filename, NULL);
335 		g_free(cur_dir);
336 	}
337 	return result;
338 }
339 
340 
341 /* get a :line:column specifier from the end of a filename (if present),
342  * return the line/column values, and remove the specifier from the string
343  * (Note that *line and *column must both be set to -1 initially) */
get_line_and_column_from_filename(gchar * filename,gint * line,gint * column)344 static void get_line_and_column_from_filename(gchar *filename, gint *line, gint *column)
345 {
346 	gsize i;
347 	gint colon_count = 0;
348 	gboolean have_number = FALSE;
349 	gsize len;
350 
351 	g_assert(*line == -1 && *column == -1);
352 
353 	if (G_UNLIKELY(EMPTY(filename)))
354 		return;
355 
356 	/* allow to open files like "test:0" */
357 	if (g_file_test(filename, G_FILE_TEST_EXISTS))
358 		return;
359 
360 	len = strlen(filename);
361 	for (i = len - 1; i >= 1; i--)
362 	{
363 		gboolean is_colon = filename[i] == ':';
364 		gboolean is_digit = g_ascii_isdigit(filename[i]);
365 
366 		if (! is_colon && ! is_digit)
367 			break;
368 
369 		if (is_colon)
370 		{
371 			if (++colon_count > 1)
372 				break;	/* bail on 2+ colons in a row */
373 		}
374 		else
375 			colon_count = 0;
376 
377 		if (is_digit)
378 			have_number = TRUE;
379 
380 		if (is_colon && have_number)
381 		{
382 			gint number = atoi(&filename[i + 1]);
383 
384 			filename[i] = '\0';
385 			have_number = FALSE;
386 
387 			*column = *line;
388 			*line = number;
389 		}
390 
391 		if (*column >= 0)
392 			break;	/* line and column are set, so we're done */
393 	}
394 }
395 
396 
397 #ifdef G_OS_WIN32
get_windows_socket_port(void)398 static gint get_windows_socket_port(void)
399 {
400 	/* Read config file early to get TCP port number as we need it for IPC before all
401 	 * other settings are read in load_settings() */
402 	gchar *configfile = g_build_filename(app->configdir, "geany.conf", NULL);
403 	GKeyFile *config = g_key_file_new();
404 	gint port_number;
405 
406 	if (! g_file_test(configfile, G_FILE_TEST_IS_REGULAR))
407 	{
408 		geany_debug(
409 			"No user config file found, use default TCP port (%d).",
410 			SOCKET_WINDOWS_REMOTE_CMD_PORT);
411 		g_free(configfile);
412 		return SOCKET_WINDOWS_REMOTE_CMD_PORT;
413 	}
414 	g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL);
415 	port_number = utils_get_setting_integer(config, PACKAGE, "socket_remote_cmd_port",
416 		SOCKET_WINDOWS_REMOTE_CMD_PORT);
417 	geany_debug("Using TCP port number %d for IPC", port_number);
418 	g_free(configfile);
419 	g_key_file_free(config);
420 	g_return_val_if_fail(port_number >= 1024 && port_number <= (gint)G_MAXUINT16,
421 		SOCKET_WINDOWS_REMOTE_CMD_PORT);
422 	return port_number;
423 }
424 
425 
change_working_directory_on_windows(void)426 static void change_working_directory_on_windows(void)
427 {
428 	gchar *install_dir = win32_get_installation_dir();
429 
430 	/* remember original working directory for use with opening files from the command line */
431 	original_cwd = g_get_current_dir();
432 
433 	/* On Windows, change the working directory to the Geany installation path to not lock
434 	 * the directory of a file passed as command line argument (see bug #2626124).
435 	 * This also helps if plugins or other code uses relative paths to load
436 	 * any additional resources (e.g. share/geany-plugins/...). */
437 	win32_set_working_directory(install_dir);
438 
439 	g_free(install_dir);
440 }
441 #endif
442 
443 
setup_paths(void)444 static void setup_paths(void)
445 {
446 	/* convert path names to locale encoding */
447 	app->datadir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DATA));
448 	app->docdir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DOC));
449 }
450 
451 
452 /**
453  *  Checks whether the main window has been realized.
454  *  This is an easy indicator whether Geany is right now starting up (main window is not
455  *  yet realized) or whether it has finished the startup process (main window is realized).
456  *  This is because the main window is realized (i.e. actually drawn on the screen) at the
457  *  end of the startup process.
458  *
459  *  @note Maybe you want to use the @link pluginsignals.c @c "geany-startup-complete" signal @endlink
460  *        to get notified about the completed startup process.
461  *
462  *  @return @c TRUE if the Geany main window has been realized or @c FALSE otherwise.
463  *
464  *  @since 0.19
465  **/
466 GEANY_API_SYMBOL
main_is_realized(void)467 gboolean main_is_realized(void)
468 {
469 	return main_status.main_window_realized;
470 }
471 
472 
473 /**
474  *  Initialises the gettext translation system.
475  *  This is a convenience function to set up gettext for internationalisation support
476  *  in external plugins. You should call this function early in @ref plugin_init().
477  *  If the macro HAVE_LOCALE_H is defined, @c setlocale(LC_ALL, "") is called.
478  *  The codeset for the message translations is set to UTF-8.
479  *
480  *  Note that this function only setups the gettext textdomain for you. You still have
481  *  to adjust the build system of your plugin to get internationalisation support
482  *  working properly.
483  *
484  *  If you have already used @ref PLUGIN_SET_TRANSLATABLE_INFO() you
485  *  don't need to call main_locale_init() again as it has already been done.
486  *
487  *  @param locale_dir The location where the translation files should be searched. This is
488  *                    usually the @c LOCALEDIR macro, defined by the build system.
489  *                    E.g. @c $prefix/share/locale.
490  *                    Only used on non-Windows systems. On Windows, the directory is determined
491  *                    by @c g_win32_get_package_installation_directory().
492  *  @param package The package name, usually this is the @c GETTEXT_PACKAGE macro,
493  *                 defined by the build system.
494  *
495  *  @since 0.16
496  **/
497 GEANY_API_SYMBOL
main_locale_init(const gchar * locale_dir,const gchar * package)498 void main_locale_init(const gchar *locale_dir, const gchar *package)
499 {
500 #ifdef HAVE_LOCALE_H
501 	setlocale(LC_ALL, "");
502 #endif
503 
504 #ifdef G_OS_WIN32
505 	locale_dir = utils_resource_dir(RESOURCE_DIR_LOCALE);
506 #endif
507 	(void) bindtextdomain(package, locale_dir);
508 	(void) bind_textdomain_codeset(package, "UTF-8");
509 }
510 
511 
print_filetypes(void)512 static void print_filetypes(void)
513 {
514 	const GSList *list, *node;
515 
516 	filetypes_init_types();
517 	printf("Geany's filetype names:\n");
518 
519 	list = filetypes_get_sorted_by_name();
520 	foreach_slist(node, list)
521 	{
522 		GeanyFiletype *ft = node->data;
523 
524 		printf("%s\n", ft->name);
525 	}
526 	filetypes_free_types();
527 }
528 
529 
wait_for_input_on_windows(void)530 static void wait_for_input_on_windows(void)
531 {
532 #ifdef G_OS_WIN32
533 	if (verbose_mode)
534 	{
535 		geany_debug("Press any key to continue");
536 		getchar();
537 	}
538 #endif
539 }
540 
541 
parse_command_line_options(gint * argc,gchar *** argv)542 static void parse_command_line_options(gint *argc, gchar ***argv)
543 {
544 	GError *error = NULL;
545 	GOptionContext *context;
546 	gint i;
547 	CommandLineOptions def_clo = {FALSE, NULL, TRUE, -1, -1, FALSE, FALSE, FALSE};
548 
549 	/* first initialise cl_options fields with default values */
550 	cl_options = def_clo;
551 
552 	/* the GLib option parser can't handle the +NNN (line number) option,
553 	 * so we grab that here and replace it with a no-op */
554 	for (i = 1; i < (*argc); i++)
555 	{
556 		if ((*argv)[i][0] != '+')
557 			continue;
558 
559 		cl_options.goto_line = atoi((*argv)[i] + 1);
560 		(*argv)[i] = (gchar *) "--dummy";
561 	}
562 
563 	context = g_option_context_new(_("[FILES...]"));
564 
565 	g_option_context_set_summary(context, _("A fast and lightweight IDE."));
566 	g_option_context_set_description(context, _("Report bugs to https://github.com/geany/geany/issues."));
567 	g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE);
568 	g_option_group_set_translation_domain(g_option_context_get_main_group(context), GETTEXT_PACKAGE);
569 	g_option_context_add_group(context, gtk_get_option_group(FALSE));
570 	g_option_context_parse(context, argc, argv, &error);
571 	g_option_context_free(context);
572 
573 	if (error != NULL)
574 	{
575 		g_printerr("Geany: %s\n", error->message);
576 		g_error_free(error);
577 		exit(1);
578 	}
579 
580 	app->debug_mode = verbose_mode;
581 	if (app->debug_mode)
582 	{
583 		/* Since GLib 2.32 messages logged with levels INFO and DEBUG aren't output by the
584 		 * default log handler unless the G_MESSAGES_DEBUG environment variable contains the
585 		 * domain of the message or is set to the special value "all" */
586 		g_setenv("G_MESSAGES_DEBUG", "all", FALSE);
587 	}
588 
589 #ifdef G_OS_WIN32
590 	win32_init_debug_code();
591 #endif
592 
593 	if (show_version)
594 	{
595 		gchar *build_date = utils_parse_and_format_build_date(__DATE__);
596 
597 		printf(PACKAGE " %s (", main_get_version_string());
598 		/* note for translators: library versions are printed after this */
599 		printf(_("built on %s with "), build_date);
600 		printf(geany_lib_versions,
601 			GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION,
602 			GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
603 		printf(")\n");
604 		g_free(build_date);
605 		wait_for_input_on_windows();
606 		exit(0);
607 	}
608 
609 	if (print_prefix)
610 	{
611 		printf("%s\n", GEANY_PREFIX);
612 		printf("%s\n", GEANY_DATADIR);
613 		printf("%s\n", GEANY_LIBDIR);
614 		printf("%s\n", GEANY_LOCALEDIR);
615 		wait_for_input_on_windows();
616 		exit(0);
617 	}
618 
619 	if (alternate_config)
620 	{
621 		geany_debug("Using alternate configuration directory");
622 		app->configdir = alternate_config;
623 	}
624 	else
625 	{
626 		app->configdir = utils_get_user_config_dir();
627 	}
628 
629 	if (generate_tags)
630 	{
631 		gboolean ret;
632 
633 		filetypes_init_types();
634 		ret = symbols_generate_global_tags(*argc, *argv, ! no_preprocessing);
635 		filetypes_free_types();
636 		wait_for_input_on_windows();
637 		exit(ret);
638 	}
639 
640 	if (ft_names)
641 	{
642 		print_filetypes();
643 		wait_for_input_on_windows();
644 		exit(0);
645 	}
646 
647 #ifdef HAVE_SOCKET
648 	socket_info.ignore_socket = cl_options.new_instance;
649 	if (cl_options.socket_filename)
650 	{
651 		socket_info.file_name = cl_options.socket_filename;
652 	}
653 #endif
654 
655 #ifdef HAVE_VTE
656 	vte_info.lib_vte = lib_vte;
657 #endif
658 	cl_options.ignore_global_tags = ignore_global_tags;
659 
660 	if (! gtk_init_check(NULL, NULL))
661 	{	/* check whether we have a valid X display and exit if not */
662 		g_printerr("Geany: cannot open display\n");
663 		exit(1);
664 	}
665 
666 #ifdef MAC_INTEGRATION
667 	/* Create GtkosxApplication singleton - should be created shortly after gtk_init() */
668 	gtkosx_application_get();
669 #endif
670 }
671 
672 
create_config_dir(void)673 static gint create_config_dir(void)
674 {
675 	gint saved_errno = 0;
676 	gchar *conf_file = NULL;
677 	gchar *filedefs_dir = NULL;
678 	gchar *templates_dir = NULL;
679 
680 	if (! g_file_test(app->configdir, G_FILE_TEST_EXISTS))
681 	{
682 #ifndef G_OS_WIN32
683 		/* if we are *not* using an alternate config directory, we check whether the old one
684 		 * in ~/.geany still exists and try to move it */
685 		if (alternate_config == NULL)
686 		{
687 			gchar *old_dir = g_build_filename(g_get_home_dir(), ".geany", NULL);
688 			/* move the old config dir if it exists */
689 			if (g_file_test(old_dir, G_FILE_TEST_EXISTS))
690 			{
691 				if (! dialogs_show_question_full(main_widgets.window,
692 					GTK_STOCK_YES, GTK_STOCK_QUIT, _("Move it now?"),
693 					"%s",
694 					_("Geany needs to move your old configuration directory before starting.")))
695 					exit(0);
696 
697 				if (! g_file_test(app->configdir, G_FILE_TEST_IS_DIR))
698 					utils_mkdir(app->configdir, TRUE);
699 
700 				if (g_rename(old_dir, app->configdir) == 0)
701 				{
702 					dialogs_show_msgbox(GTK_MESSAGE_INFO,
703 						_("Your configuration directory has been successfully moved from \"%s\" to \"%s\"."),
704 						old_dir, app->configdir);
705 					g_free(old_dir);
706 					return 0;
707 				}
708 				else
709 				{
710 					dialogs_show_msgbox(GTK_MESSAGE_WARNING,
711 						/* for translators: the third %s in brackets is the error message which
712 						 * describes why moving the dir didn't work */
713 						_("Your old configuration directory \"%s\" could not be moved to \"%s\" (%s). "
714 						  "Please move manually the directory to the new location."),
715 						old_dir, app->configdir, g_strerror(errno));
716 				}
717 			}
718 			g_free(old_dir);
719 		}
720 #endif
721 		geany_debug("Creating configuration directory");
722 		saved_errno = utils_mkdir(app->configdir, TRUE);
723 	}
724 
725 	conf_file = g_build_filename(app->configdir, "geany.conf", NULL);
726 	filedefs_dir = g_build_filename(app->configdir, GEANY_FILEDEFS_SUBDIR, NULL);
727 	templates_dir = g_build_filename(app->configdir, GEANY_TEMPLATES_SUBDIR, NULL);
728 
729 	if (saved_errno == 0 && ! g_file_test(conf_file, G_FILE_TEST_EXISTS))
730 	{	/* check whether geany.conf can be written */
731 		saved_errno = utils_is_file_writable(app->configdir);
732 	}
733 
734 	/* make subdir for filetype definitions */
735 	if (saved_errno == 0)
736 	{
737 		gchar *filedefs_readme = g_build_filename(app->configdir,
738 					GEANY_FILEDEFS_SUBDIR, "filetypes.README", NULL);
739 
740 		if (! g_file_test(filedefs_dir, G_FILE_TEST_EXISTS))
741 		{
742 			saved_errno = utils_mkdir(filedefs_dir, FALSE);
743 		}
744 		if (saved_errno == 0 && ! g_file_test(filedefs_readme, G_FILE_TEST_EXISTS))
745 		{
746 			gchar *text = g_strconcat(
747 "Copy files from ", app->datadir, "/filedefs to this directory to overwrite "
748 "them. To use the defaults, just delete the file in this directory.\nFor more information read "
749 "the documentation (in ", app->docdir, G_DIR_SEPARATOR_S "index.html or visit " GEANY_HOMEPAGE ").", NULL);
750 			utils_write_file(filedefs_readme, text);
751 			g_free(text);
752 		}
753 		g_free(filedefs_readme);
754 	}
755 
756 	/* make subdir for template files */
757 	if (saved_errno == 0)
758 	{
759 		gchar *templates_readme = g_build_filename(app->configdir, GEANY_TEMPLATES_SUBDIR,
760 						"templates.README", NULL);
761 
762 		if (! g_file_test(templates_dir, G_FILE_TEST_EXISTS))
763 		{
764 			saved_errno = utils_mkdir(templates_dir, FALSE);
765 		}
766 		if (saved_errno == 0 && ! g_file_test(templates_readme, G_FILE_TEST_EXISTS))
767 		{
768 			gchar *text = g_strconcat(
769 "There are several template files in this directory. For these templates you can use wildcards.\n\
770 For more information read the documentation (in ", app->docdir, G_DIR_SEPARATOR_S "index.html or visit " GEANY_HOMEPAGE ").",
771 					NULL);
772 			utils_write_file(templates_readme, text);
773 			g_free(text);
774 		}
775 		g_free(templates_readme);
776 	}
777 
778 	g_free(filedefs_dir);
779 	g_free(templates_dir);
780 	g_free(conf_file);
781 
782 	return saved_errno;
783 }
784 
785 
786 /* Returns 0 if config dir is OK. */
setup_config_dir(void)787 static gint setup_config_dir(void)
788 {
789 	gint mkdir_result = 0;
790 
791 	mkdir_result = create_config_dir();
792 	if (mkdir_result != 0)
793 	{
794 		if (! dialogs_show_question(
795 			_("Configuration directory could not be created (%s).\nThere could be some problems "
796 			  "using Geany without a configuration directory.\nStart Geany anyway?"),
797 			  g_strerror(mkdir_result)))
798 		{
799 			exit(0);
800 		}
801 	}
802 	/* make configdir a real path */
803 	if (g_file_test(app->configdir, G_FILE_TEST_EXISTS))
804 		SETPTR(app->configdir, utils_get_real_path(app->configdir));
805 
806 	return mkdir_result;
807 }
808 
809 
810 #ifdef G_OS_UNIX
signal_cb(gpointer user_data)811 static gboolean signal_cb(gpointer user_data)
812 {
813 	gint sig = GPOINTER_TO_INT(user_data);
814 	if (sig == SIGTERM)
815 	{
816 		geany_debug("Received SIGTERM signal");
817 		main_quit();
818 	}
819 	return G_SOURCE_REMOVE;
820 }
821 #endif
822 
823 
824 /* Used for command-line arguments at startup or from socket.
825  * this will strip any :line:col filename suffix from locale_filename */
main_handle_filename(const gchar * locale_filename)826 gboolean main_handle_filename(const gchar *locale_filename)
827 {
828 	GeanyDocument *doc;
829 	gint line = -1, column = -1;
830 	gchar *filename;
831 
832 	g_return_val_if_fail(locale_filename, FALSE);
833 
834 	/* check whether the passed filename is an URI */
835 	filename = utils_get_path_from_uri(locale_filename);
836 	if (filename == NULL)
837 		return FALSE;
838 
839 	get_line_and_column_from_filename(filename, &line, &column);
840 	if (line >= 0)
841 		cl_options.goto_line = line;
842 	if (column >= 0)
843 		cl_options.goto_column = column;
844 
845 	if (g_file_test(filename, G_FILE_TEST_IS_REGULAR))
846 	{
847 		doc = document_open_file(filename, cl_options.readonly, NULL, NULL);
848 		/* add recent file manually if opening_session_files is set */
849 		if (doc != NULL && main_status.opening_session_files)
850 			ui_add_recent_document(doc);
851 		g_free(filename);
852 		return TRUE;
853 	}
854 	else if (file_prefs.cmdline_new_files)
855 	{	/* create new file with the given filename */
856 		gchar *utf8_filename = utils_get_utf8_from_locale(filename);
857 
858 		doc = document_find_by_filename(utf8_filename);
859 		if (doc)
860 			document_show_tab(doc);
861 		else
862 			doc = document_new_file(utf8_filename, NULL, NULL);
863 		if (doc != NULL)
864 			ui_add_recent_document(doc);
865 		g_free(utf8_filename);
866 		g_free(filename);
867 		return TRUE;
868 	}
869 	g_free(filename);
870 	return FALSE;
871 }
872 
873 
874 /* open files from command line */
open_cl_files(gint argc,gchar ** argv)875 static void open_cl_files(gint argc, gchar **argv)
876 {
877 	gint i;
878 
879 	for (i = 1; i < argc; i++)
880 	{
881 		gchar *filename = main_get_argv_filename(argv[i]);
882 
883 		if (g_file_test(filename, G_FILE_TEST_IS_DIR))
884 		{
885 			g_free(filename);
886 			continue;
887 		}
888 
889 #ifdef G_OS_WIN32
890 		/* It seems argv elements are encoded in CP1252 on a German Windows */
891 		SETPTR(filename, g_locale_to_utf8(filename, -1, NULL, NULL, NULL));
892 #endif
893 		if (filename && ! main_handle_filename(filename))
894 		{
895 			const gchar *msg = _("Could not find file '%s'.");
896 
897 			g_printerr(msg, filename);	/* also print to the terminal */
898 			g_printerr("\n");
899 			ui_set_statusbar(TRUE, msg, filename);
900 		}
901 		g_free(filename);
902 	}
903 }
904 
905 
load_session_project_file(void)906 static void load_session_project_file(void)
907 {
908 	gchar *locale_filename;
909 
910 	g_return_if_fail(project_prefs.session_file != NULL);
911 
912 	locale_filename = utils_get_locale_from_utf8(project_prefs.session_file);
913 
914 	if (G_LIKELY(!EMPTY(locale_filename)))
915 		project_load_file(locale_filename);
916 
917 	g_free(locale_filename);
918 	g_free(project_prefs.session_file);	/* no longer needed */
919 }
920 
921 
load_settings(void)922 static void load_settings(void)
923 {
924 #ifdef HAVE_VTE
925 	vte_info.load_vte_cmdline = !no_vte;
926 #endif
927 	configuration_load();
928 	/* let cmdline options overwrite configuration settings */
929 #ifdef HAVE_VTE
930 	vte_info.have_vte = vte_info.load_vte && vte_info.load_vte_cmdline;
931 #endif
932 	if (no_msgwin)
933 		ui_prefs.msgwindow_visible = FALSE;
934 
935 #ifdef HAVE_PLUGINS
936 	want_plugins = prefs.load_plugins && !no_plugins;
937 #endif
938 }
939 
940 
main_load_project_from_command_line(const gchar * locale_filename,gboolean use_session)941 void main_load_project_from_command_line(const gchar *locale_filename, gboolean use_session)
942 {
943 	gchar *pfile;
944 
945 	pfile = utils_get_path_from_uri(locale_filename);
946 	if (pfile != NULL)
947 	{
948 		if (use_session)
949 			project_load_file_with_session(pfile);
950 		else
951 			project_load_file(pfile);
952 	}
953 	g_free(pfile);
954 }
955 
956 
load_startup_files(gint argc,gchar ** argv)957 static void load_startup_files(gint argc, gchar **argv)
958 {
959 	gboolean load_session = FALSE;
960 
961 	if (argc > 1 && g_str_has_suffix(argv[1], ".geany"))
962 	{
963 		gchar *filename = main_get_argv_filename(argv[1]);
964 
965 		/* project file specified: load it, but decide the session later */
966 		main_load_project_from_command_line(filename, FALSE);
967 		argc--, argv++;
968 		/* force session load if using project-based session files */
969 		load_session = project_prefs.project_session;
970 		g_free(filename);
971 	}
972 
973 	/* Load the default session if:
974 	 * 1. "Load files from the last session" is active.
975 	 * 2. --no-session is not specified.
976 	 * 3. We are a primary instance.
977 	 * Has no effect if a CL project is loaded and using project-based session files. */
978 	if (prefs.load_session && cl_options.load_session && !cl_options.new_instance)
979 	{
980 		if (app->project == NULL)
981 			load_session_project_file();
982 		load_session = TRUE;
983 	}
984 
985 	if (load_session)
986 	{
987 		/* load session files into tabs, as they are found in the session_files variable */
988 		configuration_open_files();
989 
990 		if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook)) == 0)
991 		{
992 			ui_update_popup_copy_items(NULL);
993 			ui_update_popup_reundo_items(NULL);
994 		}
995 	}
996 
997 	open_cl_files(argc, argv);
998 }
999 
1000 
send_startup_complete(gpointer data)1001 static gboolean send_startup_complete(gpointer data)
1002 {
1003 	g_signal_emit_by_name(geany_object, "geany-startup-complete");
1004 	return FALSE;
1005 }
1006 
1007 
get_locale(void)1008 static const gchar *get_locale(void)
1009 {
1010 	const gchar *locale = "unknown";
1011 #ifdef HAVE_LOCALE_H
1012 	locale = setlocale(LC_CTYPE, NULL);
1013 #endif
1014 	return locale;
1015 }
1016 
1017 
1018 #if ! GTK_CHECK_VERSION(3, 0, 0)
1019 /* This prepends our own gtkrc file to the list of RC files to be loaded by GTK at startup.
1020  * This function *has* to be called before gtk_init().
1021  *
1022  * We have a custom RC file defining various styles we need, and we want the user to be
1023  * able to override them (e.g. if they want -- or need -- other colors).  Fair enough, one
1024  * would simply call gtk_rc_parse() with the appropriate filename.  However, the styling
1025  * rules applies in the order they are loaded, then if we load our styles after GTK has
1026  * loaded the user's ones we'd override them.
1027  *
1028  * There are 2 solutions to fix this:
1029  * 1) set our styles' priority to something with lower than "user" (actually "theme"
1030  *    priority because rules precedence are first calculated depending on the priority
1031  *    no matter of how precise the rules is, so we need to override the theme).
1032  * 2) prepend our custom style to GTK's list while keeping priority to user (which is the
1033  *    default), so it gets loaded before real user's ones and so gets overridden by them.
1034  *
1035  * One would normally go for 1 because it's ways simpler and requires less code: you just
1036  * have to add the priorities to your styles, which is a matter of adding a few ":theme" in
1037  * the RC file.  However, KDE being a bitch it doesn't set the gtk-theme-name but rather
1038  * directly includes the style to use in a user gtkrc file, which makes the theme have
1039  * "user" priority, hence overriding our styles.  So, we cannot set priorities in the RC
1040  * file if we want to support running under KDE, which pretty much leave us with no choice
1041  * but to go with solution 2, which unfortunately requires writing ugly code since GTK
1042  * don't have a gtk_rc_prepend_default_file() function.  Thank you very much KDE.
1043  *
1044  * Though, as a side benefit it also makes the code work with people using gtk-chtheme,
1045  * which also found it funny to include the theme in the user RC file. */
setup_gtk2_styles(void)1046 static void setup_gtk2_styles(void)
1047 {
1048 	gchar **gtk_files = gtk_rc_get_default_files();
1049 	gchar **new_files = g_malloc(sizeof *new_files * (g_strv_length(gtk_files) + 2));
1050 	guint i = 0;
1051 
1052 	new_files[i++] = g_build_filename(app->datadir, "geany.gtkrc", NULL);
1053 	for (; *gtk_files; gtk_files++)
1054 		new_files[i++] = g_strdup(*gtk_files);
1055 	new_files[i] = NULL;
1056 
1057 	gtk_rc_set_default_files(new_files);
1058 
1059 	g_strfreev(new_files);
1060 }
1061 #endif
1062 
1063 
1064 GEANY_EXPORT_SYMBOL
main_lib(gint argc,gchar ** argv)1065 gint main_lib(gint argc, gchar **argv)
1066 {
1067 	GeanyDocument *doc;
1068 	gint config_dir_result;
1069 	const gchar *locale;
1070 	gchar *utf8_configdir;
1071 	gchar *os_info;
1072 
1073 #if ! GLIB_CHECK_VERSION(2, 36, 0)
1074 	g_type_init();
1075 #endif
1076 
1077 	log_handlers_init();
1078 
1079 	app = g_new0(GeanyApp, 1);
1080 	memset(&main_status, 0, sizeof(GeanyStatus));
1081 	memset(&prefs, 0, sizeof(GeanyPrefs));
1082 	memset(&interface_prefs, 0, sizeof(GeanyInterfacePrefs));
1083 	memset(&toolbar_prefs, 0, sizeof(GeanyToolbarPrefs));
1084 	memset(&file_prefs, 0, sizeof(GeanyFilePrefs));
1085 	memset(&search_prefs, 0, sizeof(GeanySearchPrefs));
1086 	memset(&tool_prefs, 0, sizeof(GeanyToolPrefs));
1087 	memset(&template_prefs, 0, sizeof(GeanyTemplatePrefs));
1088 	memset(&ui_prefs, 0, sizeof(UIPrefs));
1089 	memset(&ui_widgets, 0, sizeof(UIWidgets));
1090 
1091 	setup_paths();
1092 #if ! GTK_CHECK_VERSION(3, 0, 0)
1093 	setup_gtk2_styles();
1094 #endif
1095 #ifdef ENABLE_NLS
1096 	main_locale_init(utils_resource_dir(RESOURCE_DIR_LOCALE), GETTEXT_PACKAGE);
1097 #endif
1098 	/* initialize TM before parsing command-line - needed for tag file generation */
1099 	app->tm_workspace = tm_get_workspace();
1100 	parse_command_line_options(&argc, &argv);
1101 
1102 #if ! GLIB_CHECK_VERSION(2, 32, 0)
1103 	/* Initialize GLib's thread system in case any plugins want to use it or their
1104 	 * dependencies (e.g. WebKit, Soup, ...). Deprecated since GLIB 2.32. */
1105 	if (!g_thread_supported())
1106 		g_thread_init(NULL);
1107 #endif
1108 
1109 #ifdef G_OS_UNIX
1110 	g_unix_signal_add(SIGTERM, signal_cb, GINT_TO_POINTER(SIGTERM));
1111 
1112 	/* ignore SIGPIPE signal for preventing sudden death of program */
1113 	signal(SIGPIPE, SIG_IGN);
1114 #endif
1115 
1116 	config_dir_result = setup_config_dir();
1117 #ifdef HAVE_SOCKET
1118 	/* check and create (unix domain) socket for remote operation */
1119 	if (! socket_info.ignore_socket)
1120 	{
1121 		gushort socket_port = 0;
1122 #ifdef G_OS_WIN32
1123 		socket_port = (gushort) get_windows_socket_port();
1124 #endif
1125 		socket_info.lock_socket = -1;
1126 		socket_info.lock_socket_tag = 0;
1127 		socket_info.lock_socket = socket_init(argc, argv, socket_port);
1128 		/* Quit if filenames were sent to first instance or the list of open
1129 		 * documents has been printed */
1130 		if ((socket_info.lock_socket == -2 /* socket exists */ && argc > 1) ||
1131 			cl_options.list_documents)
1132 		{
1133 			socket_finalize();
1134 			gdk_notify_startup_complete();
1135 			g_free(app->configdir);
1136 			g_free(app->datadir);
1137 			g_free(app->docdir);
1138 			g_free(app);
1139 			return 0;
1140 		}
1141 		/* Start a new instance if no command line strings were passed,
1142 		 * even if the socket already exists */
1143 		else if (socket_info.lock_socket == -2 /* socket already exists */)
1144 		{
1145 			socket_info.ignore_socket = TRUE;
1146 			cl_options.new_instance = TRUE;
1147 		}
1148 	}
1149 #endif
1150 
1151 #ifdef G_OS_WIN32
1152 	/* after we initialized the socket code and handled command line args,
1153 	 * let's change the working directory on Windows to not lock it */
1154 	change_working_directory_on_windows();
1155 #endif
1156 
1157 	locale = get_locale();
1158 	geany_debug("Geany %s, %s",
1159 		main_get_version_string(),
1160 		locale);
1161 	geany_debug(geany_lib_versions,
1162 		gtk_major_version, gtk_minor_version, gtk_micro_version,
1163 		glib_major_version, glib_minor_version, glib_micro_version);
1164 
1165 	os_info = utils_get_os_info_string();
1166 	if (os_info != NULL)
1167 	{
1168 		geany_debug("OS: %s", os_info);
1169 		g_free(os_info);
1170 	}
1171 
1172 	geany_debug("System data dir: %s", app->datadir);
1173 	utf8_configdir = utils_get_utf8_from_locale(app->configdir);
1174 	geany_debug("User config dir: %s", utf8_configdir);
1175 	g_free(utf8_configdir);
1176 
1177 	/* create the object so Geany signals can be connected in init() functions */
1178 	geany_object = geany_object_new();
1179 
1180 	/* inits */
1181 	main_init();
1182 
1183 	encodings_init();
1184 	editor_init();
1185 
1186 	/* init stash groups before loading keyfile */
1187 	configuration_init();
1188 	ui_init_prefs();
1189 	search_init();
1190 	project_init();
1191 #ifdef HAVE_PLUGINS
1192 	plugins_init();
1193 #endif
1194 	sidebar_init();
1195 	load_settings();	/* load keyfile */
1196 
1197 	msgwin_init();
1198 	build_init();
1199 	ui_create_insert_menu_items();
1200 	ui_create_insert_date_menu_items();
1201 	keybindings_init();
1202 	notebook_init();
1203 	filetypes_init();
1204 	templates_init();
1205 	navqueue_init();
1206 	document_init_doclist();
1207 	symbols_init();
1208 	editor_snippets_init();
1209 
1210 #ifdef HAVE_VTE
1211 	vte_init();
1212 #endif
1213 	ui_create_recent_menus();
1214 
1215 	ui_set_statusbar(TRUE, _("This is Geany %s."), main_get_version_string());
1216 	if (config_dir_result != 0)
1217 	{
1218 		const gchar *message = _("Configuration directory could not be created (%s).");
1219 		ui_set_statusbar(TRUE, message, g_strerror(config_dir_result));
1220 		g_warning(message, g_strerror(config_dir_result));
1221 	}
1222 #ifdef HAVE_SOCKET
1223 	if (socket_info.lock_socket == -1)
1224 	{
1225 		const gchar *message =
1226 			_("IPC socket could not be created, see Help->Debug Messages for details.");
1227 		ui_set_statusbar(TRUE, "%s", message);
1228 		g_warning("%s", message);
1229 	}
1230 #endif
1231 
1232 	/* apply all configuration options */
1233 	apply_settings();
1234 
1235 #ifdef HAVE_PLUGINS
1236 	/* load any enabled plugins before we open any documents */
1237 	if (want_plugins)
1238 		plugins_load_active();
1239 #endif
1240 
1241 	ui_sidebar_show_hide();
1242 
1243 	/* set the active sidebar page after plugins have been loaded */
1244 	gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.sidebar_notebook), ui_prefs.sidebar_page);
1245 
1246 	/* load keybinding settings after plugins have added their groups */
1247 	keybindings_load_keyfile();
1248 
1249 	/* create the custom command menu after the keybindings have been loaded to have the proper
1250 	 * accelerator shown for the menu items */
1251 	tools_create_insert_custom_command_menu_items();
1252 
1253 	/* load any command line files or session files */
1254 	main_status.opening_session_files = TRUE;
1255 	load_startup_files(argc, argv);
1256 	main_status.opening_session_files = FALSE;
1257 
1258 	/* open a new file if no other file was opened */
1259 	document_new_file_if_non_open();
1260 
1261 	ui_document_buttons_update();
1262 	ui_save_buttons_toggle(FALSE);
1263 
1264 	doc = document_get_current();
1265 	sidebar_select_openfiles_item(doc);
1266 	build_menu_update(doc);
1267 	sidebar_update_tag_list(doc, FALSE);
1268 
1269 #ifdef G_OS_WIN32
1270 	/* Manually realise the main window to be able to set the position but don't show it.
1271 	 * We don't set the position after showing the window to avoid flickering. */
1272 	gtk_widget_realize(main_widgets.window);
1273 #endif
1274 	setup_window_position();
1275 
1276 	/* finally show the window */
1277 	document_grab_focus(doc);
1278 	gtk_widget_show(main_widgets.window);
1279 	main_status.main_window_realized = TRUE;
1280 
1281 	configuration_apply_settings();
1282 
1283 #ifdef HAVE_SOCKET
1284 	/* register the callback of socket input */
1285 	if (! socket_info.ignore_socket && socket_info.lock_socket > 0)
1286 	{
1287 		socket_info.read_ioc = g_io_channel_unix_new(socket_info.lock_socket);
1288 		socket_info.lock_socket_tag = g_io_add_watch(socket_info.read_ioc,
1289 						G_IO_IN | G_IO_PRI | G_IO_ERR, socket_lock_input_cb, main_widgets.window);
1290 	}
1291 #endif
1292 
1293 	/* when we are really done with setting everything up and the main event loop is running,
1294 	 * tell other components, mainly plugins, that startup is complete */
1295 	g_idle_add_full(G_PRIORITY_LOW, send_startup_complete, NULL, NULL);
1296 
1297 #ifdef MAC_INTEGRATION
1298 	/* OS X application ready - has to be called before entering main loop */
1299 	gtkosx_application_ready(gtkosx_application_get());
1300 #endif
1301 
1302 	gtk_main();
1303 	return 0;
1304 }
1305 
1306 
queue_free(GQueue * queue)1307 static void queue_free(GQueue *queue)
1308 {
1309 	while (! g_queue_is_empty(queue))
1310 	{
1311 		g_free(g_queue_pop_tail(queue));
1312 	}
1313 	g_queue_free(queue);
1314 }
1315 
1316 
do_main_quit(void)1317 static gboolean do_main_quit(void)
1318 {
1319 	configuration_save();
1320 
1321 	if (app->project != NULL)
1322 	{
1323 		if (!project_close(FALSE))   /* save project session files */
1324 			return FALSE;
1325 	}
1326 
1327 	if (!document_close_all())
1328 		return FALSE;
1329 
1330 	geany_debug("Quitting...");
1331 
1332 	main_status.quitting = TRUE;
1333 
1334 #ifdef HAVE_SOCKET
1335 	socket_finalize();
1336 #endif
1337 
1338 #ifdef HAVE_PLUGINS
1339 	plugins_finalize();
1340 #endif
1341 
1342 	navqueue_free();
1343 	keybindings_free();
1344 	notebook_free();
1345 	highlighting_free_styles();
1346 	templates_free_templates();
1347 	msgwin_finalize();
1348 	search_finalize();
1349 	build_finalize();
1350 	document_finalize();
1351 	symbols_finalize();
1352 	project_finalize();
1353 	editor_finalize();
1354 	editor_snippets_free();
1355 	encodings_finalize();
1356 	toolbar_finalize();
1357 	sidebar_finalize();
1358 	configuration_finalize();
1359 	filetypes_free_types();
1360 	log_finalize();
1361 
1362 	tm_workspace_free();
1363 	g_free(app->configdir);
1364 	g_free(app->datadir);
1365 	g_free(app->docdir);
1366 	g_free(prefs.default_open_path);
1367 	g_free(prefs.custom_plugin_path);
1368 	g_free(ui_prefs.custom_date_format);
1369 	g_free(ui_prefs.color_picker_palette);
1370 	g_free(interface_prefs.editor_font);
1371 	g_free(interface_prefs.tagbar_font);
1372 	g_free(interface_prefs.msgwin_font);
1373 	g_free(editor_prefs.long_line_color);
1374 	g_free(editor_prefs.comment_toggle_mark);
1375 	g_free(editor_prefs.color_scheme);
1376 	g_free(tool_prefs.context_action_cmd);
1377 	g_free(template_prefs.developer);
1378 	g_free(template_prefs.company);
1379 	g_free(template_prefs.mail);
1380 	g_free(template_prefs.initials);
1381 	g_free(template_prefs.version);
1382 	g_free(tool_prefs.term_cmd);
1383 	g_free(tool_prefs.browser_cmd);
1384 	g_free(tool_prefs.grep_cmd);
1385 	g_free(printing_prefs.external_print_cmd);
1386 	g_free(printing_prefs.page_header_datefmt);
1387 	g_strfreev(ui_prefs.custom_commands);
1388 	g_strfreev(ui_prefs.custom_commands_labels);
1389 
1390 	queue_free(ui_prefs.recent_queue);
1391 	queue_free(ui_prefs.recent_projects_queue);
1392 
1393 	if (ui_widgets.prefs_dialog && GTK_IS_WIDGET(ui_widgets.prefs_dialog)) gtk_widget_destroy(ui_widgets.prefs_dialog);
1394 	if (ui_widgets.open_fontsel && GTK_IS_WIDGET(ui_widgets.open_fontsel)) gtk_widget_destroy(ui_widgets.open_fontsel);
1395 	if (ui_widgets.open_colorsel && GTK_IS_WIDGET(ui_widgets.open_colorsel)) gtk_widget_destroy(ui_widgets.open_colorsel);
1396 #ifdef HAVE_VTE
1397 	if (vte_info.have_vte) vte_close();
1398 	g_free(vte_info.lib_vte);
1399 	g_free(vte_info.dir);
1400 #endif
1401 	gtk_widget_destroy(main_widgets.window);
1402 
1403 	/* destroy popup menus */
1404 	if (main_widgets.editor_menu && GTK_IS_WIDGET(main_widgets.editor_menu))
1405 					gtk_widget_destroy(main_widgets.editor_menu);
1406 	if (ui_widgets.toolbar_menu && GTK_IS_WIDGET(ui_widgets.toolbar_menu))
1407 					gtk_widget_destroy(ui_widgets.toolbar_menu);
1408 	if (msgwindow.popup_status_menu && GTK_IS_WIDGET(msgwindow.popup_status_menu))
1409 					gtk_widget_destroy(msgwindow.popup_status_menu);
1410 	if (msgwindow.popup_msg_menu && GTK_IS_WIDGET(msgwindow.popup_msg_menu))
1411 					gtk_widget_destroy(msgwindow.popup_msg_menu);
1412 	if (msgwindow.popup_compiler_menu && GTK_IS_WIDGET(msgwindow.popup_compiler_menu))
1413 					gtk_widget_destroy(msgwindow.popup_compiler_menu);
1414 
1415 	g_object_unref(geany_object);
1416 	geany_object = NULL;
1417 
1418 	g_free(original_cwd);
1419 	g_free(app);
1420 
1421 	ui_finalize_builder();
1422 
1423 	gtk_main_quit();
1424 
1425 	return TRUE;
1426 }
1427 
1428 
check_no_unsaved(void)1429 static gboolean check_no_unsaved(void)
1430 {
1431 	guint i;
1432 
1433 	for (i = 0; i < documents_array->len; i++)
1434 	{
1435 		if (documents[i]->is_valid && documents[i]->changed)
1436 		{
1437 			return FALSE;
1438 		}
1439 	}
1440 	return TRUE;    /* no unsaved edits */
1441 }
1442 
1443 
1444 /* Returns false when quitting is aborted due to user cancellation */
main_quit(void)1445 gboolean main_quit(void)
1446 {
1447 	main_status.quitting = TRUE;
1448 
1449 	if (! check_no_unsaved())
1450 	{
1451 		if (do_main_quit())
1452 			return TRUE;
1453 	}
1454 	else
1455 	if (! prefs.confirm_exit ||
1456 		dialogs_show_question_full(NULL, GTK_STOCK_QUIT, GTK_STOCK_CANCEL, NULL,
1457 			_("Do you really want to quit?")))
1458 	{
1459 		if (do_main_quit())
1460 			return TRUE;
1461 	}
1462 
1463 	main_status.quitting = FALSE;
1464 	return FALSE;
1465 }
1466 
1467 /**
1468  *  Reloads most of Geany's configuration files without restarting. Currently the following
1469  *  files are reloaded: all template files, also new file templates and the 'New (with template)'
1470  *  menus will be updated, Snippets (snippets.conf), filetype extensions (filetype_extensions.conf),
1471  *  and 'settings' and 'build_settings' sections of the filetype definition files.
1472  *
1473  *  Plugins may call this function if they changed any of these files (e.g. a configuration file
1474  *  editor plugin).
1475  *
1476  *  @since 0.15
1477  **/
1478 GEANY_API_SYMBOL
main_reload_configuration(void)1479 void main_reload_configuration(void)
1480 {
1481 	/* reload templates */
1482 	templates_free_templates();
1483 	templates_init();
1484 
1485 	/* reload snippets */
1486 	editor_snippets_free();
1487 	editor_snippets_init();
1488 
1489 	filetypes_reload_extensions();
1490 	filetypes_reload();
1491 
1492 	/* C tag names to ignore */
1493 	symbols_reload_config_files();
1494 
1495 	ui_set_statusbar(TRUE, _("Configuration files reloaded."));
1496 }
1497