[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