[geany/geany] d33758: Move Geany's core into a library (libgeany)

Matthew Brush git-noreply at xxxxx
Fri Apr 10 15:07:01 UTC 2015


Branch:      refs/heads/master
Author:      Matthew Brush <matt at geany.org>
Committer:   Thomas Martitz <kugel at rockbox.org>
Date:        Tue, 10 Mar 2015 22:09:46 UTC
Commit:      d33758da926ca124db674240c431b8b07bb0e683
             https://github.com/geany/geany/commit/d33758da926ca124db674240c431b8b07bb0e683

Log Message:
-----------
Move Geany's core into a library (libgeany)

This will allow plugins to link against the core when accessing API
functions, now that the macro/struct/funcptr stuff is gone.

Also convert the helper libraries into Libtool helper libraries as
linking a shared library against static libraries is (apparently) not
portable.


Modified Paths:
--------------
    configure.ac
    geany.pc.in
    plugins/Makefile.am
    po/POTFILES.in
    scintilla/Makefile.am
    src/Makefile.am
    src/libmain.c
    src/main.c
    src/main.h
    tagmanager/ctags/Makefile.am
    tagmanager/mio/Makefile.am
    tagmanager/src/Makefile.am

Modified: configure.ac
3 lines changed, 0 insertions(+), 3 deletions(-)
===================================================================
@@ -122,9 +122,6 @@ AC_SUBST([pkgdatadir])
 GEANY_CHECK_DOCUTILS
 GEANY_CHECK_DOXYGEN
 
-#FIXME: replace this with a real check that the compiler supports the argument
-CFLAGS="${CFLAGS} -fvisibility=hidden"
-
 # Output
 AC_CONFIG_FILES([
 		Makefile


Modified: geany.pc.in
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -10,5 +10,5 @@ Name: Geany
 Description: A fast and lightweight IDE using GTK2
 Requires: @DEPENDENCIES@
 Version: @VERSION@
-Libs: -L${libdir}
+Libs: -L${libdir} -lgeany
 Cflags: -DGTK -I${includedir}/geany -I${includedir}/geany/tagmanager -I${includedir}/geany/scintilla


Modified: plugins/Makefile.am
15 lines changed, 7 insertions(+), 8 deletions(-)
===================================================================
@@ -19,7 +19,6 @@ filebrowser_la_LDFLAGS   = -module -avoid-version -no-undefined
 splitwindow_la_LDFLAGS   = -module -avoid-version -no-undefined
 
 if PLUGINS
-
 # Plugins to be installed
 plugin_LTLIBRARIES = \
 	classbuilder.la \
@@ -49,13 +48,13 @@ saveactions_la_CFLAGS   = -DG_LOG_DOMAIN=\""SaveActions"\"
 filebrowser_la_CFLAGS   = -DG_LOG_DOMAIN=\""FileBrowser"\"
 splitwindow_la_CFLAGS   = -DG_LOG_DOMAIN=\""SplitWindow"\"
 
-demoplugin_la_LIBADD    = $(GTK_LIBS)
-classbuilder_la_LIBADD  = $(GTK_LIBS)
-htmlchars_la_LIBADD     = $(GTK_LIBS)
-export_la_LIBADD        = $(GTK_LIBS) -lm
-saveactions_la_LIBADD   = $(GTK_LIBS)
-filebrowser_la_LIBADD   = $(GTK_LIBS)
-splitwindow_la_LIBADD   = $(GTK_LIBS)
+demoplugin_la_LIBADD    = $(top_builddir)/src/libgeany.la $(GTK_LIBS)
+classbuilder_la_LIBADD  = $(top_builddir)/src/libgeany.la $(GTK_LIBS)
+htmlchars_la_LIBADD     = $(top_builddir)/src/libgeany.la $(GTK_LIBS)
+export_la_LIBADD        = $(top_builddir)/src/libgeany.la $(GTK_LIBS) -lm
+saveactions_la_LIBADD   = $(top_builddir)/src/libgeany.la $(GTK_LIBS)
+filebrowser_la_LIBADD   = $(top_builddir)/src/libgeany.la $(GTK_LIBS)
+splitwindow_la_LIBADD   = $(top_builddir)/src/libgeany.la $(GTK_LIBS)
 
 endif # PLUGINS
 


Modified: po/POTFILES.in
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -16,8 +16,8 @@ src/geanyentryaction.c
 src/highlighting.c
 src/keybindings.c
 src/keyfile.c
+src/libmain.c
 src/log.c
-src/main.c
 src/msgwindow.c
 src/navqueue.c
 src/notebook.c


Modified: scintilla/Makefile.am
7 lines changed, 4 insertions(+), 3 deletions(-)
===================================================================
@@ -1,7 +1,7 @@
 
 SUBDIRS = include
 
-noinst_LIBRARIES=libscintilla.a
+noinst_LTLIBRARIES=libscintilla.la
 
 AM_CXXFLAGS = -DNDEBUG -DGTK -DSCI_LEXER -DG_THREADS_IMPL_NONE
 
@@ -139,9 +139,10 @@ src/XPM.cxx \
 src/XPM.h \
 $(LEXER_SRCS)
 
-libscintilla_a_SOURCES = $(SRCS)
+libscintilla_la_SOURCES = $(SRCS)
 
-AM_CPPFLAGS = -I$(top_srcdir) -I$(srcdir)/include -I$(srcdir)/src -I$(srcdir)/lexlib @GTK_CFLAGS@
+AM_CPPFLAGS = -I$(top_srcdir) -I$(srcdir)/include -I$(srcdir)/src -I$(srcdir)/lexlib @GTK_CFLAGS@ \
+	-fvisibility=hidden
 
 marshallers: gtk/scintilla-marshal.list
 	glib-genmarshal --prefix scintilla_marshal gtk/scintilla-marshal.list --header > gtk/scintilla-marshal.h


Modified: src/Makefile.am
45 lines changed, 26 insertions(+), 19 deletions(-)
===================================================================
@@ -14,6 +14,10 @@ EXTRA_DIST = \
 	$(top_srcdir)/src/dynamicsymbols.list
 
 bin_PROGRAMS = geany
+lib_LTLIBRARIES = libgeany.la
+
+geany_SOURCES = main.c
+geany_LDADD = libgeany.la $(GTK_LIBS) $(GTHREAD_LIBS) $(INTLLIBS)
 
 SRCS = \
 	about.c about.h \
@@ -35,7 +39,7 @@ SRCS = \
 	keybindings.c keybindings.h \
 	keyfile.c keyfile.h \
 	log.c log.h \
-	main.c main.h geany.h \
+	libmain.c main.h geany.h \
 	msgwindow.c msgwindow.h \
 	navqueue.c navqueue.h \
 	notebook.c notebook.h \
@@ -107,18 +111,19 @@ nodist_EXTRA_geany_SOURCES = dummy.cxx
 if MINGW
 # build Geany for Windows on non-Windows systems (cross-compile)
 
-geany_SOURCES = $(SRCS) win32.c win32.h
+libgeany_la_SOURCES = $(SRCS) win32.c win32.h
 
-geany_LDADD = \
-	$(top_builddir)/scintilla/libscintilla.a \
-	$(top_builddir)/tagmanager/ctags/libctags.a \
-	$(top_builddir)/tagmanager/mio/libmio.a \
-	$(top_builddir)/tagmanager/src/libtagmanager.a \
+libgeany_la_LIBADD = \
+	$(top_builddir)/scintilla/libscintilla.la \
+	$(top_builddir)/tagmanager/ctags/libctags.la \
+	$(top_builddir)/tagmanager/mio/libmio.la \
+	$(top_builddir)/tagmanager/src/libtagmanager.la \
 	@GTK_LIBS@ \
 	@GTHREAD_LIBS@ \
 	$(INTLLIBS) \
-	-lole32 -luuid -lwsock32 \
-	geany_private.res
+	-lole32 -luuid -lwsock32 -lcomdlg32
+
+geany_LDADD += geany_private.res  -lcomdlg32
 
 AM_CFLAGS = -DGEANY_DATADIR=\"data\" \
 			-DGEANY_DOCDIR=\"\" \
@@ -127,9 +132,10 @@ AM_CFLAGS = -DGEANY_DATADIR=\"data\" \
 			-DGEANY_PREFIX=\"\" \
 			-DGEANY_PRIVATE \
 			-DGTK \
-			-DG_LOG_DOMAIN=\""Geany"\"
+			-DG_LOG_DOMAIN=\""Geany"\" \
+			-fvisibility=hidden
 
-geany_LDFLAGS =	-mwindows -mms-bitfields
+libgeany_la_LDFLAGS =	-mwindows -mms-bitfields -no-undefined
 
 WINDRES = $(host_alias)-windres
 
@@ -142,19 +148,19 @@ clean-local:
 else
 # build Geany for all other platforms
 
-geany_SOURCES = $(SRCS) vte.c vte.h
+libgeany_la_SOURCES = $(SRCS) vte.c vte.h
 
-geany_LDADD = \
-	$(top_builddir)/scintilla/libscintilla.a \
-	$(top_builddir)/tagmanager/ctags/libctags.a \
-	$(top_builddir)/tagmanager/mio/libmio.a \
-	$(top_builddir)/tagmanager/src/libtagmanager.a \
+libgeany_la_LIBADD = \
+	$(top_builddir)/scintilla/libscintilla.la \
+	$(top_builddir)/tagmanager/ctags/libctags.la \
+	$(top_builddir)/tagmanager/mio/libmio.la \
+	$(top_builddir)/tagmanager/src/libtagmanager.la \
 	@GTK_LIBS@ \
 	@GTHREAD_LIBS@ \
 	$(MAC_INTEGRATION_LIBS) \
 	$(INTLLIBS)
 
-geany_LDFLAGS = -Wl,--dynamic-list="$(srcdir)/dynamicsymbols.list"
+libgeany_la_LDFLAGS = -Wl,--dynamic-list="$(srcdir)/dynamicsymbols.list"
 
 AM_CFLAGS = -DGEANY_DATADIR=\""$(datadir)"\" \
 			-DGEANY_DOCDIR=\""$(docdir)"\" \
@@ -163,7 +169,8 @@ AM_CFLAGS = -DGEANY_DATADIR=\""$(datadir)"\" \
 			-DGEANY_PREFIX=\""$(prefix)"\" \
 			-DGEANY_PRIVATE \
 			-DGTK \
-			-DG_LOG_DOMAIN=\""Geany"\"
+			-DG_LOG_DOMAIN=\""Geany"\" \
+			-fvisibility=hidden
 
 clean-local:
 


Modified: src/libmain.c
1406 lines changed, 1406 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,1406 @@
+/*
+ *      libmain.c - this file is part of Geany, a fast and lightweight IDE
+ *
+ *      Copyright 2005-2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
+ *      Copyright 2006-2012 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+ *
+ *      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.,
+ *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/**
+ * @file: main.h
+ * Main program-related commands.
+ * Handles program initialization and cleanup.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "main.h"
+
+#include "app.h"
+#include "build.h"
+#include "callbacks.h"
+#include "dialogs.h"
+#include "document.h"
+#include "encodings.h"
+#include "filetypes.h"
+#include "geanyobject.h"
+#include "highlighting.h"
+#include "keybindings.h"
+#include "keyfile.h"
+#include "log.h"
+#include "msgwindow.h"
+#include "navqueue.h"
+#include "notebook.h"
+#include "pluginexport.h"
+#include "plugins.h"
+#include "prefs.h"
+#include "printing.h"
+#include "sidebar.h"
+#ifdef HAVE_SOCKET
+# include "socket.h"
+#endif
+#include "support.h"
+#include "symbols.h"
+#include "templates.h"
+#include "toolbar.h"
+#include "tools.h"
+#include "ui_utils.h"
+#include "utils.h"
+#include "vte.h"
+#include "win32.h"
+#include "osx.h"
+
+#include "gtkcompat.h"
+
+#include <signal.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib/gstdio.h>
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+
+GeanyApp	*app;
+gboolean	ignore_callback;	/* hack workaround for GTK+ toggle button callback problem */
+
+GeanyStatus	 main_status;
+CommandLineOptions cl_options;	/* fields initialised in parse_command_line_options */
+
+static gchar *original_cwd = NULL;
+
+static const gchar geany_lib_versions[] = "GTK %u.%u.%u, GLib %u.%u.%u";
+
+static gboolean want_plugins;
+
+/* command-line options */
+static gboolean verbose_mode = FALSE;
+static gboolean ignore_global_tags = FALSE;
+static gboolean no_msgwin = FALSE;
+static gboolean show_version = FALSE;
+static gchar *alternate_config = NULL;
+#ifdef HAVE_VTE
+static gboolean no_vte = FALSE;
+static gchar *lib_vte = NULL;
+#endif
+static gboolean generate_tags = FALSE;
+static gboolean no_preprocessing = FALSE;
+static gboolean ft_names = FALSE;
+static gboolean print_prefix = FALSE;
+#ifdef HAVE_PLUGINS
+static gboolean no_plugins = FALSE;
+#endif
+static gboolean dummy = FALSE;
+
+/* in alphabetical order of short options */
+static GOptionEntry entries[] =
+{
+	{ "column", 0, 0, G_OPTION_ARG_INT, &cl_options.goto_column, N_("Set initial column number for the first opened file (useful in conjunction with --line)"), NULL },
+	{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &alternate_config, N_("Use an alternate configuration directory"), NULL },
+	{ "ft-names", 0, 0, G_OPTION_ARG_NONE, &ft_names, N_("Print internal filetype names"), NULL },
+	{ "generate-tags", 'g', 0, G_OPTION_ARG_NONE, &generate_tags, N_("Generate global tags file (see documentation)"), NULL },
+	{ "no-preprocessing", 'P', 0, G_OPTION_ARG_NONE, &no_preprocessing, N_("Don't preprocess C/C++ files when generating tags"), NULL },
+#ifdef HAVE_SOCKET
+	{ "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 },
+	{ "socket-file", 0, 0, G_OPTION_ARG_FILENAME, &cl_options.socket_filename, N_("Use this socket filename for communication with a running Geany instance"), NULL },
+	{ "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 },
+#endif
+	{ "line", 'l', 0, G_OPTION_ARG_INT, &cl_options.goto_line, N_("Set initial line number for the first opened file"), NULL },
+	{ "no-msgwin", 'm', 0, G_OPTION_ARG_NONE, &no_msgwin, N_("Don't show message window at startup"), NULL },
+	{ "no-ctags", 'n', 0, G_OPTION_ARG_NONE, &ignore_global_tags, N_("Don't load auto completion data (see documentation)"), NULL },
+#ifdef HAVE_PLUGINS
+	{ "no-plugins", 'p', 0, G_OPTION_ARG_NONE, &no_plugins, N_("Don't load plugins"), NULL },
+#endif
+	{ "print-prefix", 0, 0, G_OPTION_ARG_NONE, &print_prefix, N_("Print Geany's installation prefix"), NULL },
+	{ "read-only", 'r', 0, G_OPTION_ARG_NONE, &cl_options.readonly, N_("Open all FILES in read-only mode (see documention)"), NULL },
+	{ "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 },
+#ifdef HAVE_VTE
+	{ "no-terminal", 't', 0, G_OPTION_ARG_NONE, &no_vte, N_("Don't load terminal support"), NULL },
+	{ "vte-lib", 0, 0, G_OPTION_ARG_FILENAME, &lib_vte, N_("Filename of libvte.so"), NULL },
+#endif
+	{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose_mode, N_("Be verbose"), NULL },
+	{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Show version and exit"), NULL },
+	{ "dummy", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &dummy, NULL, NULL }, /* for +NNN line number arguments */
+	{ NULL, 0, 0, 0, NULL, NULL, NULL }
+};
+
+
+static void setup_window_position(void)
+{
+	/* interprets the saved window geometry */
+	if (!prefs.save_winpos)
+		return;
+
+	if (ui_prefs.geometry[0] != -1 && ui_prefs.geometry[1] != -1)
+		gtk_window_move(GTK_WINDOW(main_widgets.window),
+			ui_prefs.geometry[0], ui_prefs.geometry[1]);
+
+	if (ui_prefs.geometry[2] != -1 && ui_prefs.geometry[3] != -1)
+		gtk_window_set_default_size(GTK_WINDOW(main_widgets.window),
+			ui_prefs.geometry[2], ui_prefs.geometry[3]);
+
+	if (ui_prefs.geometry[4] == 1)
+		gtk_window_maximize(GTK_WINDOW(main_widgets.window));
+}
+
+
+/* special things for the initial setup of the checkboxes and related stuff
+ * an action on a setting is only performed if the setting is not equal to the program default
+ * (all the following code is not perfect but it works for the moment) */
+static void apply_settings(void)
+{
+	ui_update_fold_items();
+
+	/* toolbar, message window and sidebar are by default visible, so don't change it if it is true */
+	toolbar_show_hide();
+	if (! ui_prefs.msgwindow_visible)
+	{
+		ignore_callback = TRUE;
+		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_show_messages_window1")), FALSE);
+		gtk_widget_hide(main_widgets.message_window_notebook);
+		ignore_callback = FALSE;
+	}
+	if (! ui_prefs.sidebar_visible)
+	{
+		ignore_callback = TRUE;
+		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_show_sidebar1")), FALSE);
+		ignore_callback = FALSE;
+	}
+
+	toolbar_apply_settings();
+	toolbar_update_ui();
+
+	ui_update_view_editor_menu_items();
+
+	/* hide statusbar if desired */
+	if (! interface_prefs.statusbar_visible)
+	{
+		gtk_widget_hide(ui_widgets.statusbar);
+	}
+
+	/* set the tab placements of the notebooks */
+	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(main_widgets.notebook), interface_prefs.tab_pos_editor);
+	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(msgwindow.notebook), interface_prefs.tab_pos_msgwin);
+	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(main_widgets.sidebar_notebook), interface_prefs.tab_pos_sidebar);
+
+	/* whether to show notebook tabs or not */
+	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(main_widgets.notebook), interface_prefs.show_notebook_tabs);
+
+#ifdef HAVE_VTE
+	if (! vte_info.have_vte)
+#endif
+	{
+		gtk_widget_set_sensitive(
+			ui_lookup_widget(main_widgets.window, "send_selection_to_vte1"), FALSE);
+	}
+
+	if (interface_prefs.sidebar_pos != GTK_POS_LEFT)
+		ui_swap_sidebar_pos();
+
+	gtk_orientable_set_orientation(GTK_ORIENTABLE(ui_lookup_widget(main_widgets.window, "vpaned1")),
+		interface_prefs.msgwin_orientation);
+}
+
+
+static void main_init(void)
+{
+	/* add our icon path in case we aren't installed in the system prefix */
+	gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), utils_resource_dir(RESOURCE_DIR_ICON));
+
+	/* inits */
+	ui_init_stock_items();
+
+	ui_init_builder();
+
+	main_widgets.window				= NULL;
+	app->project			= NULL;
+	ui_widgets.open_fontsel		= NULL;
+	ui_widgets.open_colorsel	= NULL;
+	ui_widgets.prefs_dialog		= NULL;
+	main_status.main_window_realized = FALSE;
+	file_prefs.tab_order_ltr		= FALSE;
+	file_prefs.tab_order_beside		= FALSE;
+	main_status.quitting			= FALSE;
+	ignore_callback	= FALSE;
+	app->tm_workspace		= tm_get_workspace();
+	ui_prefs.recent_queue				= g_queue_new();
+	ui_prefs.recent_projects_queue		= g_queue_new();
+	main_status.opening_session_files	= FALSE;
+
+	main_widgets.window = create_window1();
+
+	/* add recent projects to the Project menu */
+	ui_widgets.recent_projects_menuitem = ui_lookup_widget(main_widgets.window, "recent_projects1");
+	ui_widgets.recent_projects_menu_menubar = gtk_menu_new();
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(ui_widgets.recent_projects_menuitem),
+							ui_widgets.recent_projects_menu_menubar);
+
+	/* store important pointers for later reference */
+	main_widgets.toolbar = toolbar_init();
+	main_widgets.sidebar_notebook = ui_lookup_widget(main_widgets.window, "notebook3");
+	main_widgets.notebook = ui_lookup_widget(main_widgets.window, "notebook1");
+	main_widgets.editor_menu = create_edit_menu1();
+	main_widgets.tools_menu = ui_lookup_widget(main_widgets.window, "tools1_menu");
+	main_widgets.message_window_notebook = ui_lookup_widget(main_widgets.window, "notebook_info");
+	main_widgets.project_menu = ui_lookup_widget(main_widgets.window, "menu_project1_menu");
+
+	ui_widgets.toolbar_menu = create_toolbar_popup_menu1();
+	ui_init();
+#ifdef MAC_INTEGRATION
+	osx_ui_init();
+#endif
+
+	/* set widget names for matching with .gtkrc-2.0 */
+	gtk_widget_set_name(main_widgets.window, "GeanyMainWindow");
+	gtk_widget_set_name(ui_widgets.toolbar_menu, "GeanyToolbarMenu");
+	gtk_widget_set_name(main_widgets.editor_menu, "GeanyEditMenu");
+	gtk_widget_set_name(ui_lookup_widget(main_widgets.window, "menubar1"), "GeanyMenubar");
+	gtk_widget_set_name(main_widgets.toolbar, "GeanyToolbar");
+
+	gtk_window_set_default_size(GTK_WINDOW(main_widgets.window),
+		GEANY_WINDOW_DEFAULT_WIDTH, GEANY_WINDOW_DEFAULT_HEIGHT);
+}
+
+
+const gchar *main_get_version_string(void)
+{
+	static gchar full[] = VERSION " (git >= " REVISION ")";
+
+	if (utils_str_equal(REVISION, "-1"))
+		return VERSION;
+	else
+		return full;
+}
+
+
+/* get the full file path of a command-line argument
+ * N.B. the result should be freed and may contain '/../' or '/./ ' */
+gchar *main_get_argv_filename(const gchar *filename)
+{
+	gchar *result;
+
+	if (g_path_is_absolute(filename) || utils_is_uri(filename))
+		result = g_strdup(filename);
+	else
+	{
+		/* use current dir */
+		gchar *cur_dir = NULL;
+		if (original_cwd == NULL)
+			cur_dir = g_get_current_dir();
+		else
+			cur_dir = g_strdup(original_cwd);
+
+		result = g_strjoin(
+			G_DIR_SEPARATOR_S, cur_dir, filename, NULL);
+		g_free(cur_dir);
+	}
+	return result;
+}
+
+
+/* get a :line:column specifier from the end of a filename (if present),
+ * return the line/column values, and remove the specifier from the string
+ * (Note that *line and *column must both be set to -1 initially) */
+static void get_line_and_column_from_filename(gchar *filename, gint *line, gint *column)
+{
+	gsize i;
+	gint colon_count = 0;
+	gboolean have_number = FALSE;
+	gsize len;
+
+	g_assert(*line == -1 && *column == -1);
+
+	if (G_UNLIKELY(EMPTY(filename)))
+		return;
+
+	/* allow to open files like "test:0" */
+	if (g_file_test(filename, G_FILE_TEST_EXISTS))
+		return;
+
+	len = strlen(filename);
+	for (i = len - 1; i >= 1; i--)
+	{
+		gboolean is_colon = filename[i] == ':';
+		gboolean is_digit = g_ascii_isdigit(filename[i]);
+
+		if (! is_colon && ! is_digit)
+			break;
+
+		if (is_colon)
+		{
+			if (++colon_count > 1)
+				break;	/* bail on 2+ colons in a row */
+		}
+		else
+			colon_count = 0;
+
+		if (is_digit)
+			have_number = TRUE;
+
+		if (is_colon && have_number)
+		{
+			gint number = atoi(&filename[i + 1]);
+
+			filename[i] = '\0';
+			have_number = FALSE;
+
+			*column = *line;
+			*line = number;
+		}
+
+		if (*column >= 0)
+			break;	/* line and column are set, so we're done */
+	}
+}
+
+
+#ifdef G_OS_WIN32
+static void change_working_directory_on_windows(void)
+{
+	gchar *install_dir = win32_get_installation_dir();
+
+	/* remember original working directory for use with opening files from the command line */
+	original_cwd = g_get_current_dir();
+
+	/* On Windows, change the working directory to the Geany installation path to not lock
+	 * the directory of a file passed as command line argument (see bug #2626124).
+	 * This also helps if plugins or other code uses relative paths to load
+	 * any additional resources (e.g. share/geany-plugins/...). */
+	win32_set_working_directory(install_dir);
+
+	g_free(install_dir);
+}
+#endif
+
+
+static void setup_paths(void)
+{
+	/* convert path names to locale encoding */
+	app->datadir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DATA));
+	app->docdir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DOC));
+}
+
+
+/**
+ *  Checks whether the main window has been realized.
+ *  This is an easy indicator whether Geany is right now starting up (main window is not
+ *  yet realized) or whether it has finished the startup process (main window is realized).
+ *  This is because the main window is realized (i.e. actually drawn on the screen) at the
+ *  end of the startup process.
+ *
+ *  @note Maybe you want to use the @link pluginsignals.c @c "geany-startup-complete" signal @endlink
+ *        to get notified about the completed startup process.
+ *
+ *  @return @c TRUE if the Geany main window has been realized or @c FALSE otherwise.
+ *
+ *  @since 0.19
+ **/
+GEANY_API_SYMBOL
+gboolean main_is_realized(void)
+{
+	return main_status.main_window_realized;
+}
+
+
+/**
+ *  Initialises the gettext translation system.
+ *  This is a convenience function to set up gettext for internationalisation support
+ *  in external plugins. You should call this function early in @ref plugin_init().
+ *  If the macro HAVE_LOCALE_H is defined, @c setlocale(LC_ALL, "") is called.
+ *  The codeset for the message translations is set to UTF-8.
+ *
+ *  Note that this function only setups the gettext textdomain for you. You still have
+ *  to adjust the build system of your plugin to get internationalisation support
+ *  working properly.
+ *
+ *  If you have already used @ref PLUGIN_SET_TRANSLATABLE_INFO() you
+ *  don't need to call main_locale_init() again as it has already been done.
+ *
+ *  @param locale_dir The location where the translation files should be searched. This is
+ *                    usually the @c LOCALEDIR macro, defined by the build system.
+ *                    E.g. @c $prefix/share/locale.
+ *                    Only used on non-Windows systems. On Windows, the directory is determined
+ *                    by @c g_win32_get_package_installation_directory().
+ *  @param package The package name, usually this is the @c GETTEXT_PACKAGE macro,
+ *                 defined by the build system.
+ *
+ *  @since 0.16
+ **/
+GEANY_API_SYMBOL
+void main_locale_init(const gchar *locale_dir, const gchar *package)
+{
+#ifdef HAVE_LOCALE_H
+	setlocale(LC_ALL, "");
+#endif
+
+#ifdef G_OS_WIN32
+	locale_dir = utils_resource_dir(RESOURCE_DIR_LOCALE);
+#endif
+	(void) bindtextdomain(package, locale_dir);
+	(void) bind_textdomain_codeset(package, "UTF-8");
+}
+
+
+static void print_filetypes(void)
+{
+	const GSList *list, *node;
+
+	filetypes_init_types();
+	printf("Geany's filetype names:\n");
+
+	list = filetypes_get_sorted_by_name();
+	foreach_slist(node, list)
+	{
+		GeanyFiletype *ft = node->data;
+
+		printf("%s\n", ft->name);
+	}
+	filetypes_free_types();
+}
+
+
+static void wait_for_input_on_windows(void)
+{
+#ifdef G_OS_WIN32
+	if (verbose_mode)
+	{
+		geany_debug("Press any key to continue");
+		getchar();
+	}
+#endif
+}
+
+
+static void parse_command_line_options(gint *argc, gchar ***argv)
+{
+	GError *error = NULL;
+	GOptionContext *context;
+	gint i;
+	CommandLineOptions def_clo = {FALSE, NULL, TRUE, -1, -1, FALSE, FALSE, FALSE};
+
+	/* first initialise cl_options fields with default values */
+	cl_options = def_clo;
+
+	/* the GLib option parser can't handle the +NNN (line number) option,
+	 * so we grab that here and replace it with a no-op */
+	for (i = 1; i < (*argc); i++)
+	{
+		if ((*argv)[i][0] != '+')
+			continue;
+
+		cl_options.goto_line = atoi((*argv)[i] + 1);
+		(*argv)[i] = (gchar *) "--dummy";
+	}
+
+	context = g_option_context_new(_("[FILES...]"));
+
+	g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE);
+	g_option_group_set_translation_domain(g_option_context_get_main_group(context), GETTEXT_PACKAGE);
+	g_option_context_add_group(context, gtk_get_option_group(FALSE));
+	g_option_context_parse(context, argc, argv, &error);
+	g_option_context_free(context);
+
+	if (error != NULL)
+	{
+		g_printerr("Geany: %s\n", error->message);
+		g_error_free(error);
+		exit(1);
+	}
+
+	app->debug_mode = verbose_mode;
+	if (app->debug_mode)
+	{
+		/* Since GLib 2.32 messages logged with levels INFO and DEBUG aren't output by the
+		 * default log handler unless the G_MESSAGES_DEBUG environment variable contains the
+		 * domain of the message or is set to the special value "all" */
+		g_setenv("G_MESSAGES_DEBUG", "all", FALSE);
+	}
+
+#ifdef G_OS_WIN32
+	win32_init_debug_code();
+#endif
+
+	if (show_version)
+	{
+		gchar *build_date = utils_parse_and_format_build_date(__DATE__);
+
+		printf(PACKAGE " %s (", main_get_version_string());
+		/* note for translators: library versions are printed after this */
+		printf(_("built on %s with "), build_date);
+		printf(geany_lib_versions,
+			GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION,
+			GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
+		printf(")\n");
+		g_free(build_date);
+		wait_for_input_on_windows();
+		exit(0);
+	}
+
+	if (print_prefix)
+	{
+		printf("%s\n", GEANY_PREFIX);
+		printf("%s\n", GEANY_DATADIR);
+		printf("%s\n", GEANY_LIBDIR);
+		printf("%s\n", GEANY_LOCALEDIR);
+		wait_for_input_on_windows();
+		exit(0);
+	}
+
+	if (alternate_config)
+	{
+		geany_debug("alternate config: %s", alternate_config);
+		app->configdir = alternate_config;
+	}
+	else
+	{
+		app->configdir = utils_get_user_config_dir();
+	}
+
+	if (generate_tags)
+	{
+		gboolean ret;
+
+		filetypes_init_types();
+		ret = symbols_generate_global_tags(*argc, *argv, ! no_preprocessing);
+		filetypes_free_types();
+		wait_for_input_on_windows();
+		exit(ret);
+	}
+
+	if (ft_names)
+	{
+		print_filetypes();
+		wait_for_input_on_windows();
+		exit(0);
+	}
+
+#ifdef HAVE_SOCKET
+	socket_info.ignore_socket = cl_options.new_instance;
+	if (cl_options.socket_filename)
+	{
+		socket_info.file_name = cl_options.socket_filename;
+	}
+#endif
+
+#ifdef HAVE_VTE
+	vte_info.lib_vte = lib_vte;
+#endif
+	cl_options.ignore_global_tags = ignore_global_tags;
+
+	if (! gtk_init_check(NULL, NULL))
+	{	/* check whether we have a valid X display and exit if not */
+		g_printerr("Geany: cannot open display\n");
+		exit(1);
+	}
+
+#ifdef MAC_INTEGRATION
+	/* Create GtkosxApplication singleton - should be created shortly after gtk_init() */
+	gtkosx_application_get();
+#endif
+}
+
+
+static gint create_config_dir(void)
+{
+	gint saved_errno = 0;
+	gchar *conf_file = NULL;
+	gchar *filedefs_dir = NULL;
+	gchar *templates_dir = NULL;
+
+	if (! g_file_test(app->configdir, G_FILE_TEST_EXISTS))
+	{
+#ifndef G_OS_WIN32
+		/* if we are *not* using an alternate config directory, we check whether the old one
+		 * in ~/.geany still exists and try to move it */
+		if (alternate_config == NULL)
+		{
+			gchar *old_dir = g_build_filename(g_get_home_dir(), ".geany", NULL);
+			/* move the old config dir if it exists */
+			if (g_file_test(old_dir, G_FILE_TEST_EXISTS))
+			{
+				if (! dialogs_show_question_full(main_widgets.window,
+					GTK_STOCK_YES, GTK_STOCK_QUIT, _("Move it now?"),
+					"%s",
+					_("Geany needs to move your old configuration directory before starting.")))
+					exit(0);
+
+				if (! g_file_test(app->configdir, G_FILE_TEST_IS_DIR))
+					utils_mkdir(app->configdir, TRUE);
+
+				if (g_rename(old_dir, app->configdir) == 0)
+				{
+					dialogs_show_msgbox(GTK_MESSAGE_INFO,
+						_("Your configuration directory has been successfully moved from \"%s\" to \"%s\"."),
+						old_dir, app->configdir);
+					g_free(old_dir);
+					return 0;
+				}
+				else
+				{
+					dialogs_show_msgbox(GTK_MESSAGE_WARNING,
+						/* for translators: the third %s in brackets is the error message which
+						 * describes why moving the dir didn't work */
+						_("Your old configuration directory \"%s\" could not be moved to \"%s\" (%s). "
+						  "Please move manually the directory to the new location."),
+						old_dir, app->configdir, g_strerror(errno));
+				}
+			}
+			g_free(old_dir);
+		}
+#endif
+		geany_debug("creating config directory %s", app->configdir);
+		saved_errno = utils_mkdir(app->configdir, TRUE);
+	}
+
+	conf_file = g_build_filename(app->configdir, "geany.conf", NULL);
+	filedefs_dir = g_build_filename(app->configdir, GEANY_FILEDEFS_SUBDIR, NULL);
+	templates_dir = g_build_filename(app->configdir, GEANY_TEMPLATES_SUBDIR, NULL);
+
+	if (saved_errno == 0 && ! g_file_test(conf_file, G_FILE_TEST_EXISTS))
+	{	/* check whether geany.conf can be written */
+		saved_errno = utils_is_file_writable(app->configdir);
+	}
+
+	/* make subdir for filetype definitions */
+	if (saved_errno == 0)
+	{
+		gchar *filedefs_readme = g_build_filename(app->configdir,
+					GEANY_FILEDEFS_SUBDIR, "filetypes.README", NULL);
+
+		if (! g_file_test(filedefs_dir, G_FILE_TEST_EXISTS))
+		{
+			saved_errno = utils_mkdir(filedefs_dir, FALSE);
+		}
+		if (saved_errno == 0 && ! g_file_test(filedefs_readme, G_FILE_TEST_EXISTS))
+		{
+			gchar *text = g_strconcat(
+"Copy files from ", app->datadir, " to this directory to overwrite "
+"them. To use the defaults, just delete the file in this directory.\nFor more information read "
+"the documentation (in ", app->docdir, G_DIR_SEPARATOR_S "index.html or visit " GEANY_HOMEPAGE ").", NULL);
+			utils_write_file(filedefs_readme, text);
+			g_free(text);
+		}
+		g_free(filedefs_readme);
+	}
+
+	/* make subdir for template files */
+	if (saved_errno == 0)
+	{
+		gchar *templates_readme = g_build_filename(app->configdir, GEANY_TEMPLATES_SUBDIR,
+						"templates.README", NULL);
+
+		if (! g_file_test(templates_dir, G_FILE_TEST_EXISTS))
+		{
+			saved_errno = utils_mkdir(templates_dir, FALSE);
+		}
+		if (saved_errno == 0 && ! g_file_test(templates_readme, G_FILE_TEST_EXISTS))
+		{
+			gchar *text = g_strconcat(
+"There are several template files in this directory. For these templates you can use wildcards.\n\
+For more information read the documentation (in ", app->docdir, G_DIR_SEPARATOR_S "index.html or visit " GEANY_HOMEPAGE ").",
+					NULL);
+			utils_write_file(templates_readme, text);
+			g_free(text);
+		}
+		g_free(templates_readme);
+	}
+
+	g_free(filedefs_dir);
+	g_free(templates_dir);
+	g_free(conf_file);
+
+	return saved_errno;
+}
+
+
+/* Returns 0 if config dir is OK. */
+static gint setup_config_dir(void)
+{
+	gint mkdir_result = 0;
+
+	/* convert configdir to locale encoding to avoid troubles */
+	SETPTR(app->configdir, utils_get_locale_from_utf8(app->configdir));
+
+	mkdir_result = create_config_dir();
+	if (mkdir_result != 0)
+	{
+		if (! dialogs_show_question(
+			_("Configuration directory could not be created (%s).\nThere could be some problems "
+			  "using Geany without a configuration directory.\nStart Geany anyway?"),
+			  g_strerror(mkdir_result)))
+		{
+			exit(0);
+		}
+	}
+	/* make configdir a real path */
+	if (g_file_test(app->configdir, G_FILE_TEST_EXISTS))
+		SETPTR(app->configdir, tm_get_real_path(app->configdir));
+
+	return mkdir_result;
+}
+
+/* Signal handling removed since main_quit() uses functions that are
+ * illegal in signal handlers
+static void signal_cb(gint sig)
+{
+	if (sig == SIGTERM)
+	{
+		main_quit();
+	}
+}
+ */
+
+/* Used for command-line arguments at startup or from socket.
+ * this will strip any :line:col filename suffix from locale_filename */
+gboolean main_handle_filename(const gchar *locale_filename)
+{
+	GeanyDocument *doc;
+	gint line = -1, column = -1;
+	gchar *filename;
+
+	g_return_val_if_fail(locale_filename, FALSE);
+
+	/* check whether the passed filename is an URI */
+	filename = utils_get_path_from_uri(locale_filename);
+	if (filename == NULL)
+		return FALSE;
+
+	get_line_and_column_from_filename(filename, &line, &column);
+	if (line >= 0)
+		cl_options.goto_line = line;
+	if (column >= 0)
+		cl_options.goto_column = column;
+
+	if (g_file_test(filename, G_FILE_TEST_IS_REGULAR))
+	{
+		doc = document_open_file(filename, cl_options.readonly, NULL, NULL);
+		/* add recent file manually if opening_session_files is set */
+		if (doc != NULL && main_status.opening_session_files)
+			ui_add_recent_document(doc);
+		g_free(filename);
+		return TRUE;
+	}
+	else if (file_prefs.cmdline_new_files)
+	{	/* create new file with the given filename */
+		gchar *utf8_filename = utils_get_utf8_from_locale(filename);
+
+		doc = document_new_file(utf8_filename, NULL, NULL);
+		if (doc != NULL)
+			ui_add_recent_document(doc);
+		g_free(utf8_filename);
+		g_free(filename);
+		return TRUE;
+	}
+	g_free(filename);
+	return FALSE;
+}
+
+
+/* open files from command line */
+static void open_cl_files(gint argc, gchar **argv)
+{
+	gint i;
+
+	for (i = 1; i < argc; i++)
+	{
+		gchar *filename = main_get_argv_filename(argv[i]);
+
+		if (g_file_test(filename, G_FILE_TEST_IS_DIR))
+		{
+			g_free(filename);
+			continue;
+		}
+
+#ifdef G_OS_WIN32
+		/* It seems argv elements are encoded in CP1252 on a German Windows */
+		SETPTR(filename, g_locale_to_utf8(filename, -1, NULL, NULL, NULL));
+#endif
+		if (filename && ! main_handle_filename(filename))
+		{
+			const gchar *msg = _("Could not find file '%s'.");
+
+			g_printerr(msg, filename);	/* also print to the terminal */
+			g_printerr("\n");
+			ui_set_statusbar(TRUE, msg, filename);
+		}
+		g_free(filename);
+	}
+}
+
+
+static void load_session_project_file(void)
+{
+	gchar *locale_filename;
+
+	g_return_if_fail(project_prefs.session_file != NULL);
+
+	locale_filename = utils_get_locale_from_utf8(project_prefs.session_file);
+
+	if (G_LIKELY(!EMPTY(locale_filename)))
+		project_load_file(locale_filename);
+
+	g_free(locale_filename);
+	g_free(project_prefs.session_file);	/* no longer needed */
+}
+
+
+static void load_settings(void)
+{
+	configuration_load();
+	/* let cmdline options overwrite configuration settings */
+#ifdef HAVE_VTE
+	vte_info.have_vte = (no_vte) ? FALSE : vte_info.load_vte;
+#endif
+	if (no_msgwin)
+		ui_prefs.msgwindow_visible = FALSE;
+
+#ifdef HAVE_PLUGINS
+	want_plugins = prefs.load_plugins && !no_plugins;
+#endif
+}
+
+
+void main_load_project_from_command_line(const gchar *locale_filename, gboolean use_session)
+{
+	gchar *pfile;
+
+	pfile = utils_get_path_from_uri(locale_filename);
+	if (pfile != NULL)
+	{
+		if (use_session)
+			project_load_file_with_session(pfile);
+		else
+			project_load_file(pfile);
+	}
+	g_free(pfile);
+}
+
+
+static void load_startup_files(gint argc, gchar **argv)
+{
+	gboolean load_session = FALSE;
+
+	if (argc > 1 && g_str_has_suffix(argv[1], ".geany"))
+	{
+		gchar *filename = main_get_argv_filename(argv[1]);
+
+		/* project file specified: load it, but decide the session later */
+		main_load_project_from_command_line(filename, FALSE);
+		argc--, argv++;
+		/* force session load if using project-based session files */
+		load_session = project_prefs.project_session;
+		g_free(filename);
+	}
+
+	/* Load the default session if:
+	 * 1. "Load files from the last session" is active.
+	 * 2. --no-session is not specified.
+	 * 3. We are a primary instance.
+	 * Has no effect if a CL project is loaded and using project-based session files. */
+	if (prefs.load_session && cl_options.load_session && !cl_options.new_instance)
+	{
+		if (app->project == NULL)
+			load_session_project_file();
+		load_session = TRUE;
+	}
+
+	if (load_session)
+	{
+		/* load session files into tabs, as they are found in the session_files variable */
+		configuration_open_files();
+
+		if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook)) == 0)
+		{
+			ui_update_popup_copy_items(NULL);
+			ui_update_popup_reundo_items(NULL);
+		}
+	}
+
+	open_cl_files(argc, argv);
+}
+
+
+static gboolean send_startup_complete(gpointer data)
+{
+	g_signal_emit_by_name(geany_object, "geany-startup-complete");
+	return FALSE;
+}
+
+
+static const gchar *get_locale(void)
+{
+	const gchar *locale = "unknown";
+#ifdef HAVE_LOCALE_H
+	locale = setlocale(LC_CTYPE, NULL);
+#endif
+	return locale;
+}
+
+
+#if ! GTK_CHECK_VERSION(3, 0, 0)
+/* This prepends our own gtkrc file to the list of RC files to be loaded by GTK at startup.
+ * This function *has* to be called before gtk_init().
+ *
+ * We have a custom RC file defining various styles we need, and we want the user to be
+ * able to override them (e.g. if they want -- or need -- other colors).  Fair enough, one
+ * would simply call gtk_rc_parse() with the appropriate filename.  However, the styling
+ * rules applies in the order they are loaded, then if we load our styles after GTK has
+ * loaded the user's ones we'd override them.
+ *
+ * There are 2 solutions to fix this:
+ * 1) set our styles' priority to something with lower than "user" (actually "theme"
+ *    priority because rules precedence are first calculated depending on the priority
+ *    no matter of how precise the rules is, so we need to override the theme).
+ * 2) prepend our custom style to GTK's list while keeping priority to user (which is the
+ *    default), so it gets loaded before real user's ones and so gets overridden by them.
+ *
+ * One would normally go for 1 because it's ways simpler and requires less code: you just
+ * have to add the priorities to your styles, which is a matter of adding a few ":theme" in
+ * the RC file.  However, KDE being a bitch it doesn't set the gtk-theme-name but rather
+ * directly includes the style to use in a user gtkrc file, which makes the theme have
+ * "user" priority, hence overriding our styles.  So, we cannot set priorities in the RC
+ * file if we want to support running under KDE, which pretty much leave us with no choice
+ * but to go with solution 2, which unfortunately requires writing ugly code since GTK
+ * don't have a gtk_rc_prepend_default_file() function.  Thank you very much KDE.
+ *
+ * Though, as a side benefit it also makes the code work with people using gtk-chtheme,
+ * which also found it funny to include the theme in the user RC file. */
+static void setup_gtk2_styles(void)
+{
+	gchar **gtk_files = gtk_rc_get_default_files();
+	gchar **new_files = g_malloc(sizeof *new_files * (g_strv_length(gtk_files) + 2));
+	guint i = 0;
+
+	new_files[i++] = g_build_filename(app->datadir, "geany.gtkrc", NULL);
+	for (; *gtk_files; gtk_files++)
+		new_files[i++] = g_strdup(*gtk_files);
+	new_files[i] = NULL;
+
+	gtk_rc_set_default_files(new_files);
+
+	g_strfreev(new_files);
+}
+#endif
+
+
+GEANY_EXPORT_SYMBOL
+gint main_lib(gint argc, gchar **argv)
+{
+	GeanyDocument *doc;
+	gint config_dir_result;
+	const gchar *locale;
+
+#if ! GLIB_CHECK_VERSION(2, 36, 0)
+	g_type_init();
+#endif
+
+	log_handlers_init();
+
+	app = g_new0(GeanyApp, 1);
+	memset(&main_status, 0, sizeof(GeanyStatus));
+	memset(&prefs, 0, sizeof(GeanyPrefs));
+	memset(&interface_prefs, 0, sizeof(GeanyInterfacePrefs));
+	memset(&toolbar_prefs, 0, sizeof(GeanyToolbarPrefs));
+	memset(&file_prefs, 0, sizeof(GeanyFilePrefs));
+	memset(&search_prefs, 0, sizeof(GeanySearchPrefs));
+	memset(&tool_prefs, 0, sizeof(GeanyToolPrefs));
+	memset(&template_prefs, 0, sizeof(GeanyTemplatePrefs));
+	memset(&ui_prefs, 0, sizeof(UIPrefs));
+	memset(&ui_widgets, 0, sizeof(UIWidgets));
+
+	setup_paths();
+#if ! GTK_CHECK_VERSION(3, 0, 0)
+	setup_gtk2_styles();
+#endif
+#ifdef ENABLE_NLS
+	main_locale_init(utils_resource_dir(RESOURCE_DIR_LOCALE), GETTEXT_PACKAGE);
+#endif
+	parse_command_line_options(&argc, &argv);
+
+#if ! GLIB_CHECK_VERSION(2, 32, 0)
+	/* Initialize GLib's thread system in case any plugins want to use it or their
+	 * dependencies (e.g. WebKit, Soup, ...). Deprecated since GLIB 2.32. */
+	if (!g_thread_supported())
+		g_thread_init(NULL);
+#endif
+
+	/* removed as signal handling was wrong, see signal_cb()
+	signal(SIGTERM, signal_cb); */
+
+#ifdef G_OS_UNIX
+	/* ignore SIGPIPE signal for preventing sudden death of program */
+	signal(SIGPIPE, SIG_IGN);
+#endif
+
+	config_dir_result = setup_config_dir();
+#ifdef HAVE_SOCKET
+	/* check and create (unix domain) socket for remote operation */
+	if (! socket_info.ignore_socket)
+	{
+		socket_info.lock_socket = -1;
+		socket_info.lock_socket_tag = 0;
+		socket_info.lock_socket = socket_init(argc, argv);
+		/* Quit if filenames were sent to first instance or the list of open
+		 * documents has been printed */
+		if ((socket_info.lock_socket == -2 /* socket exists */ && argc > 1) ||
+			cl_options.list_documents)
+		{
+			socket_finalize();
+			gdk_notify_startup_complete();
+			g_free(app->configdir);
+			g_free(app->datadir);
+			g_free(app->docdir);
+			g_free(app);
+			return 0;
+		}
+		/* Start a new instance if no command line strings were passed,
+		 * even if the socket already exists */
+		else if (socket_info.lock_socket == -2 /* socket already exists */)
+		{
+			socket_info.ignore_socket = TRUE;
+			cl_options.new_instance = TRUE;
+		}
+	}
+#endif
+
+#ifdef G_OS_WIN32
+	/* after we initialized the socket code and handled command line args,
+	 * let's change the working directory on Windows to not lock it */
+	change_working_directory_on_windows();
+#endif
+
+	locale = get_locale();
+	geany_debug("Geany %s, %s",
+		main_get_version_string(),
+		locale);
+	geany_debug(geany_lib_versions,
+		gtk_major_version, gtk_minor_version, gtk_micro_version,
+		glib_major_version, glib_minor_version, glib_micro_version);
+	geany_debug("System data dir: %s", app->datadir);
+	geany_debug("User config dir: %s", app->configdir);
+
+	/* create the object so Geany signals can be connected in init() functions */
+	geany_object = geany_object_new();
+
+	/* inits */
+	main_init();
+
+	encodings_init();
+	editor_init();
+
+	/* init stash groups before loading keyfile */
+	configuration_init();
+	ui_init_prefs();
+	search_init();
+	project_init();
+#ifdef HAVE_PLUGINS
+	plugins_init();
+#endif
+	sidebar_init();
+	load_settings();	/* load keyfile */
+
+	msgwin_init();
+	build_init();
+	ui_create_insert_menu_items();
+	ui_create_insert_date_menu_items();
+	keybindings_init();
+	notebook_init();
+	filetypes_init();
+	templates_init();
+	navqueue_init();
+	document_init_doclist();
+	symbols_init();
+	editor_snippets_init();
+
+#ifdef HAVE_VTE
+	vte_init();
+#endif
+	ui_create_recent_menus();
+
+	ui_set_statusbar(TRUE, _("This is Geany %s."), main_get_version_string());
+	if (config_dir_result != 0)
+		ui_set_statusbar(TRUE, _("Configuration directory could not be created (%s)."),
+			g_strerror(config_dir_result));
+
+	/* apply all configuration options */
+	apply_settings();
+
+#ifdef HAVE_PLUGINS
+	/* load any enabled plugins before we open any documents */
+	if (want_plugins)
+		plugins_load_active();
+#endif
+
+	ui_sidebar_show_hide();
+
+	/* set the active sidebar page after plugins have been loaded */
+	gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.sidebar_notebook), ui_prefs.sidebar_page);
+
+	/* load keybinding settings after plugins have added their groups */
+	keybindings_load_keyfile();
+
+	/* create the custom command menu after the keybindings have been loaded to have the proper
+	 * accelerator shown for the menu items */
+	tools_create_insert_custom_command_menu_items();
+
+	/* load any command line files or session files */
+	main_status.opening_session_files = TRUE;
+	load_startup_files(argc, argv);
+	main_status.opening_session_files = FALSE;
+
+	/* open a new file if no other file was opened */
+	document_new_file_if_non_open();
+
+	ui_document_buttons_update();
+	ui_save_buttons_toggle(FALSE);
+
+	doc = document_get_current();
+	sidebar_select_openfiles_item(doc);
+	build_menu_update(doc);
+	sidebar_update_tag_list(doc, FALSE);
+
+#ifdef G_OS_WIN32
+	/* Manually realise the main window to be able to set the position but don't show it.
+	 * We don't set the position after showing the window to avoid flickering. */
+	gtk_widget_realize(main_widgets.window);
+#endif
+	setup_window_position();
+
+	/* finally show the window */
+	document_grab_focus(doc);
+	gtk_widget_show(main_widgets.window);
+	main_status.main_window_realized = TRUE;
+
+	configuration_apply_settings();
+
+#ifdef HAVE_SOCKET
+	/* register the callback of socket input */
+	if (! socket_info.ignore_socket && socket_info.lock_socket > 0)
+	{
+		socket_info.read_ioc = g_io_channel_unix_new(socket_info.lock_socket);
+		socket_info.lock_socket_tag = g_io_add_watch(socket_info.read_ioc,
+						G_IO_IN | G_IO_PRI | G_IO_ERR, socket_lock_input_cb, main_widgets.window);
+	}
+#endif
+
+	/* when we are really done with setting everything up and the main event loop is running,
+	 * tell other components, mainly plugins, that startup is complete */
+	g_idle_add_full(G_PRIORITY_LOW, send_startup_complete, NULL, NULL);
+
+#ifdef MAC_INTEGRATION
+	/* OS X application ready - has to be called before entering main loop */
+	gtkosx_application_ready(gtkosx_application_get());
+#endif
+
+	gtk_main();
+	return 0;
+}
+
+
+static void queue_free(GQueue *queue)
+{
+	while (! g_queue_is_empty(queue))
+	{
+		g_free(g_queue_pop_tail(queue));
+	}
+	g_queue_free(queue);
+}
+
+
+static void do_main_quit(void)
+{
+	geany_debug("Quitting...");
+
+	configuration_save();
+
+	if (app->project != NULL)
+		project_close(FALSE);   /* save project session files */
+
+	document_close_all();
+
+	main_status.quitting = TRUE;
+
+#ifdef HAVE_SOCKET
+	socket_finalize();
+#endif
+
+#ifdef HAVE_PLUGINS
+	plugins_finalize();
+#endif
+
+	navqueue_free();
+	keybindings_free();
+	notebook_free();
+	highlighting_free_styles();
+	templates_free_templates();
+	msgwin_finalize();
+	search_finalize();
+	build_finalize();
+	document_finalize();
+	symbols_finalize();
+	project_finalize();
+	editor_finalize();
+	editor_snippets_free();
+	encodings_finalize();
+	toolbar_finalize();
+	sidebar_finalize();
+	configuration_finalize();
+	filetypes_free_types();
+	log_finalize();
+
+	tm_workspace_free();
+	g_free(app->configdir);
+	g_free(app->datadir);
+	g_free(app->docdir);
+	g_free(prefs.default_open_path);
+	g_free(prefs.custom_plugin_path);
+	g_free(ui_prefs.custom_date_format);
+	g_free(interface_prefs.editor_font);
+	g_free(interface_prefs.tagbar_font);
+	g_free(interface_prefs.msgwin_font);
+	g_free(editor_prefs.long_line_color);
+	g_free(editor_prefs.comment_toggle_mark);
+	g_free(editor_prefs.color_scheme);
+	g_free(tool_prefs.context_action_cmd);
+	g_free(template_prefs.developer);
+	g_free(template_prefs.company);
+	g_free(template_prefs.mail);
+	g_free(template_prefs.initials);
+	g_free(template_prefs.version);
+	g_free(tool_prefs.term_cmd);
+	g_free(tool_prefs.browser_cmd);
+	g_free(tool_prefs.grep_cmd);
+	g_free(printing_prefs.external_print_cmd);
+	g_free(printing_prefs.page_header_datefmt);
+	g_strfreev(ui_prefs.custom_commands);
+	g_strfreev(ui_prefs.custom_commands_labels);
+
+	queue_free(ui_prefs.recent_queue);
+	queue_free(ui_prefs.recent_projects_queue);
+
+	if (ui_widgets.prefs_dialog && GTK_IS_WIDGET(ui_widgets.prefs_dialog)) gtk_widget_destroy(ui_widgets.prefs_dialog);
+	if (ui_widgets.open_fontsel && GTK_IS_WIDGET(ui_widgets.open_fontsel)) gtk_widget_destroy(ui_widgets.open_fontsel);
+	if (ui_widgets.open_colorsel && GTK_IS_WIDGET(ui_widgets.open_colorsel)) gtk_widget_destroy(ui_widgets.open_colorsel);
+#ifdef HAVE_VTE
+	if (vte_info.have_vte) vte_close();
+	g_free(vte_info.lib_vte);
+	g_free(vte_info.dir);
+#endif
+	gtk_widget_destroy(main_widgets.window);
+
+	/* destroy popup menus */
+	if (main_widgets.editor_menu && GTK_IS_WIDGET(main_widgets.editor_menu))
+					gtk_widget_destroy(main_widgets.editor_menu);
+	if (ui_widgets.toolbar_menu && GTK_IS_WIDGET(ui_widgets.toolbar_menu))
+					gtk_widget_destroy(ui_widgets.toolbar_menu);
+	if (msgwindow.popup_status_menu && GTK_IS_WIDGET(msgwindow.popup_status_menu))
+					gtk_widget_destroy(msgwindow.popup_status_menu);
+	if (msgwindow.popup_msg_menu && GTK_IS_WIDGET(msgwindow.popup_msg_menu))
+					gtk_widget_destroy(msgwindow.popup_msg_menu);
+	if (msgwindow.popup_compiler_menu && GTK_IS_WIDGET(msgwindow.popup_compiler_menu))
+					gtk_widget_destroy(msgwindow.popup_compiler_menu);
+
+	g_object_unref(geany_object);
+	geany_object = NULL;
+
+	g_free(original_cwd);
+	g_free(app);
+
+	ui_finalize_builder();
+
+	gtk_main_quit();
+}
+
+
+static gboolean check_no_unsaved(void)
+{
+	guint i;
+
+	for (i = 0; i < documents_array->len; i++)
+	{
+		if (documents[i]->is_valid && documents[i]->changed)
+		{
+			return FALSE;
+		}
+	}
+	return TRUE;    /* no unsaved edits */
+}
+
+
+/* Returns false when quitting is aborted due to user cancellation */
+gboolean main_quit(void)
+{
+	main_status.quitting = TRUE;
+
+	if (! check_no_unsaved())
+	{
+		if (document_account_for_unsaved())
+		{
+			do_main_quit();
+			return TRUE;
+		}
+	}
+	else
+	if (! prefs.confirm_exit ||
+		dialogs_show_question_full(NULL, GTK_STOCK_QUIT, GTK_STOCK_CANCEL, NULL,
+			_("Do you really want to quit?")))
+	{
+		do_main_quit();
+		return TRUE;
+	}
+
+	main_status.quitting = FALSE;
+	return FALSE;
+}
+
+/**
+ *  Reloads most of Geany's configuration files without restarting. Currently the following
+ *  files are reloaded: all template files, also new file templates and the 'New (with template)'
+ *  menus will be updated, Snippets (snippets.conf), filetype extensions (filetype_extensions.conf),
+ *  and 'settings' and 'build_settings' sections of the filetype definition files.
+ *
+ *  Plugins may call this function if they changed any of these files (e.g. a configuration file
+ *  editor plugin).
+ *
+ *  @since 0.15
+ **/
+GEANY_API_SYMBOL
+void main_reload_configuration(void)
+{
+	/* reload templates */
+	templates_free_templates();
+	templates_init();
+
+	/* reload snippets */
+	editor_snippets_free();
+	editor_snippets_init();
+
+	filetypes_reload_extensions();
+	filetypes_reload();
+
+	/* C tag names to ignore */
+	symbols_reload_config_files();
+
+	ui_set_statusbar(TRUE, _("Configuration files reloaded."));
+}


Modified: src/main.c
1385 lines changed, 4 insertions(+), 1381 deletions(-)
===================================================================
@@ -1,8 +1,7 @@
 /*
  *      main.c - this file is part of Geany, a fast and lightweight IDE
  *
- *      Copyright 2005-2012 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
- *      Copyright 2006-2012 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
+ *      Copyright 2014 Matthew Brush <mbrush at codebrainz.ca>
  *
  *      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
@@ -19,1387 +18,11 @@
  *      51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-/**
- * @file: main.h
- * Main program-related commands.
- * Handles program initialization and cleanup.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
+/* See libmain.c for the real entry-point code. */
 
 #include "main.h"
 
-#include "app.h"
-#include "build.h"
-#include "callbacks.h"
-#include "dialogs.h"
-#include "document.h"
-#include "encodings.h"
-#include "filetypes.h"
-#include "geanyobject.h"
-#include "highlighting.h"
-#include "keybindings.h"
-#include "keyfile.h"
-#include "log.h"
-#include "msgwindow.h"
-#include "navqueue.h"
-#include "notebook.h"
-#include "pluginexport.h"
-#include "plugins.h"
-#include "prefs.h"
-#include "printing.h"
-#include "sidebar.h"
-#ifdef HAVE_SOCKET
-# include "socket.h"
-#endif
-#include "support.h"
-#include "symbols.h"
-#include "templates.h"
-#include "toolbar.h"
-#include "tools.h"
-#include "ui_utils.h"
-#include "utils.h"
-#include "vte.h"
-#include "win32.h"
-#include "osx.h"
-
-#include "gtkcompat.h"
-
-#include <signal.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <glib/gstdio.h>
-
-#ifdef HAVE_LOCALE_H
-# include <locale.h>
-#endif
-
-
-GeanyApp	*app;
-gboolean	ignore_callback;	/* hack workaround for GTK+ toggle button callback problem */
-
-GeanyStatus	 main_status;
-CommandLineOptions cl_options;	/* fields initialised in parse_command_line_options */
-
-static gchar *original_cwd = NULL;
-
-static const gchar geany_lib_versions[] = "GTK %u.%u.%u, GLib %u.%u.%u";
-
-static gboolean want_plugins;
-
-/* command-line options */
-static gboolean verbose_mode = FALSE;
-static gboolean ignore_global_tags = FALSE;
-static gboolean no_msgwin = FALSE;
-static gboolean show_version = FALSE;
-static gchar *alternate_config = NULL;
-#ifdef HAVE_VTE
-static gboolean no_vte = FALSE;
-static gchar *lib_vte = NULL;
-#endif
-static gboolean generate_tags = FALSE;
-static gboolean no_preprocessing = FALSE;
-static gboolean ft_names = FALSE;
-static gboolean print_prefix = FALSE;
-#ifdef HAVE_PLUGINS
-static gboolean no_plugins = FALSE;
-#endif
-static gboolean dummy = FALSE;
-
-/* in alphabetical order of short options */
-static GOptionEntry entries[] =
-{
-	{ "column", 0, 0, G_OPTION_ARG_INT, &cl_options.goto_column, N_("Set initial column number for the first opened file (useful in conjunction with --line)"), NULL },
-	{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &alternate_config, N_("Use an alternate configuration directory"), NULL },
-	{ "ft-names", 0, 0, G_OPTION_ARG_NONE, &ft_names, N_("Print internal filetype names"), NULL },
-	{ "generate-tags", 'g', 0, G_OPTION_ARG_NONE, &generate_tags, N_("Generate global tags file (see documentation)"), NULL },
-	{ "no-preprocessing", 'P', 0, G_OPTION_ARG_NONE, &no_preprocessing, N_("Don't preprocess C/C++ files when generating tags"), NULL },
-#ifdef HAVE_SOCKET
-	{ "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 },
-	{ "socket-file", 0, 0, G_OPTION_ARG_FILENAME, &cl_options.socket_filename, N_("Use this socket filename for communication with a running Geany instance"), NULL },
-	{ "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 },
-#endif
-	{ "line", 'l', 0, G_OPTION_ARG_INT, &cl_options.goto_line, N_("Set initial line number for the first opened file"), NULL },
-	{ "no-msgwin", 'm', 0, G_OPTION_ARG_NONE, &no_msgwin, N_("Don't show message window at startup"), NULL },
-	{ "no-ctags", 'n', 0, G_OPTION_ARG_NONE, &ignore_global_tags, N_("Don't load auto completion data (see documentation)"), NULL },
-#ifdef HAVE_PLUGINS
-	{ "no-plugins", 'p', 0, G_OPTION_ARG_NONE, &no_plugins, N_("Don't load plugins"), NULL },
-#endif
-	{ "print-prefix", 0, 0, G_OPTION_ARG_NONE, &print_prefix, N_("Print Geany's installation prefix"), NULL },
-	{ "read-only", 'r', 0, G_OPTION_ARG_NONE, &cl_options.readonly, N_("Open all FILES in read-only mode (see documention)"), NULL },
-	{ "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 },
-#ifdef HAVE_VTE
-	{ "no-terminal", 't', 0, G_OPTION_ARG_NONE, &no_vte, N_("Don't load terminal support"), NULL },
-	{ "vte-lib", 0, 0, G_OPTION_ARG_FILENAME, &lib_vte, N_("Filename of libvte.so"), NULL },
-#endif
-	{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose_mode, N_("Be verbose"), NULL },
-	{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Show version and exit"), NULL },
-	{ "dummy", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &dummy, NULL, NULL }, /* for +NNN line number arguments */
-	{ NULL, 0, 0, 0, NULL, NULL, NULL }
-};
-
-
-static void setup_window_position(void)
-{
-	/* interprets the saved window geometry */
-	if (!prefs.save_winpos)
-		return;
-
-	if (ui_prefs.geometry[0] != -1 && ui_prefs.geometry[1] != -1)
-		gtk_window_move(GTK_WINDOW(main_widgets.window),
-			ui_prefs.geometry[0], ui_prefs.geometry[1]);
-
-	if (ui_prefs.geometry[2] != -1 && ui_prefs.geometry[3] != -1)
-		gtk_window_set_default_size(GTK_WINDOW(main_widgets.window),
-			ui_prefs.geometry[2], ui_prefs.geometry[3]);
-
-	if (ui_prefs.geometry[4] == 1)
-		gtk_window_maximize(GTK_WINDOW(main_widgets.window));
-}
-
-
-/* special things for the initial setup of the checkboxes and related stuff
- * an action on a setting is only performed if the setting is not equal to the program default
- * (all the following code is not perfect but it works for the moment) */
-static void apply_settings(void)
-{
-	ui_update_fold_items();
-
-	/* toolbar, message window and sidebar are by default visible, so don't change it if it is true */
-	toolbar_show_hide();
-	if (! ui_prefs.msgwindow_visible)
-	{
-		ignore_callback = TRUE;
-		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_show_messages_window1")), FALSE);
-		gtk_widget_hide(main_widgets.message_window_notebook);
-		ignore_callback = FALSE;
-	}
-	if (! ui_prefs.sidebar_visible)
-	{
-		ignore_callback = TRUE;
-		gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(ui_lookup_widget(main_widgets.window, "menu_show_sidebar1")), FALSE);
-		ignore_callback = FALSE;
-	}
-
-	toolbar_apply_settings();
-	toolbar_update_ui();
-
-	ui_update_view_editor_menu_items();
-
-	/* hide statusbar if desired */
-	if (! interface_prefs.statusbar_visible)
-	{
-		gtk_widget_hide(ui_widgets.statusbar);
-	}
-
-	/* set the tab placements of the notebooks */
-	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(main_widgets.notebook), interface_prefs.tab_pos_editor);
-	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(msgwindow.notebook), interface_prefs.tab_pos_msgwin);
-	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(main_widgets.sidebar_notebook), interface_prefs.tab_pos_sidebar);
-
-	/* whether to show notebook tabs or not */
-	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(main_widgets.notebook), interface_prefs.show_notebook_tabs);
-
-#ifdef HAVE_VTE
-	if (! vte_info.have_vte)
-#endif
-	{
-		gtk_widget_set_sensitive(
-			ui_lookup_widget(main_widgets.window, "send_selection_to_vte1"), FALSE);
-	}
-
-	if (interface_prefs.sidebar_pos != GTK_POS_LEFT)
-		ui_swap_sidebar_pos();
-
-	gtk_orientable_set_orientation(GTK_ORIENTABLE(ui_lookup_widget(main_widgets.window, "vpaned1")),
-		interface_prefs.msgwin_orientation);
-}
-
-
-static void main_init(void)
-{
-	/* add our icon path in case we aren't installed in the system prefix */
-	gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), utils_resource_dir(RESOURCE_DIR_ICON));
-
-	/* inits */
-	ui_init_stock_items();
-
-	ui_init_builder();
-
-	main_widgets.window				= NULL;
-	app->project			= NULL;
-	ui_widgets.open_fontsel		= NULL;
-	ui_widgets.open_colorsel	= NULL;
-	ui_widgets.prefs_dialog		= NULL;
-	main_status.main_window_realized = FALSE;
-	file_prefs.tab_order_ltr		= FALSE;
-	file_prefs.tab_order_beside		= FALSE;
-	main_status.quitting			= FALSE;
-	ignore_callback	= FALSE;
-	app->tm_workspace		= tm_get_workspace();
-	ui_prefs.recent_queue				= g_queue_new();
-	ui_prefs.recent_projects_queue		= g_queue_new();
-	main_status.opening_session_files	= FALSE;
-
-	main_widgets.window = create_window1();
-
-	/* add recent projects to the Project menu */
-	ui_widgets.recent_projects_menuitem = ui_lookup_widget(main_widgets.window, "recent_projects1");
-	ui_widgets.recent_projects_menu_menubar = gtk_menu_new();
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(ui_widgets.recent_projects_menuitem),
-							ui_widgets.recent_projects_menu_menubar);
-
-	/* store important pointers for later reference */
-	main_widgets.toolbar = toolbar_init();
-	main_widgets.sidebar_notebook = ui_lookup_widget(main_widgets.window, "notebook3");
-	main_widgets.notebook = ui_lookup_widget(main_widgets.window, "notebook1");
-	main_widgets.editor_menu = create_edit_menu1();
-	main_widgets.tools_menu = ui_lookup_widget(main_widgets.window, "tools1_menu");
-	main_widgets.message_window_notebook = ui_lookup_widget(main_widgets.window, "notebook_info");
-	main_widgets.project_menu = ui_lookup_widget(main_widgets.window, "menu_project1_menu");
-
-	ui_widgets.toolbar_menu = create_toolbar_popup_menu1();
-	ui_init();
-#ifdef MAC_INTEGRATION
-	osx_ui_init();
-#endif
-
-	/* set widget names for matching with .gtkrc-2.0 */
-	gtk_widget_set_name(main_widgets.window, "GeanyMainWindow");
-	gtk_widget_set_name(ui_widgets.toolbar_menu, "GeanyToolbarMenu");
-	gtk_widget_set_name(main_widgets.editor_menu, "GeanyEditMenu");
-	gtk_widget_set_name(ui_lookup_widget(main_widgets.window, "menubar1"), "GeanyMenubar");
-	gtk_widget_set_name(main_widgets.toolbar, "GeanyToolbar");
-
-	gtk_window_set_default_size(GTK_WINDOW(main_widgets.window),
-		GEANY_WINDOW_DEFAULT_WIDTH, GEANY_WINDOW_DEFAULT_HEIGHT);
-}
-
-
-const gchar *main_get_version_string(void)
-{
-	static gchar full[] = VERSION " (git >= " REVISION ")";
-
-	if (utils_str_equal(REVISION, "-1"))
-		return VERSION;
-	else
-		return full;
-}
-
-
-/* get the full file path of a command-line argument
- * N.B. the result should be freed and may contain '/../' or '/./ ' */
-gchar *main_get_argv_filename(const gchar *filename)
-{
-	gchar *result;
-
-	if (g_path_is_absolute(filename) || utils_is_uri(filename))
-		result = g_strdup(filename);
-	else
-	{
-		/* use current dir */
-		gchar *cur_dir = NULL;
-		if (original_cwd == NULL)
-			cur_dir = g_get_current_dir();
-		else
-			cur_dir = g_strdup(original_cwd);
-
-		result = g_strjoin(
-			G_DIR_SEPARATOR_S, cur_dir, filename, NULL);
-		g_free(cur_dir);
-	}
-	return result;
-}
-
-
-/* get a :line:column specifier from the end of a filename (if present),
- * return the line/column values, and remove the specifier from the string
- * (Note that *line and *column must both be set to -1 initially) */
-static void get_line_and_column_from_filename(gchar *filename, gint *line, gint *column)
-{
-	gsize i;
-	gint colon_count = 0;
-	gboolean have_number = FALSE;
-	gsize len;
-
-	g_assert(*line == -1 && *column == -1);
-
-	if (G_UNLIKELY(EMPTY(filename)))
-		return;
-
-	/* allow to open files like "test:0" */
-	if (g_file_test(filename, G_FILE_TEST_EXISTS))
-		return;
-
-	len = strlen(filename);
-	for (i = len - 1; i >= 1; i--)
-	{
-		gboolean is_colon = filename[i] == ':';
-		gboolean is_digit = g_ascii_isdigit(filename[i]);
-
-		if (! is_colon && ! is_digit)
-			break;
-
-		if (is_colon)
-		{
-			if (++colon_count > 1)
-				break;	/* bail on 2+ colons in a row */
-		}
-		else
-			colon_count = 0;
-
-		if (is_digit)
-			have_number = TRUE;
-
-		if (is_colon && have_number)
-		{
-			gint number = atoi(&filename[i + 1]);
-
-			filename[i] = '\0';
-			have_number = FALSE;
-
-			*column = *line;
-			*line = number;
-		}
-
-		if (*column >= 0)
-			break;	/* line and column are set, so we're done */
-	}
-}
-
-
-#ifdef G_OS_WIN32
-static void change_working_directory_on_windows(void)
-{
-	gchar *install_dir = win32_get_installation_dir();
-
-	/* remember original working directory for use with opening files from the command line */
-	original_cwd = g_get_current_dir();
-
-	/* On Windows, change the working directory to the Geany installation path to not lock
-	 * the directory of a file passed as command line argument (see bug #2626124).
-	 * This also helps if plugins or other code uses relative paths to load
-	 * any additional resources (e.g. share/geany-plugins/...). */
-	win32_set_working_directory(install_dir);
-
-	g_free(install_dir);
-}
-#endif
-
-
-static void setup_paths(void)
-{
-	/* convert path names to locale encoding */
-	app->datadir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DATA));
-	app->docdir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DOC));
-}
-
-
-/**
- *  Checks whether the main window has been realized.
- *  This is an easy indicator whether Geany is right now starting up (main window is not
- *  yet realized) or whether it has finished the startup process (main window is realized).
- *  This is because the main window is realized (i.e. actually drawn on the screen) at the
- *  end of the startup process.
- *
- *  @note Maybe you want to use the @link pluginsignals.c @c "geany-startup-complete" signal @endlink
- *        to get notified about the completed startup process.
- *
- *  @return @c TRUE if the Geany main window has been realized or @c FALSE otherwise.
- *
- *  @since 0.19
- **/
-GEANY_API_SYMBOL
-gboolean main_is_realized(void)
-{
-	return main_status.main_window_realized;
-}
-
-
-/**
- *  Initialises the gettext translation system.
- *  This is a convenience function to set up gettext for internationalisation support
- *  in external plugins. You should call this function early in @ref plugin_init().
- *  If the macro HAVE_LOCALE_H is defined, @c setlocale(LC_ALL, "") is called.
- *  The codeset for the message translations is set to UTF-8.
- *
- *  Note that this function only setups the gettext textdomain for you. You still have
- *  to adjust the build system of your plugin to get internationalisation support
- *  working properly.
- *
- *  If you have already used @ref PLUGIN_SET_TRANSLATABLE_INFO() you
- *  don't need to call main_locale_init() again as it has already been done.
- *
- *  @param locale_dir The location where the translation files should be searched. This is
- *                    usually the @c LOCALEDIR macro, defined by the build system.
- *                    E.g. @c $prefix/share/locale.
- *                    Only used on non-Windows systems. On Windows, the directory is determined
- *                    by @c g_win32_get_package_installation_directory().
- *  @param package The package name, usually this is the @c GETTEXT_PACKAGE macro,
- *                 defined by the build system.
- *
- *  @since 0.16
- **/
-GEANY_API_SYMBOL
-void main_locale_init(const gchar *locale_dir, const gchar *package)
-{
-#ifdef HAVE_LOCALE_H
-	setlocale(LC_ALL, "");
-#endif
-
-#ifdef G_OS_WIN32
-	locale_dir = utils_resource_dir(RESOURCE_DIR_LOCALE);
-#endif
-	(void) bindtextdomain(package, locale_dir);
-	(void) bind_textdomain_codeset(package, "UTF-8");
-}
-
-
-static void print_filetypes(void)
-{
-	const GSList *list, *node;
-
-	filetypes_init_types();
-	printf("Geany's filetype names:\n");
-
-	list = filetypes_get_sorted_by_name();
-	foreach_slist(node, list)
-	{
-		GeanyFiletype *ft = node->data;
-
-		printf("%s\n", ft->name);
-	}
-	filetypes_free_types();
-}
-
-
-static void wait_for_input_on_windows(void)
-{
-#ifdef G_OS_WIN32
-	if (verbose_mode)
-	{
-		geany_debug("Press any key to continue");
-		getchar();
-	}
-#endif
-}
-
-
-static void parse_command_line_options(gint *argc, gchar ***argv)
-{
-	GError *error = NULL;
-	GOptionContext *context;
-	gint i;
-	CommandLineOptions def_clo = {FALSE, NULL, TRUE, -1, -1, FALSE, FALSE, FALSE};
-
-	/* first initialise cl_options fields with default values */
-	cl_options = def_clo;
-
-	/* the GLib option parser can't handle the +NNN (line number) option,
-	 * so we grab that here and replace it with a no-op */
-	for (i = 1; i < (*argc); i++)
-	{
-		if ((*argv)[i][0] != '+')
-			continue;
-
-		cl_options.goto_line = atoi((*argv)[i] + 1);
-		(*argv)[i] = (gchar *) "--dummy";
-	}
-
-	context = g_option_context_new(_("[FILES...]"));
-
-	g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE);
-	g_option_group_set_translation_domain(g_option_context_get_main_group(context), GETTEXT_PACKAGE);
-	g_option_context_add_group(context, gtk_get_option_group(FALSE));
-	g_option_context_parse(context, argc, argv, &error);
-	g_option_context_free(context);
-
-	if (error != NULL)
-	{
-		g_printerr("Geany: %s\n", error->message);
-		g_error_free(error);
-		exit(1);
-	}
-
-	app->debug_mode = verbose_mode;
-	if (app->debug_mode)
-	{
-		/* Since GLib 2.32 messages logged with levels INFO and DEBUG aren't output by the
-		 * default log handler unless the G_MESSAGES_DEBUG environment variable contains the
-		 * domain of the message or is set to the special value "all" */
-		g_setenv("G_MESSAGES_DEBUG", "all", FALSE);
-	}
-
-#ifdef G_OS_WIN32
-	win32_init_debug_code();
-#endif
-
-	if (show_version)
-	{
-		gchar *build_date = utils_parse_and_format_build_date(__DATE__);
-
-		printf(PACKAGE " %s (", main_get_version_string());
-		/* note for translators: library versions are printed after this */
-		printf(_("built on %s with "), build_date);
-		printf(geany_lib_versions,
-			GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION,
-			GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
-		printf(")\n");
-		g_free(build_date);
-		wait_for_input_on_windows();
-		exit(0);
-	}
-
-	if (print_prefix)
-	{
-		printf("%s\n", GEANY_PREFIX);
-		printf("%s\n", GEANY_DATADIR);
-		printf("%s\n", GEANY_LIBDIR);
-		printf("%s\n", GEANY_LOCALEDIR);
-		wait_for_input_on_windows();
-		exit(0);
-	}
-
-	if (alternate_config)
-	{
-		geany_debug("alternate config: %s", alternate_config);
-		app->configdir = alternate_config;
-	}
-	else
-	{
-		app->configdir = utils_get_user_config_dir();
-	}
-
-	if (generate_tags)
-	{
-		gboolean ret;
-
-		filetypes_init_types();
-		ret = symbols_generate_global_tags(*argc, *argv, ! no_preprocessing);
-		filetypes_free_types();
-		wait_for_input_on_windows();
-		exit(ret);
-	}
-
-	if (ft_names)
-	{
-		print_filetypes();
-		wait_for_input_on_windows();
-		exit(0);
-	}
-
-#ifdef HAVE_SOCKET
-	socket_info.ignore_socket = cl_options.new_instance;
-	if (cl_options.socket_filename)
-	{
-		socket_info.file_name = cl_options.socket_filename;
-	}
-#endif
-
-#ifdef HAVE_VTE
-	vte_info.lib_vte = lib_vte;
-#endif
-	cl_options.ignore_global_tags = ignore_global_tags;
-
-	if (! gtk_init_check(NULL, NULL))
-	{	/* check whether we have a valid X display and exit if not */
-		g_printerr("Geany: cannot open display\n");
-		exit(1);
-	}
-
-#ifdef MAC_INTEGRATION
-	/* Create GtkosxApplication singleton - should be created shortly after gtk_init() */
-	gtkosx_application_get();
-#endif
-}
-
-
-static gint create_config_dir(void)
-{
-	gint saved_errno = 0;
-	gchar *conf_file = NULL;
-	gchar *filedefs_dir = NULL;
-	gchar *templates_dir = NULL;
-
-	if (! g_file_test(app->configdir, G_FILE_TEST_EXISTS))
-	{
-#ifndef G_OS_WIN32
-		/* if we are *not* using an alternate config directory, we check whether the old one
-		 * in ~/.geany still exists and try to move it */
-		if (alternate_config == NULL)
-		{
-			gchar *old_dir = g_build_filename(g_get_home_dir(), ".geany", NULL);
-			/* move the old config dir if it exists */
-			if (g_file_test(old_dir, G_FILE_TEST_EXISTS))
-			{
-				if (! dialogs_show_question_full(main_widgets.window,
-					GTK_STOCK_YES, GTK_STOCK_QUIT, _("Move it now?"),
-					"%s",
-					_("Geany needs to move your old configuration directory before starting.")))
-					exit(0);
-
-				if (! g_file_test(app->configdir, G_FILE_TEST_IS_DIR))
-					utils_mkdir(app->configdir, TRUE);
-
-				if (g_rename(old_dir, app->configdir) == 0)
-				{
-					dialogs_show_msgbox(GTK_MESSAGE_INFO,
-						_("Your configuration directory has been successfully moved from \"%s\" to \"%s\"."),
-						old_dir, app->configdir);
-					g_free(old_dir);
-					return 0;
-				}
-				else
-				{
-					dialogs_show_msgbox(GTK_MESSAGE_WARNING,
-						/* for translators: the third %s in brackets is the error message which
-						 * describes why moving the dir didn't work */
-						_("Your old configuration directory \"%s\" could not be moved to \"%s\" (%s). "
-						  "Please move manually the directory to the new location."),
-						old_dir, app->configdir, g_strerror(errno));
-				}
-			}
-			g_free(old_dir);
-		}
-#endif
-		geany_debug("creating config directory %s", app->configdir);
-		saved_errno = utils_mkdir(app->configdir, TRUE);
-	}
-
-	conf_file = g_build_filename(app->configdir, "geany.conf", NULL);
-	filedefs_dir = g_build_filename(app->configdir, GEANY_FILEDEFS_SUBDIR, NULL);
-	templates_dir = g_build_filename(app->configdir, GEANY_TEMPLATES_SUBDIR, NULL);
-
-	if (saved_errno == 0 && ! g_file_test(conf_file, G_FILE_TEST_EXISTS))
-	{	/* check whether geany.conf can be written */
-		saved_errno = utils_is_file_writable(app->configdir);
-	}
-
-	/* make subdir for filetype definitions */
-	if (saved_errno == 0)
-	{
-		gchar *filedefs_readme = g_build_filename(app->configdir,
-					GEANY_FILEDEFS_SUBDIR, "filetypes.README", NULL);
-
-		if (! g_file_test(filedefs_dir, G_FILE_TEST_EXISTS))
-		{
-			saved_errno = utils_mkdir(filedefs_dir, FALSE);
-		}
-		if (saved_errno == 0 && ! g_file_test(filedefs_readme, G_FILE_TEST_EXISTS))
-		{
-			gchar *text = g_strconcat(
-"Copy files from ", app->datadir, " to this directory to overwrite "
-"them. To use the defaults, just delete the file in this directory.\nFor more information read "
-"the documentation (in ", app->docdir, G_DIR_SEPARATOR_S "index.html or visit " GEANY_HOMEPAGE ").", NULL);
-			utils_write_file(filedefs_readme, text);
-			g_free(text);
-		}
-		g_free(filedefs_readme);
-	}
-
-	/* make subdir for template files */
-	if (saved_errno == 0)
-	{
-		gchar *templates_readme = g_build_filename(app->configdir, GEANY_TEMPLATES_SUBDIR,
-						"templates.README", NULL);
-
-		if (! g_file_test(templates_dir, G_FILE_TEST_EXISTS))
-		{
-			saved_errno = utils_mkdir(templates_dir, FALSE);
-		}
-		if (saved_errno == 0 && ! g_file_test(templates_readme, G_FILE_TEST_EXISTS))
-		{
-			gchar *text = g_strconcat(
-"There are several template files in this directory. For these templates you can use wildcards.\n\
-For more information read the documentation (in ", app->docdir, G_DIR_SEPARATOR_S "index.html or visit " GEANY_HOMEPAGE ").",
-					NULL);
-			utils_write_file(templates_readme, text);
-			g_free(text);
-		}
-		g_free(templates_readme);
-	}
-
-	g_free(filedefs_dir);
-	g_free(templates_dir);
-	g_free(conf_file);
-
-	return saved_errno;
-}
-
-
-/* Returns 0 if config dir is OK. */
-static gint setup_config_dir(void)
-{
-	gint mkdir_result = 0;
-
-	/* convert configdir to locale encoding to avoid troubles */
-	SETPTR(app->configdir, utils_get_locale_from_utf8(app->configdir));
-
-	mkdir_result = create_config_dir();
-	if (mkdir_result != 0)
-	{
-		if (! dialogs_show_question(
-			_("Configuration directory could not be created (%s).\nThere could be some problems "
-			  "using Geany without a configuration directory.\nStart Geany anyway?"),
-			  g_strerror(mkdir_result)))
-		{
-			exit(0);
-		}
-	}
-	/* make configdir a real path */
-	if (g_file_test(app->configdir, G_FILE_TEST_EXISTS))
-		SETPTR(app->configdir, tm_get_real_path(app->configdir));
-
-	return mkdir_result;
-}
-
-/* Signal handling removed since main_quit() uses functions that are
- * illegal in signal handlers
-static void signal_cb(gint sig)
-{
-	if (sig == SIGTERM)
-	{
-		main_quit();
-	}
-}
- */
-
-/* Used for command-line arguments at startup or from socket.
- * this will strip any :line:col filename suffix from locale_filename */
-gboolean main_handle_filename(const gchar *locale_filename)
-{
-	GeanyDocument *doc;
-	gint line = -1, column = -1;
-	gchar *filename;
-
-	g_return_val_if_fail(locale_filename, FALSE);
-
-	/* check whether the passed filename is an URI */
-	filename = utils_get_path_from_uri(locale_filename);
-	if (filename == NULL)
-		return FALSE;
-
-	get_line_and_column_from_filename(filename, &line, &column);
-	if (line >= 0)
-		cl_options.goto_line = line;
-	if (column >= 0)
-		cl_options.goto_column = column;
-
-	if (g_file_test(filename, G_FILE_TEST_IS_REGULAR))
-	{
-		doc = document_open_file(filename, cl_options.readonly, NULL, NULL);
-		/* add recent file manually if opening_session_files is set */
-		if (doc != NULL && main_status.opening_session_files)
-			ui_add_recent_document(doc);
-		g_free(filename);
-		return TRUE;
-	}
-	else if (file_prefs.cmdline_new_files)
-	{	/* create new file with the given filename */
-		gchar *utf8_filename = utils_get_utf8_from_locale(filename);
-
-		doc = document_new_file(utf8_filename, NULL, NULL);
-		if (doc != NULL)
-			ui_add_recent_document(doc);
-		g_free(utf8_filename);
-		g_free(filename);
-		return TRUE;
-	}
-	g_free(filename);
-	return FALSE;
-}
-
-
-/* open files from command line */
-static void open_cl_files(gint argc, gchar **argv)
-{
-	gint i;
-
-	for (i = 1; i < argc; i++)
-	{
-		gchar *filename = main_get_argv_filename(argv[i]);
-
-		if (g_file_test(filename, G_FILE_TEST_IS_DIR))
-		{
-			g_free(filename);
-			continue;
-		}
-
-#ifdef G_OS_WIN32
-		/* It seems argv elements are encoded in CP1252 on a German Windows */
-		SETPTR(filename, g_locale_to_utf8(filename, -1, NULL, NULL, NULL));
-#endif
-		if (filename && ! main_handle_filename(filename))
-		{
-			const gchar *msg = _("Could not find file '%s'.");
-
-			g_printerr(msg, filename);	/* also print to the terminal */
-			g_printerr("\n");
-			ui_set_statusbar(TRUE, msg, filename);
-		}
-		g_free(filename);
-	}
-}
-
-
-static void load_session_project_file(void)
-{
-	gchar *locale_filename;
-
-	g_return_if_fail(project_prefs.session_file != NULL);
-
-	locale_filename = utils_get_locale_from_utf8(project_prefs.session_file);
-
-	if (G_LIKELY(!EMPTY(locale_filename)))
-		project_load_file(locale_filename);
-
-	g_free(locale_filename);
-	g_free(project_prefs.session_file);	/* no longer needed */
-}
-
-
-static void load_settings(void)
-{
-	configuration_load();
-	/* let cmdline options overwrite configuration settings */
-#ifdef HAVE_VTE
-	vte_info.have_vte = (no_vte) ? FALSE : vte_info.load_vte;
-#endif
-	if (no_msgwin)
-		ui_prefs.msgwindow_visible = FALSE;
-
-#ifdef HAVE_PLUGINS
-	want_plugins = prefs.load_plugins && !no_plugins;
-#endif
-}
-
-
-void main_load_project_from_command_line(const gchar *locale_filename, gboolean use_session)
-{
-	gchar *pfile;
-
-	pfile = utils_get_path_from_uri(locale_filename);
-	if (pfile != NULL)
-	{
-		if (use_session)
-			project_load_file_with_session(pfile);
-		else
-			project_load_file(pfile);
-	}
-	g_free(pfile);
-}
-
-
-static void load_startup_files(gint argc, gchar **argv)
-{
-	gboolean load_session = FALSE;
-
-	if (argc > 1 && g_str_has_suffix(argv[1], ".geany"))
-	{
-		gchar *filename = main_get_argv_filename(argv[1]);
-
-		/* project file specified: load it, but decide the session later */
-		main_load_project_from_command_line(filename, FALSE);
-		argc--, argv++;
-		/* force session load if using project-based session files */
-		load_session = project_prefs.project_session;
-		g_free(filename);
-	}
-
-	/* Load the default session if:
-	 * 1. "Load files from the last session" is active.
-	 * 2. --no-session is not specified.
-	 * 3. We are a primary instance.
-	 * Has no effect if a CL project is loaded and using project-based session files. */
-	if (prefs.load_session && cl_options.load_session && !cl_options.new_instance)
-	{
-		if (app->project == NULL)
-			load_session_project_file();
-		load_session = TRUE;
-	}
-
-	if (load_session)
-	{
-		/* load session files into tabs, as they are found in the session_files variable */
-		configuration_open_files();
-
-		if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook)) == 0)
-		{
-			ui_update_popup_copy_items(NULL);
-			ui_update_popup_reundo_items(NULL);
-		}
-	}
-
-	open_cl_files(argc, argv);
-}
-
-
-static gboolean send_startup_complete(gpointer data)
-{
-	g_signal_emit_by_name(geany_object, "geany-startup-complete");
-	return FALSE;
-}
-
-
-static const gchar *get_locale(void)
+int main(int argc, char **argv)
 {
-	const gchar *locale = "unknown";
-#ifdef HAVE_LOCALE_H
-	locale = setlocale(LC_CTYPE, NULL);
-#endif
-	return locale;
-}
-
-
-#if ! GTK_CHECK_VERSION(3, 0, 0)
-/* This prepends our own gtkrc file to the list of RC files to be loaded by GTK at startup.
- * This function *has* to be called before gtk_init().
- *
- * We have a custom RC file defining various styles we need, and we want the user to be
- * able to override them (e.g. if they want -- or need -- other colors).  Fair enough, one
- * would simply call gtk_rc_parse() with the appropriate filename.  However, the styling
- * rules applies in the order they are loaded, then if we load our styles after GTK has
- * loaded the user's ones we'd override them.
- *
- * There are 2 solutions to fix this:
- * 1) set our styles' priority to something with lower than "user" (actually "theme"
- *    priority because rules precedence are first calculated depending on the priority
- *    no matter of how precise the rules is, so we need to override the theme).
- * 2) prepend our custom style to GTK's list while keeping priority to user (which is the
- *    default), so it gets loaded before real user's ones and so gets overridden by them.
- *
- * One would normally go for 1 because it's ways simpler and requires less code: you just
- * have to add the priorities to your styles, which is a matter of adding a few ":theme" in
- * the RC file.  However, KDE being a bitch it doesn't set the gtk-theme-name but rather
- * directly includes the style to use in a user gtkrc file, which makes the theme have
- * "user" priority, hence overriding our styles.  So, we cannot set priorities in the RC
- * file if we want to support running under KDE, which pretty much leave us with no choice
- * but to go with solution 2, which unfortunately requires writing ugly code since GTK
- * don't have a gtk_rc_prepend_default_file() function.  Thank you very much KDE.
- *
- * Though, as a side benefit it also makes the code work with people using gtk-chtheme,
- * which also found it funny to include the theme in the user RC file. */
-static void setup_gtk2_styles(void)
-{
-	gchar **gtk_files = gtk_rc_get_default_files();
-	gchar **new_files = g_malloc(sizeof *new_files * (g_strv_length(gtk_files) + 2));
-	guint i = 0;
-
-	new_files[i++] = g_build_filename(app->datadir, "geany.gtkrc", NULL);
-	for (; *gtk_files; gtk_files++)
-		new_files[i++] = g_strdup(*gtk_files);
-	new_files[i] = NULL;
-
-	gtk_rc_set_default_files(new_files);
-
-	g_strfreev(new_files);
-}
-#endif
-
-
-gint main(gint argc, gchar **argv)
-{
-	GeanyDocument *doc;
-	gint config_dir_result;
-	const gchar *locale;
-
-#if ! GLIB_CHECK_VERSION(2, 36, 0)
-	g_type_init();
-#endif
-
-	log_handlers_init();
-
-	app = g_new0(GeanyApp, 1);
-	memset(&main_status, 0, sizeof(GeanyStatus));
-	memset(&prefs, 0, sizeof(GeanyPrefs));
-	memset(&interface_prefs, 0, sizeof(GeanyInterfacePrefs));
-	memset(&toolbar_prefs, 0, sizeof(GeanyToolbarPrefs));
-	memset(&file_prefs, 0, sizeof(GeanyFilePrefs));
-	memset(&search_prefs, 0, sizeof(GeanySearchPrefs));
-	memset(&tool_prefs, 0, sizeof(GeanyToolPrefs));
-	memset(&template_prefs, 0, sizeof(GeanyTemplatePrefs));
-	memset(&ui_prefs, 0, sizeof(UIPrefs));
-	memset(&ui_widgets, 0, sizeof(UIWidgets));
-
-	setup_paths();
-#if ! GTK_CHECK_VERSION(3, 0, 0)
-	setup_gtk2_styles();
-#endif
-#ifdef ENABLE_NLS
-	main_locale_init(utils_resource_dir(RESOURCE_DIR_LOCALE), GETTEXT_PACKAGE);
-#endif
-	parse_command_line_options(&argc, &argv);
-
-#if ! GLIB_CHECK_VERSION(2, 32, 0)
-	/* Initialize GLib's thread system in case any plugins want to use it or their
-	 * dependencies (e.g. WebKit, Soup, ...). Deprecated since GLIB 2.32. */
-	if (!g_thread_supported())
-		g_thread_init(NULL);
-#endif
-
-	/* removed as signal handling was wrong, see signal_cb()
-	signal(SIGTERM, signal_cb); */
-
-#ifdef G_OS_UNIX
-	/* ignore SIGPIPE signal for preventing sudden death of program */
-	signal(SIGPIPE, SIG_IGN);
-#endif
-
-	config_dir_result = setup_config_dir();
-#ifdef HAVE_SOCKET
-	/* check and create (unix domain) socket for remote operation */
-	if (! socket_info.ignore_socket)
-	{
-		socket_info.lock_socket = -1;
-		socket_info.lock_socket_tag = 0;
-		socket_info.lock_socket = socket_init(argc, argv);
-		/* Quit if filenames were sent to first instance or the list of open
-		 * documents has been printed */
-		if ((socket_info.lock_socket == -2 /* socket exists */ && argc > 1) ||
-			cl_options.list_documents)
-		{
-			socket_finalize();
-			gdk_notify_startup_complete();
-			g_free(app->configdir);
-			g_free(app->datadir);
-			g_free(app->docdir);
-			g_free(app);
-			return 0;
-		}
-		/* Start a new instance if no command line strings were passed,
-		 * even if the socket already exists */
-		else if (socket_info.lock_socket == -2 /* socket already exists */)
-		{
-			socket_info.ignore_socket = TRUE;
-			cl_options.new_instance = TRUE;
-		}
-	}
-#endif
-
-#ifdef G_OS_WIN32
-	/* after we initialized the socket code and handled command line args,
-	 * let's change the working directory on Windows to not lock it */
-	change_working_directory_on_windows();
-#endif
-
-	locale = get_locale();
-	geany_debug("Geany %s, %s",
-		main_get_version_string(),
-		locale);
-	geany_debug(geany_lib_versions,
-		gtk_major_version, gtk_minor_version, gtk_micro_version,
-		glib_major_version, glib_minor_version, glib_micro_version);
-	geany_debug("System data dir: %s", app->datadir);
-	geany_debug("User config dir: %s", app->configdir);
-
-	/* create the object so Geany signals can be connected in init() functions */
-	geany_object = geany_object_new();
-
-	/* inits */
-	main_init();
-
-	encodings_init();
-	editor_init();
-
-	/* init stash groups before loading keyfile */
-	configuration_init();
-	ui_init_prefs();
-	search_init();
-	project_init();
-#ifdef HAVE_PLUGINS
-	plugins_init();
-#endif
-	sidebar_init();
-	load_settings();	/* load keyfile */
-
-	msgwin_init();
-	build_init();
-	ui_create_insert_menu_items();
-	ui_create_insert_date_menu_items();
-	keybindings_init();
-	notebook_init();
-	filetypes_init();
-	templates_init();
-	navqueue_init();
-	document_init_doclist();
-	symbols_init();
-	editor_snippets_init();
-
-#ifdef HAVE_VTE
-	vte_init();
-#endif
-	ui_create_recent_menus();
-
-	ui_set_statusbar(TRUE, _("This is Geany %s."), main_get_version_string());
-	if (config_dir_result != 0)
-		ui_set_statusbar(TRUE, _("Configuration directory could not be created (%s)."),
-			g_strerror(config_dir_result));
-
-	/* apply all configuration options */
-	apply_settings();
-
-#ifdef HAVE_PLUGINS
-	/* load any enabled plugins before we open any documents */
-	if (want_plugins)
-		plugins_load_active();
-#endif
-
-	ui_sidebar_show_hide();
-
-	/* set the active sidebar page after plugins have been loaded */
-	gtk_notebook_set_current_page(GTK_NOTEBOOK(main_widgets.sidebar_notebook), ui_prefs.sidebar_page);
-
-	/* load keybinding settings after plugins have added their groups */
-	keybindings_load_keyfile();
-
-	/* create the custom command menu after the keybindings have been loaded to have the proper
-	 * accelerator shown for the menu items */
-	tools_create_insert_custom_command_menu_items();
-
-	/* load any command line files or session files */
-	main_status.opening_session_files = TRUE;
-	load_startup_files(argc, argv);
-	main_status.opening_session_files = FALSE;
-
-	/* open a new file if no other file was opened */
-	document_new_file_if_non_open();
-
-	ui_document_buttons_update();
-	ui_save_buttons_toggle(FALSE);
-
-	doc = document_get_current();
-	sidebar_select_openfiles_item(doc);
-	build_menu_update(doc);
-	sidebar_update_tag_list(doc, FALSE);
-
-#ifdef G_OS_WIN32
-	/* Manually realise the main window to be able to set the position but don't show it.
-	 * We don't set the position after showing the window to avoid flickering. */
-	gtk_widget_realize(main_widgets.window);
-#endif
-	setup_window_position();
-
-	/* finally show the window */
-	document_grab_focus(doc);
-	gtk_widget_show(main_widgets.window);
-	main_status.main_window_realized = TRUE;
-
-	configuration_apply_settings();
-
-#ifdef HAVE_SOCKET
-	/* register the callback of socket input */
-	if (! socket_info.ignore_socket && socket_info.lock_socket > 0)
-	{
-		socket_info.read_ioc = g_io_channel_unix_new(socket_info.lock_socket);
-		socket_info.lock_socket_tag = g_io_add_watch(socket_info.read_ioc,
-						G_IO_IN | G_IO_PRI | G_IO_ERR, socket_lock_input_cb, main_widgets.window);
-	}
-#endif
-
-	/* when we are really done with setting everything up and the main event loop is running,
-	 * tell other components, mainly plugins, that startup is complete */
-	g_idle_add_full(G_PRIORITY_LOW, send_startup_complete, NULL, NULL);
-
-#ifdef MAC_INTEGRATION
-	/* OS X application ready - has to be called before entering main loop */
-	gtkosx_application_ready(gtkosx_application_get());
-#endif
-	
-	gtk_main();
-	return 0;
-}
-
-
-static void queue_free(GQueue *queue)
-{
-	while (! g_queue_is_empty(queue))
-	{
-		g_free(g_queue_pop_tail(queue));
-	}
-	g_queue_free(queue);
-}
-
-
-static void do_main_quit(void)
-{
-	geany_debug("Quitting...");
-
-	configuration_save();
-
-	if (app->project != NULL)
-		project_close(FALSE);   /* save project session files */
-
-	document_close_all();
-
-	main_status.quitting = TRUE;
-
-#ifdef HAVE_SOCKET
-	socket_finalize();
-#endif
-
-#ifdef HAVE_PLUGINS
-	plugins_finalize();
-#endif
-
-	navqueue_free();
-	keybindings_free();
-	notebook_free();
-	highlighting_free_styles();
-	templates_free_templates();
-	msgwin_finalize();
-	search_finalize();
-	build_finalize();
-	document_finalize();
-	symbols_finalize();
-	project_finalize();
-	editor_finalize();
-	editor_snippets_free();
-	encodings_finalize();
-	toolbar_finalize();
-	sidebar_finalize();
-	configuration_finalize();
-	filetypes_free_types();
-	log_finalize();
-
-	tm_workspace_free();
-	g_free(app->configdir);
-	g_free(app->datadir);
-	g_free(app->docdir);
-	g_free(prefs.default_open_path);
-	g_free(prefs.custom_plugin_path);
-	g_free(ui_prefs.custom_date_format);
-	g_free(interface_prefs.editor_font);
-	g_free(interface_prefs.tagbar_font);
-	g_free(interface_prefs.msgwin_font);
-	g_free(editor_prefs.long_line_color);
-	g_free(editor_prefs.comment_toggle_mark);
-	g_free(editor_prefs.color_scheme);
-	g_free(tool_prefs.context_action_cmd);
-	g_free(template_prefs.developer);
-	g_free(template_prefs.company);
-	g_free(template_prefs.mail);
-	g_free(template_prefs.initials);
-	g_free(template_prefs.version);
-	g_free(tool_prefs.term_cmd);
-	g_free(tool_prefs.browser_cmd);
-	g_free(tool_prefs.grep_cmd);
-	g_free(printing_prefs.external_print_cmd);
-	g_free(printing_prefs.page_header_datefmt);
-	g_strfreev(ui_prefs.custom_commands);
-	g_strfreev(ui_prefs.custom_commands_labels);
-
-	queue_free(ui_prefs.recent_queue);
-	queue_free(ui_prefs.recent_projects_queue);
-
-	if (ui_widgets.prefs_dialog && GTK_IS_WIDGET(ui_widgets.prefs_dialog)) gtk_widget_destroy(ui_widgets.prefs_dialog);
-	if (ui_widgets.open_fontsel && GTK_IS_WIDGET(ui_widgets.open_fontsel)) gtk_widget_destroy(ui_widgets.open_fontsel);
-	if (ui_widgets.open_colorsel && GTK_IS_WIDGET(ui_widgets.open_colorsel)) gtk_widget_destroy(ui_widgets.open_colorsel);
-#ifdef HAVE_VTE
-	if (vte_info.have_vte) vte_close();
-	g_free(vte_info.lib_vte);
-	g_free(vte_info.dir);
-#endif
-	gtk_widget_destroy(main_widgets.window);
-
-	/* destroy popup menus */
-	if (main_widgets.editor_menu && GTK_IS_WIDGET(main_widgets.editor_menu))
-					gtk_widget_destroy(main_widgets.editor_menu);
-	if (ui_widgets.toolbar_menu && GTK_IS_WIDGET(ui_widgets.toolbar_menu))
-					gtk_widget_destroy(ui_widgets.toolbar_menu);
-	if (msgwindow.popup_status_menu && GTK_IS_WIDGET(msgwindow.popup_status_menu))
-					gtk_widget_destroy(msgwindow.popup_status_menu);
-	if (msgwindow.popup_msg_menu && GTK_IS_WIDGET(msgwindow.popup_msg_menu))
-					gtk_widget_destroy(msgwindow.popup_msg_menu);
-	if (msgwindow.popup_compiler_menu && GTK_IS_WIDGET(msgwindow.popup_compiler_menu))
-					gtk_widget_destroy(msgwindow.popup_compiler_menu);
-
-	g_object_unref(geany_object);
-	geany_object = NULL;
-
-	g_free(original_cwd);
-	g_free(app);
-
-	ui_finalize_builder();
-
-	gtk_main_quit();
-}
-
-
-static gboolean check_no_unsaved(void)
-{
-	guint i;
-
-	for (i = 0; i < documents_array->len; i++)
-	{
-		if (documents[i]->is_valid && documents[i]->changed)
-		{
-			return FALSE;
-		}
-	}
-	return TRUE;    /* no unsaved edits */
-}
-
-
-/* Returns false when quitting is aborted due to user cancellation */
-gboolean main_quit(void)
-{
-	main_status.quitting = TRUE;
-
-	if (! check_no_unsaved())
-	{
-		if (document_account_for_unsaved())
-		{
-			do_main_quit();
-			return TRUE;
-		}
-	}
-	else
-	if (! prefs.confirm_exit ||
-		dialogs_show_question_full(NULL, GTK_STOCK_QUIT, GTK_STOCK_CANCEL, NULL,
-			_("Do you really want to quit?")))
-	{
-		do_main_quit();
-		return TRUE;
-	}
-
-	main_status.quitting = FALSE;
-	return FALSE;
-}
-
-/**
- *  Reloads most of Geany's configuration files without restarting. Currently the following
- *  files are reloaded: all template files, also new file templates and the 'New (with template)'
- *  menus will be updated, Snippets (snippets.conf), filetype extensions (filetype_extensions.conf),
- *  and 'settings' and 'build_settings' sections of the filetype definition files.
- *
- *  Plugins may call this function if they changed any of these files (e.g. a configuration file
- *  editor plugin).
- *
- *  @since 0.15
- **/
-GEANY_API_SYMBOL
-void main_reload_configuration(void)
-{
-	/* reload templates */
-	templates_free_templates();
-	templates_init();
-
-	/* reload snippets */
-	editor_snippets_free();
-	editor_snippets_init();
-
-	filetypes_reload_extensions();
-	filetypes_reload();
-
-	/* C tag names to ignore */
-	symbols_reload_config_files();
-
-	ui_set_statusbar(TRUE, _("Configuration files reloaded."));
+	return main_lib(argc, argv);
 }


Modified: src/main.h
2 lines changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -75,6 +75,8 @@ gboolean main_handle_filename(const gchar *locale_filename);
 
 void main_load_project_from_command_line(const gchar *locale_filename, gboolean use_session);
 
+gint main_lib(gint argc, gchar **argv);
+
 #endif /* GEANY_PRIVATE */
 
 G_END_DECLS


Modified: tagmanager/ctags/Makefile.am
7 lines changed, 4 insertions(+), 3 deletions(-)
===================================================================
@@ -3,12 +3,13 @@ AM_CPPFLAGS = \
 	-I$(srcdir)/.. \
 	-DG_LOG_DOMAIN=\"CTags\"
 AM_CFLAGS = \
-	$(GTK_CFLAGS)
+	$(GTK_CFLAGS) \
+	-fvisibility=hidden
 
 EXTRA_DIST = \
 	makefile.win32
 
-noinst_LIBRARIES = libctags.a
+noinst_LTLIBRARIES = libctags.la
 
 parsers = \
 	abaqus.c \
@@ -53,7 +54,7 @@ parsers = \
 	verilog.c \
 	vhdl.c
 
-libctags_a_SOURCES = \
+libctags_la_SOURCES = \
 	args.c \
 	args.h \
 	ctags.c \


Modified: tagmanager/mio/Makefile.am
6 lines changed, 3 insertions(+), 3 deletions(-)
===================================================================
@@ -1,9 +1,9 @@
-noinst_LIBRARIES = libmio.a
+noinst_LTLIBRARIES = libmio.la
 
 AM_CPPFLAGS = -DG_LOG_DOMAIN=\"MIO\" #-DMIO_DEBUG
-AM_CFLAGS   = $(GTK_CFLAGS)
+AM_CFLAGS   = $(GTK_CFLAGS) -fvisibility=hidden
 
-libmio_a_SOURCES = mio.c
+libmio_la_SOURCES = mio.c
 
 EXTRA_DIST = \
 	mio.h \


Modified: tagmanager/src/Makefile.am
7 lines changed, 4 insertions(+), 3 deletions(-)
===================================================================
@@ -5,12 +5,13 @@ AM_CPPFLAGS = \
 	-DGEANY_PRIVATE \
 	-DG_LOG_DOMAIN=\"Tagmanager\"
 AM_CFLAGS = \
-	$(GTK_CFLAGS)
+	$(GTK_CFLAGS) \
+	-fvisibility=hidden
 
 EXTRA_DIST = \
 	makefile.win32
 
-noinst_LIBRARIES = libtagmanager.a
+noinst_LTLIBRARIES = libtagmanager.la
 
 tagmanager_includedir = $(includedir)/geany/tagmanager
 tagmanager_include_HEADERS = \
@@ -20,7 +21,7 @@ tagmanager_include_HEADERS = \
 	tm_workspace.h
 
 
-libtagmanager_a_SOURCES =\
+libtagmanager_la_SOURCES =\
 	tm_tagmanager.h \
 	tm_parser.h \
 	tm_source_file.h \



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list