Use gtk-mac-integration so app bundle can be created on OS X

This patch adds the gtk-mac-integration library and uses it to
adjust various paths in Geany to point it inside the app bundle
if Geany runs from inside the bundle.

It adds the utils_resource_dir() utility function to return
correct directories for various kinds of resources for all supported
operating systems. Using this function the patch adjusts all Geany
resource, plugin, icon, doc, and locale paths.
This commit is contained in:
Jiří Techet 2015-02-04 00:27:34 +01:00
parent 87af9597fc
commit 18d517bd95
9 changed files with 151 additions and 60 deletions

View File

@ -105,6 +105,7 @@ GEANY_CHECK_MINGW
GEANY_CHECK_SOCKET
GEANY_CHECK_VTE
GEANY_CHECK_MAC_INTEGRATION
GEANY_CHECK_THE_FORCE dnl hehe
# i18n

View File

@ -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)])
])
])

View File

@ -10,6 +10,7 @@ EXTRA_DIST = \
keybindingsprivate.h \
pluginprivate.h \
projectprivate.h \
osx.h \
makefile.win32
bin_PROGRAMS = geany
@ -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)"\" \

View File

@ -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();
@ -400,30 +392,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 +444,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 +607,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 +1024,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 +1198,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;
}

30
src/osx.h Normal file
View File

@ -0,0 +1,30 @@
/*
* 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>
#endif /* MAC_INTEGRATION */
#endif /* GEANY_OSX_H */

View File

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

View File

@ -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,61 @@ 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];
}

View File

@ -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,8 @@ gchar *utils_parse_and_format_build_date(const gchar *input);
gchar *utils_get_user_config_dir(void);
const gchar *utils_resource_dir(GeanyResourceDirType type);
#endif /* GEANY_PRIVATE */
G_END_DECLS

View File

@ -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