Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
0f07b31aa8 |
255
ChangeLog.sm
Normal file
255
ChangeLog.sm
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
2012-03-06:
|
||||||
|
|
||||||
|
* src/sm.c:
|
||||||
|
On normal (non-sm) exit, only delete the session file if
|
||||||
|
running under Gnome, to preserve permanent sessions.
|
||||||
|
* src/main.c:
|
||||||
|
Updated for the new load_startup_files().
|
||||||
|
|
||||||
|
2012-01-06 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/sm.c:
|
||||||
|
Don't interact if running under xfce sm - until they fix it.
|
||||||
|
Don't save yourself if main window is not realized, that's some
|
||||||
|
startup message loop and the configuration is not initialized.
|
||||||
|
|
||||||
|
2011-07-10 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/callbacks.c:
|
||||||
|
Include sm.h for sm_discard().
|
||||||
|
* src/sm.c:
|
||||||
|
Include glib/gstdio.h for g_unlink().
|
||||||
|
Don't disable the main window while exiting. Nobody does, and if
|
||||||
|
anything, the Window Manager should do it.
|
||||||
|
|
||||||
|
2011-04-24 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/keyfile.c, src/keyfile.h, src/sm.c:
|
||||||
|
Updated to free the string returned from utils_build_path().
|
||||||
|
|
||||||
|
2011-04-09 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/keyfile.c, src/keyfile.h, src/sm.c:
|
||||||
|
Updated to use utils_build_path().
|
||||||
|
* src/sm.c:
|
||||||
|
Use g_path_is_absolute() instead of checking for G_DIR_SEPARATOR.
|
||||||
|
* src/document.c:
|
||||||
|
Don't check for external document changes while exiting a session
|
||||||
|
to prevent reload file prompts.
|
||||||
|
|
||||||
|
2010-10-16 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/main.c:
|
||||||
|
Replaced new_session with load_default_session. May also be used
|
||||||
|
for "Open at the same workspace", to inhibit loading the default
|
||||||
|
session if another primary instance is already running.
|
||||||
|
|
||||||
|
2010-10-09 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/main.c, src/main.h:
|
||||||
|
Reverted cl_options.socket_filename, since "Open files in Geany at
|
||||||
|
the same workspace" was reverted.
|
||||||
|
|
||||||
|
* src/sm.c:
|
||||||
|
Some refactoring and documentation fixes.
|
||||||
|
|
||||||
|
2010-10-08 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/sm.c:
|
||||||
|
On shutdown cancelled: don't call save done if already done, signal
|
||||||
|
save yourself failed.
|
||||||
|
If interaction is required but refused, at least save configuration
|
||||||
|
and signal success.
|
||||||
|
|
||||||
|
2010-09-26 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/stash.c:
|
||||||
|
Reverted 5121's always write the default value for [missing]
|
||||||
|
hidden preference. Not significant enough for a workaround.
|
||||||
|
|
||||||
|
2010-09-25 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/main.c, src/main.h
|
||||||
|
Replaced cl_options.socket_filename with socket_info.file_name to
|
||||||
|
support "Open files in Geany at the same workspace".
|
||||||
|
|
||||||
|
2010-07-05 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/sm.c:
|
||||||
|
Try to expand relative executable name. For GSM.
|
||||||
|
|
||||||
|
* src/sm.c, src/callbacks.c:
|
||||||
|
Remove the session file on normal (non-sm) quit. For GSM.
|
||||||
|
|
||||||
|
* src/keyfile.c:
|
||||||
|
Don't check the session file with G_FILE_TEST_IS_SYMLINK.
|
||||||
|
|
||||||
|
* src/sm.c, src/sm.h, src/main.c, src/utils.c, src/utils.h:
|
||||||
|
Replaced type * identifier with type *identifier.
|
||||||
|
|
||||||
|
2010-06-20 Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/main.c:
|
||||||
|
Simply g_strdup(alternate_config) to preserve it, as suggested by
|
||||||
|
Eugene Arshinov.
|
||||||
|
|
||||||
|
* src/utils.c, src/sm.c:
|
||||||
|
Store the filenames directly instead of using tm_get_real_path().
|
||||||
|
|
||||||
|
* src/utils.c:
|
||||||
|
Don't store zero integer arguments.
|
||||||
|
|
||||||
|
2010-05-20 Dimitar Zhekov <hamster(at)mbox(dot)contact(dot)bg>
|
||||||
|
|
||||||
|
* src/sm.c:
|
||||||
|
Don't save configuration on interactive SmSaveGlobal.
|
||||||
|
Don't ask to cancel shutdown if not a shutdown.
|
||||||
|
Don't set the userid property if the user name can't be determined.
|
||||||
|
|
||||||
|
2010-05-19 Dimitar Zhekov <hamster(at)mbox(dot)contact(dot)bg>
|
||||||
|
|
||||||
|
* src/main.c:
|
||||||
|
Altered setup_config_dir() to avoid discarding alternate_config.
|
||||||
|
|
||||||
|
* src/document.c, src/keyfile.c:
|
||||||
|
Fixed a few bugs.
|
||||||
|
|
||||||
|
* src/sm.c:
|
||||||
|
Moved the interactive configuration_save() after SmcInteractDone(),
|
||||||
|
so that any Untitled files are remembered with their new names.
|
||||||
|
|
||||||
|
2010-05-18 Dimitar Zhekov <hamster(at)mbox(dot)contact(dot)bg>
|
||||||
|
|
||||||
|
* src/sm.c, src/main.h, src/callbacks.c:
|
||||||
|
Prevent user interaction with Geany between save yourself done and
|
||||||
|
save complete / die / cancel shutdown. See sm_prevent_interaction().
|
||||||
|
|
||||||
|
* src/keyfile.c, src/keyfile.h
|
||||||
|
configuration_load(): renamed suffix to libsm_client_id, fallback to
|
||||||
|
geany.conf if session file not found.
|
||||||
|
configuration_load(): renamed suffix to libsm_client_id, save file
|
||||||
|
list if libsm_client_id != NULL.
|
||||||
|
|
||||||
|
2010-05-17 Dimitar Zhekov <hamster(at)mbox(dot)contact(dot)bg>
|
||||||
|
|
||||||
|
* src/sm.c, src/sm.h:
|
||||||
|
Modified all sm_ callbacks to handle the sm1 shutdown.
|
||||||
|
|
||||||
|
* src/document.c, src/document.h:
|
||||||
|
Extracted the prompt-and-save part of document_account_for_unsaved()
|
||||||
|
in a new document_prompt_for_unsaved() function to preserve the
|
||||||
|
"modified" file flags in the case of a cancelled shutdown.
|
||||||
|
|
||||||
|
* src/callbacks.c:
|
||||||
|
Reverted the changes not required for sm1.
|
||||||
|
|
||||||
|
2010-05-16 Dimitar Zhekov <hamster(at)mbox(dot)contact(dot)bg>
|
||||||
|
|
||||||
|
* src/utils.c, src/utils.h:
|
||||||
|
Altered utils_option_entry_reverse_parse() to support only the types
|
||||||
|
used by optentries[] and to expand relative filenames to absolute.
|
||||||
|
|
||||||
|
* src/keyfile.c, src/keyfile.h:
|
||||||
|
Added configuration_name(suffix), added support for suffix in
|
||||||
|
configuration_load() and configuration_save(). Altered some other
|
||||||
|
functions to use configuration_name().
|
||||||
|
|
||||||
|
2010-05-15 Dimitar Zhekov <hamster(at)mbox(dot)contact(dot)bg>
|
||||||
|
|
||||||
|
* src/main.c:
|
||||||
|
Changes to load_session_project_file(), load_settings() and
|
||||||
|
load_startup_files() to handle the x11 session startup variant.
|
||||||
|
|
||||||
|
* src/project.c, src/project.h:
|
||||||
|
Added load_session parameter project_load_file() and load_config().
|
||||||
|
X11 session startup passes FALSE to avoid loading project files.
|
||||||
|
|
||||||
|
* src/sm.c:
|
||||||
|
Combined sm_*_props() into sm_set_props(), invoked from sm_init().
|
||||||
|
|
||||||
|
2010-05-14 Dimitar Zhekov <hamster(at)mbox(dot)contact(dot)bg>
|
||||||
|
|
||||||
|
* geany.glade, src/interface.c, src/keyfile.c, src/prefs.c,
|
||||||
|
src/prefs.h, src/project.c, src/project.h, srs/utils.c, src/utils.h,
|
||||||
|
src/main.c, src/main.h:
|
||||||
|
Removed the changes that will not be required for sm1: "load session
|
||||||
|
even if any files opened", "--new-instance implies --no-session",
|
||||||
|
"--project". Reverted load_startup_files().
|
||||||
|
|
||||||
|
* src/main.c:
|
||||||
|
Marked "--no-session" as non-persistent. The open files should be
|
||||||
|
restored as they were when Geany was stopped, not started.
|
||||||
|
|
||||||
|
* src/main.c:
|
||||||
|
Moved sm_init() before main_init() so that the session main window
|
||||||
|
attributes can be applied. Replaced gtk_set_client_id() with
|
||||||
|
gdk_set_sm_client_id().
|
||||||
|
|
||||||
|
2010-02-23 Eugene Arshinov <earshinov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/main.c:
|
||||||
|
Change the behaviour of the setting controlled by "Preferences >
|
||||||
|
General > Misc > Use project-based session files" check button. Now
|
||||||
|
if you open a project via command-line, files from the default
|
||||||
|
session are not automatically appended to it.
|
||||||
|
|
||||||
|
|
||||||
|
2010-02-22 Eugene Arshinov <earshinov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/main.c, src/main.h, src/socket.c:
|
||||||
|
Use a separate command-line option to specify a project to be opened.
|
||||||
|
* src/sm.c:
|
||||||
|
Remember opened project across restarts.
|
||||||
|
* src/socket.c:
|
||||||
|
Fix opening project in already running instance (via socket).
|
||||||
|
|
||||||
|
|
||||||
|
2010-02-15 Eugene Arshinov <earshinov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/project.c, src/sm.c, src/utils.c, src/utils.h:
|
||||||
|
Use absolute paths to project files. Particularly, paths to recent
|
||||||
|
projects' files are now stored as absolute.
|
||||||
|
* src/main.c:
|
||||||
|
Load files from command line even if a project is being opened.
|
||||||
|
* geany.glade, src/interface.c, src/keyfile.c, src/main.c,
|
||||||
|
src/prefs.c, src/prefs.h:
|
||||||
|
Add a GUI preference to control whether the default session is
|
||||||
|
loaded if any files are opened via command-line (fix #2838686).
|
||||||
|
Location of the preference: General > Startup tab > Startup frame.
|
||||||
|
|
||||||
|
|
||||||
|
2010-02-07 Eugene Arshinov <earshinov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* src/main.c:
|
||||||
|
Rewrite load_startup_files() function. Fix the bug with opening a
|
||||||
|
project while specifying -s command line option. E.g.,
|
||||||
|
`geany -s project.geany' now correctly loads the project instead of
|
||||||
|
showing a blank document and clearing the project silently.
|
||||||
|
|
||||||
|
|
||||||
|
2010-01-24 Eugene Arshinov <earshinov(at)gmail(dot)com>
|
||||||
|
|
||||||
|
* doc/Doxyfile.in, src/Makefile.am, src/main.c, src/makefile.win32,
|
||||||
|
src/sm.c, src/sm.h, wscript:
|
||||||
|
Extract libSM-related code into separate sm.{c,h} files, make some
|
||||||
|
refactoring, and write code comments for Doxygen.
|
||||||
|
* src/keyfile.c, src/main.c:
|
||||||
|
Make --new-instance command line option imply --no-session.
|
||||||
|
* src/sm.c:
|
||||||
|
Handle --no-session command line option properly.
|
||||||
|
* src/main.c, src/main.h, src/sm.c, src/utils.c, src/utils.h:
|
||||||
|
Add "reverse parser" of GOptionEntry. Handle all command-line options.
|
||||||
|
|
||||||
|
|
||||||
|
2009-12-08 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
|
||||||
|
|
||||||
|
* src/Makefile.am, configure.in, wscript:
|
||||||
|
Detect libSM X session management library (patch by Eugene Arshinov,
|
||||||
|
thanks).
|
||||||
|
* src/project.c, src/project.h, src/callbacks.c, src/document.c,
|
||||||
|
src/document.h, src/main.c, src/main.h:
|
||||||
|
Refactor quitting code into main_save() and main_finalize() (patch by
|
||||||
|
Eugene Arshinov, thanks).
|
||||||
|
* src/main.c:
|
||||||
|
Restart Geany and restore some state when logging in (patch by
|
||||||
|
Eugene Arshinov, thanks).
|
20
configure.ac
20
configure.ac
@ -94,6 +94,26 @@ GEANY_CHECK_THE_FORCE dnl hehe
|
|||||||
# i18n
|
# i18n
|
||||||
GEANY_I18N
|
GEANY_I18N
|
||||||
|
|
||||||
|
# libSM for X session management
|
||||||
|
SM_LIBS=""
|
||||||
|
AC_ARG_ENABLE(libsm,
|
||||||
|
[ --enable-libsm enable X session management support [[]]],
|
||||||
|
[enable_libsm=$enableval], [enable_libsm=yes])
|
||||||
|
AC_MSG_CHECKING([whether to use LibSM])
|
||||||
|
if test x"$enable_libsm" = xyes; then
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_CHECK_HEADERS(X11/SM/SMlib.h, [SM_LIBS="-lSM -lICE"], enable_libsm=no)
|
||||||
|
if test x"$enable_libsm" = xyes; then
|
||||||
|
AC_DEFINE(HAVE_LIBSM, 1, [Define to 1 if you have libSM installed])
|
||||||
|
else
|
||||||
|
AC_MSG_WARN([X session management will not be supported])
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
fi
|
||||||
|
AC_SUBST(SM_LIBS)
|
||||||
|
|
||||||
|
|
||||||
GEANY_DATA_DIR=`eval echo ${datarootdir}/geany`
|
GEANY_DATA_DIR=`eval echo ${datarootdir}/geany`
|
||||||
AC_SUBST([GEANY_DATA_DIR])
|
AC_SUBST([GEANY_DATA_DIR])
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ SEARCH_INCLUDES = NO
|
|||||||
INCLUDE_PATH =
|
INCLUDE_PATH =
|
||||||
INCLUDE_FILE_PATTERNS =
|
INCLUDE_FILE_PATTERNS =
|
||||||
# make G_GNUC_PRINTF a no-op unless doxygen would ignore functions with varargs
|
# make G_GNUC_PRINTF a no-op unless doxygen would ignore functions with varargs
|
||||||
PREDEFINED = "G_GNUC_PRINTF(x,y)=" HAVE_PLUGINS GEANY_FUNCTIONS_H
|
PREDEFINED = "G_GNUC_PRINTF(x,y)=" HAVE_PLUGINS GEANY_FUNCTIONS_H HAVE_LIBSM
|
||||||
EXPAND_AS_DEFINED =
|
EXPAND_AS_DEFINED =
|
||||||
SKIP_FUNCTION_MACROS = NO
|
SKIP_FUNCTION_MACROS = NO
|
||||||
#---------------------------------------------------------------------------
|
#---------------------------------------------------------------------------
|
||||||
|
@ -37,6 +37,7 @@ SRCS = \
|
|||||||
project.c project.h \
|
project.c project.h \
|
||||||
sciwrappers.c sciwrappers.h \
|
sciwrappers.c sciwrappers.h \
|
||||||
search.c search.h \
|
search.c search.h \
|
||||||
|
sm.c sm.h \
|
||||||
socket.c socket.h \
|
socket.c socket.h \
|
||||||
stash.c stash.h \
|
stash.c stash.h \
|
||||||
support.h \
|
support.h \
|
||||||
@ -131,6 +132,7 @@ geany_LDADD = \
|
|||||||
$(top_builddir)/tagmanager/src/libtagmanager.a \
|
$(top_builddir)/tagmanager/src/libtagmanager.a \
|
||||||
@GTK_LIBS@ \
|
@GTK_LIBS@ \
|
||||||
@GTHREAD_LIBS@ \
|
@GTHREAD_LIBS@ \
|
||||||
|
@SM_LIBS@ \
|
||||||
$(INTLLIBS)
|
$(INTLLIBS)
|
||||||
|
|
||||||
AM_CFLAGS = -DGEANY_DATADIR=\""$(datadir)"\" \
|
AM_CFLAGS = -DGEANY_DATADIR=\""$(datadir)"\" \
|
||||||
|
@ -65,6 +65,7 @@
|
|||||||
#include "toolbar.h"
|
#include "toolbar.h"
|
||||||
#include "highlighting.h"
|
#include "highlighting.h"
|
||||||
#include "pluginutils.h"
|
#include "pluginutils.h"
|
||||||
|
#include "sm.h"
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_VTE
|
#ifdef HAVE_VTE
|
||||||
@ -86,21 +87,6 @@ static gboolean insert_callback_from_menu = FALSE;
|
|||||||
/*static gboolean switch_tv_notebook_page = FALSE; */
|
/*static gboolean switch_tv_notebook_page = FALSE; */
|
||||||
|
|
||||||
|
|
||||||
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 */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* set editor_info.click_pos to the current cursor position if insert_callback_from_menu is TRUE
|
/* set editor_info.click_pos to the current cursor position if insert_callback_from_menu is TRUE
|
||||||
* to prevent invalid cursor positions which can cause segfaults */
|
* to prevent invalid cursor positions which can cause segfaults */
|
||||||
static void verify_click_pos(GeanyDocument *doc)
|
static void verify_click_pos(GeanyDocument *doc)
|
||||||
@ -116,7 +102,7 @@ static void verify_click_pos(GeanyDocument *doc)
|
|||||||
/* should only be called from on_exit_clicked */
|
/* should only be called from on_exit_clicked */
|
||||||
static void quit_app(void)
|
static void quit_app(void)
|
||||||
{
|
{
|
||||||
configuration_save();
|
configuration_save(NULL);
|
||||||
|
|
||||||
if (app->project != NULL)
|
if (app->project != NULL)
|
||||||
project_close(FALSE); /* save project session files */
|
project_close(FALSE); /* save project session files */
|
||||||
@ -125,6 +111,7 @@ static void quit_app(void)
|
|||||||
|
|
||||||
main_status.quitting = TRUE;
|
main_status.quitting = TRUE;
|
||||||
|
|
||||||
|
sm_discard();
|
||||||
main_quit();
|
main_quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,9 +119,12 @@ static void quit_app(void)
|
|||||||
/* wrapper function to abort exit process if cancel button is pressed */
|
/* wrapper function to abort exit process if cancel button is pressed */
|
||||||
G_MODULE_EXPORT gboolean on_exit_clicked(GtkWidget *widget, gpointer gdata)
|
G_MODULE_EXPORT gboolean on_exit_clicked(GtkWidget *widget, gpointer gdata)
|
||||||
{
|
{
|
||||||
|
if (main_status.prevent_interaction)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
main_status.quitting = TRUE;
|
main_status.quitting = TRUE;
|
||||||
|
|
||||||
if (! check_no_unsaved())
|
if (document_any_unsaved())
|
||||||
{
|
{
|
||||||
if (document_account_for_unsaved())
|
if (document_account_for_unsaved())
|
||||||
{
|
{
|
||||||
|
@ -2765,12 +2765,23 @@ GeanyDocument *document_clone(GeanyDocument *old_doc, const gchar *utf8_filename
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* @note If successful, this should always be followed up with a call to
|
/* @return TRUE if there are some unsaved documents */
|
||||||
* document_close_all().
|
gboolean document_any_unsaved(void)
|
||||||
* @return TRUE if all files were saved or had their changes discarded. */
|
|
||||||
gboolean document_account_for_unsaved(void)
|
|
||||||
{
|
{
|
||||||
guint i, p, page_count;
|
guint i;
|
||||||
|
|
||||||
|
foreach_document(i)
|
||||||
|
if (documents[i]->changed)
|
||||||
|
return TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* @return TRUE if all files were saved or had their changes discarded.
|
||||||
|
* The files with discarded changes remain marked as modified. */
|
||||||
|
gboolean document_prompt_for_unsaved(void)
|
||||||
|
{
|
||||||
|
guint p, page_count;
|
||||||
|
|
||||||
page_count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook));
|
page_count = gtk_notebook_get_n_pages(GTK_NOTEBOOK(main_widgets.notebook));
|
||||||
/* iterate over documents in tabs order */
|
/* iterate over documents in tabs order */
|
||||||
@ -2784,6 +2795,19 @@ gboolean document_account_for_unsaved(void)
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* @note If successful, this should always be followed up with a call to
|
||||||
|
* document_close_all().
|
||||||
|
* @return TRUE if all files were saved or had their changes discarded. */
|
||||||
|
gboolean document_account_for_unsaved(void)
|
||||||
|
{
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
if (!document_prompt_for_unsaved())
|
||||||
|
return FALSE;
|
||||||
/* all documents should now be accounted for, so ignore any changes */
|
/* all documents should now be accounted for, so ignore any changes */
|
||||||
foreach_document (i)
|
foreach_document (i)
|
||||||
{
|
{
|
||||||
@ -2901,6 +2925,10 @@ gboolean document_check_disk_status(GeanyDocument *doc, gboolean force)
|
|||||||
|| doc->real_path == NULL || doc->priv->is_remote)
|
|| doc->real_path == NULL || doc->priv->is_remote)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
/* ignore changes while exiting session */
|
||||||
|
if (main_status.prevent_interaction)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
use_gio_filemon = (doc->priv->monitor != NULL);
|
use_gio_filemon = (doc->priv->monitor != NULL);
|
||||||
|
|
||||||
if (use_gio_filemon)
|
if (use_gio_filemon)
|
||||||
|
@ -206,6 +206,10 @@ void document_try_focus(GeanyDocument *doc, GtkWidget *source_widget);
|
|||||||
|
|
||||||
gboolean document_close(GeanyDocument *doc);
|
gboolean document_close(GeanyDocument *doc);
|
||||||
|
|
||||||
|
gboolean document_any_unsaved(void);
|
||||||
|
|
||||||
|
gboolean document_prompt_for_unsaved(void);
|
||||||
|
|
||||||
gboolean document_account_for_unsaved(void);
|
gboolean document_account_for_unsaved(void);
|
||||||
|
|
||||||
gboolean document_close_all(void);
|
gboolean document_close_all(void);
|
||||||
|
@ -573,10 +573,10 @@ static void save_ui_prefs(GKeyFile *config)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void configuration_save(void)
|
void configuration_save(const gchar *libsm_client_id)
|
||||||
{
|
{
|
||||||
GKeyFile *config = g_key_file_new();
|
GKeyFile *config = g_key_file_new();
|
||||||
gchar *configfile = g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "geany.conf", NULL);
|
gchar *configfile = configuration_name(libsm_client_id);
|
||||||
gchar *data;
|
gchar *data;
|
||||||
|
|
||||||
g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL);
|
g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL);
|
||||||
@ -590,7 +590,7 @@ void configuration_save(void)
|
|||||||
save_recent_files(config, ui_prefs.recent_queue, "recent_files");
|
save_recent_files(config, ui_prefs.recent_queue, "recent_files");
|
||||||
save_recent_files(config, ui_prefs.recent_projects_queue, "recent_projects");
|
save_recent_files(config, ui_prefs.recent_projects_queue, "recent_projects");
|
||||||
|
|
||||||
if (cl_options.load_session)
|
if (cl_options.load_session || libsm_client_id)
|
||||||
configuration_save_session_files(config);
|
configuration_save_session_files(config);
|
||||||
#ifdef HAVE_VTE
|
#ifdef HAVE_VTE
|
||||||
else if (vte_info.have_vte)
|
else if (vte_info.have_vte)
|
||||||
@ -984,7 +984,7 @@ static void load_ui_prefs(GKeyFile *config)
|
|||||||
*/
|
*/
|
||||||
void configuration_save_default_session(void)
|
void configuration_save_default_session(void)
|
||||||
{
|
{
|
||||||
gchar *configfile = g_strconcat(app->configdir, G_DIR_SEPARATOR_S, "geany.conf", NULL);
|
gchar *configfile = configuration_name(NULL);
|
||||||
gchar *data;
|
gchar *data;
|
||||||
GKeyFile *config = g_key_file_new();
|
GKeyFile *config = g_key_file_new();
|
||||||
|
|
||||||
@ -1008,7 +1008,7 @@ void configuration_save_default_session(void)
|
|||||||
*/
|
*/
|
||||||
void configuration_reload_default_session(void)
|
void configuration_reload_default_session(void)
|
||||||
{
|
{
|
||||||
gchar *configfile = g_build_filename(app->configdir, "geany.conf", NULL);
|
gchar *configfile = configuration_name(NULL);
|
||||||
GKeyFile *config = g_key_file_new();
|
GKeyFile *config = g_key_file_new();
|
||||||
|
|
||||||
g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL);
|
g_key_file_load_from_file(config, configfile, G_KEY_FILE_NONE, NULL);
|
||||||
@ -1020,11 +1020,18 @@ void configuration_reload_default_session(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gboolean configuration_load(void)
|
gboolean configuration_load(const gchar *libsm_client_id)
|
||||||
{
|
{
|
||||||
gchar *configfile = g_build_filename(app->configdir, "geany.conf", NULL);
|
gchar *configfile = configuration_name(libsm_client_id);
|
||||||
GKeyFile *config = g_key_file_new();
|
GKeyFile *config = g_key_file_new();
|
||||||
|
|
||||||
|
if (libsm_client_id && ! g_file_test(configfile, G_FILE_TEST_IS_REGULAR))
|
||||||
|
{ /* session config file does not exist, so try falling back to geany.conf */
|
||||||
|
geany_debug("No session config file found, trying to use default configuration.");
|
||||||
|
g_free(configfile);
|
||||||
|
configfile = configuration_name(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (! g_file_test(configfile, G_FILE_TEST_IS_REGULAR))
|
if (! g_file_test(configfile, G_FILE_TEST_IS_REGULAR))
|
||||||
{ /* config file does not (yet) exist, so try to load a global config file which may be */
|
{ /* config file does not (yet) exist, so try to load a global config file which may be */
|
||||||
/* created by distributors */
|
/* created by distributors */
|
||||||
@ -1216,3 +1223,20 @@ void configuration_finalize(void)
|
|||||||
g_ptr_array_free(keyfile_groups, TRUE);
|
g_ptr_array_free(keyfile_groups, TRUE);
|
||||||
g_ptr_array_free(pref_groups, TRUE);
|
g_ptr_array_free(pref_groups, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gchar *configuration_name(const gchar *suffix)
|
||||||
|
{
|
||||||
|
gchar *configfile;
|
||||||
|
|
||||||
|
if (suffix)
|
||||||
|
{
|
||||||
|
gchar *configbase = g_strconcat("geany-", suffix, ".conf", NULL);
|
||||||
|
configfile = g_build_filename(app->configdir, configbase, NULL);
|
||||||
|
g_free(configbase);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
configfile = g_build_filename(app->configdir, "geany.conf", NULL);
|
||||||
|
|
||||||
|
return configfile;
|
||||||
|
}
|
||||||
|
@ -37,9 +37,12 @@ void configuration_add_pref_group(struct StashGroup *group, gboolean for_prefs_d
|
|||||||
|
|
||||||
void configuration_add_various_pref_group(struct StashGroup *group);
|
void configuration_add_various_pref_group(struct StashGroup *group);
|
||||||
|
|
||||||
void configuration_save(void);
|
/* return newly allocated "app->configdir/geany[-suffix].conf" name */
|
||||||
|
gchar *configuration_name(const gchar *suffix);
|
||||||
|
|
||||||
gboolean configuration_load(void);
|
void configuration_save(const gchar *libsm_client_id);
|
||||||
|
|
||||||
|
gboolean configuration_load(const gchar *libsm_client_id);
|
||||||
|
|
||||||
void configuration_open_files(void);
|
void configuration_open_files(void);
|
||||||
|
|
||||||
|
62
src/main.c
62
src/main.c
@ -71,6 +71,7 @@
|
|||||||
#include "printing.h"
|
#include "printing.h"
|
||||||
#include "toolbar.h"
|
#include "toolbar.h"
|
||||||
#include "geanyobject.h"
|
#include "geanyobject.h"
|
||||||
|
#include "sm.h"
|
||||||
|
|
||||||
#ifdef HAVE_SOCKET
|
#ifdef HAVE_SOCKET
|
||||||
# include "socket.h"
|
# include "socket.h"
|
||||||
@ -114,9 +115,17 @@ static gboolean print_prefix = FALSE;
|
|||||||
static gboolean no_plugins = FALSE;
|
static gboolean no_plugins = FALSE;
|
||||||
#endif
|
#endif
|
||||||
static gboolean dummy = FALSE;
|
static gboolean dummy = FALSE;
|
||||||
|
static gchar *libsm_client_id = NULL;
|
||||||
|
|
||||||
|
/* WARNING: Do not change values of variables where values of command-line options are stored!
|
||||||
|
* This is, they should remain unchanged after `g_option_context_parse' returns.
|
||||||
|
* Otherwise, "restart command" for X session management may be filled improperly.
|
||||||
|
*
|
||||||
|
* NOTE: Currently optentries of type G_OPTION_ARG_CALLBACK are not supported by
|
||||||
|
* X session management support implementation.
|
||||||
|
*/
|
||||||
/* in alphabetical order of short options */
|
/* in alphabetical order of short options */
|
||||||
static GOptionEntry entries[] =
|
GOptionEntry optentries[] =
|
||||||
{
|
{
|
||||||
{ "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 },
|
{ "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 },
|
{ "config", 'c', 0, G_OPTION_ARG_FILENAME, &alternate_config, N_("Use an alternate configuration directory"), NULL },
|
||||||
@ -144,9 +153,41 @@ static GOptionEntry entries[] =
|
|||||||
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose_mode, N_("Be verbose"), NULL },
|
{ "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 },
|
{ "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 */
|
{ "dummy", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &dummy, NULL, NULL }, /* for +NNN line number arguments */
|
||||||
|
{ "libsm-client-id", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &libsm_client_id, NULL, NULL },
|
||||||
|
/* add new options here and in `optentries_aux' below */
|
||||||
{ NULL, 0, 0, 0, NULL, NULL, NULL }
|
{ NULL, 0, 0, 0, NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GeanyOptionEntryAux optentries_aux[] = {
|
||||||
|
{FALSE}, /* "column" */
|
||||||
|
{TRUE}, /* "config" */
|
||||||
|
{FALSE}, /* "ft-names */
|
||||||
|
{FALSE}, /* "generate-tags" */
|
||||||
|
{FALSE}, /* "no-preprocessing" */
|
||||||
|
#ifdef HAVE_SOCKET
|
||||||
|
{TRUE}, /* "new-instance" */
|
||||||
|
{TRUE}, /* "socket-file" */
|
||||||
|
{FALSE}, /* "list-documents" */
|
||||||
|
#endif
|
||||||
|
{FALSE}, /* "line" */
|
||||||
|
{TRUE}, /* "no-msgwin" */
|
||||||
|
{TRUE}, /* "no-ctags" */
|
||||||
|
#ifdef HAVE_PLUGINS
|
||||||
|
{TRUE}, /* "no-plugins" */
|
||||||
|
#endif
|
||||||
|
{FALSE}, /* "print-prefix" */
|
||||||
|
{FALSE}, /* "read-only" */
|
||||||
|
{FALSE}, /* "no-session" */
|
||||||
|
#ifdef HAVE_VTE
|
||||||
|
{TRUE}, /* "no-terminal" */
|
||||||
|
{TRUE}, /* "vte-lib" */
|
||||||
|
#endif
|
||||||
|
{TRUE}, /* "verbose" */
|
||||||
|
{FALSE}, /* "version" */
|
||||||
|
{FALSE}, /* "dummy" */
|
||||||
|
{FALSE}, /* "libsm-client-id" option is handled separately */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static void setup_window_position(void)
|
static void setup_window_position(void)
|
||||||
{
|
{
|
||||||
@ -514,7 +555,7 @@ static void parse_command_line_options(gint *argc, gchar ***argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
context = g_option_context_new(_("[FILES...]"));
|
context = g_option_context_new(_("[FILES...]"));
|
||||||
g_option_context_add_main_entries(context, entries, GETTEXT_PACKAGE);
|
g_option_context_add_main_entries(context, optentries, GETTEXT_PACKAGE);
|
||||||
g_option_group_set_translation_domain(g_option_context_get_main_group(context), 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_add_group(context, gtk_get_option_group(FALSE));
|
||||||
g_option_context_parse(context, argc, argv, &error);
|
g_option_context_parse(context, argc, argv, &error);
|
||||||
@ -566,7 +607,7 @@ static void parse_command_line_options(gint *argc, gchar ***argv)
|
|||||||
if (alternate_config)
|
if (alternate_config)
|
||||||
{
|
{
|
||||||
geany_debug("alternate config: %s", alternate_config);
|
geany_debug("alternate config: %s", alternate_config);
|
||||||
app->configdir = alternate_config;
|
app->configdir = g_strdup(alternate_config);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -845,7 +886,7 @@ static void load_session_project_file(void)
|
|||||||
locale_filename = utils_get_locale_from_utf8(project_prefs.session_file);
|
locale_filename = utils_get_locale_from_utf8(project_prefs.session_file);
|
||||||
|
|
||||||
if (G_LIKELY(NZV(locale_filename)))
|
if (G_LIKELY(NZV(locale_filename)))
|
||||||
project_load_file(locale_filename);
|
project_load_file(locale_filename, libsm_client_id == NULL);
|
||||||
|
|
||||||
g_free(locale_filename);
|
g_free(locale_filename);
|
||||||
g_free(project_prefs.session_file); /* no longer needed */
|
g_free(project_prefs.session_file); /* no longer needed */
|
||||||
@ -854,7 +895,7 @@ static void load_session_project_file(void)
|
|||||||
|
|
||||||
static void load_settings(void)
|
static void load_settings(void)
|
||||||
{
|
{
|
||||||
configuration_load();
|
configuration_load(libsm_client_id);
|
||||||
/* let cmdline options overwrite configuration settings */
|
/* let cmdline options overwrite configuration settings */
|
||||||
#ifdef HAVE_VTE
|
#ifdef HAVE_VTE
|
||||||
vte_info.have_vte = (no_vte) ? FALSE : vte_info.load_vte;
|
vte_info.have_vte = (no_vte) ? FALSE : vte_info.load_vte;
|
||||||
@ -878,7 +919,7 @@ void main_load_project_from_command_line(const gchar *locale_filename, gboolean
|
|||||||
if (use_session)
|
if (use_session)
|
||||||
project_load_file_with_session(pfile);
|
project_load_file_with_session(pfile);
|
||||||
else
|
else
|
||||||
project_load_file(pfile);
|
project_load_file(pfile, TRUE);
|
||||||
}
|
}
|
||||||
g_free(pfile);
|
g_free(pfile);
|
||||||
}
|
}
|
||||||
@ -901,8 +942,10 @@ static void load_startup_files(gint argc, gchar **argv)
|
|||||||
* 1. "Load files from the last session" is active.
|
* 1. "Load files from the last session" is active.
|
||||||
* 2. --no-session is not specified.
|
* 2. --no-session is not specified.
|
||||||
* 3. We are a primary instance.
|
* 3. We are a primary instance.
|
||||||
* Has no effect if a CL project is loaded and using project-based session files. */
|
* 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)
|
* Alternative XSMP case: load the xsmp session files, there is no CL project. */
|
||||||
|
if ((prefs.load_session && cl_options.load_session && !cl_options.new_instance) ||
|
||||||
|
libsm_client_id)
|
||||||
{
|
{
|
||||||
if (app->project == NULL)
|
if (app->project == NULL)
|
||||||
load_session_project_file();
|
load_session_project_file();
|
||||||
@ -1024,6 +1067,7 @@ gint main(gint argc, gchar **argv)
|
|||||||
geany_object = geany_object_new();
|
geany_object = geany_object_new();
|
||||||
|
|
||||||
/* inits */
|
/* inits */
|
||||||
|
sm_init(argv[0], libsm_client_id);
|
||||||
main_init();
|
main_init();
|
||||||
|
|
||||||
encodings_init();
|
encodings_init();
|
||||||
@ -1171,6 +1215,8 @@ void main_quit()
|
|||||||
{
|
{
|
||||||
geany_debug("Quitting...");
|
geany_debug("Quitting...");
|
||||||
|
|
||||||
|
sm_finalize();
|
||||||
|
|
||||||
#ifdef HAVE_SOCKET
|
#ifdef HAVE_SOCKET
|
||||||
socket_finalize();
|
socket_finalize();
|
||||||
#endif
|
#endif
|
||||||
|
15
src/main.h
15
src/main.h
@ -23,6 +23,20 @@
|
|||||||
#ifndef GEANY_MAIN_H
|
#ifndef GEANY_MAIN_H
|
||||||
#define GEANY_MAIN_H
|
#define GEANY_MAIN_H
|
||||||
|
|
||||||
|
/** Information about command line entries that can not be stored in GOptionEntry. */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Indicates whether the value of a command-line option should go to "restart command".
|
||||||
|
* See X session management support implementation in sm.{c,h}.
|
||||||
|
*/
|
||||||
|
gboolean persist_upon_restart;
|
||||||
|
}
|
||||||
|
GeanyOptionEntryAux;
|
||||||
|
|
||||||
|
extern GOptionEntry optentries[];
|
||||||
|
extern GeanyOptionEntryAux optentries_aux[];
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
gboolean new_instance;
|
gboolean new_instance;
|
||||||
@ -46,6 +60,7 @@ typedef struct GeanyStatus
|
|||||||
* (used to prevent notebook switch page signals) */
|
* (used to prevent notebook switch page signals) */
|
||||||
gboolean quitting; /* state when Geany is quitting completely */
|
gboolean quitting; /* state when Geany is quitting completely */
|
||||||
gboolean main_window_realized;
|
gboolean main_window_realized;
|
||||||
|
gboolean prevent_interaction; /* state while saving SM session; the main window is locked */
|
||||||
}
|
}
|
||||||
GeanyStatus;
|
GeanyStatus;
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ endif
|
|||||||
OBJS = about.o build.o callbacks.o dialogs.o document.o editor.o encodings.o filetypes.o \
|
OBJS = about.o build.o callbacks.o dialogs.o document.o editor.o encodings.o filetypes.o \
|
||||||
geanyentryaction.o geanymenubuttonaction.o geanyobject.o geanywraplabel.o highlighting.o \
|
geanyentryaction.o geanymenubuttonaction.o geanyobject.o geanywraplabel.o highlighting.o \
|
||||||
keybindings.o keyfile.o log.o main.o msgwindow.o navqueue.o notebook.o \
|
keybindings.o keyfile.o log.o main.o msgwindow.o navqueue.o notebook.o \
|
||||||
plugins.o pluginutils.o prefs.o printing.o project.o sciwrappers.o search.o \
|
plugins.o pluginutils.o prefs.o printing.o project.o sciwrappers.o search.o sm.o \
|
||||||
socket.o stash.o symbols.o templates.o toolbar.o tools.o sidebar.o \
|
socket.o stash.o symbols.o templates.o toolbar.o tools.o sidebar.o \
|
||||||
ui_utils.o utils.o win32.o
|
ui_utils.o utils.o win32.o
|
||||||
|
|
||||||
|
@ -1269,7 +1269,7 @@ on_prefs_dialog_response(GtkDialog *dialog, gint response, gpointer user_data)
|
|||||||
ui_update_statusbar(doc, -1);
|
ui_update_statusbar(doc, -1);
|
||||||
|
|
||||||
/* store all settings */
|
/* store all settings */
|
||||||
configuration_save();
|
configuration_save(NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response == GTK_RESPONSE_HELP)
|
if (response == GTK_RESPONSE_HELP)
|
||||||
|
@ -80,7 +80,7 @@ typedef struct _PropertyDialogElements
|
|||||||
|
|
||||||
static gboolean update_config(const PropertyDialogElements *e, gboolean new_project);
|
static gboolean update_config(const PropertyDialogElements *e, gboolean new_project);
|
||||||
static void on_file_save_button_clicked(GtkButton *button, PropertyDialogElements *e);
|
static void on_file_save_button_clicked(GtkButton *button, PropertyDialogElements *e);
|
||||||
static gboolean load_config(const gchar *filename);
|
static gboolean load_config(const gchar *filename, gboolean load_session);
|
||||||
static gboolean write_config(gboolean emit_signal);
|
static gboolean write_config(gboolean emit_signal);
|
||||||
static void on_name_entry_changed(GtkEditable *editable, PropertyDialogElements *e);
|
static void on_name_entry_changed(GtkEditable *editable, PropertyDialogElements *e);
|
||||||
static void on_entries_changed(GtkEditable *editable, PropertyDialogElements *e);
|
static void on_entries_changed(GtkEditable *editable, PropertyDialogElements *e);
|
||||||
@ -211,7 +211,7 @@ void project_new(void)
|
|||||||
|
|
||||||
gboolean project_load_file_with_session(const gchar *locale_file_name)
|
gboolean project_load_file_with_session(const gchar *locale_file_name)
|
||||||
{
|
{
|
||||||
if (project_load_file(locale_file_name))
|
if (project_load_file(locale_file_name, TRUE))
|
||||||
{
|
{
|
||||||
if (project_prefs.project_session)
|
if (project_prefs.project_session)
|
||||||
{
|
{
|
||||||
@ -929,11 +929,11 @@ static void on_radio_long_line_custom_toggled(GtkToggleButton *radio, GtkWidget
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
gboolean project_load_file(const gchar *locale_file_name)
|
gboolean project_load_file(const gchar *locale_file_name, gboolean load_session)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail(locale_file_name != NULL, FALSE);
|
g_return_val_if_fail(locale_file_name != NULL, FALSE);
|
||||||
|
|
||||||
if (load_config(locale_file_name))
|
if (load_config(locale_file_name, load_session))
|
||||||
{
|
{
|
||||||
gchar *utf8_filename = utils_get_utf8_from_locale(locale_file_name);
|
gchar *utf8_filename = utils_get_utf8_from_locale(locale_file_name);
|
||||||
|
|
||||||
@ -957,8 +957,9 @@ gboolean project_load_file(const gchar *locale_file_name)
|
|||||||
/* Reads the given filename and creates a new project with the data found in the file.
|
/* Reads the given filename and creates a new project with the data found in the file.
|
||||||
* At this point there should not be an already opened project in Geany otherwise it will just
|
* At this point there should not be an already opened project in Geany otherwise it will just
|
||||||
* return.
|
* return.
|
||||||
* The filename is expected in the locale encoding. */
|
* The filename is expected in the locale encoding. Both project_session preference and
|
||||||
static gboolean load_config(const gchar *filename)
|
* load_session must be TRUE for the project session files to be loaded. */
|
||||||
|
static gboolean load_config(const gchar *filename, gboolean load_session)
|
||||||
{
|
{
|
||||||
GKeyFile *config;
|
GKeyFile *config;
|
||||||
GeanyProject *p;
|
GeanyProject *p;
|
||||||
@ -992,7 +993,7 @@ static gboolean load_config(const gchar *filename)
|
|||||||
apply_editor_prefs();
|
apply_editor_prefs();
|
||||||
|
|
||||||
build_load_menu(config, GEANY_BCS_PROJ, (gpointer)p);
|
build_load_menu(config, GEANY_BCS_PROJ, (gpointer)p);
|
||||||
if (project_prefs.project_session)
|
if (project_prefs.project_session && load_session)
|
||||||
{
|
{
|
||||||
/* save current (non-project) session (it could has been changed since program startup) */
|
/* save current (non-project) session (it could has been changed since program startup) */
|
||||||
configuration_save_default_session();
|
configuration_save_default_session();
|
||||||
|
@ -79,7 +79,7 @@ void project_build_properties(void);
|
|||||||
gboolean project_ask_close(void);
|
gboolean project_ask_close(void);
|
||||||
|
|
||||||
|
|
||||||
gboolean project_load_file(const gchar *locale_file_name);
|
gboolean project_load_file(const gchar *locale_file_name, gboolean load_session);
|
||||||
|
|
||||||
gboolean project_load_file_with_session(const gchar *locale_file_name);
|
gboolean project_load_file_with_session(const gchar *locale_file_name);
|
||||||
|
|
||||||
|
588
src/sm.c
Normal file
588
src/sm.c
Normal file
@ -0,0 +1,588 @@
|
|||||||
|
/*
|
||||||
|
* sm.c - this file is part of Geany, a fast and lightweight IDE
|
||||||
|
*
|
||||||
|
* Copyright 2009 Eugene Arshinov <earshinov(at)gmail(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.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Changes by Dimitar Zhekov <dimitar(dot)zhekov(at)gmail(dot)com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @file sm.c
|
||||||
|
* Provides X session management protocol (XSMP) support using libSM library.
|
||||||
|
*
|
||||||
|
* In order to support XSMP, we have to support Inter-Client Exchange
|
||||||
|
* Protocol (ICE). This file takes care of the latter too.
|
||||||
|
*
|
||||||
|
* Typical usage:
|
||||||
|
* @c sm_init() is called when Geany is starting.
|
||||||
|
* @c sm_discard() is called on normal (non-sm) quit.
|
||||||
|
* @c sm_finalize() is called when Geany is quitting.
|
||||||
|
*
|
||||||
|
* According to libSM documentation, client should retain the same ID after
|
||||||
|
* it is restarted. The main module (@c main.c) maintains "--libsm-client-id"
|
||||||
|
* command-line option and passes the specified value (if any) to @c sm_init().
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* As libSM is not available on Windows,
|
||||||
|
* it is safe enough to use POSIX-specific things here.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSM
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
#include <glib/gstdio.h>
|
||||||
|
|
||||||
|
#include <X11/SM/SMlib.h>
|
||||||
|
#include <X11/ICE/ICElib.h>
|
||||||
|
|
||||||
|
#include "geany.h"
|
||||||
|
#include "main.h" /* for cl_options, main_status */
|
||||||
|
#include "ui_utils.h" /* for main_widgets */
|
||||||
|
#include "document.h" /* for unsaved documents */
|
||||||
|
#include "utils.h" /* for option reverse parsing */
|
||||||
|
#include "keyfile.h" /* for configuration save */
|
||||||
|
|
||||||
|
|
||||||
|
static void ice_connection_watch(IceConn icecon, IcePointer client_data, Bool opening,
|
||||||
|
IcePointer *watch_data);
|
||||||
|
static gboolean ice_iochannel_watch(GIOChannel *source, GIOCondition condition, gpointer data);
|
||||||
|
|
||||||
|
static SmcConn sm_connect(const char *libsm_client_id);
|
||||||
|
static void sm_set_props(const char *argv0);
|
||||||
|
static void sm_prevent_interaction(gboolean prevent);
|
||||||
|
static void sm_finish_save(SmcConn smcon);
|
||||||
|
|
||||||
|
static void sm_save_yourself_callback(SmcConn smcon, SmPointer client_data,
|
||||||
|
int save_type, Bool shutdown, int interact_style, Bool fast);
|
||||||
|
static void sm_interact_callback(SmcConn smcon, SmPointer client_data);
|
||||||
|
static void sm_save_complete_callback(SmcConn smcon, SmPointer client_data);
|
||||||
|
static void sm_shutdown_cancelled_callback(SmcConn smcon, SmPointer client_data);
|
||||||
|
static void sm_die_callback(SmcConn smcon, SmPointer client_data);
|
||||||
|
|
||||||
|
|
||||||
|
/* LibSM connection object initialized in @c sm_init() and used in @c sm_finalize(). */
|
||||||
|
static SmcConn smc_conn = 0;
|
||||||
|
|
||||||
|
/* LibSM new client id. Initialized by @c sm_init() and used in many places. */
|
||||||
|
static char *new_client_id = NULL;
|
||||||
|
|
||||||
|
/* The save_type and shutdown values received by the last save yourself callback. */
|
||||||
|
static int sm_last_save_type;
|
||||||
|
static Bool sm_last_shutdown;
|
||||||
|
/* Whether the last save yourself request was completed and signalled as done. */
|
||||||
|
static gboolean sm_last_save_done;
|
||||||
|
|
||||||
|
/* To check for improper Gnome/Xfce xsmp implementations */
|
||||||
|
char *sm_vendor = NULL;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @name Exported functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize XSMP support.
|
||||||
|
*
|
||||||
|
* @param argv0 Value of @c argv[0] used to define Geany's restart command.
|
||||||
|
* @param libsm_client_id Client-ID specified with "--libsm-client-id" command line
|
||||||
|
* option or @c NULL if the option was not passed.
|
||||||
|
*
|
||||||
|
* This function connects to the session manager using @c sm_connect(). If
|
||||||
|
* everything is successful, it stores libSM connection object and the new session id
|
||||||
|
* in the global variables @c smcon and @c new_client_id, and calls @c sm_set_props().
|
||||||
|
*
|
||||||
|
* This function should be called on Geany startup, before the main window is realized.
|
||||||
|
*
|
||||||
|
* When Geany is compiled without XSMP support, this function is a no-op.
|
||||||
|
*/
|
||||||
|
void sm_init(const char *argv0, const char *libsm_client_id)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBSM
|
||||||
|
/* This function should be called once */
|
||||||
|
g_assert(!smc_conn);
|
||||||
|
if (smc_conn)
|
||||||
|
return;
|
||||||
|
|
||||||
|
smc_conn = sm_connect(libsm_client_id);
|
||||||
|
if (smc_conn)
|
||||||
|
{
|
||||||
|
sm_vendor = SmcVendor(smc_conn);
|
||||||
|
gdk_set_sm_client_id(new_client_id);
|
||||||
|
sm_set_props(argv0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove the saved session file.
|
||||||
|
*
|
||||||
|
* Should be called on normal (non-sm) Geany quit, since GSM does not execute
|
||||||
|
* the discard command. Ignored in other managers to preserve permanent sessions.
|
||||||
|
*
|
||||||
|
* When Geany is compiled without XSMP support, this function is a no-op.
|
||||||
|
*/
|
||||||
|
void sm_discard(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBSM
|
||||||
|
if (smc_conn && g_str_has_prefix(sm_vendor, "Gnome"))
|
||||||
|
{
|
||||||
|
gchar *configfile = configuration_name(new_client_id);
|
||||||
|
g_unlink(configfile);
|
||||||
|
g_free(configfile);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Perform cleanup.
|
||||||
|
*
|
||||||
|
* Call this function when XSMP support is no longer needed. In fact it is
|
||||||
|
* called when Geany is quitting.
|
||||||
|
*
|
||||||
|
* When Geany is compiled without XSMP support, this function is a no-op.
|
||||||
|
*/
|
||||||
|
void sm_finalize(void)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_LIBSM
|
||||||
|
if (smc_conn)
|
||||||
|
{
|
||||||
|
free(sm_vendor);
|
||||||
|
free(new_client_id);
|
||||||
|
SmcCloseConnection(smc_conn, 0, NULL);
|
||||||
|
smc_conn = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* @} */
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSM
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @name ICE support
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ICE connection watcher used to attach a GIOChannel to each ICE connection
|
||||||
|
* so that this connection can be handled in GTK main loop.
|
||||||
|
*
|
||||||
|
* @param icecon ICE connection.
|
||||||
|
* @param client_data Client data specified in @c IceAddConnectionWatch() function call.
|
||||||
|
* Currently it is not used.
|
||||||
|
* @param opening Whether @c icecon is opening or closing.
|
||||||
|
* @param watch_data A piece of data that can be set when @c icecon is opening and
|
||||||
|
* read when it is closing. We store GIOChannel watcher ID here.
|
||||||
|
*
|
||||||
|
* We attach @c ice_iochannel_watch GIOChannel watcher to every created GIOChannel
|
||||||
|
* in order to handle messages. This is how session manager communicates to Geany.
|
||||||
|
*
|
||||||
|
* @see sm_connect()
|
||||||
|
*/
|
||||||
|
static void ice_connection_watch(IceConn icecon, IcePointer client_data,
|
||||||
|
Bool opening, IcePointer *watch_data)
|
||||||
|
{
|
||||||
|
guint input_id;
|
||||||
|
|
||||||
|
if (opening)
|
||||||
|
{
|
||||||
|
GIOChannel *channel = g_io_channel_unix_new(IceConnectionNumber(icecon));
|
||||||
|
|
||||||
|
input_id = g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR,
|
||||||
|
ice_iochannel_watch, icecon);
|
||||||
|
g_io_channel_unref(channel);
|
||||||
|
*watch_data = (IcePointer) GUINT_TO_POINTER(input_id);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
input_id = GPOINTER_TO_UINT((gpointer) *watch_data);
|
||||||
|
g_source_remove(input_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A watcher attached to a GIOChannel corresponding to an ICE connection.
|
||||||
|
*
|
||||||
|
* @param source A GIOChannel corresponding to an ICE connection.
|
||||||
|
* @param condition
|
||||||
|
* @param data Client data specified in @c g_io_add_watch() function call.
|
||||||
|
* An ICE connection object (of type @c IceConn) is stored here.
|
||||||
|
* @return Return FALSE to remove the GIOChannel.
|
||||||
|
*
|
||||||
|
* This function calls @c IceProcessMessages causing an appropriate libSM
|
||||||
|
* callback to be invoked.
|
||||||
|
*
|
||||||
|
* @see ice_connection_watch()
|
||||||
|
*/
|
||||||
|
static gboolean ice_iochannel_watch(GIOChannel *source, GIOCondition condition, gpointer data)
|
||||||
|
{
|
||||||
|
IceConn icecon = (IceConn) data;
|
||||||
|
IceProcessMessages(icecon, NULL, NULL);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @}
|
||||||
|
* @name libSM support implementation
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Connect to the session manager.
|
||||||
|
*
|
||||||
|
* @param libsm_client_id LibSM client ID saved from the previous session,
|
||||||
|
* or @c NULL if there was no previous session.
|
||||||
|
* @return libSM connection object or @c 0 if connection to the session manager fails.
|
||||||
|
*/
|
||||||
|
static SmcConn sm_connect(const char *libsm_client_id)
|
||||||
|
{
|
||||||
|
static const SmcCallbacks callbacks = {
|
||||||
|
{ sm_save_yourself_callback, NULL },
|
||||||
|
{ sm_die_callback, NULL },
|
||||||
|
{ sm_save_complete_callback, NULL },
|
||||||
|
{ sm_shutdown_cancelled_callback, NULL } };
|
||||||
|
|
||||||
|
gchar err[256] = "";
|
||||||
|
SmcConn smcon;
|
||||||
|
|
||||||
|
if (!g_getenv("SESSION_MANAGER"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
IceAddConnectionWatch(ice_connection_watch, NULL);
|
||||||
|
|
||||||
|
smcon = SmcOpenConnection(NULL, NULL,
|
||||||
|
SmProtoMajor, SmProtoMinor,
|
||||||
|
SmcSaveYourselfProcMask |
|
||||||
|
SmcDieProcMask |
|
||||||
|
SmcSaveCompleteProcMask |
|
||||||
|
SmcShutdownCancelledProcMask,
|
||||||
|
(SmcCallbacks *) &callbacks,
|
||||||
|
(char *) libsm_client_id, &new_client_id,
|
||||||
|
sizeof err, err);
|
||||||
|
|
||||||
|
if (!smcon)
|
||||||
|
{
|
||||||
|
g_warning("While connecting to session manager:\n%s.", err);
|
||||||
|
IceRemoveConnectionWatch(ice_connection_watch, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return smcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set the libSM properties.
|
||||||
|
*
|
||||||
|
* @param argv0 Value of @c argv[0].
|
||||||
|
*/
|
||||||
|
static void sm_set_props(const char *argv0)
|
||||||
|
{
|
||||||
|
char *executable_path;
|
||||||
|
gchar *curdir = g_get_current_dir();
|
||||||
|
const gchar *username = g_get_user_name();
|
||||||
|
char *client_id_arg = g_strconcat("--libsm-client-id=", new_client_id, NULL);
|
||||||
|
gchar *configfile = configuration_name(new_client_id);
|
||||||
|
|
||||||
|
SmPropValue curdir_val = { strlen(curdir), curdir};
|
||||||
|
SmPropValue userid_val, program_val, client_id_val;
|
||||||
|
SmPropValue discard_val[3] = { { 2, "rm" }, { 2, "-f" },
|
||||||
|
{ strlen(configfile), (char *) configfile } };
|
||||||
|
|
||||||
|
SmProp program_prop = { SmProgram, SmARRAY8, 1, &program_val };
|
||||||
|
SmProp userid_prop = { SmUserID, SmARRAY8, 1, &userid_val };
|
||||||
|
SmProp curdir_prop = { SmCurrentDirectory, SmARRAY8, 1, &curdir_val };
|
||||||
|
SmProp restart_prop, clone_prop;
|
||||||
|
SmProp discard_prop = { SmDiscardCommand, SmLISTofARRAY8, 3, discard_val };
|
||||||
|
|
||||||
|
SmProp *props[4] = { &program_prop, &curdir_prop, &restart_prop, &discard_prop };
|
||||||
|
|
||||||
|
int i, arg_max, argc;
|
||||||
|
SmPropValue *arg_val;
|
||||||
|
|
||||||
|
/* -- end of declarations -- */
|
||||||
|
|
||||||
|
/* GSM does not work with relative executable names, try to obtain absolute. */
|
||||||
|
if (g_path_is_absolute(argv0) || (executable_path = tm_get_real_path(argv0)) == NULL)
|
||||||
|
executable_path = g_strdup(argv0);
|
||||||
|
|
||||||
|
program_val.length = strlen(executable_path);
|
||||||
|
program_val.value = executable_path;
|
||||||
|
client_id_val.length = strlen(client_id_arg);
|
||||||
|
client_id_val.value = client_id_arg;
|
||||||
|
|
||||||
|
for (i = 0, arg_max = 2; optentries[i].long_name; i++)
|
||||||
|
if (optentries_aux[i].persist_upon_restart)
|
||||||
|
arg_max++;
|
||||||
|
|
||||||
|
arg_val = g_new(SmPropValue, arg_max);
|
||||||
|
arg_val[0] = program_val;
|
||||||
|
arg_val[1] = client_id_val;
|
||||||
|
|
||||||
|
for (i = 0, argc = 2; optentries[i].long_name; i++)
|
||||||
|
{
|
||||||
|
if (optentries_aux[i].persist_upon_restart)
|
||||||
|
{
|
||||||
|
char *option = utils_option_entry_reverse_parse(&optentries[i]);
|
||||||
|
|
||||||
|
if (option)
|
||||||
|
{
|
||||||
|
arg_val[argc].length = strlen(option);
|
||||||
|
arg_val[argc].value = option;
|
||||||
|
argc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restart_prop.name = SmRestartCommand;
|
||||||
|
restart_prop.type = SmLISTofARRAY8;
|
||||||
|
restart_prop.num_vals = argc;
|
||||||
|
restart_prop.vals = arg_val;
|
||||||
|
|
||||||
|
SmcSetProperties(smc_conn, 4, props);
|
||||||
|
|
||||||
|
arg_val[1] = program_val;
|
||||||
|
clone_prop.name = SmCloneCommand;
|
||||||
|
clone_prop.type = SmLISTofARRAY8;
|
||||||
|
clone_prop.num_vals = argc - 1;
|
||||||
|
clone_prop.vals = arg_val + 1;
|
||||||
|
props[0] = &clone_prop;
|
||||||
|
SmcSetProperties(smc_conn, 1, props);
|
||||||
|
|
||||||
|
if (username)
|
||||||
|
{
|
||||||
|
userid_val.length = strlen(username);
|
||||||
|
userid_val.value = (char *) username;
|
||||||
|
props[0] = &userid_prop;
|
||||||
|
SmcSetProperties(smc_conn, 1, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free(executable_path);
|
||||||
|
g_free(curdir);
|
||||||
|
g_free(client_id_arg);
|
||||||
|
g_free(configfile);
|
||||||
|
for (i = 2; i < argc; i++)
|
||||||
|
g_free(arg_val[i].value);
|
||||||
|
g_free(arg_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @}
|
||||||
|
* @name Utility functions used by the libSM callbacks.
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Prevent/allow user interaction with Geany if shutting down.
|
||||||
|
*
|
||||||
|
* @param prevent TRUE to prevent interaction, FALSE to allow.
|
||||||
|
*
|
||||||
|
* The new 6.9/7.0 XSMP specification is not very clear whether interaction should
|
||||||
|
* be prevented if not shutting down. But the rationale is to prevent anything the
|
||||||
|
* user does after the save being lost, which can only happen if shutting down.
|
||||||
|
*/
|
||||||
|
static void sm_prevent_interaction(gboolean prevent)
|
||||||
|
{
|
||||||
|
if (sm_last_shutdown)
|
||||||
|
{
|
||||||
|
/* Disabling the main window takes time, nobody does it,
|
||||||
|
and that is window/session manager's job anyway. */
|
||||||
|
/*gtk_widget_set_sensitive(main_widgets.window, prevent == FALSE);*/
|
||||||
|
main_status.prevent_interaction = prevent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finish an interactive or non-interactive save yourself.
|
||||||
|
*
|
||||||
|
* @param smcon LibSM connection object.
|
||||||
|
*/
|
||||||
|
static void sm_finish_save(SmcConn smcon)
|
||||||
|
{
|
||||||
|
if (sm_last_save_type == SmSaveLocal || sm_last_save_type == SmSaveBoth)
|
||||||
|
configuration_save(new_client_id);
|
||||||
|
|
||||||
|
/* SaveYourselfDone() may take some time, while the assignment
|
||||||
|
is a single instruction. So it's safer in that order. */
|
||||||
|
sm_last_save_done = TRUE;
|
||||||
|
SmcSaveYourselfDone(smcon, TRUE);
|
||||||
|
sm_prevent_interaction(TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @}
|
||||||
|
* @name libSM callbacks
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Save Yourself" callback.
|
||||||
|
*
|
||||||
|
* @param smcon LibSM connection object.
|
||||||
|
* @param client_data Client data specified when the callback was registered.
|
||||||
|
* Currently it is not used.
|
||||||
|
* @param save_type Specifies the type of information that should be saved.
|
||||||
|
* @param shutdown Specifies if a shutdown is taking place.
|
||||||
|
* @param interact_style The type of interaction allowed with the user.
|
||||||
|
* @param fast If True, the client should save its state as quickly as possible.
|
||||||
|
*
|
||||||
|
* See libSM documentation for more details.
|
||||||
|
*
|
||||||
|
* If there are any unsaved documents and interaction with the user is allowed,
|
||||||
|
* we make an "Interact Request", so that the session manager sends us an "Interact"
|
||||||
|
* message, and return.
|
||||||
|
*
|
||||||
|
* Otherwise, we save the configuration and are ready to handle a "Save Complete",
|
||||||
|
* "Shutdown Cancelled" or "Die" message.
|
||||||
|
*
|
||||||
|
* @see sm_interact_callback()
|
||||||
|
* @see sm_save_complete_callback()
|
||||||
|
* @see sm_shutdown_cancelled_callback()
|
||||||
|
* @see sm_die_callback()
|
||||||
|
*/
|
||||||
|
static void sm_save_yourself_callback(SmcConn smcon, SmPointer client_data,
|
||||||
|
int save_type, Bool shutdown, int interact_style, Bool fast)
|
||||||
|
{
|
||||||
|
/* Main window not realized means some startup dialog loop,
|
||||||
|
so the configuration/interface are not initialized yet. */
|
||||||
|
if (main_status.main_window_realized)
|
||||||
|
{
|
||||||
|
sm_last_save_type = save_type;
|
||||||
|
sm_last_shutdown = shutdown;
|
||||||
|
sm_last_save_done = FALSE;
|
||||||
|
|
||||||
|
if (!(save_type == SmSaveGlobal || save_type == SmSaveBoth) &&
|
||||||
|
interact_style == SmInteractStyleAny && document_any_unsaved() &&
|
||||||
|
!g_str_has_prefix(sm_vendor, "xfce") &&
|
||||||
|
SmcInteractRequest(smcon, SmDialogNormal, sm_interact_callback, NULL))
|
||||||
|
{
|
||||||
|
return; /* sm_interact_callback() takes over */
|
||||||
|
}
|
||||||
|
|
||||||
|
sm_finish_save(smcon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Interact" callback.
|
||||||
|
*
|
||||||
|
* @param smcon LibSM connection object.
|
||||||
|
* @param client_data Client data specified when the callback was registered.
|
||||||
|
* Currently it is not used.
|
||||||
|
*
|
||||||
|
* See libSM documentation for more details.
|
||||||
|
*
|
||||||
|
* The session manager sends us an "Interact" message after we make an
|
||||||
|
* "Interact Request" in @c sm_save_yourself_callback(). Here we are allowed to
|
||||||
|
* interact with the user, so we ask whether to the save changed documents (the
|
||||||
|
* user also can cancel the shutdown), and save the configuration. After that we
|
||||||
|
* are ready to handle a "Save Complete", "Shutdown Cancelled" or "Die" message.
|
||||||
|
*
|
||||||
|
* @see sm_shutdown_cancelled_callback()
|
||||||
|
* @see sm_die_callback()
|
||||||
|
*/
|
||||||
|
static void sm_interact_callback(SmcConn smcon, SmPointer client_data)
|
||||||
|
{
|
||||||
|
gboolean unsaved = !document_prompt_for_unsaved();
|
||||||
|
SmcInteractDone(smcon, sm_last_shutdown && unsaved);
|
||||||
|
sm_finish_save(smcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Save Complete" callback.
|
||||||
|
*
|
||||||
|
* @param smcon LibSM connection object.
|
||||||
|
* @param client_data Client data specified when the callback was registered.
|
||||||
|
* Currently it is not used.
|
||||||
|
*
|
||||||
|
* See libSM documentation for more details.
|
||||||
|
*
|
||||||
|
* Unfreeze and continue normally.
|
||||||
|
*/
|
||||||
|
static void sm_save_complete_callback(SmcConn smcon, SmPointer client_data)
|
||||||
|
{
|
||||||
|
sm_prevent_interaction(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Shutdown Cancelled" callback.
|
||||||
|
*
|
||||||
|
* @param smcon LibSM connection object.
|
||||||
|
* @param client_data Client data specified when the callback was registered.
|
||||||
|
* Currently it is not used.
|
||||||
|
*
|
||||||
|
* See libSM documentation for more details.
|
||||||
|
*
|
||||||
|
* Signal save yourself if needed and unfreeze.
|
||||||
|
*/
|
||||||
|
static void sm_shutdown_cancelled_callback(SmcConn smcon, SmPointer client_data)
|
||||||
|
{
|
||||||
|
if (!sm_last_save_done)
|
||||||
|
SmcSaveYourselfDone(smcon, FALSE);
|
||||||
|
sm_prevent_interaction(FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Die" callback.
|
||||||
|
*
|
||||||
|
* @param smcon LibSM connection object.
|
||||||
|
* @param client_data Client data specified when the callback was registered.
|
||||||
|
* Currently it is not used.
|
||||||
|
*
|
||||||
|
* See libSM documentation for more details.
|
||||||
|
*
|
||||||
|
* The session manager asks us to quit Geany and we do it. When quitting, the
|
||||||
|
* main module (@c main.c) will call @c sm_finalize() where we will close the
|
||||||
|
* connection to the session manager.
|
||||||
|
*/
|
||||||
|
static void sm_die_callback(SmcConn smcon, SmPointer client_data)
|
||||||
|
{
|
||||||
|
main_status.quitting = TRUE;
|
||||||
|
main_quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* @} */
|
||||||
|
|
||||||
|
#endif
|
32
src/sm.h
Normal file
32
src/sm.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* sm.h - this file is part of Geany, a fast and lightweight IDE
|
||||||
|
*
|
||||||
|
* Copyright 2009 Eugene Arshinov <earshinov(at)gmail(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.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GEANY_SM_H
|
||||||
|
#define GEANY_SM_H 1
|
||||||
|
|
||||||
|
void sm_init(const char *argv0, const char *libsm_client_id);
|
||||||
|
|
||||||
|
void sm_discard(void);
|
||||||
|
|
||||||
|
void sm_finalize(void);
|
||||||
|
|
||||||
|
#endif
|
46
src/utils.c
46
src/utils.c
@ -2068,6 +2068,52 @@ gchar **utils_copy_environment(const gchar **exclude_vars, const gchar *first_va
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* "Reverse parse" @c GOptionEntry
|
||||||
|
*
|
||||||
|
* @param optentry Object to parse.
|
||||||
|
* @return Newly-allocated option string or NULL.
|
||||||
|
*
|
||||||
|
* Function takes the information about the option entry stored in @c optentry
|
||||||
|
* and the option's value by the address stored in @c optentry. It returns a newly
|
||||||
|
* allocated option string, or NULL if none required (or if the option type is not
|
||||||
|
* supported). Any relative file names are converted to absolute.
|
||||||
|
*
|
||||||
|
* The resulting string must be freed with @c g_free().
|
||||||
|
*/
|
||||||
|
gchar *utils_option_entry_reverse_parse(const GOptionEntry *optentry)
|
||||||
|
{
|
||||||
|
gchar *s = NULL;
|
||||||
|
|
||||||
|
switch (optentry->arg)
|
||||||
|
{
|
||||||
|
case G_OPTION_ARG_NONE:
|
||||||
|
{
|
||||||
|
gboolean val = *(gboolean *)optentry->arg_data;
|
||||||
|
gboolean reverse = (optentry->flags & G_OPTION_FLAG_REVERSE);
|
||||||
|
if ((val && !reverse) || (!val && reverse)) /* logical XOR */
|
||||||
|
s = g_strdup_printf("--%s", optentry->long_name);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case G_OPTION_ARG_INT:
|
||||||
|
if (*(gint *)optentry->arg_data)
|
||||||
|
s = g_strdup_printf("--%s=%d", optentry->long_name, *(gint *)optentry->arg_data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case G_OPTION_ARG_STRING:
|
||||||
|
case G_OPTION_ARG_FILENAME:
|
||||||
|
if (*(gchar **)optentry->arg_data)
|
||||||
|
s = g_strdup_printf("--%s=%s", optentry->long_name, *(gchar **)optentry->arg_data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
g_warning("%s: %s: %d\n", G_STRFUNC, "Unsupported option entry type", optentry->arg);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Joins @a first and @a second into a new string vector, freeing the originals.
|
/* Joins @a first and @a second into a new string vector, freeing the originals.
|
||||||
* The original contents are reused. */
|
* The original contents are reused. */
|
||||||
gchar **utils_strv_join(gchar **first, gchar **second)
|
gchar **utils_strv_join(gchar **first, gchar **second)
|
||||||
|
@ -277,6 +277,8 @@ gchar *utils_str_remove_chars(gchar *string, const gchar *chars);
|
|||||||
|
|
||||||
gchar **utils_copy_environment(const gchar **exclude_vars, const gchar *first_varname, ...) G_GNUC_NULL_TERMINATED;
|
gchar **utils_copy_environment(const gchar **exclude_vars, const gchar *first_varname, ...) G_GNUC_NULL_TERMINATED;
|
||||||
|
|
||||||
|
gchar *utils_option_entry_reverse_parse(const GOptionEntry *optentry);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
15
wscript
15
wscript
@ -129,7 +129,7 @@ geany_sources = set([
|
|||||||
'src/highlighting.c', 'src/keybindings.c',
|
'src/highlighting.c', 'src/keybindings.c',
|
||||||
'src/keyfile.c', 'src/log.c', 'src/main.c', 'src/msgwindow.c', 'src/navqueue.c', 'src/notebook.c',
|
'src/keyfile.c', 'src/log.c', 'src/main.c', 'src/msgwindow.c', 'src/navqueue.c', 'src/notebook.c',
|
||||||
'src/plugins.c', 'src/pluginutils.c', 'src/prefix.c', 'src/prefs.c', 'src/printing.c', 'src/project.c',
|
'src/plugins.c', 'src/pluginutils.c', 'src/prefix.c', 'src/prefs.c', 'src/printing.c', 'src/project.c',
|
||||||
'src/sciwrappers.c', 'src/search.c', 'src/socket.c', 'src/stash.c',
|
'src/sciwrappers.c', 'src/search.c', 'src/sm.c', 'src/socket.c', 'src/stash.c',
|
||||||
'src/symbols.c',
|
'src/symbols.c',
|
||||||
'src/templates.c', 'src/toolbar.c', 'src/tools.c', 'src/sidebar.c',
|
'src/templates.c', 'src/toolbar.c', 'src/tools.c', 'src/sidebar.c',
|
||||||
'src/ui_utils.c', 'src/utils.c'])
|
'src/ui_utils.c', 'src/utils.c'])
|
||||||
@ -181,6 +181,12 @@ def configure(conf):
|
|||||||
gtk_version = conf.check_cfg(modversion='gtk+-2.0', uselib_store='GTK') or 'Unknown'
|
gtk_version = conf.check_cfg(modversion='gtk+-2.0', uselib_store='GTK') or 'Unknown'
|
||||||
conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
|
conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
|
||||||
|
|
||||||
|
# Find libSM
|
||||||
|
if not Options.options.no_libsm:
|
||||||
|
sm_version = conf.check_cfg(package='sm', uselib_store='SM', args='--cflags --libs', mandatory=False)
|
||||||
|
if sm_version is None:
|
||||||
|
Options.options.no_libsm = True
|
||||||
|
|
||||||
# Windows specials
|
# Windows specials
|
||||||
if is_win32:
|
if is_win32:
|
||||||
if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
|
if conf.env['PREFIX'].lower() == tempfile.gettempdir().lower():
|
||||||
@ -232,6 +238,7 @@ def configure(conf):
|
|||||||
_define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
|
_define_from_opt(conf, 'HAVE_PLUGINS', not conf.options.no_plugins, None)
|
||||||
_define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
|
_define_from_opt(conf, 'HAVE_SOCKET', not conf.options.no_socket, None)
|
||||||
_define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
|
_define_from_opt(conf, 'HAVE_VTE', not conf.options.no_vte, None)
|
||||||
|
_define_from_opt(conf, 'HAVE_LIBSM', not Options.options.no_libsm, None)
|
||||||
|
|
||||||
conf.write_config_header('config.h', remove=False)
|
conf.write_config_header('config.h', remove=False)
|
||||||
|
|
||||||
@ -250,6 +257,7 @@ def configure(conf):
|
|||||||
conf.msg('Using GTK version', gtk_version)
|
conf.msg('Using GTK version', gtk_version)
|
||||||
conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
|
conf.msg('Build with plugin support', conf.options.no_plugins and 'no' or 'yes')
|
||||||
conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
|
conf.msg('Use virtual terminal support', conf.options.no_vte and 'no' or 'yes')
|
||||||
|
conf.msg('Build with X session management support', conf.options.no_libsm and 'no' or 'yes')
|
||||||
if revision is not None:
|
if revision is not None:
|
||||||
conf.msg('Compiling Git revision', revision)
|
conf.msg('Compiling Git revision', revision)
|
||||||
|
|
||||||
@ -268,6 +276,9 @@ def options(opt):
|
|||||||
opt.add_option('--disable-vte', action='store_true', default=False,
|
opt.add_option('--disable-vte', action='store_true', default=False,
|
||||||
help='compile without support for an embedded virtual terminal [[default: No]',
|
help='compile without support for an embedded virtual terminal [[default: No]',
|
||||||
dest='no_vte')
|
dest='no_vte')
|
||||||
|
opt.add_option('--disable-libsm', action='store_true', default=target_is_win32(os.environ),
|
||||||
|
help='compile without X session management support [[default: No]',
|
||||||
|
dest='no_libsm')
|
||||||
# Paths
|
# Paths
|
||||||
opt.add_option('--mandir', type='string', default='',
|
opt.add_option('--mandir', type='string', default='',
|
||||||
help='man documentation', dest='mandir')
|
help='man documentation', dest='mandir')
|
||||||
@ -363,7 +374,7 @@ def build(bld):
|
|||||||
includes = ['.', 'scintilla/include', 'tagmanager/src'],
|
includes = ['.', 'scintilla/include', 'tagmanager/src'],
|
||||||
defines = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
|
defines = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
|
||||||
linkflags = [] if is_win32 else ['-Wl,--export-dynamic'],
|
linkflags = [] if is_win32 else ['-Wl,--export-dynamic'],
|
||||||
uselib = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'SUNOS_SOCKET'],
|
uselib = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'SUNOS_SOCKET', 'SM'],
|
||||||
use = ['scintilla', 'ctags', 'tagmanager', 'mio'])
|
use = ['scintilla', 'ctags', 'tagmanager', 'mio'])
|
||||||
|
|
||||||
# geanyfunctions.h
|
# geanyfunctions.h
|
||||||
|
Loading…
x
Reference in New Issue
Block a user