diff --git a/icons/calibre.png b/icons/calibre.png new file mode 100644 index 0000000000..7a6b0c45e0 Binary files /dev/null and b/icons/calibre.png differ diff --git a/icons/icns/make_iconsets.py b/icons/icns/make_iconsets.py new file mode 100644 index 0000000000..ec353c93b3 --- /dev/null +++ b/icons/icns/make_iconsets.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# vim:fileencoding=utf-8 +from __future__ import (unicode_literals, division, absolute_import, + print_function) + +__license__ = 'GPL v3' +__copyright__ = '2014, Kovid Goyal ' + +import os, shutil, subprocess + +d, j, a = (getattr(os.path, x) for x in ('dirname', 'join', 'abspath')) +base = d(a(__file__)) +os.chdir(base) + +imgsrc = j(d(d(base)), 'imgsrc') +sources = {'calibre':j(d(base), 'calibre.png'), 'ebook-edit':j(imgsrc, 'tweak.svg'), 'ebook-viewer':j(imgsrc, 'viewer.svg')} + +for name, src in sources.iteritems(): + iconset = name + '.iconset' + if os.path.exists(iconset): + shutil.rmtree(iconset) + os.mkdir(iconset) + os.chdir(iconset) + try: + for sz in (16, 32, 128, 256, 512, 1024): + iname = 'icon_{0}x{0}.png'.format(sz) + iname2x = 'icon_{0}x{0}@2x.png'.format(sz // 2) + if src.endswith('.svg'): + subprocess.check_call(['rsvg-convert', src, '-w', str(sz), '-h', str(sz), '-o', iname]) + else: + # We have a 512x512 png image + if sz == 512: + shutil.copy2(src, iname) + else: + subprocess.check_call(['convert', src, '-resize', '{0}x{0}'.format(sz), iname]) + if sz > 16: + shutil.copy2(iname, iname2x) + if sz > 512: + os.remove(iname) + finally: + os.chdir('..') + diff --git a/icons/library.icns b/icons/library.icns deleted file mode 100644 index 1b796e2fe0..0000000000 Binary files a/icons/library.icns and /dev/null differ diff --git a/setup/installer/osx/app/main.py b/setup/installer/osx/app/main.py index 63f6db25b1..de1392a516 100644 --- a/setup/installer/osx/app/main.py +++ b/setup/installer/osx/app/main.py @@ -188,6 +188,7 @@ class Py2App(object): self.compile_py_modules() self.create_console_app() + self.create_gui_apps() self.copy_site() self.create_exe() @@ -317,8 +318,12 @@ class Py2App(object): c = join(self.build_dir, 'Contents') for x in ('Frameworks', 'MacOS', 'Resources'): os.makedirs(join(c, x)) - for x in ('library.icns', 'book.icns'): + for x in ('book.icns',): shutil.copyfile(join('icons', x), join(self.resources_dir, x)) + for x in glob.glob(join('icons', 'icns', '*.iconset')): + subprocess.check_call([ + 'iconutil', '-c', 'icns', x, '-o', join( + self.resources_dir, basename(x).partition('.')[0] + '.icns')]) @flush def add_calibre_plugins(self): @@ -355,7 +360,7 @@ class Py2App(object): NSHumanReadableCopyright='Copyright 2014, Kovid Goyal', CFBundleGetInfoString=('calibre, an E-book management ' 'application. Visit http://calibre-ebook.com for details.'), - CFBundleIconFile='library.icns', + CFBundleIconFile='calibre.icns', NSHighResolutionCapable=True, LSApplicationCategoryType='public.app-category.productivity', LSEnvironment=env @@ -590,11 +595,12 @@ class Py2App(object): cc_dir = os.path.join(self.contents_dir, 'console.app', 'Contents') os.makedirs(cc_dir) for x in os.listdir(self.contents_dir): - if x == 'console.app': + if x.endswith('.app'): continue if x == 'Info.plist': plist = plistlib.readPlist(join(self.contents_dir, x)) plist['LSUIElement'] = '1' + plist['CFBundleIdentifier'] = 'com.calibre-ebook.console' plist.pop('CFBundleDocumentTypes') plistlib.writePlist(plist, join(cc_dir, x)) else: @@ -605,6 +611,26 @@ class Py2App(object): shutil.copytree(join(SW, 'build/notifier.app'), join( self.contents_dir, 'calibre-notifier.app')) + @flush + def create_gui_apps(self): + info('\nCreating launcher apps for viewer and editor') + for launcher in ('ebook-viewer', 'ebook-edit'): + cc_dir = os.path.join(self.contents_dir, launcher + '.app', 'Contents') + os.makedirs(cc_dir) + for x in os.listdir(self.contents_dir): + if x.endswith('.app'): + continue + if x == 'Info.plist': + plist = plistlib.readPlist(join(self.contents_dir, x)) + plist['CFBundleDisplayName'] = plist['CFBundleName'] = {'ebook-viewer':'E-book Viewer', 'ebook-edit':'Edit Book'}[launcher] + plist['CFBundleExecutable'] = launcher + plist['CFBundleIconFile'] = launcher + '.icns' + plist['CFBundleIdentifier'] = 'com.calibre-ebook.' + launcher + plist.pop('CFBundleDocumentTypes') + plistlib.writePlist(plist, join(cc_dir, x)) + else: + os.symlink(join('../..', x), join(cc_dir, x)) + @flush def copy_site(self): base = os.path.dirname(__file__) diff --git a/src/calibre/utils/ipc/launch.py b/src/calibre/utils/ipc/launch.py index 08bd592735..4f5a546729 100644 --- a/src/calibre/utils/ipc/launch.py +++ b/src/calibre/utils/ipc/launch.py @@ -58,8 +58,7 @@ class Worker(object): e = self.exe_name if iswindows: return os.path.join(os.path.dirname(sys.executable), - e+'.exe' if isfrozen else \ - 'Scripts\\%s.exe'%e) + e+'.exe' if isfrozen else 'Scripts\\%s.exe'%e) if isosx: return os.path.join(sys.console_binaries_path, e) @@ -72,11 +71,12 @@ class Worker(object): return c return e - @property def gui_executable(self): if isosx: - return os.path.join(sys.binaries_path, self.exe_name) + if self.job_name in {'ebook-viewer', 'ebook-edit'}: + return self.executable.replace('/console.app/', '/%s.app/' % self.job_name) + return os.path.join(sys.binaries_path, self.exe_name) return self.executable @@ -111,13 +111,15 @@ class Worker(object): @property def returncode(self): - if not hasattr(self, 'child'): return None + if not hasattr(self, 'child'): + return None self.child.poll() return self.child.returncode @property def pid(self): - if not hasattr(self, 'child'): return None + if not hasattr(self, 'child'): + return None return getattr(self.child, 'pid', None) def close_log_file(self): @@ -143,9 +145,10 @@ class Worker(object): except: pass - def __init__(self, env, gui=False): + def __init__(self, env, gui=False, job_name=None): self._env = {} self.gui = gui + self.job_name = job_name # Windows cannot handle unicode env vars for k, v in env.iteritems(): try: diff --git a/src/calibre/utils/ipc/server.py b/src/calibre/utils/ipc/server.py index 48b8a0f2dc..e0edaee9f1 100644 --- a/src/calibre/utils/ipc/server.py +++ b/src/calibre/utils/ipc/server.py @@ -159,7 +159,7 @@ class Server(Thread): self.start() - def launch_worker(self, gui=False, redirect_output=None): + def launch_worker(self, gui=False, redirect_output=None, job_name=None): start = time.time() with self._worker_launch_lock: self.launched_worker_count += 1 @@ -175,15 +175,15 @@ class Server(Thread): 'CALIBRE_WORKER_KEY' : hexlify(self.auth_key), 'CALIBRE_WORKER_RESULT' : hexlify(rfile.encode('utf-8')), } - cw = self.do_launch(env, gui, redirect_output, rfile) + cw = self.do_launch(env, gui, redirect_output, rfile, job_name=job_name) if isinstance(cw, basestring): raise CriticalError('Failed to launch worker process:\n'+cw) if DEBUG: print 'Worker Launch took:', time.time() - start return cw - def do_launch(self, env, gui, redirect_output, rfile): - w = Worker(env, gui=gui) + def do_launch(self, env, gui, redirect_output, rfile, job_name=None): + w = Worker(env, gui=gui, job_name=job_name) try: w(redirect_output=redirect_output) @@ -204,7 +204,7 @@ class Server(Thread): self.add_jobs_queue.put(job) def run_job(self, job, gui=True, redirect_output=False): - w = self.launch_worker(gui=gui, redirect_output=redirect_output) + w = self.launch_worker(gui=gui, redirect_output=redirect_output, job_name=getattr(job, 'name', None)) w.start_job(job) def run(self):