Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Wed, 04 Mar 2015 11:40:45 UTC
Commit: 7fa8b3a6953f734593e027a7ef7a8f93064be04c
https://github.com/geany/geany/commit/7fa8b3a6953f734593e027a7ef7a8f93064be…
Log Message:
-----------
Backport adaptive scrolling patch from scintilla
Modified Paths:
--------------
scintilla/gtk/ScintillaGTK.cxx
Modified: scintilla/gtk/ScintillaGTK.cxx
7 lines changed, 4 insertions(+), 3 deletions(-)
===================================================================
@@ -1988,10 +1988,11 @@ gint ScintillaGTK::ScrollEvent(GtkWidget *widget, GdkEventScroll *event) {
// Compute amount and direction to scroll (even tho on win32 there is
// intensity of scrolling info in the native message, gtk doesn't
// support this so we simulate similarly adaptive scrolling)
- // Note that this is disabled on OS X (Darwin) where the X11 server already has
- // and adaptive scrolling algorithm that fights with this one
+ // Note that this is disabled on OS X (Darwin) with the X11 backend
+ // where the X11 server already has an adaptive scrolling algorithm
+ // that fights with this one
int cLineScroll;
-#if defined(__MWERKS__) || defined(__APPLE_CPP__) || defined(__APPLE_CC__)
+#if defined(__APPLE__) && !defined(GDK_WINDOWING_QUARTZ)
cLineScroll = sciThis->linesPerScroll;
if (cLineScroll == 0)
cLineScroll = 4;
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Wed, 04 Mar 2015 11:40:45 UTC
Commit: a9912c3c35dd231d8232e88564a664a8d91e4bf0
https://github.com/geany/geany/commit/a9912c3c35dd231d8232e88564a664a8d91e4…
Log Message:
-----------
Don't use single menu for "New with template" shared by toolbar and menubar
The current implementation uses single menu for the toolbar and
menubar and reparents it when file menu is shown/hidden.
Connectiong "show"/"hide" signals doesn't work for menu items
on OS X (and I suppose Ubuntu either) so the template submenu is
never shown in the File menu.
The easiest fix seems to be having two identical menus the same
way we have them for recent files.
Modified Paths:
--------------
src/templates.c
Modified: src/templates.c
81 lines changed, 27 insertions(+), 54 deletions(-)
===================================================================
@@ -50,7 +50,8 @@
GeanyTemplatePrefs template_prefs;
-static GtkWidget *new_with_template_menu = NULL; /* submenu used for both file menu and toolbar */
+static GtkWidget *new_with_template_menu = NULL;
+static GtkWidget *new_with_template_toolbar_menu = NULL;
/* TODO: implement custom insertion templates instead? */
static gchar *templates[GEANY_MAX_TEMPLATES];
@@ -257,7 +258,7 @@ static void add_file_item(const gchar *fname, GtkWidget *menu)
}
-static gboolean add_custom_template_items(void)
+static void populate_file_template_menu(GtkWidget *menu)
{
GSList *list = utils_get_config_files(GEANY_TEMPLATES_SUBDIR G_DIR_SEPARATOR_S "files");
GSList *node;
@@ -266,40 +267,25 @@ static gboolean add_custom_template_items(void)
{
gchar *fname = node->data;
- add_file_item(fname, new_with_template_menu);
+ add_file_item(fname, menu);
g_free(fname);
}
g_slist_free(list);
- return list != NULL;
}
static void create_file_template_menu(void)
{
- new_with_template_menu = gtk_menu_new();
- add_custom_template_items();
-
- /* unless the file menu is showing, menu should be in the toolbar widget */
- geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION(
- toolbar_get_action_by_name("New")), new_with_template_menu);
-}
-
+ GtkWidget *item;
-static void on_file_menu_show(GtkWidget *item)
-{
- geany_menu_button_action_set_menu(
- GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), NULL);
+ new_with_template_menu = gtk_menu_new();
item = ui_lookup_widget(main_widgets.window, "menu_new_with_template1");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), new_with_template_menu);
-}
-
-static void on_file_menu_hide(GtkWidget *item)
-{
- item = ui_lookup_widget(main_widgets.window, "menu_new_with_template1");
- gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), NULL);
- geany_menu_button_action_set_menu(
- GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), new_with_template_menu);
+ new_with_template_toolbar_menu = gtk_menu_new();
+ g_object_ref(new_with_template_toolbar_menu);
+ geany_menu_button_action_set_menu(GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")),
+ new_with_template_toolbar_menu);
}
@@ -328,23 +314,15 @@ void templates_init(void)
init_general_templates();
- create_file_template_menu();
- /* we hold our own ref for the menu as it has no parent whilst being moved */
- g_object_ref(new_with_template_menu);
-
- /* only connect signals to persistent objects once */
if (!init_done)
{
- GtkWidget *item;
- /* reparent the template menu as needed */
- item = ui_lookup_widget(main_widgets.window, "file1");
- item = gtk_menu_item_get_submenu(GTK_MENU_ITEM(item));
- g_signal_connect(item, "show", G_CALLBACK(on_file_menu_show), NULL);
- g_signal_connect(item, "hide", G_CALLBACK(on_file_menu_hide), NULL);
-
+ create_file_template_menu();
g_signal_connect(geany_object, "document-save", G_CALLBACK(on_document_save), NULL);
+ init_done = TRUE;
}
- init_done = TRUE;
+
+ populate_file_template_menu(new_with_template_menu);
+ populate_file_template_menu(new_with_template_toolbar_menu);
}
@@ -527,30 +505,25 @@ gchar *templates_get_template_changelog(GeanyDocument *doc)
}
-void templates_free_templates(void)
+static void free_template_menu_items(GtkWidget *menu)
{
- gint i;
GList *children, *item;
- /* disconnect the menu from the action widget, so destroying the items below doesn't
- * trigger rebuilding of the menu on each item destroy */
- geany_menu_button_action_set_menu(
- GEANY_MENU_BUTTON_ACTION(toolbar_get_action_by_name("New")), NULL);
-
- for (i = 0; i < GEANY_MAX_TEMPLATES; i++)
- {
- g_free(templates[i]);
- }
- /* destroy "New with template" sub menu items (in case we want to reload the templates) */
- children = gtk_container_get_children(GTK_CONTAINER(new_with_template_menu));
+ children = gtk_container_get_children(GTK_CONTAINER(menu));
foreach_list(item, children)
- {
gtk_widget_destroy(GTK_WIDGET(item->data));
- }
g_list_free(children);
+}
- g_object_unref(new_with_template_menu);
- new_with_template_menu = NULL;
+
+void templates_free_templates(void)
+{
+ gint i;
+
+ for (i = 0; i < GEANY_MAX_TEMPLATES; i++)
+ g_free(templates[i]);
+ free_template_menu_items(new_with_template_menu);
+ free_template_menu_items(new_with_template_toolbar_menu);
}
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Wed, 04 Mar 2015 11:40:36 UTC
Commit: 562885765dbd600626558372a409832cb4cda77e
https://github.com/geany/geany/commit/562885765dbd600626558372a409832cb4cda…
Log Message:
-----------
React to various useful gtk-mac-integration signals
NSApplicationBlockTermination signal is emitted when clicking
the Quit menu to check whether the application permits
quitting - react accordingly.
---
NSApplicationOpenFile signal is emitted when
* file is dragged on the application icon
* application is selected from "Open with" menu after right-clicking
the file
* when double-clicking a file for which the application is default
editor/viewer
* when file is opened from command-line
When the application isn't running, it is first started and then this
signal is emitted.
Use the signal to open files. In addition, when the opened file
has the ".geany" suffix, open it (but only if the project isn't already
open). The project has to be opened in idle function because blocking
the signal handler for a long time by the project-close confirmation
dialog causes problems.
Modified Paths:
--------------
src/osx.c
Modified: src/osx.c
61 lines changed, 60 insertions(+), 1 deletions(-)
===================================================================
@@ -23,6 +23,61 @@
#include "osx.h"
#include "ui_utils.h"
+#include "main.h"
+
+
+static gboolean app_block_termination_cb(GtkosxApplication *app, gpointer data)
+{
+ return !main_quit();
+}
+
+
+/* For some reason osx doesn't like when the NSApplicationOpenFile handler blocks for
+ * a long time which may be caused by the project_ask_close() below. Finish the
+ * NSApplicationOpenFile handler immediately and perform the potentially blocking
+ * code on idle in this function. */
+static gboolean open_project_idle(gchar *locale_path)
+{
+ gchar *utf8_path;
+
+ utf8_path = utils_get_utf8_from_locale(locale_path);
+ if (app->project == NULL ||
+ (g_strcmp0(utf8_path, app->project->file_name) != 0 && project_ask_close()))
+ project_load_file_with_session(locale_path);
+ g_free(utf8_path);
+ g_free(locale_path);
+ return FALSE;
+}
+
+
+static gboolean app_open_file_cb(GtkosxApplication *osx_app, gchar *path, gpointer user_data)
+{
+ gchar opened = FALSE;
+ gchar *locale_path;
+
+ locale_path = utils_get_locale_from_utf8(path);
+
+ if (!g_path_is_absolute(locale_path))
+ {
+ gchar *cwd = g_get_current_dir();
+ SETPTR(locale_path, g_build_filename(cwd, locale_path, NULL));
+ g_free(cwd);
+ }
+
+ if (g_str_has_suffix(path, ".geany"))
+ {
+ g_idle_add((GSourceFunc)open_project_idle, locale_path);
+ opened = TRUE;
+ }
+ else
+ {
+ opened = document_open_file(locale_path, FALSE, NULL, NULL) != NULL;
+ g_free(locale_path);
+ }
+
+ return opened;
+}
+
void osx_ui_init(void)
{
@@ -43,7 +98,11 @@ void osx_ui_init(void)
gtkosx_application_set_help_menu(osx_app, GTK_MENU_ITEM(item));
gtkosx_application_set_use_quartz_accelerators(osx_app, FALSE);
+
+ g_signal_connect(osx_app, "NSApplicationBlockTermination",
+ G_CALLBACK(app_block_termination_cb), NULL);
+ g_signal_connect(osx_app, "NSApplicationOpenFile",
+ G_CALLBACK(app_open_file_cb), NULL);
}
#endif /* MAC_INTEGRATION */
-
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Wed, 04 Mar 2015 11:40:36 UTC
Commit: ada4595264def0f96d40e223f41243b46580fc1b
https://github.com/geany/geany/commit/ada4595264def0f96d40e223f41243b46580f…
Log Message:
-----------
Use global menubar on OS X
We have to disable quartz accelerator handling because otherwise
accelerators are performed also from other windows than the main
Geany editor (e.g. Ctrl+V with find dialog open performs the keybinding
Ctrl+V and inserts the text to the editor).
OS X applications have an extra menu entry to the left of the File menu -
an "application menu". This menu usually contains About, Preferences,
Quit. Many users, however, may be used to Geany from other platforms
and expect Preferences to be under the Edit menu so leave them there.
Quit and About are rarely used and the application menu is the place where
they are supposed to be - move these entries from other Geany menus there
and hide them in the affected menus (the quit entry is inserted automatically,
we just need to hide it from File).
Also tell OS X the Help menu is dedicated to help (we get search in
menu entries by name for free thanks to this).
The global menu should refresh automatically based on user actions.
Unfortunately this is not the case when gtk_menu_reorder_child()
is used because it does not emit any signals so the gtk-mac-integration
library doesn't see this call. Refresh the menu manually after calling
this function.
Modified Paths:
--------------
src/Makefile.am
src/main.c
src/osx.c
src/osx.h
src/ui_utils.c
wscript
Modified: src/Makefile.am
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -10,7 +10,6 @@ EXTRA_DIST = \
keybindingsprivate.h \
pluginprivate.h \
projectprivate.h \
- osx.h \
makefile.win32
bin_PROGRAMS = geany
@@ -39,6 +38,7 @@ SRCS = \
msgwindow.c msgwindow.h \
navqueue.c navqueue.h \
notebook.c notebook.h \
+ osx.c osx.h \
plugins.c plugins.h \
pluginutils.c pluginutils.h \
prefix.c prefix.h \
Modified: src/main.c
3 lines changed, 3 insertions(+), 0 deletions(-)
===================================================================
@@ -266,6 +266,9 @@ static void main_init(void)
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");
Modified: src/osx.c
49 lines changed, 49 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,49 @@
+/*
+ * osx.c - this file is part of Geany, a fast and lightweight IDE
+ *
+ * Copyright 2015 Jiri Techet <techet(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.
+ */
+
+#ifdef MAC_INTEGRATION
+
+#include "osx.h"
+
+#include "ui_utils.h"
+
+void osx_ui_init(void)
+{
+ GtkWidget *item;
+ GtkosxApplication *osx_app = gtkosx_application_get();
+
+ item = ui_lookup_widget(main_widgets.window, "menubar1");
+ gtk_widget_hide(item);
+ gtkosx_application_set_menu_bar(osx_app, GTK_MENU_SHELL(item));
+
+ item = ui_lookup_widget(main_widgets.window, "menu_quit1");
+ gtk_widget_hide(item);
+
+ item = ui_lookup_widget(main_widgets.window, "menu_info1");
+ gtkosx_application_insert_app_menu_item(osx_app, item, 0);
+
+ item = ui_lookup_widget(main_widgets.window, "menu_help1");
+ gtkosx_application_set_help_menu(osx_app, GTK_MENU_ITEM(item));
+
+ gtkosx_application_set_use_quartz_accelerators(osx_app, FALSE);
+}
+
+#endif /* MAC_INTEGRATION */
+
Modified: src/osx.h
6 lines changed, 6 insertions(+), 0 deletions(-)
===================================================================
@@ -25,6 +25,12 @@
#include <gtkosxapplication.h>
+G_BEGIN_DECLS
+
+void osx_ui_init(void);
+
+G_END_DECLS
+
#endif /* MAC_INTEGRATION */
#endif /* GEANY_OSX_H */
Modified: src/ui_utils.c
20 lines changed, 17 insertions(+), 3 deletions(-)
===================================================================
@@ -50,6 +50,7 @@
#include "toolbar.h"
#include "utils.h"
#include "win32.h"
+#include "osx.h"
#include "gtkcompat.h"
@@ -1307,6 +1308,19 @@ void ui_update_recent_project_menu(void)
}
+/* Use instead of gtk_menu_reorder_child() to update the menubar properly on OS X */
+static void menu_reorder_child(GtkMenu *menu, GtkWidget *child, gint position)
+{
+ gtk_menu_reorder_child(menu, child, position);
+#ifdef MAC_INTEGRATION
+ /* On OS X GtkMenuBar is kept in sync with the native OS X menubar using
+ * signals. Unfortunately gtk_menu_reorder_child() doesn't emit anything
+ * so we have to update the OS X menubar manually. */
+ gtkosx_application_sync_menubar(gtkosx_application_get());
+#endif
+}
+
+
static void add_recent_file_menu_item(const gchar *utf8_filename, GeanyRecentFiles *grf, GtkWidget *menu)
{
GtkWidget *child = gtk_menu_item_new_with_label(utf8_filename);
@@ -1320,7 +1334,7 @@ static void add_recent_file_menu_item(const gchar *utf8_filename, GeanyRecentFil
* gtk_menu_shell_prepend() doesn't emit GtkContainer's "add" signal
* which we need in GeanyMenubuttonAction */
gtk_container_add(GTK_CONTAINER(menu), child);
- gtk_menu_reorder_child(GTK_MENU(menu), child, 0);
+ menu_reorder_child(GTK_MENU(menu), child, 0);
}
g_signal_connect(child, "activate", G_CALLBACK(grf->activate_cb), NULL);
}
@@ -1350,7 +1364,7 @@ static void recent_file_loaded(const gchar *utf8_filename, GeanyRecentFiles *grf
item = g_list_find_custom(children, utf8_filename, (GCompareFunc) find_recent_file_item);
/* either reorder or prepend a new one */
if (item)
- gtk_menu_reorder_child(GTK_MENU(parents[i]), item->data, 0);
+ menu_reorder_child(GTK_MENU(parents[i]), item->data, 0);
else
add_recent_file_menu_item(utf8_filename, grf, parents[i]);
g_list_free(children);
@@ -2781,7 +2795,7 @@ void ui_menu_sort_by_label(GtkMenu *menu)
pos = 0;
foreach_list(node, list)
{
- gtk_menu_reorder_child(menu, node->data, pos);
+ menu_reorder_child(menu, node->data, pos);
pos++;
}
g_list_free(list);
Modified: wscript
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -131,7 +131,7 @@ geany_sources = set([
'src/editor.c', 'src/encodings.c', 'src/filetypes.c', 'src/geanyentryaction.c',
'src/geanymenubuttonaction.c', 'src/geanyobject.c', 'src/geanywraplabel.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/osx.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/symbols.c',
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).
Branch: refs/heads/master
Author: Jiří Techet <techet(a)gmail.com>
Committer: Jiří Techet <techet(a)gmail.com>
Date: Wed, 04 Mar 2015 10:48:53 UTC
Commit: 7b5df86bd14dac77e1d66ede4b8240cd99e8ba48
https://github.com/geany/geany/commit/7b5df86bd14dac77e1d66ede4b8240cd99e8b…
Log Message:
-----------
Create geany_run_script.sh in the temporary directory instead of the working directory
Under some conditions, geany_run_script.sh is not deleted and we
have no means to detect this in Geany (e.g. when the terminal emulator
is started correctly but it fails to execute the script for some reason).
In this case it is better to keep the garbage in /tmp than the working
directory. Apart from that, it eliminates potential transfer of the run script
over a NFS and eliminates the visibility of the script in working directory
on Windows.
Apart from that this patch fixes some locale/utf8 conversion problems
and other subtle problems with the previous implementation.
Modified Paths:
--------------
doc/geany.txt
src/build.c
Modified: doc/geany.txt
5 lines changed, 3 insertions(+), 2 deletions(-)
===================================================================
@@ -3018,8 +3018,9 @@ The Terminal field of the tools preferences tab requires a command to
execute the terminal program and to pass it the name of the Geany run
script that it should execute in a Bourne compatible shell (eg /bin/sh).
The marker "%c" is substituted with the name of the Geany run script,
-which is created in the working directory set in the Build commands
-dialog, see `Build menu commands dialog`_ for details.
+which is created in the temporary directory and which changes the working
+directory to the directory set in the Build commands dialog, see
+`Build menu commands dialog`_ for details.
As an example the default (Linux) command is::
Modified: src/build.c
167 lines changed, 71 insertions(+), 96 deletions(-)
===================================================================
@@ -91,9 +91,9 @@ typedef struct RunInfo
static RunInfo *run_info;
#ifdef G_OS_WIN32
-static const gchar RUN_SCRIPT_CMD[] = "geany_run_script.bat";
+static const gchar RUN_SCRIPT_CMD[] = "geany_run_script_XXXXXX.bat";
#else
-static const gchar RUN_SCRIPT_CMD[] = "./geany_run_script.sh";
+static const gchar RUN_SCRIPT_CMD[] = "geany_run_script_XXXXXX.sh";
#endif
/* pack group (<8) and command (<32) into a user_data pointer */
@@ -128,7 +128,7 @@ static guint build_items_count = 9;
static void build_exit_cb(GPid child_pid, gint status, gpointer user_data);
static gboolean build_iofunc(GIOChannel *ioc, GIOCondition cond, gpointer data);
#endif
-static gboolean build_create_shellscript(const gchar *fname, const gchar *working_dir, const gchar *cmd, gboolean autoclose, GError **error);
+static gchar *build_create_shellscript(const gchar *working_dir, const gchar *cmd, gboolean autoclose, GError **error);
static GPid build_spawn_cmd(GeanyDocument *doc, const gchar *cmd, const gchar *dir);
static void set_stop_button(gboolean stop);
static void run_exit_cb(GPid child_pid, gint status, gpointer user_data);
@@ -879,54 +879,49 @@ static GPid build_spawn_cmd(GeanyDocument *doc, const gchar *cmd, const gchar *d
}
-/* Returns: NULL if there was an error, or the working directory the script was created in.
- * vte_cmd_nonscript is the location of a string which is filled with the command to be used
- * when vc->skip_run_script is set, otherwise it will be set to NULL */
-static gchar *prepare_run_script(GeanyDocument *doc, gchar **vte_cmd_nonscript, guint cmdindex)
+/* Returns: NULL if there was an error, or the command to be executed. If Geany is
+ * set to use a run script, the returned value is a path to the script that runs
+ * the command; otherwise the command itself is returned. working_dir is a pointer
+ * to the working directory from which the command is executed. Both strings are
+ * in the locale encoding. */
+static gchar *prepare_run_cmd(GeanyDocument *doc, gchar **working_dir, guint cmdindex)
{
GeanyBuildCommand *cmd = NULL;
- gchar *working_dir = NULL;
const gchar *cmd_working_dir;
gboolean autoclose = FALSE;
- gboolean result = FALSE;
- gchar *tmp;
- gchar *cmd_string;
+ gchar *cmd_string_utf8, *working_dir_utf8, *run_cmd, *cmd_string;
GError *error = NULL;
- if (vte_cmd_nonscript != NULL)
- *vte_cmd_nonscript = NULL;
-
cmd = get_build_cmd(doc, GEANY_GBG_EXEC, cmdindex, NULL);
- cmd_string = build_replace_placeholder(doc, cmd->command);
+ cmd_string_utf8 = build_replace_placeholder(doc, cmd->command);
cmd_working_dir = cmd->working_dir;
if (EMPTY(cmd_working_dir))
cmd_working_dir = "%d";
- working_dir = build_replace_placeholder(doc, cmd_working_dir); /* in utf-8 */
+ working_dir_utf8 = build_replace_placeholder(doc, cmd_working_dir);
+ *working_dir = utils_get_locale_from_utf8(working_dir_utf8);
/* only test whether working dir exists, don't change it or else Windows support will break
* (gspawn-win32-helper.exe is used by GLib and must be in $PATH which means current working
* dir where geany.exe was started from, so we can't change it) */
- if (EMPTY(working_dir) || ! g_file_test(working_dir, G_FILE_TEST_EXISTS) ||
- ! g_file_test(working_dir, G_FILE_TEST_IS_DIR))
+ if (EMPTY(*working_dir) || ! g_file_test(*working_dir, G_FILE_TEST_EXISTS) ||
+ ! g_file_test(*working_dir, G_FILE_TEST_IS_DIR))
{
ui_set_statusbar(TRUE, _("Failed to change the working directory to \"%s\""),
- !EMPTY(working_dir) ? working_dir : "<NULL>" );
- utils_free_pointers(2, cmd_string, working_dir, NULL);
+ !EMPTY(working_dir_utf8) ? working_dir_utf8 : "<NULL>" );
+ utils_free_pointers(3, cmd_string_utf8, working_dir_utf8, *working_dir, NULL);
return NULL;
}
+ cmd_string = utils_get_locale_from_utf8(cmd_string_utf8);
+
#ifdef HAVE_VTE
if (vte_info.have_vte && vc->run_in_vte)
{
if (vc->skip_run_script)
{
- if (vte_cmd_nonscript != NULL)
- *vte_cmd_nonscript = cmd_string;
- else
- g_free(cmd_string);
-
- return working_dir;
+ utils_free_pointers(2, cmd_string_utf8, working_dir_utf8, NULL);
+ return cmd_string;
}
else
/* don't wait for user input at the end of script when we are running in VTE */
@@ -934,38 +929,31 @@ static gchar *prepare_run_script(GeanyDocument *doc, gchar **vte_cmd_nonscript,
}
#endif
- /* RUN_SCRIPT_CMD should be ok in UTF8 without converting in locale because it
- * contains no umlauts */
- tmp = g_build_filename(working_dir, RUN_SCRIPT_CMD, NULL);
- result = build_create_shellscript(tmp, working_dir, cmd_string, autoclose, &error);
- if (! result)
+ run_cmd = build_create_shellscript(*working_dir, cmd_string, autoclose, &error);
+ if (!run_cmd)
{
ui_set_statusbar(TRUE, _("Failed to execute \"%s\" (start-script could not be created: %s)"),
- !EMPTY(cmd_string) ? cmd_string : NULL, error->message);
+ !EMPTY(cmd_string_utf8) ? cmd_string_utf8 : NULL, error->message);
g_error_free(error);
+ g_free(*working_dir);
}
- utils_free_pointers(2, cmd_string, tmp, NULL);
-
- if (result)
- return working_dir;
-
- g_free(working_dir);
- return NULL;
+ utils_free_pointers(3, cmd_string_utf8, working_dir_utf8, cmd_string, NULL);
+ return run_cmd;
}
static GPid build_run_cmd(GeanyDocument *doc, guint cmdindex)
{
gchar *working_dir;
- gchar *vte_cmd_nonscript = NULL;
+ gchar *run_cmd = NULL;
GError *error = NULL;
if (! DOC_VALID(doc) || doc->file_name == NULL)
return (GPid) 0;
- working_dir = prepare_run_script(doc, &vte_cmd_nonscript, cmdindex);
- if (working_dir == NULL)
+ run_cmd = prepare_run_cmd(doc, &working_dir, cmdindex);
+ if (run_cmd == NULL)
return (GPid) 0;
run_info[cmdindex].file_type_id = doc->file_type->id;
@@ -975,28 +963,23 @@ static GPid build_run_cmd(GeanyDocument *doc, guint cmdindex)
{
gchar *vte_cmd;
+ /* VTE expects commands in UTF-8 */
+ SETPTR(run_cmd, utils_get_utf8_from_locale(run_cmd));
+ SETPTR(working_dir, utils_get_utf8_from_locale(working_dir));
+
if (vc->skip_run_script)
- {
- SETPTR(vte_cmd_nonscript, utils_get_utf8_from_locale(vte_cmd_nonscript));
- vte_cmd = g_strconcat(vte_cmd_nonscript, "\n", NULL);
- g_free(vte_cmd_nonscript);
- }
+ vte_cmd = g_strconcat(run_cmd, "\n", NULL);
else
- vte_cmd = g_strconcat("\n/bin/sh ", RUN_SCRIPT_CMD, "\n", NULL);
+ vte_cmd = g_strconcat("\n/bin/sh ", run_cmd, "\n", NULL);
- /* change into current directory if it is not done by default */
- if (! vc->follow_path)
- {
- /* we need to convert the working_dir back to UTF-8 because the VTE expects it */
- gchar *utf8_working_dir = utils_get_utf8_from_locale(working_dir);
- vte_cwd(utf8_working_dir, TRUE);
- g_free(utf8_working_dir);
- }
+ vte_cwd(working_dir, TRUE);
if (! vte_send_cmd(vte_cmd))
{
ui_set_statusbar(FALSE,
_("Could not execute the file in the VTE because it probably contains a command."));
geany_debug("Could not execute the file in the VTE because it probably contains a command.");
+ if (!vc->skip_run_script)
+ g_unlink(run_cmd);
}
/* show the VTE */
@@ -1025,8 +1008,7 @@ static GPid build_run_cmd(GeanyDocument *doc, guint cmdindex)
_("Could not parse terminal command \"%s\" "
"(check Terminal tool setting in Preferences)"), tool_prefs.term_cmd);
run_info[cmdindex].pid = (GPid) 1;
- script_path = g_build_filename(working_dir, RUN_SCRIPT_CMD, NULL);
- g_unlink(script_path);
+ g_unlink(run_cmd);
goto free_strings;
}
@@ -1044,14 +1026,13 @@ static GPid build_run_cmd(GeanyDocument *doc, guint cmdindex)
_("Could not find terminal \"%s\" "
"(check path for Terminal tool setting in Preferences)"), tool_prefs.term_cmd);
run_info[cmdindex].pid = (GPid) 1;
- script_path = g_build_filename(working_dir, RUN_SCRIPT_CMD, NULL);
- g_unlink(script_path);
+ g_unlink(run_cmd);
goto free_strings;
}
for (i = 0; i < argv_len; i++)
{
- utils_str_replace_all(&(argv[i]), "%c", RUN_SCRIPT_CMD);
+ utils_str_replace_all(&(argv[i]), "%c", run_cmd);
}
if (! g_spawn_async(working_dir, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD,
@@ -1060,8 +1041,7 @@ static GPid build_run_cmd(GeanyDocument *doc, guint cmdindex)
geany_debug("g_spawn_async() failed: %s", error->message);
ui_set_statusbar(TRUE, _("Process failed (%s)"), error->message);
g_error_free(error);
- script_path = g_build_filename(working_dir, RUN_SCRIPT_CMD, NULL);
- g_unlink(script_path);
+ g_unlink(run_cmd);
error = NULL;
run_info[cmdindex].pid = (GPid) 0;
}
@@ -1079,6 +1059,7 @@ static GPid build_run_cmd(GeanyDocument *doc, guint cmdindex)
}
g_free(working_dir);
+ g_free(run_cmd);
return run_info[cmdindex].pid;
}
@@ -1270,36 +1251,28 @@ static void run_exit_cb(GPid child_pid, gint status, gpointer user_data)
}
-static void set_file_error_from_errno(GError **error, gint err, const gchar *prefix)
-{
- g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(err), "%s%s%s",
- prefix ? prefix : "", prefix ? ": " : "", g_strerror(err));
-}
-
-
/* write a little shellscript to call the executable (similar to anjuta_launcher but "internal")
- * fname is the full file name (including path) for the script to create */
-static gboolean build_create_shellscript(const gchar *fname, const gchar *working_dir, const gchar *cmd, gboolean autoclose, GError **error)
+ * working_dir and cmd are both in the locale encoding
+ * it returns the full file name (including path) of the created script in the locale encoding */
+static gchar *build_create_shellscript(const gchar *working_dir, const gchar *cmd, gboolean autoclose, GError **error)
{
- FILE *fp;
- gchar *str;
+ gint fd;
+ gchar *str, *fname;
gboolean success = TRUE;
#ifdef G_OS_WIN32
gchar *expanded_cmd;
#else
gchar *escaped_dir;
#endif
+ fd = g_file_open_tmp (RUN_SCRIPT_CMD, &fname, error);
+ if (fd < 0)
+ return NULL;
+ close(fd);
- fp = g_fopen(fname, "w");
- if (! fp)
- {
- set_file_error_from_errno(error, errno, "Failed to create file");
- return FALSE;
- }
#ifdef G_OS_WIN32
/* Expand environment variables like %blah%. */
expanded_cmd = win32_expand_environment_variables(cmd);
- str = g_strdup_printf("%s\n\n%s\ndel \"%%0\"\n\npause\n", expanded_cmd, (autoclose) ? "" : "pause");
+ str = g_strdup_printf("cd \"%s\"\n\n%s\n\n%s\ndel \"%%0\"\n\npause\n", working_dir, expanded_cmd, (autoclose) ? "" : "pause");
g_free(expanded_cmd);
#else
escaped_dir = g_strescape(working_dir, NULL);
@@ -1311,29 +1284,31 @@ static gboolean build_create_shellscript(const gchar *fname, const gchar *workin
g_free(escaped_dir);
#endif
- if (fputs(str, fp) < 0)
- {
- set_file_error_from_errno(error, errno, "Failed to write file");
+ if (!g_file_set_contents(fname, str, -1, error))
success = FALSE;
- }
g_free(str);
-
- if (fclose(fp) != 0)
- {
- if (error && ! *error) /* don't set error twice */
- set_file_error_from_errno(error, errno, "Failed to close file");
- success = FALSE;
- }
#ifdef __APPLE__
- if (g_chmod(fname, 0777) != 0)
+ if (success && g_chmod(fname, 0777) != 0)
{
- if (error && ! *error) /* don't set error twice */
- set_file_error_from_errno(error, errno, "Failed to make file executable");
+ if (error)
+ {
+ gint errsv = errno;
+
+ g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errsv),
+ "Failed to make file executable: %s", g_strerror(errsv));
+ }
success = FALSE;
}
#endif
- return success;
+ if (!success)
+ {
+ g_unlink(fname);
+ g_free(fname);
+ fname = NULL;
+ }
+
+ return fname;
}
--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).