[geany/geany] 05e19b: Merge pull request #419 from techee/osx-integration

Colomban Wendling git-noreply at xxxxx
Wed Mar 4 13:08:11 UTC 2015


Branch:      refs/heads/master
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Colomban Wendling <ban at herbesfolles.org>
Date:        Wed, 04 Mar 2015 13:08:11 UTC
Commit:      05e19be0a3c83d169217ad6708e56eeed286e30c
             https://github.com/geany/geany/commit/05e19be0a3c83d169217ad6708e56eeed286e30c

Log Message:
-----------
Merge pull request #419 from techee/osx-integration

OS X integration


Modified Paths:
--------------
    configure.ac
    m4/geany-mac-integration.m4
    scintilla/gtk/ScintillaGTK.cxx
    src/Makefile.am
    src/keybindings.c
    src/main.c
    src/notebook.c
    src/osx.c
    src/osx.h
    src/plugins.c
    src/templates.c
    src/ui_utils.c
    src/utils.c
    src/utils.h
    wscript

Modified: configure.ac
1 lines changed, 1 insertions(+), 0 deletions(-)
===================================================================
@@ -105,6 +105,7 @@ GEANY_CHECK_MINGW
 
 GEANY_CHECK_SOCKET
 GEANY_CHECK_VTE
+GEANY_CHECK_MAC_INTEGRATION
 GEANY_CHECK_THE_FORCE dnl hehe
 
 # i18n


Modified: m4/geany-mac-integration.m4
18 lines changed, 18 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,18 @@
+dnl GEANY_CHECK_MAC_INTEGRATION
+dnl Check for gtk-mac-integration to enable improved OS X integration
+dnl
+AC_DEFUN([GEANY_CHECK_MAC_INTEGRATION],
+[
+	AC_ARG_ENABLE([mac-integration],
+			[AS_HELP_STRING([--enable-mac-integration],
+					[use gtk-mac-integration to enable improved OS X integration [default=no]])],
+			[geany_enable_mac_integration="$enableval"],
+			[geany_enable_mac_integration="no"])
+
+	AS_IF([test "x$geany_enable_mac_integration" = "xyes"],
+	[
+		AS_IF([test "x$enable_gtk3" = xyes],
+			[PKG_CHECK_MODULES(MAC_INTEGRATION, gtk-mac-integration-gtk3)], 
+			[PKG_CHECK_MODULES(MAC_INTEGRATION, gtk-mac-integration-gtk2)])
+	])
+])


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;


Modified: src/Makefile.am
4 lines changed, 3 insertions(+), 1 deletions(-)
===================================================================
@@ -38,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 \
@@ -89,7 +90,7 @@ AM_CPPFLAGS = \
 	-I$(top_srcdir) \
 	-I$(top_srcdir)/scintilla/include \
 	-I$(top_srcdir)/tagmanager/src \
-	@GTK_CFLAGS@ @GTHREAD_CFLAGS@
+	@GTK_CFLAGS@ @GTHREAD_CFLAGS@ $(MAC_INTEGRATION_CFLAGS)
 
 # tell automake we have a C++ file so it uses the C++ linker we need for Scintilla
 nodist_EXTRA_geany_SOURCES = dummy.cxx
@@ -142,6 +143,7 @@ geany_LDADD = \
 	$(top_builddir)/tagmanager/src/libtagmanager.a \
 	@GTK_LIBS@ \
 	@GTHREAD_LIBS@ \
+	$(MAC_INTEGRATION_LIBS) \
 	$(INTLLIBS)
 
 AM_CFLAGS = -DGEANY_DATADIR=\""$(datadir)"\" \


Modified: src/keybindings.c
28 lines changed, 1 insertions(+), 27 deletions(-)
===================================================================
@@ -1101,23 +1101,6 @@ static gboolean check_menu_key(GeanyDocument *doc, guint keyval, guint state, gu
 
 
 #ifdef HAVE_VTE
-static gboolean on_menu_expose_event(GtkWidget *widget, GdkEventExpose *event,
-		gpointer user_data)
-{
-	if (!gtk_widget_get_sensitive(widget))
-		gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE);
-	return FALSE;
-}
-
-
-#if GTK_CHECK_VERSION(3, 0, 0)
-static gboolean on_menu_draw(GtkWidget *widget, cairo_t *cr, gpointer user_data)
-{
-	return on_menu_expose_event(widget, NULL, user_data);
-}
-#endif
-
-
 static gboolean set_sensitive(gpointer widget)
 {
 	gtk_widget_set_sensitive(GTK_WIDGET(widget), TRUE);
@@ -1158,16 +1141,7 @@ static gboolean check_vte(GdkModifierType state, guint keyval)
 	 * Note: maybe there's a better way of doing this ;-) */
 	widget = ui_lookup_widget(main_widgets.window, "menubar1");
 	gtk_widget_set_sensitive(widget, FALSE);
-	{
-		/* make the menubar sensitive before it is redrawn */
-		static gboolean connected = FALSE;
-		if (!connected)
-#if GTK_CHECK_VERSION(3, 0, 0)
-			g_signal_connect(widget, "draw", G_CALLBACK(on_menu_draw), NULL);
-#else
-			g_signal_connect(widget, "expose-event", G_CALLBACK(on_menu_expose_event), NULL);
-#endif
-	}
+	g_idle_add_full(G_PRIORITY_HIGH, set_sensitive, widget, NULL);
 
 	widget = main_widgets.editor_menu;
 	gtk_widget_set_sensitive(widget, FALSE);


Modified: src/main.c
67 lines changed, 20 insertions(+), 47 deletions(-)
===================================================================
@@ -62,6 +62,7 @@
 #include "utils.h"
 #include "vte.h"
 #include "win32.h"
+#include "osx.h"
 
 #include "gtkcompat.h"
 
@@ -224,16 +225,7 @@ static void apply_settings(void)
 static void main_init(void)
 {
 	/* add our icon path in case we aren't installed in the system prefix */
-	gchar *path;
-#ifdef G_OS_WIN32
-	gchar *install_dir = win32_get_installation_dir();
-	path = g_build_filename(install_dir, "share", "icons", NULL);
-	g_free(install_dir);
-#else
-	path = g_build_filename(GEANY_DATADIR, "icons", NULL);
-#endif
-	gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), path);
-	g_free(path);
+	gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), utils_resource_dir(RESOURCE_DIR_ICON));
 
 	/* inits */
 	ui_init_stock_items();
@@ -274,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");
@@ -400,30 +395,9 @@ static void change_working_directory_on_windows(void)
 
 static void setup_paths(void)
 {
-	gchar *data_dir;
-	gchar *doc_dir;
-
-	/* set paths */
-#ifdef G_OS_WIN32
-	/* use the installation directory(the one where geany.exe is located) as the base for the
-	 * documentation and data files */
-	gchar *install_dir = win32_get_installation_dir();
-
-	data_dir = g_build_filename(install_dir, "data", NULL); /* e.g. C:\Program Files\geany\data */
-	doc_dir = g_build_filename(install_dir, "doc", NULL);
-
-	g_free(install_dir);
-#else
-	data_dir = g_build_filename(GEANY_DATADIR, "geany", NULL); /* e.g. /usr/share/geany */
-	doc_dir = g_build_filename(GEANY_DOCDIR, "html", NULL);
-#endif
-
 	/* convert path names to locale encoding */
-	app->datadir = utils_get_locale_from_utf8(data_dir);
-	app->docdir = utils_get_locale_from_utf8(doc_dir);
-
-	g_free(data_dir);
-	g_free(doc_dir);
+	app->datadir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DATA));
+	app->docdir = utils_get_locale_from_utf8(utils_resource_dir(RESOURCE_DIR_DOC));
 }
 
 
@@ -473,26 +447,15 @@ gboolean main_is_realized(void)
  **/
 void main_locale_init(const gchar *locale_dir, const gchar *package)
 {
-	gchar *l_locale_dir = NULL;
-
 #ifdef HAVE_LOCALE_H
 	setlocale(LC_ALL, "");
 #endif
 
 #ifdef G_OS_WIN32
-	{
-		gchar *install_dir = win32_get_installation_dir();
-		/* e.g. C:\Program Files\geany\lib\locale */
-		l_locale_dir = g_build_filename(install_dir, "share", "locale", NULL);
-		g_free(install_dir);
-	}
-#else
-	l_locale_dir = g_strdup(locale_dir);
+	locale_dir = utils_resource_dir(RESOURCE_DIR_LOCALE);
 #endif
-
-	(void) bindtextdomain(package, l_locale_dir);
+	(void) bindtextdomain(package, locale_dir);
 	(void) bind_textdomain_codeset(package, "UTF-8");
-	g_free(l_locale_dir);
 }
 
 
@@ -647,6 +610,11 @@ static void parse_command_line_options(gint *argc, gchar ***argv)
 		g_printerr("Geany: cannot open display\n");
 		exit(1);
 	}
+
+#ifdef MAC_INTEGRATION
+	/* Create GtkosxApplication singleton - should be created shortly after gtk_init() */
+	gtkosx_application_get();
+#endif
 }
 
 
@@ -1059,7 +1027,7 @@ gint main(gint argc, gchar **argv)
 	setup_gtk2_styles();
 #endif
 #ifdef ENABLE_NLS
-	main_locale_init(GEANY_LOCALEDIR, GETTEXT_PACKAGE);
+	main_locale_init(utils_resource_dir(RESOURCE_DIR_LOCALE), GETTEXT_PACKAGE);
 #endif
 	parse_command_line_options(&argc, &argv);
 
@@ -1233,6 +1201,11 @@ gint main(gint argc, gchar **argv)
 	 * tell other components, mainly plugins, that startup is complete */
 	g_idle_add_full(G_PRIORITY_LOW, send_startup_complete, NULL, NULL);
 
+#ifdef MAC_INTEGRATION
+	/* OS X application ready - has to be called before entering main loop */
+	gtkosx_application_ready(gtkosx_application_get());
+#endif
+	
 	gtk_main();
 	return 0;
 }


Modified: src/notebook.c
23 lines changed, 4 insertions(+), 19 deletions(-)
===================================================================
@@ -419,29 +419,14 @@ static void tab_bar_menu_activate_cb(GtkMenuItem *menuitem, gpointer data)
 
 static void on_open_in_new_window_activate(GtkMenuItem *menuitem, gpointer user_data)
 {
-	gchar *geany_path;
 	GeanyDocument *doc = user_data;
+	gchar *doc_path;
 
 	g_return_if_fail(doc->is_valid);
 
-	geany_path = g_find_program_in_path("geany");
-
-	if (geany_path)
-	{
-		gchar *doc_path = utils_get_locale_from_utf8(doc->file_name);
-		gchar *argv[] = {geany_path, "-i", doc_path, NULL};
-		GError *err = NULL;
-
-		if (!utils_spawn_async(NULL, argv, NULL, 0, NULL, NULL, NULL, &err))
-		{
-			g_printerr("Unable to open new window: %s", err->message);
-			g_error_free(err);
-		}
-		g_free(doc_path);
-		g_free(geany_path);
-	}
-	else
-		g_printerr("Unable to find 'geany'");
+	doc_path = utils_get_locale_from_utf8(doc->file_name);
+	utils_start_new_geany_instance(doc_path);
+	g_free(doc_path);
 }
 
 


Modified: src/osx.c
131 lines changed, 131 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,131 @@
+/*
+ *      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 "utils.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;
+}
+
+
+static void on_new_window(GtkMenuItem *menuitem, G_GNUC_UNUSED gpointer user_data)
+{
+	utils_start_new_geany_instance(NULL);
+}
+
+
+static void app_active_cb(GtkosxApplication* app, G_GNUC_UNUSED gpointer user_data)
+{
+	GeanyDocument *doc = document_get_current();
+	if (doc)
+		document_check_disk_status(doc, TRUE);
+}
+
+
+void osx_ui_init(void)
+{
+	GtkWidget *item, *menu;
+	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);
+
+	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);
+	g_signal_connect(osx_app, "NSApplicationDidBecomeActive",
+					G_CALLBACK(app_active_cb), NULL);
+
+	menu = gtk_menu_new();
+	item = gtk_menu_item_new_with_label("New Window");
+	g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(on_new_window), NULL);
+	gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
+	gtkosx_application_set_dock_menu(osx_app, GTK_MENU_SHELL(menu));
+}
+
+#endif /* MAC_INTEGRATION */


Modified: src/osx.h
36 lines changed, 36 insertions(+), 0 deletions(-)
===================================================================
@@ -0,0 +1,36 @@
+/*
+ *      osx.h - 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.
+ */
+
+#ifndef GEANY_OSX_H
+#define GEANY_OSX_H 1
+
+#ifdef MAC_INTEGRATION
+
+#include <gtkosxapplication.h>
+
+G_BEGIN_DECLS
+
+void osx_ui_init(void);
+
+G_END_DECLS
+
+#endif /* MAC_INTEGRATION */
+
+#endif /* GEANY_OSX_H */


Modified: src/plugins.c
12 lines changed, 1 insertions(+), 11 deletions(-)
===================================================================
@@ -999,17 +999,7 @@ load_plugins_from_path(const gchar *path)
 
 static gchar *get_plugin_path(void)
 {
-#ifdef G_OS_WIN32
-	gchar *path;
-	gchar *install_dir = win32_get_installation_dir();
-
-	path = g_build_filename(install_dir, "lib", NULL);
-	g_free(install_dir);
-
-	return path;
-#else
-	return g_build_filename(GEANY_LIBDIR, "geany", NULL);
-#endif
+	return g_strdup(utils_resource_dir(RESOURCE_DIR_PLUGIN));
 }
 
 


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);
 }
 
 


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: src/utils.c
92 lines changed, 92 insertions(+), 0 deletions(-)
===================================================================
@@ -38,6 +38,7 @@
 #include "templates.h"
 #include "ui_utils.h"
 #include "win32.h"
+#include "osx.h"
 
 #include <stdlib.h>
 #include <ctype.h>
@@ -2088,3 +2089,94 @@ gchar *utils_get_user_config_dir(void)
 	return g_build_filename(g_get_user_config_dir(), "geany", NULL);
 #endif
 }
+
+
+static gboolean is_osx_bundle(void)
+{
+#ifdef MAC_INTEGRATION
+	gchar *bundle_id = gtkosx_application_get_bundle_id();
+	if (bundle_id)
+	{
+		g_free(bundle_id);
+		return TRUE;
+	}
+#endif
+	return FALSE;
+}
+
+
+const gchar *utils_resource_dir(GeanyResourceDirType type)
+{
+	static const gchar *resdirs[RESOURCE_DIR_COUNT] = {NULL};
+
+	if (!resdirs[RESOURCE_DIR_DATA])
+	{
+#ifdef G_OS_WIN32
+		gchar *prefix = win32_get_installation_dir();
+
+		resdirs[RESOURCE_DIR_DATA] = g_build_filename(prefix, "data", NULL);
+		resdirs[RESOURCE_DIR_ICON] = g_build_filename(prefix, "share", "icons", NULL);
+		resdirs[RESOURCE_DIR_DOC] = g_build_filename(prefix, "doc", NULL);
+		resdirs[RESOURCE_DIR_LOCALE] = g_build_filename(prefix, "share", "locale", NULL);
+		resdirs[RESOURCE_DIR_PLUGIN] = g_build_filename(prefix, "lib", NULL);
+		g_free(prefix);
+#else
+		if (is_osx_bundle())
+		{
+# ifdef MAC_INTEGRATION
+			gchar *prefix = gtkosx_application_get_resource_path();
+			
+			resdirs[RESOURCE_DIR_DATA] = g_build_filename(prefix, "share", "geany", NULL);
+			resdirs[RESOURCE_DIR_ICON] = g_build_filename(prefix, "share", "icons", NULL);
+			resdirs[RESOURCE_DIR_DOC] = g_build_filename(prefix, "share", "doc", "geany", "html", NULL);
+			resdirs[RESOURCE_DIR_LOCALE] = g_build_filename(prefix, "share", "locale", NULL);
+			resdirs[RESOURCE_DIR_PLUGIN] = g_build_filename(prefix, "lib", "geany", NULL);
+			g_free(prefix);
+# endif
+		}
+		else
+		{
+			resdirs[RESOURCE_DIR_DATA] = g_build_filename(GEANY_DATADIR, "geany", NULL);
+			resdirs[RESOURCE_DIR_ICON] = g_build_filename(GEANY_DATADIR, "icons", NULL);
+			resdirs[RESOURCE_DIR_DOC] = g_build_filename(GEANY_DOCDIR, "html", NULL);
+			resdirs[RESOURCE_DIR_LOCALE] = g_build_filename(GEANY_LOCALEDIR, NULL);
+			resdirs[RESOURCE_DIR_PLUGIN] = g_build_filename(GEANY_LIBDIR, "geany", NULL);
+		}
+#endif
+	}
+
+	return resdirs[type];
+}
+
+
+void utils_start_new_geany_instance(gchar *doc_path)
+{
+	gchar **argv;
+	const gchar *command = is_osx_bundle() ? "open" : "geany";
+	gchar *exec_path = g_find_program_in_path(command);
+
+	if (exec_path)
+	{
+		GError *err = NULL;
+
+		if (is_osx_bundle())
+		{
+			gchar *osx_argv[] = {exec_path, "-n", "-a", "Geany", doc_path, NULL};
+			argv = osx_argv;
+		}
+		else
+		{
+			gchar *unix_argv[] = {exec_path, "-i", doc_path, NULL};
+			argv = unix_argv;
+		}
+
+		if (!utils_spawn_async(NULL, argv, NULL, 0, NULL, NULL, NULL, &err))
+		{
+			g_printerr("Unable to open new window: %s", err->message);
+			g_error_free(err);
+		}
+		g_free(exec_path);
+	}
+	else
+		g_printerr("Unable to find 'geany'");
+}


Modified: src/utils.h
16 lines changed, 16 insertions(+), 0 deletions(-)
===================================================================
@@ -200,6 +200,18 @@ const gchar *utils_find_open_xml_tag_pos(const gchar sel[], gint size);
 
 #ifdef GEANY_PRIVATE
 
+typedef enum
+{
+	RESOURCE_DIR_DATA,
+	RESOURCE_DIR_ICON,
+	RESOURCE_DIR_DOC,
+	RESOURCE_DIR_LOCALE,
+	RESOURCE_DIR_PLUGIN,
+
+	RESOURCE_DIR_COUNT
+} GeanyResourceDirType;
+
+
 gint utils_get_line_endings(const gchar* buffer, gsize size);
 
 gboolean utils_isbrace(gchar c, gboolean include_angles);
@@ -294,6 +306,10 @@ gchar *utils_parse_and_format_build_date(const gchar *input);
 
 gchar *utils_get_user_config_dir(void);
 
+const gchar *utils_resource_dir(GeanyResourceDirType type);
+
+void utils_start_new_geany_instance(gchar *doc_path);
+
 #endif /* GEANY_PRIVATE */
 
 G_END_DECLS


Modified: wscript
11 lines changed, 9 insertions(+), 2 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',
@@ -226,6 +226,10 @@ def configure(conf):
     conf.check_cfg(package='gio-2.0', uselib_store='GIO', args='--cflags --libs', mandatory=True)
     gtk_version = conf.check_cfg(modversion=gtk_package_name, uselib_store='GTK') or 'Unknown'
     conf.check_cfg(package='gthread-2.0', uselib_store='GTHREAD', args='--cflags --libs')
+    if conf.options.enable_mac_integration:
+        pkgname = 'gtk-mac-integration-gtk3' if conf.options.use_gtk3 else 'gtk-mac-integration-gtk2'
+        conf.check_cfg(package=pkgname, uselib_store='MAC_INTEGRATION', 
+            mandatory=True, args='--cflags --libs')
     # remember GTK version for the build step
     conf.env['gtk_package_name'] = gtk_package_name
     conf.env['minimum_gtk_version'] = minimum_gtk_version
@@ -347,6 +351,9 @@ def options(opt):
     opt.add_option('--enable-gtk3', action='store_true', default=False,
         help='compile with GTK3 support (experimental) [[default: No]',
         dest='use_gtk3')
+    opt.add_option('--enable-mac-integration', action='store_true', default=False,
+        help='use gtk-mac-integration to enable improved OS X integration [[default: No]',
+        dest='enable_mac_integration')
     opt.add_option('--disable-html-docs', action='store_true', default=False,
         help='do not generate HTML documentation using rst2html [[default: No]',
         dest='no_html_doc')
@@ -441,7 +448,7 @@ def build(bld):
         source          = geany_sources,
         includes        = ['.', 'scintilla/include', 'tagmanager/src'],
         defines         = ['G_LOG_DOMAIN="Geany"', 'GEANY_PRIVATE'],
-        uselib          = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'SUNOS_SOCKET', 'M'],
+        uselib          = ['GTK', 'GLIB', 'GMODULE', 'GIO', 'GTHREAD', 'WIN32', 'MAC_INTEGRATION', 'SUNOS_SOCKET', 'M'],
         use             = ['scintilla', 'ctags', 'tagmanager', 'mio'])
 
     # geanyfunctions.h



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


More information about the Commits mailing list