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 @@
@@ -155,7 +154,6 @@
False
True
-
@@ -172,7 +170,6 @@
True
quit_image
False
- accelgroup1
@@ -191,6 +188,7 @@
@@ -237,6 +232,7 @@
@@ -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',