diff --git a/.gitignore b/.gitignore index 66826bbde8..e496f23c08 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,7 @@ deluge/ui/web/js/extjs/ext-extensions*.js osx/app RELEASE-VERSION .venv* +/packaging/osx/app +/packaging/osx/py2app-build +*.app +/py2app-build diff --git a/MANIFEST.in b/MANIFEST.in index d2d970fe61..11a920d658 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -23,7 +23,7 @@ recursive-exclude deluge/tests *.pyc graft deluge/ui/data recursive-exclude deluge/ui/data *.desktop *.xml -graft deluge/ui/gtkui/glade +graft deluge/ui/gtk3/glade include deluge/ui/web/index.html include deluge/ui/web/css/*.css diff --git a/deluge/i18n/util.py b/deluge/i18n/util.py index 90568fc5ba..77aebcead3 100644 --- a/deluge/i18n/util.py +++ b/deluge/i18n/util.py @@ -132,7 +132,7 @@ def setup_translation(): log.error(exception) setup_mock_translation() elif deluge.common.osx_check(): - libintl = ctypes.cdll.LoadLibrary('libintl.dylib') + libintl = ctypes.cdll.LoadLibrary('libintl.8.dylib') if libintl: libintl.bindtextdomain( diff --git a/deluge/ui/gtk3/glade/create_torrent_dialog.ui b/deluge/ui/gtk3/glade/create_torrent_dialog.ui index c27a4b8666..0166e2d0b3 100644 --- a/deluge/ui/gtk3/glade/create_torrent_dialog.ui +++ b/deluge/ui/gtk3/glade/create_torrent_dialog.ui @@ -810,6 +810,7 @@ True True + False diff --git a/deluge/ui/gtk3/glade/main_window.ui b/deluge/ui/gtk3/glade/main_window.ui index ecbb8f61c7..b51b06d7be 100644 --- a/deluge/ui/gtk3/glade/main_window.ui +++ b/deluge/ui/gtk3/glade/main_window.ui @@ -116,6 +116,7 @@ False + accelgroup1 _Add Torrent @@ -126,7 +127,6 @@ add-image False - @@ -138,7 +138,6 @@ new-image False - @@ -155,7 +154,6 @@ False True - @@ -172,7 +170,6 @@ True quit_image False - accelgroup1 @@ -191,6 +188,7 @@ True False + accelgroup1 _Preferences @@ -199,9 +197,7 @@ True prefs-image False - accelgroup1 - @@ -213,7 +209,6 @@ connection-image False - @@ -237,6 +232,7 @@ True False + accelgroup1 True @@ -297,7 +293,6 @@ _Find ... True - @@ -312,6 +307,7 @@ True False True + accelgroup1 True @@ -377,7 +373,6 @@ True False - @@ -405,7 +400,6 @@ True about-image False - accelgroup1 @@ -467,7 +461,6 @@ This will filter torrents for the current selection on the sidebar. Filter system-search-symbolic - False diff --git a/deluge/ui/gtk3/gtkui.py b/deluge/ui/gtk3/gtkui.py index 47e889c6e5..107b998851 100644 --- a/deluge/ui/gtk3/gtkui.py +++ b/deluge/ui/gtk3/gtkui.py @@ -157,14 +157,19 @@ def on_die(*args): log.debug('Win32 "die" handler registered') elif osx_check() and windowing('quartz'): try: - import gtkosx_application + gi.require_version('GtkosxApplication', '1.0') + from gi.repository import GtkosxApplication except ImportError: pass else: - self.osxapp = gtkosx_application.gtkosx_application_get() + self.osxapp = GtkosxApplication.Application() self.osxapp.connect('NSApplicationWillTerminate', on_die) log.debug('OSX quartz "die" handler registered') + if os.getenv('DELUGE_IS_RUNNING_BUNDLE') != "": + launcherpath = os.path.join(os.path.dirname(sys.argv[0]), 'Deluge') + sys.argv[0] = launcherpath + # Set process name again to fix gtk issue setproctitle(getproctitle()) @@ -182,6 +187,8 @@ def on_die(*args): # Set language if self.config['language'] is not None: set_language(self.config['language']) + elif osx_check() and os.getenv('DELUGE_IS_RUNNING_BUNDLE') != "": + set_language(os.getenv('LANG')) # Start the IPC Interface before anything else.. Just in case we are # already running. @@ -210,7 +217,7 @@ def on_die(*args): def nsapp_open_file(osxapp, filename): # Ignore command name which is raised at app launch (python opening main script). - if filename == sys.argv[0]: + if (filename == sys.argv[0] or filename == sys.argv[0]+"-bin"): return True process_args([filename]) diff --git a/deluge/ui/gtk3/menubar.py b/deluge/ui/gtk3/menubar.py index e09f394fc9..01822c3562 100644 --- a/deluge/ui/gtk3/menubar.py +++ b/deluge/ui/gtk3/menubar.py @@ -14,7 +14,12 @@ import logging import os.path -from gi.repository import Gtk +from gi import require_version + +require_version('Gtk', '3.0') +require_version('Gdk', '3.0') + +from gi.repository import Gtk, Gdk import deluge.common import deluge.component as component @@ -141,6 +146,35 @@ def __init__(self): self.builder.connect_signals(self) self.change_sensitivity = ['menuitem_addtorrent'] + menubar = self.main_builder.get_object('menubar') + group = Gtk.accel_groups_from_object(self.mainwindow.window)[0] + + file_menu = self.main_builder.get_object('menu_file').get_submenu() + edit_menu = self.main_builder.get_object('menu_edit').get_submenu() + torrent_menu = self.main_builder.get_object('menu_torrent').get_submenu() + view_menu = self.main_builder.get_object('menu_view').get_submenu() + help_menu = self.main_builder.get_object('menu_help').get_submenu() + + Gtk.Menu.set_accel_group(file_menu, group) + Gtk.Menu.set_accel_group(edit_menu, group) + Gtk.Menu.set_accel_group(torrent_menu, group) + Gtk.Menu.set_accel_group(view_menu, group) + Gtk.Menu.set_accel_group(help_menu, group) + + Gtk.Menu.set_accel_path(file_menu, "/File") + Gtk.Menu.set_accel_path(edit_menu, "/Edit") + Gtk.Menu.set_accel_path(torrent_menu, "/Torrent") + Gtk.Menu.set_accel_path(view_menu, "/View") + Gtk.Menu.set_accel_path(help_menu, "/Help") + + Gtk.AccelMap.add_entry(Gtk.MenuItem.get_accel_path(self.main_builder.get_object('menuitem_addtorrent')), Gdk.unicode_to_keyval(ord('o')), Gdk.ModifierType.CONTROL_MASK) + Gtk.AccelMap.add_entry(Gtk.MenuItem.get_accel_path(self.main_builder.get_object('menuitem_createtorrent')), Gdk.unicode_to_keyval(ord('n')), Gdk.ModifierType.CONTROL_MASK) + Gtk.AccelMap.add_entry(Gtk.MenuItem.get_accel_path(self.main_builder.get_object('menuitem_quitdaemon')), Gdk.unicode_to_keyval(ord('q')), Gdk.ModifierType.SHIFT_MASK | Gdk.ModifierType.CONTROL_MASK) + Gtk.AccelMap.add_entry(Gtk.MenuItem.get_accel_path(self.main_builder.get_object('menuitem_preferences')), Gdk.unicode_to_keyval(ord('p')), Gdk.ModifierType.CONTROL_MASK) + Gtk.AccelMap.add_entry(Gtk.MenuItem.get_accel_path(self.main_builder.get_object('menuitem_connectionmanager')), Gdk.unicode_to_keyval(ord('m')), Gdk.ModifierType.CONTROL_MASK) + Gtk.AccelMap.add_entry(Gtk.MenuItem.get_accel_path(self.main_builder.get_object('find_menuitem')), Gdk.unicode_to_keyval(ord('f')), Gdk.ModifierType.CONTROL_MASK) + Gtk.AccelMap.add_entry(Gtk.MenuItem.get_accel_path(self.main_builder.get_object('menuitem_faq')), Gdk.keyval_from_name('F1'), 0) + def start(self): for widget in self.change_sensitivity: diff --git a/deluge/ui/gtk3/menubar_osx.py b/deluge/ui/gtk3/menubar_osx.py index 1df6fab08f..f27d73a214 100644 --- a/deluge/ui/gtk3/menubar_osx.py +++ b/deluge/ui/gtk3/menubar_osx.py @@ -8,48 +8,29 @@ # from __future__ import unicode_literals +from gi import require_version -from gi.repository.Gdk import ModifierType -from gi.repository.Gtk import SeparatorMenuItem, accel_groups_from_object -from gi.repository.Gtk.AccelFlags import VISIBLE +require_version('Gtk', '3.0') +require_version('Gdk', '3.0') -from deluge.configmanager import ConfigManager - - -def accel_swap(item, group, skey, smod, dkey, dmod): - # Accel map hack broken, see ticket #3078 - # item.remove_accelerator(group, ord(skey), smod) - item.add_accelerator('activate', group, ord(dkey), dmod, VISIBLE) +from gi.repository import Gtk, Gdk +from deluge.configmanager import ConfigManager -def accel_meta(item, group, key): - accel_swap(item, group, key, ModifierType.CONTROL_MASK, key, ModifierType.META_MASK) +def menubar_osx(gtkui, osxapp): + def accel_swap(item, key, modifier): + Gtk.AccelMap.change_entry(Gtk.MenuItem.get_accel_path(main_builder.get_object(item)), Gdk.keyval_from_name(key), modifier, True) -def menubar_osx(gtkui, osxapp): main_builder = gtkui.mainwindow.get_builder() menubar = main_builder.get_object('menubar') - group = accel_groups_from_object(gtkui.mainwindow.window)[0] + group = Gtk.accel_groups_from_object(gtkui.mainwindow.window)[0] config = ConfigManager('gtk3ui.conf') - - # NOTE: accel maps doesn't work with glade file format - # because of libglade not setting MenuItem accel groups - # That's why we remove / set accelerators by hand... (dirty) - # Clean solution: migrate glades files to gtkbuilder format file_menu = main_builder.get_object('menu_file').get_submenu() file_items = file_menu.get_children() - accel_meta(file_items[0], group, 'o') - accel_meta(file_items[1], group, 'n') quit_all_item = file_items[3] - accel_swap( - quit_all_item, - group, - 'q', - ModifierType.SHIFT_MASK | ModifierType.CONTROL_MASK, - 'q', - ModifierType.SHIFT_MASK | ModifierType.META_MASK, - ) + for item in range(2, len(file_items)): # remove quits file_menu.remove(file_items[item]) @@ -57,13 +38,9 @@ def menubar_osx(gtkui, osxapp): edit_menu = menu_widget.get_submenu() edit_items = edit_menu.get_children() pref_item = edit_items[0] - accel_swap( - pref_item, group, 'p', ModifierType.CONTROL_MASK, ',', ModifierType.META_MASK - ) edit_menu.remove(pref_item) conn_item = edit_items[1] - accel_meta(conn_item, group, 'm') edit_menu.remove(conn_item) menubar.remove(menu_widget) @@ -74,14 +51,23 @@ def menubar_osx(gtkui, osxapp): help_menu.remove(about_item) help_menu.remove(help_items[3]) # separator + # Change accelerators + accel_swap('menuitem_addtorrent', 'o', Gdk.ModifierType.META_MASK) + accel_swap('menuitem_createtorrent', 'n', Gdk.ModifierType.META_MASK) + accel_swap('menuitem_quitdaemon', 'q', Gdk.ModifierType.SHIFT_MASK | Gdk.ModifierType.META_MASK) + accel_swap('menuitem_preferences', 'comma', Gdk.ModifierType.META_MASK) + accel_swap('menuitem_connectionmanager', 'm', Gdk.ModifierType.META_MASK) + accel_swap('find_menuitem', 'f', Gdk.ModifierType.META_MASK) + accel_swap('menuitem_faq', 'question', Gdk.ModifierType.META_MASK) + menubar.hide() osxapp.set_menu_bar(menubar) # populate app menu osxapp.insert_app_menu_item(about_item, 0) - osxapp.insert_app_menu_item(SeparatorMenuItem(), 1) + osxapp.insert_app_menu_item(Gtk.SeparatorMenuItem(), 1) osxapp.insert_app_menu_item(pref_item, 2) if not config['standalone']: osxapp.insert_app_menu_item(conn_item, 3) if quit_all_item.get_visible(): - osxapp.insert_app_menu_item(SeparatorMenuItem(), 4) - osxapp.insert_app_menu_item(quit_all_item, 5) + osxapp.insert_app_menu_item(Gtk.SeparatorMenuItem(), 4) + osxapp.insert_app_menu_item(quit_all_item, 5) \ No newline at end of file diff --git a/packaging/osx/Info.plist.in b/packaging/osx/Info.plist.in index 7021497a20..6cb6e869b6 100644 --- a/packaging/osx/Info.plist.in +++ b/packaging/osx/Info.plist.in @@ -55,5 +55,16 @@ + CFBundleURLTypes + + + CFBundleURLName + BitTorrent Magnet URL + CFBundleURLSchemes + + magnet + + + diff --git a/packaging/osx/deluge b/packaging/osx/deluge deleted file mode 100755 index 023977f7d0..0000000000 --- a/packaging/osx/deluge +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/bash - -EXEC="exec" - -name="`basename $0`" -if [[ "$0" == `pwd`* ]] || [[ "$0" == "/"* ]]; then - full_path="$0" -else - full_path="`pwd`/$0" -fi -tmp=`dirname "$full_path"` -tmp=`dirname "$tmp"` -bundle=`dirname "$tmp"` -bundle_contents=${bundle%"/Contents"}"/Contents" -bundle_macos="$bundle_contents"/MacOS -bundle_res="$bundle_contents"/Resources -bundle_lib="$bundle_res"/lib -bundle_data="$bundle_res"/share -bundle_etc="$bundle_res"/etc - -export DYLD_FALLBACK_LIBRARY_PATH="$bundle_lib" -export XDG_CONFIG_DIRS="$bundle_etc"/xdg -export XDG_DATA_DIRS="$bundle_data" -export GTK_DATA_PREFIX="$bundle_res" -export GTK_EXE_PREFIX="$bundle_res" -export GTK_PATH="$bundle_res" -export GTK2_RC_FILES="$bundle_etc/gtk-2.0/gtkrc" -export GTK_IM_MODULE_FILE="$bundle_etc/gtk-2.0/gtk.immodules" -export GDK_PIXBUF_MODULE_FILE="$bundle_lib/gdk-pixbuf-2.0/2.10.0/loaders.cache" -export PANGO_RC_FILE="$bundle_etc/pango/pangorc" -export PANGO_LIBDIR="$bundle_lib" -export PANGO_SYSCONFDIR="$bundle_etc" - -#Set $PYTHON to point inside the bundle -export PYTHON="$bundle_macos/python" -export PYTHONHOME="$bundle_res" -#Add the bundle's python modules -PYTHONPATH="$bundle_lib:$PYTHONPATH" -PYTHONPATH="$bundle_lib/python/lib-dynload/:$PYTHONPATH" -PYTHONPATH="$bundle_lib/python/:$PYTHONPATH" -PYTHONPATH="$bundle_lib/pygtk/2.0:$PYTHONPATH" -export PYTHONPATH - -# Ensure deluged is available by adding macos dir to path. -PATH=$bundle_macos:$PATH - -# We need a UTF-8 locale. -lang=`defaults read .GlobalPreferences AppleLocale 2>/dev/null` -if test "$?" != "0"; then - lang=`defaults read .GlobalPreferences AppleCollationOrder 2>/dev/null | sed 's/_.*//'` -fi -LANG="" -if test "$lang" != ""; then - LANG="`grep \"\`echo $lang\`_\" /usr/share/locale/locale.alias | \ - tail -n1 | sed 's/\./ /' | awk '{print $2}'`" -fi -if test "$LANG" == ""; then - export LANG="C" -else - export LANG="$LANG.utf8" -fi - -if test -f "$bundle_lib/charset.alias"; then - export CHARSETALIASDIR="$bundle_lib" -fi - -# Extra arguments can be added in environment.sh. -EXTRA_ARGS= -if test -f "$bundle_res/environment.sh"; then - source "$bundle_res/environment.sh" -fi - -# Strip out the argument added by the OS. -if [ "x`echo "x$1" | sed -e "s/^x-psn_.*//"`" == "x" ]; then - shift 1 -fi - -# Note that we're calling $PYTHON here to override the version used. -$EXEC "$PYTHON" "$bundle_macos/Deluge-bin" "$@" diff --git a/packaging/osx/deluge-console b/packaging/osx/deluge-console deleted file mode 100755 index e1e20e8345..0000000000 --- a/packaging/osx/deluge-console +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -EXEC="exec" - -name="`basename $0`" -if [[ "$0" == `pwd`* ]] || [[ "$0" == "/"* ]]; then - full_path="$0" -else - full_path="`pwd`/$0" -fi -tmp=`dirname "$full_path"` -tmp=`dirname "$tmp"` -bundle=`dirname "$tmp"` -bundle_contents=${bundle%"/Contents"}"/Contents" -bundle_macos="$bundle_contents"/MacOS -bundle_res="$bundle_contents"/Resources -bundle_lib="$bundle_res"/lib -bundle_data="$bundle_res"/share -bundle_etc="$bundle_res"/etc - -export DYLD_FALLBACK_LIBRARY_PATH="$bundle_lib" -export XDG_CONFIG_DIRS="$bundle_etc"/xdg -export XDG_DATA_DIRS="$bundle_data" - -#Set $PYTHON to point inside the bundle -export PYTHON="$bundle_macos/python" -export PYTHONHOME="$bundle_res" -#Add the bundle's python modules -PYTHONPATH="$bundle_lib:$PYTHONPATH" -PYTHONPATH="$bundle_lib/python/lib-dynload/:$PYTHONPATH" -PYTHONPATH="$bundle_lib/python/:$PYTHONPATH" -export PYTHONPATH - -# Ensure deluged is available by adding macos dir to path. -PATH=$bundle_macos:$PATH - -# We need a UTF-8 locale. -lang=`defaults read .GlobalPreferences AppleLocale 2>/dev/null` -if test "$?" != "0"; then - lang=`defaults read .GlobalPreferences AppleCollationOrder 2>/dev/null | sed 's/_.*//'` -fi -LANG="" -if test "$lang" != ""; then - LANG="`grep \"\`echo $lang\`_\" /usr/share/locale/locale.alias | \ - tail -n1 | sed 's/\./ /' | awk '{print $2}'`" -fi -if test "$LANG" == ""; then - export LANG="C" -else - export LANG="$LANG.utf8" -fi - -if test -f "$bundle_lib/charset.alias"; then - export CHARSETALIASDIR="$bundle_lib" -fi - -# Extra arguments can be added in environment.sh. -EXTRA_ARGS= -if test -f "$bundle_res/environment.sh"; then - source "$bundle_res/environment.sh" -fi - -# Strip out the argument added by the OS. -if [ "x`echo "x$1" | sed -e "s/^x-psn_.*//"`" == "x" ]; then - shift 1 -fi - -# Note that we're calling $PYTHON here to override the version used. -$EXEC "$PYTHON" "$bundle_macos/deluge-console-bin" "$@" diff --git a/packaging/osx/deluge-launcher b/packaging/osx/deluge-launcher new file mode 100755 index 0000000000..cc5f04ccdd --- /dev/null +++ b/packaging/osx/deluge-launcher @@ -0,0 +1,119 @@ +#!/bin/sh +if test "x$GTK_DEBUG_LAUNCHER" != x; then + set -x +fi + +if test "x$GTK_DEBUG_GDB" != x; then + EXEC="gdb --args" +else + EXEC=exec +fi + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "${SOURCE}" ] + do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )" + SOURCE="$(readlink "${SOURCE}")" + [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located + done +CURRDIR="$( cd -P "$( dirname "$SOURCE" )" && cd ../.. && pwd )" + +name=`basename "$0"` +bundle="${CURRDIR}" +bundle_contents="${bundle}/Contents" +bundle_macos="${bundle}/Contents/MacOS" +bundle_res="${bundle_contents}/Resources" +bundle_lib="${bundle_res}/lib" +bundle_bin="${bundle_res}/bin" +bundle_data="${bundle_res}/share" +bundle_etc="${bundle_res}/etc" + +export DYLD_FALLBACK_LIBRARY_PATH="${bundle_lib}" + +if [ ! -d "${HOME}/Library/Preferences/org.deluge-2.0" ]; then + mkdir -p "${HOME}/Library/Preferences/org.deluge-2.0" +fi + +if [ ! -d "${HOME}/Library/Logs/org.deluge-2.0" ]; then + mkdir -p "${HOME}/Library/Logs/org.deluge-2.0" +fi + +if [ -d "${HOME}/.config/deluge" ]; then + echo "Found Deluge config data at '${HOME}/.config/deluge'..." + if [ ! -d "${HOME}/Library/Preferences/org.deluge-2.0/gtk3ui_state" ]; then + echo "Copying config data to '${HOME}/Library/Preferences/org.deluge-2.0'." + rsync -r --exclude "deluged.pid" --exclude "deluged.log" --exclude "plugins" --exclude "gtkui*" "${HOME}/.config/deluge/" "${HOME}/Library/Preferences/org.deluge-2.0/" + else + echo "We'll just ignore it since there is Deluge 2.x config data already at '${HOME}/Library/Preferences/org.deluge-2.0'" + fi +fi + +export XDG_DOWNLOAD_DIR="${HOME}/Downloads" +export XDG_CONFIG_HOME="${HOME}/Library/Preferences/org.deluge-2.0" +export XDG_CONFIG_DIRS="${XDG_CONFIG_HOME}" +export XDG_DATA_DIRS="${bundle_data}" +export GTK_DATA_PREFIX="${bundle_res}" +export GTK_EXE_PREFIX="${bundle_res}" +export GTK_PATH="${bundle_res}" +export GI_TYPELIB_PATH="${bundle_lib}/girepository-1.0" + +export DELUGE_IS_RUNNING_BUNDLE=1 +export DELUGE_BUNDLE_I18N="${bundle_data}/locale" + +if [ "$(defaults read -g AppleInterfaceStyle 2>/dev/null)" ]; then + GTK_THEME="McOS-CTLina-Dark" +else + GTK_THEME="McOS-CTLina" +fi +export GTK_THEME + +#Set $PYTHON to point inside the bundle +export PYTHON="${bundle_macos}/python" +export PYTHONHOME="${bundle_res}" +#Add the bundle's python modules +export PYTHONPATH="${bundle_lib}/python/zope:${bundle_lib}/python:${bundle_lib}:${bundle_lib}/python/lib-dynload:${PYTHONPATH}" + +# Ensure deluged is available by adding macos dir to path. +export PATH="${bundle_macos}":$PATH + +export GDK_PIXBUF_MODULEDIR="${bundle_lib}/gdk-pixbuf-2.0/2.10.0/loaders/" +export GDK_PIXBUF_MODULE_FILE="${bundle_lib}/gdk-pixbuf-2.0/2.10.0/loaders.cache" +if [ `uname -r | cut -d . -f 1` -ge 10 ]; then + export GTK_IM_MODULE_FILE="${bundle_lib}/gtk-3.0/3.0.0/immodules.cache" +fi + +# We need a UTF-8 locale. +lang=`defaults read .GlobalPreferences AppleLocale 2>/dev/null` +if test "$?" != "0"; then + lang=`defaults read .GlobalPreferences AppleCollationOrder 2>/dev/null | sed 's/_.*//'` +fi +LANG="" +if test "$lang" != ""; then + LANG="`grep \"\`echo $lang\`_\" /usr/share/locale/locale.alias | \ + tail -n1 | sed 's/\./ /' | awk '{print $2}'`" +fi +if test "$LANG" == ""; then + export LANG="C" +else + export LANG="$LANG.utf8" +fi + +if test -f "$bundle_lib/charset.alias"; then + export CHARSETALIASDIR="$bundle_lib" +fi + +export LC_ALL=C +export LANG=$(echo $(defaults read -g AppleLanguages | sed '/"/!d;s/["[:space:]]//g;s/-/_/') | cut -d',' -f1).UTF-8 + +# Extra arguments can be added in environment.sh. +EXTRA_ARGS= +if test -f "${bundle_res}/environment.sh"; then + source "${bundle_res}/environment.sh" +fi + +# Strip out the argument added by the OS. +if /bin/expr "x${1}" : '^x-psn_' > /dev/null; then + shift 1 +fi +LOGTIMESTAMP=$(date +'%Y-%m-%d_%H-%M-%S') +${EXEC} "${PYTHON}" "${bundle_macos}"/${name}-bin --config="${XDG_CONFIG_HOME}" --logfile="${HOME}/Library/Logs/org.deluge-2.0/${name}-${LOGTIMESTAMP}.log" --loglevel info "$@" ${EXTRA_ARGS} \ No newline at end of file diff --git a/packaging/osx/deluge-macports.bundle b/packaging/osx/deluge-macports.bundle new file mode 100644 index 0000000000..59d758ee4c --- /dev/null +++ b/packaging/osx/deluge-macports.bundle @@ -0,0 +1,51 @@ + + + + /opt/local + ${env:PY2APP_PREFIX} + ${env:DELUGEDIR} + ${env:PY2APP_PREFIX}/Resources/lib/python${env:PY2APP_PYTHON_VERSION} + app + gtk+-3.0 + ${project}/deluge-launcher + + ${project}/Info.plist + ${prefix:py2app}/MacOS/deluge-gtk + ${prefix:py2app}/MacOS/deluged + ${prefix:py2app}/MacOS/deluge-web + ${prefix:py2app}/MacOS/deluge-console + + ${prefix:py2app}/Frameworks/Python.framework/Versions/${env:PY2APP_PYTHON_VERSION}/Python + ${prefix:py2app}/MacOS/python + + + ${prefix}/lib/gdk-pixbuf-2.0/${pkg:gdk-pixbuf-2.0:gdk_pixbuf_binary_version}/loaders/*.so + ${prefix}/lib/${gtkdir}/${pkg:${gtk}:gtk_binary_version}/immodules/*.so + ${prefix:py2app}/Resources/include + ${prefix}/share/glib-2.0/schemas/gschemas.compiled + ${prefix:py2app}/Resources/*.so + ${prefix:py2app}/Resources/*.py* + ${prefix:py2app}/Resources/*.sh + ${prefix:py2app}/Frameworks/*.dylib + ${prefix}/lib/libgtkmacintegration-gtk3.2.dylib + ${prefix:py2app}/Resources/lib/python*.zip + ${prefix:py2app}/Resources/lib/python${env:PY2APP_PYTHON_VERSION} + ${prefix}/share/gir-1.0/*.gir + + ${prefix}/share/themes/McOs-CTLina-Dark + ${prefix}/share/themes/McOs-CTLina + ${prefix}/share/themes/Mac + Adwaita + hicolor + + ${project}/deluge.icns + ${project}/torrent.icns + + ${project}/deluge-launcher + ${project}/deluge-launcher + ${project}/deluge-launcher + ${prefix}/share/locale + ${prefix}/share/locale + ${prefix}/share/locale + ${prefix:deluge}/deluge/i18n + diff --git a/packaging/osx/deluge-web b/packaging/osx/deluge-web deleted file mode 100755 index e66f550c0c..0000000000 --- a/packaging/osx/deluge-web +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -EXEC="exec" - -name="`basename $0`" -if [[ "$0" == `pwd`* ]] || [[ "$0" == "/"* ]]; then - full_path="$0" -else - full_path="`pwd`/$0" -fi -tmp=`dirname "$full_path"` -tmp=`dirname "$tmp"` -bundle=`dirname "$tmp"` -bundle_contents=${bundle%"/Contents"}"/Contents" -bundle_macos="$bundle_contents"/MacOS -bundle_res="$bundle_contents"/Resources -bundle_lib="$bundle_res"/lib -bundle_data="$bundle_res"/share -bundle_etc="$bundle_res"/etc - -export DYLD_FALLBACK_LIBRARY_PATH="$bundle_lib" -export XDG_CONFIG_DIRS="$bundle_etc"/xdg -export XDG_DATA_DIRS="$bundle_data" - -#Set $PYTHON to point inside the bundle -export PYTHON="$bundle_macos/python" -export PYTHONHOME="$bundle_res" -#Add the bundle's python modules -PYTHONPATH="$bundle_lib:$PYTHONPATH" -PYTHONPATH="$bundle_lib/python/lib-dynload/:$PYTHONPATH" -PYTHONPATH="$bundle_lib/python/:$PYTHONPATH" -export PYTHONPATH - -# Ensure deluged is available by adding macos dir to path. -PATH=$bundle_macos:$PATH - -# We need a UTF-8 locale. -lang=`defaults read .GlobalPreferences AppleLocale 2>/dev/null` -if test "$?" != "0"; then - lang=`defaults read .GlobalPreferences AppleCollationOrder 2>/dev/null | sed 's/_.*//'` -fi -LANG="" -if test "$lang" != ""; then - LANG="`grep \"\`echo $lang\`_\" /usr/share/locale/locale.alias | \ - tail -n1 | sed 's/\./ /' | awk '{print $2}'`" -fi -if test "$LANG" == ""; then - export LANG="C" -else - export LANG="$LANG.utf8" -fi - -if test -f "$bundle_lib/charset.alias"; then - export CHARSETALIASDIR="$bundle_lib" -fi - -# Extra arguments can be added in environment.sh. -EXTRA_ARGS= -if test -f "$bundle_res/environment.sh"; then - source "$bundle_res/environment.sh" -fi - -# Strip out the argument added by the OS. -if [ "x`echo "x$1" | sed -e "s/^x-psn_.*//"`" == "x" ]; then - shift 1 -fi - -# Note that we're calling $PYTHON here to override the version used. -$EXEC "$PYTHON" "$bundle_macos/deluge-web-bin" "$@" diff --git a/packaging/osx/deluged b/packaging/osx/deluged deleted file mode 100755 index 28cebc082c..0000000000 --- a/packaging/osx/deluged +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -EXEC="exec" - -name="`basename $0`" -if [[ "$0" == `pwd`* ]] || [[ "$0" == "/"* ]]; then - full_path="$0" -else - full_path="`pwd`/$0" -fi -tmp=`dirname "$full_path"` -tmp=`dirname "$tmp"` -bundle=`dirname "$tmp"` -bundle_contents=${bundle%"/Contents"}"/Contents" -bundle_macos="$bundle_contents"/MacOS -bundle_res="$bundle_contents"/Resources -bundle_lib="$bundle_res"/lib -bundle_data="$bundle_res"/share -bundle_etc="$bundle_res"/etc - -export DYLD_FALLBACK_LIBRARY_PATH="$bundle_lib" -export XDG_CONFIG_DIRS="$bundle_etc"/xdg -export XDG_DATA_DIRS="$bundle_data" - -#Set $PYTHON to point inside the bundle -export PYTHON="$bundle_macos/python" -export PYTHONHOME="$bundle_res" -#Add the bundle's python modules -PYTHONPATH="$bundle_lib:$PYTHONPATH" -PYTHONPATH="$bundle_lib/python/lib-dynload/:$PYTHONPATH" -PYTHONPATH="$bundle_lib/python/:$PYTHONPATH" -export PYTHONPATH - -# Ensure deluged is available by adding macos dir to path. -PATH=$bundle_macos:$PATH - -# We need a UTF-8 locale. -lang=`defaults read .GlobalPreferences AppleLocale 2>/dev/null` -if test "$?" != "0"; then - lang=`defaults read .GlobalPreferences AppleCollationOrder 2>/dev/null | sed 's/_.*//'` -fi -LANG="" -if test "$lang" != ""; then - LANG="`grep \"\`echo $lang\`_\" /usr/share/locale/locale.alias | \ - tail -n1 | sed 's/\./ /' | awk '{print $2}'`" -fi -if test "$LANG" == ""; then - export LANG="C" -else - export LANG="$LANG.utf8" -fi - -if test -f "$bundle_lib/charset.alias"; then - export CHARSETALIASDIR="$bundle_lib" -fi - -# Extra arguments can be added in environment.sh. -EXTRA_ARGS= -if test -f "$bundle_res/environment.sh"; then - source "$bundle_res/environment.sh" -fi - -# Strip out the argument added by the OS. -if [ "x`echo "x$1" | sed -e "s/^x-psn_.*//"`" == "x" ]; then - shift 1 -fi - -# Note that we're calling $PYTHON here to override the version used. -$EXEC "$PYTHON" "$bundle_macos/deluged-bin" "$@" diff --git a/packaging/osx/gtkrc b/packaging/osx/gtkrc deleted file mode 100644 index a77430b685..0000000000 --- a/packaging/osx/gtkrc +++ /dev/null @@ -1,10 +0,0 @@ -gtk-theme-name = "Clearlooks" -gtk-enable-mnemonics = 0 - -# Workaround for non-ascii display issue details -# here: http://bugs.gramps-project.org/view.php?id=5474 -style "user-font" -{ - font_name="Arial Unicode MS" -} -widget_class "*" style "user-font" diff --git a/packaging/osx/make-app b/packaging/osx/make-app.sh similarity index 98% rename from packaging/osx/make-app rename to packaging/osx/make-app.sh index 9489f6c0dd..4585be09de 100644 --- a/packaging/osx/make-app +++ b/packaging/osx/make-app.sh @@ -1,4 +1,5 @@ #!/bin/bash +set -o errexit APPDIR="./app/Deluge.app" RSCDIR="${APPDIR}/Contents/Resources" diff --git a/packaging/osx/make-macports-app.sh b/packaging/osx/make-macports-app.sh new file mode 100755 index 0000000000..b9b3ed665a --- /dev/null +++ b/packaging/osx/make-macports-app.sh @@ -0,0 +1,153 @@ +#!/bin/bash +set -o errexit + +SOURCE="${BASH_SOURCE[0]}" +while [ -h "${SOURCE}" ] + do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "${SOURCE}" )" && pwd )" + SOURCE="$(readlink "${SOURCE}")" + [[ "${SOURCE}" != /* ]] && SOURCE="${DIR}/${SOURCE}" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located + done +CURRDIR="$( cd -P "$( dirname "$SOURCE" )" && cd ../.. && pwd )" + +if [ -z "${BUILDDIR}" ]; then +export BUILDDIR="${CURRDIR}/py2app-build/" +fi + + +APPDIR="./app/Deluge.app" +RSCDIR="${APPDIR}/Contents/Resources" +LIBDIR="${RSCDIR}/lib" +VERSION=$(cat ../../RELEASE-VERSION) +YEAR=$(date +'%Y') + +export DELUGEDIR=$(cd ../../ && pwd) + +echo "DELUGEDIR: ${DELUGEDIR}" + +if [ -z "${PY2APP_PREFIX}" ]; then +export PY2APP_PREFIX="${BUILDDIR}/app/deluge.app/Contents/" +fi + + +function msg() { echo "==> $1"; } + +echo "*** Packaging Deluge.app to $APPDIR..." + +msg "Clearing build dir" +rm -fr $BUILDDIR + +msg "Clearing app dir" +rm -fr $APPDIR + +pushd ../../ +python3 setup.py clean --all +find ./ \( -name '__pycache__' -or -name 'build' \) -type d -ls -depth -delete +msg "Running build" +msg "Creating app skeleton" +python3 setup.py py2app --verbose --dist-dir "${BUILDDIR}/app" --no-strip --graph --xref --use-faulthandler --verbose-interpreter +msg "Creating Wheel" +python3 setup.py bdist_wheel --dist-dir "${BUILDDIR}/wheel" +rm -fv "${BUILDDIR}/app/deluge.app/Contents/MacOS/deluge" +python3 setup.py install_scripts --install-dir "${BUILDDIR}/app/deluge.app/Contents/MacOS/" +popd + +export PY2APP_PYTHON_VERSION=$("${PY2APP_PREFIX}/MacOS/python" --version | sed 's|Python ||' | cut -f 1,2 -d '.') + +SITEPACKAGES="/opt/local/Library/Frameworks/Python.framework/Versions/${PY2APP_PYTHON_VERSION}/lib/python${PY2APP_PYTHON_VERSION}/site-packages" + +msg "Create Info.plist for Deluge $version" +sed -e s/%VERSION%/$VERSION/ -e s/%YEAR%/$YEAR/ Info.plist.in > Info.plist + +msg "Calling gtk-mac-bundler to create the skeleton" +gtk-mac-bundler deluge-macports.bundle + +msg "Unzip site-packages and make python softlink without version number" +pushd ${LIBDIR} || exit 1 +ln -sf "./python${PY2APP_PYTHON_VERSION}" "./python" +unzip -nq python*.zip -d "./python/" +rm python*.zip +popd + +msg "Replacing deluge by its wheel..." +rm -fr "${LIBDIR}/python/deluge" +deluge_wheel="${BUILDDIR}/wheel/deluge*.whl" +unzip -nq ${deluge_wheel} -d "${LIBDIR}/python/" + +msg "Will now try to fix dependencies manually because gtk-mac-bundler sucks at that" +msg "First, let's fix the Python executable." + +install_name_tool -change "@executable_path/../Frameworks/Python.framework/Versions/${PY2APP_PYTHON_VERSION}/Python" "@rpath/libpython${PY2APP_PYTHON_VERSION}.dylib" "${APPDIR}/Contents/MacOS/python" + +msg "Generating charset.alias..." + +/opt/local/share/gettext/intl/config.charset $(uname -m)-apple-$(uname -s)-$(uname -r) > "${LIBDIR}/charset.alias" + +msg "Getting list of files to fix..." + +FILES=$( + find "${APPDIR}" -type f \ + | xargs file \ + | grep ' Mach-O '|awk -F ':' '{print $1}' +) +OLDPATH='\/opt\/local\/lib\/libgcc\/|\/opt\/local\/lib\/|@executable_path\/..\/Frameworks\/' +msg "Replacing pathnames and @executable_path/../Frameworks/ with @rpath/..." + +for file in $FILES +do + set -x + chmod 755 "${file}" + install_name_tool -id "@rpath/$(basename ${file})" "${file}" + ( install_name_tool -delete_rpath /opt/local/lib "${file}" 2>/dev/null || true) + ( install_name_tool -delete_rpath @executable_path/../Frameworks "${file}" 2>/dev/null || true) + ( install_name_tool -delete_rpath /opt/local/lib/libgcc "${file}" 2>/dev/null || true) + { set +x; } 2>/dev/null + otool -L "${file}" \ + | grep -E "\t${OLDPATH}" \ + | sed -E "s/${OLDPATH}//" \ + | awk -v fname="$file" -v old_path_1="/opt/local/lib/libgcc/" -v old_path_2="/opt/local/lib/" -v old_path_3="@executable_path/../Frameworks/" '{ \ + print "set -x\n\ + install_name_tool -change "old_path_1 $1" @rpath/"$1\ + " -change "old_path_2 $1" @rpath/"$1\ + " -change "old_path_3 $1" @rpath/"$1" "fname"\n\ + { set +x; } 2>/dev/null"\ + }' \ + | bash + install_name_tool -add_rpath @executable_path/../Resources/lib "${file}" +done + +msg "Copying distribution info for dependencies..." +# Ideally either py2app or gtk-mac-bundler would take care of this but I guess that's too much to ask. +# Maybe we can remove this eventually if they get their shit together. +cp -Rv "${SITEPACKAGES}"/zope.interface-*.egg-info \ + "${SITEPACKAGES}"/setproctitle-*.egg-info \ + "${SITEPACKAGES}"/six-*.egg-info \ + "${SITEPACKAGES}"/chardet*.egg-info \ + "${SITEPACKAGES}"/Mako*.egg-info \ + "${SITEPACKAGES}"/Pillow*.egg-info \ + "${SITEPACKAGES}"/pyxdg-*.egg-info \ + "${SITEPACKAGES}"/pycairo-*.egg-info \ + "${SITEPACKAGES}"/PyGObject-*.egg-info \ + "${SITEPACKAGES}"/pyOpenSSL-*.egg-info \ + "${SITEPACKAGES}"/rencode-*.egg-info \ + "${SITEPACKAGES}"/pyasn1-*.egg-info \ + "${SITEPACKAGES}"/pyasn1_modules-*.egg-info \ + "${SITEPACKAGES}"/pyasn1-*.egg-info \ + "${SITEPACKAGES}"/Twisted-*.egg-info \ + "${SITEPACKAGES}"/setuptools-*.egg-info \ + "${SITEPACKAGES}"/MarkupSafe-*.egg-info \ + "${SITEPACKAGES}"/cryptography-*.egg-info \ + "${SITEPACKAGES}"/idna-*.egg-info \ + "${SITEPACKAGES}"/service_identity-*.egg-info \ + "${SITEPACKAGES}"/attrs-*.egg-info \ + "${SITEPACKAGES}"/PyHamcrest-*.egg-info \ + "${SITEPACKAGES}"/hyperlink-*.egg-info \ + "${SITEPACKAGES}"/Automat-*.egg-info \ + "${SITEPACKAGES}"/incremental-*.egg-info \ + "${SITEPACKAGES}"/constantly-*.egg-info \ + "${SITEPACKAGES}"/asn1crypto-*.egg-info \ + "${SITEPACKAGES}"/pycparser-*.egg-info \ + "${SITEPACKAGES}"/cffi-*.egg-info \ + "${LIBDIR}/python${PY2APP_PYTHON_VERSION}/" + +echo "*** Packaging done:$(du -hs ${APPDIR} | cut -f 1)" diff --git a/setup.cfg b/setup.cfg index e52fa07cd2..cf10d968a0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,15 +15,14 @@ builder = spelling [py2app] app = ['deluge/ui/ui_entry.py'] arch = x86_64 -# arch = i386 iconfile = packaging/osx/deluge.icns site-packages = false -includes = glib, gio, cairo, pango, pangocairo, atk, gobject, gtk.keysyms, - twisted.internet, twisted.internet.utils, twisted.protocols, - zope.interface, mako.cache, email.mime, libtorrent, gtkosx_application, - HTMLParser +includes = gi, gi.repository, cairo, twisted.internet.*, twisted.web.*, twisted.python, twisted.trial, twisted.application, + rencode, zope.interface, mako, mimetypes, libtorrent, OpenSSL, gi.repository.GdkPixbuf, + six, gettext, html.parser, urllib.parse, setproctitle, pygame.mixer_music, numpy.array, + GeoIP, PIL.Image, chardet, xdg, pyasn1, pyasn1_modules, service_identity, pkg_resources.py2_warn frameworks = CoreFoundation, Foundation, AppKit - +packages = gi [isort] known_standard_library = future_builtins known_third_party = diff --git a/setup.py b/setup.py index 184a29a25d..9b96dbaa74 100755 --- a/setup.py +++ b/setup.py @@ -534,7 +534,7 @@ def run(self): ] _package_data['deluge.ui.gtk3'] = ['glade/*.ui'] -setup_requires = ['setuptools', 'wheel'] +setup_requires = ['setuptools', 'wheel', 'py2app'] install_requires = [ 'twisted[tls]>=17.1', # Add pyasn1 for setuptools workaround: @@ -542,6 +542,7 @@ def run(self): 'pyasn1', 'rencode', 'pyopenssl', + 'pygobject', 'pyxdg', 'pillow', 'mako',