def run(): """Run the program.""" try: import pkg_resources except ImportError: # gettext isn't initialized yet, since pkg_resources is required to find translation files. # Thus, localizing these messages is pointless. log._print("The package 'pkg_resources' could not be found.") log._print("You need to install the 'setuptools' package, which also includes pkg_resources.") log._print("Note: On most distributions, 'distribute' supersedes 'setuptools'.") wait_and_exit() # Load configuration and setup localisation. preferences.read_preferences_file() from mcomix import i18n i18n.install_gettext() # Retrieve and parse command line arguments. argv = portability.get_commandline_args() opts, args = parse_arguments(argv) # First things first: set the log level. log.setLevel(opts.loglevel) # On Windows, update the fontconfig cache manually, before MComix starts # using Gtk, since the process may take several minutes, during which the # main window will just be frozen if the work is left to Gtk itself... if opts.update_fontconfig_cache: # First, update fontconfig cache. log.debug('starting fontconfig cache update') try: from mcomix.win32 import fc_cache from mcomix import process fc_cache.update() log.debug('fontconfig cache updated') except Exception as e: log.error('during fontconfig cache update', exc_info=e) # And then replace current MComix process with a fresh one # (that will not try to update the cache again). exe = sys.argv[0] if sys.platform == 'win32' and exe.endswith('.py'): # Find the interpreter. exe = process.find_executable(('pythonw.exe', 'python.exe')) args = [exe, sys.argv[0]] else: args = [exe] if sys.platform == 'win32': args.append('--no-update-fontconfig-cache') args.extend(argv) if '--update-fontconfig-cache' in args: args.remove('--update-fontconfig-cache') log.debug('restarting MComix from fresh: os.execv(%s, %s)', repr(exe), args) try: if sys.platform == 'win32': # Of course we can't use os.execv on Windows because it will # mangle arguments containing spaces or non-ascii characters... process.Win32Popen(args) sys.exit(0) else: os.execv(exe, args) except Exception as e: log.error('os.execv(%s, %s) failed', exe, str(args), exc_info=e) wait_and_exit() # Check for PyGTK and PIL dependencies. try: import pygtk pygtk.require('2.0') import gtk assert gtk.gtk_version >= (2, 12, 0) assert gtk.pygtk_version >= (2, 12, 0) import gobject gobject.threads_init() except AssertionError: log.error( _("You do not have the required versions of GTK+ and PyGTK installed.") ) log.error( _('Installed GTK+ version is: %s') % \ '.'.join([str(n) for n in gtk.gtk_version]) ) log.error( _('Required GTK+ version is: 2.12.0 or higher') ) log.error( _('Installed PyGTK version is: %s') % \ '.'.join([str(n) for n in gtk.pygtk_version]) ) log.error( _('Required PyGTK version is: 2.12.0 or higher') ) wait_and_exit() except ImportError: log.error( _('Required PyGTK version is: 2.12.0 or higher') ) log.error( _('No version of PyGTK was found on your system.') ) log.error( _('This error might be caused by missing GTK+ libraries.') ) wait_and_exit() try: import PIL.Image assert PIL.Image.VERSION >= '1.1.5' except AssertionError: log.error( _("You don't have the required version of the Python Imaging"), end=' ') log.error( _('Library (PIL) installed.') ) log.error( _('Installed PIL version is: %s') % Image.VERSION ) log.error( _('Required PIL version is: 1.1.5 or higher') ) wait_and_exit() except ImportError: log.error( _('Python Imaging Library (PIL) 1.1.5 or higher is required.') ) log.error( _('No version of the Python Imaging Library was found on your system.') ) wait_and_exit() if not os.path.exists(constants.DATA_DIR): os.makedirs(constants.DATA_DIR, 0700) if not os.path.exists(constants.CONFIG_DIR): os.makedirs(constants.CONFIG_DIR, 0700) from mcomix import icons icons.load_icons() open_path = None open_page = 1 if len(args) == 1: open_path = args[0] elif len(args) > 1: open_path = args elif preferences.prefs['auto load last file'] \ and preferences.prefs['path to last file'] \ and os.path.isfile(preferences.prefs['path to last file']): open_path = preferences.prefs['path to last file'] open_page = preferences.prefs['page of last file'] # Some languages require a RTL layout if preferences.prefs['language'] in ('he', 'fa'): gtk.widget_set_default_direction(gtk.TEXT_DIR_RTL) gtk.gdk.set_program_class(constants.APPNAME) from mcomix import main window = main.MainWindow(fullscreen = opts.fullscreen, is_slideshow = opts.slideshow, show_library = opts.library, manga_mode = opts.manga, double_page = opts.doublepage, zoom_mode = opts.zoommode, open_path = open_path, open_page = open_page) main.set_main_window(window) if 'win32' != sys.platform: # Add a SIGCHLD handler to reap zombie processes. def on_sigchld(signum, frame): try: os.waitpid(-1, os.WNOHANG) except OSError: pass signal.signal(signal.SIGCHLD, on_sigchld) signal.signal(signal.SIGTERM, lambda: gobject.idle_add(window.terminate_program)) try: gtk.main() except KeyboardInterrupt: # Will not always work because of threading. window.terminate_program()
def run(): '''Run the program.''' # Load configuration and setup localisation. preferences.read_preferences_file() from mcomix import i18n i18n.install_gettext() # Retrieve and parse command line arguments. args = parse_arguments() if args.version: print_version() # First things first: set the log level. log.setLevel(log.levels[args.loglevel]) # Check Python version try: assert sys.version_info[:3] >= constants.REQUIRED_PYTHON_VERSION except AssertionError: log.error(_('You don\'t have the required version of the Python installed.')) log.error(_('Installed Python version is: %s') % '.'.join(str(n) for n in sys.version_info)) log.error(_('Required Python version is: %s or higher') % '.'.join(str(n) for n in constants.REQUIRED_PYTHON_VERSION)) wait_and_exit() # Check for PyGTK and PIL dependencies. try: from gi import version_info as gi_version_info if gi_version_info < (3, 30, 0): log.error(_('You do not have the required versions of PyGObject installed.')) wait_and_exit() from gi import require_version require_version('PangoCairo', '1.0') require_version('Gtk', '3.0') require_version('Gdk', '3.0') from gi.repository import Gdk, GdkPixbuf, Gtk, GLib if (Gtk.get_major_version(), Gtk.get_minor_version()) < (3, 24): log.error(_('You do not have the required versions of GTK+ 3 gir bindings installed.')) wait_and_exit() except ValueError: log.error(_('You do not have the required versions of GTK+ 3.0 installed.')) wait_and_exit() except ImportError: log.error(_('No version of GObject was found on your system.')) log.error(_('This error might be caused by missing GTK+ libraries.')) wait_and_exit() try: import PIL assert [int(n) for n in PIL.__version__.split('.')[:3]] >= [int(n) for n in constants.REQUIRED_PIL_VERSION.split('.')] except AttributeError: log.error(_('You don\'t have the required version of the Pillow installed.')) log.error(_('Required Pillow version is: %s or higher') % constants.REQUIRED_PIL_VERSION) wait_and_exit() except ValueError: log.error(_('Unrecognized Pillow version: %s') % PIL.__version__) log.error(_('Required Pillow version is: %s or higher') % constants.REQUIRED_PIL_VERSION) wait_and_exit() except ImportError: log.error(_('Pillow %s or higher is required.') % constants.REQUIRED_PIL_VERSION) log.error(_('No version of the Pillow was found on your system.')) wait_and_exit() except AssertionError: log.error(_('You don\'t have the required version of the Pillow installed.')) log.error(_('Installed PIL version is: %s') % PIL.__version__) log.error(_('Required Pillow version is: %s or higher') % constants.REQUIRED_PIL_VERSION) wait_and_exit() log.info('Image loaders: Pillow [%s], GDK [%s])', PIL.__version__,GdkPixbuf.PIXBUF_VERSION) if not os.path.exists(constants.DATA_DIR): os.makedirs(constants.DATA_DIR, 0o700) if not os.path.exists(constants.CONFIG_DIR): os.makedirs(constants.CONFIG_DIR, 0o700) from mcomix import icons icons.load_icons() open_path = args.path or None open_page = 1 if isinstance(open_path, list): n = 0 while n<len(open_path): p = os.path.join(constants.STARTDIR, open_path[n]) p = os.path.normpath(p) if not os.path.exists(p): log.error(_('{} not exists.').format(p)) open_path.pop(n) continue open_path[n] = p n += 1 if not open_path: open_path = None if not open_path and preferences.prefs['auto load last file'] \ and preferences.prefs['path to last file'] \ and os.path.isfile(preferences.prefs['path to last file']): open_path = preferences.prefs['path to last file'] open_page = preferences.prefs['page of last file'] # Some languages require a RTL layout if preferences.prefs['language'] in ('he', 'fa'): Gtk.Widget.set_default_direction(Gtk.TextDirection.RTL) Gdk.set_program_class(constants.APPNAME) settings = Gtk.Settings.get_default() # Enable icons for menu items. settings.props.gtk_menu_images = True from mcomix import main window = main.MainWindow(fullscreen = args.fullscreen, is_slideshow = args.slideshow, show_library = args.library, manga_mode = args.manga, double_page = args.doublepage, zoom_mode = args.zoommode, open_path = open_path, open_page = open_page) main.set_main_window(window) if 'win32' != sys.platform: # Add a SIGCHLD handler to reap zombie processes. def on_sigchld(signum, frame): try: os.waitpid(-1, os.WNOHANG) except OSError: pass signal.signal(signal.SIGCHLD, on_sigchld) for sig in (signal.SIGINT, signal.SIGTERM): signal.signal(sig, lambda signum, stack: GLib.idle_add(window.terminate_program)) try: Gtk.main() except KeyboardInterrupt: # Will not always work because of threading. window.terminate_program()
try: import pkg_resources except ImportError: # gettext isn't initialized yet, since pkg_resources is required to find translation files. # Thus, localizing these messages is pointless. print "The package 'pkg_resources' could not be found." print "You need to install the 'setuptools' package, which also includes pkg_resources." print "Note: On most distributions, 'distribute' supersedes 'setuptools'." wait_and_exit() preferences.read_preferences_file() from mcomix import i18n i18n.install_gettext() from mcomix.log import print_ # Check for PyGTK and PIL dependencies. try: import pygtk pygtk.require('2.0') import gtk assert gtk.gtk_version >= (2, 12, 0) assert gtk.pygtk_version >= (2, 12, 0) import gobject gobject.threads_init()
def run(): """Run the program.""" # Load configuration and setup localisation. preferences.read_preferences_file() from mcomix import i18n i18n.install_gettext() # Retrieve and parse command line arguments. argv = portability.get_commandline_args() opts, args = parse_arguments(argv) # First things first: set the log level. log.setLevel(opts.loglevel) # Check for PyGTK and PIL dependencies. try: from gi import require_version require_version('PangoCairo', '1.0') require_version('Gtk', '3.0') require_version('Gdk', '3.0') from gi.repository import Gdk, Gtk, GLib from gi import version_info as gi_version_info if gi_version_info < (3,11,0): from gi.repository import GObject GObject.threads_init() except AssertionError: log.error( _("You do not have the required versions of GTK+ 3.0 and PyGObject installed.") ) wait_and_exit() except ImportError: log.error( _('No version of GObject was found on your system.') ) log.error( _('This error might be caused by missing GTK+ libraries.') ) wait_and_exit() try: import PIL.Image assert PIL.Image.VERSION >= '1.1.5' except AssertionError: log.error( _("You don't have the required version of the Python Imaging"), end=' ') log.error( _('Library (PIL) installed.') ) log.error( _('Installed PIL version is: %s') % Image.VERSION ) log.error( _('Required PIL version is: 1.1.5 or higher') ) wait_and_exit() except ImportError: log.error( _('Python Imaging Library (PIL) 1.1.5 or higher is required.') ) log.error( _('No version of the Python Imaging Library was found on your system.') ) wait_and_exit() if not os.path.exists(constants.DATA_DIR): os.makedirs(constants.DATA_DIR, 0o700) if not os.path.exists(constants.CONFIG_DIR): os.makedirs(constants.CONFIG_DIR, 0o700) from mcomix import icons icons.load_icons() open_path = None open_page = 1 if len(args) == 1: open_path = args[0] elif len(args) > 1: open_path = args elif preferences.prefs['auto load last file'] \ and preferences.prefs['path to last file'] \ and os.path.isfile(preferences.prefs['path to last file']): open_path = preferences.prefs['path to last file'] open_page = preferences.prefs['page of last file'] # Some languages require a RTL layout if preferences.prefs['language'] in ('he', 'fa'): Gtk.widget_set_default_direction(Gtk.TextDirection.RTL) Gdk.set_program_class(constants.APPNAME) settings = Gtk.Settings.get_default() # Enable icons for menu items. settings.props.gtk_menu_images = True from mcomix import main window = main.MainWindow(fullscreen = opts.fullscreen, is_slideshow = opts.slideshow, show_library = opts.library, manga_mode = opts.manga, double_page = opts.doublepage, zoom_mode = opts.zoommode, open_path = open_path, open_page = open_page) main.set_main_window(window) if 'win32' != sys.platform: # Add a SIGCHLD handler to reap zombie processes. def on_sigchld(signum, frame): try: os.waitpid(-1, os.WNOHANG) except OSError: pass signal.signal(signal.SIGCHLD, on_sigchld) for sig in (signal.SIGINT, signal.SIGTERM): signal.signal(sig, lambda signum, stack: GLib.idle_add(window.terminate_program)) try: Gtk.main() except KeyboardInterrupt: # Will not always work because of threading. window.terminate_program()
def update(args=[], notification_delay=3, notification_duration=3): '''Update fontconfig cache by calling fc-cache.exe manually. The function will block until fc-cache.exe has finished. If the update takes more than <notification_delay> seconds, a notification window will be shown for at least <notification_duration> seconds. ''' cmd = [fc_cache_exe] cmd.extend(args) proc = process.popen(cmd, stdout=process.NULL) notif_time = time.time() + notification_delay end_time = notif_time + notification_duration i18n.install_gettext() import pygtk pygtk.require('2.0') import gtk, gobject gobject.threads_init() class Window(gtk.Window): def __init__(self): super(Window, self).__init__() self.set_title('MComix') self.set_border_width(10) self.set_wmclass('MComix', 'MComix') self.set_resizable(False) self.set_deletable(False) self._displayed = False vbox = gtk.VBox(spacing=5) label = gtk.Label( _('Updating font cache. This may take a few minutes.')) vbox.pack_start(label) self._spinner = gtk.Spinner() vbox.pack_start(self._spinner, expand=False, fill=False) vbox.show_all() self.add(vbox) self.set_geometry_hints(vbox) gobject.timeout_add(200, self._on_ping) def _on_ping(self): now = time.time() returncode = proc.poll() if returncode is None: # Process is still running. if now <= notif_time: # Not enough time elapsed, do not show dialog yet. return True else: # Process has terminated. if not notif_time < now < end_time: # Dialog is not being shown or it has already # been displayed for the required amount of time. gtk.main_quit() return False if not self._displayed: # Show dialog. self.show() self._spinner.start() self._displayed = True return True # Create a very simple fontconfig configuration, # with a temporary cache directory, and only a few fonts. tmpdir = tempfile.mkdtemp(suffix='-mcomix-fc_cache') try: cachedir = os.path.join(tmpdir, 'cache') os.mkdir(cachedir) config = os.path.join(tmpdir, 'fonts.conf') exe_dir = os.path.dirname(os.path.abspath(sys.argv[0])) with open(config, 'w') as f: f.write('''<?xml version="1.0"?> <!DOCTYPE fontconfig SYSTEM "fonts.dtd"> <fontconfig> <dir>c:/Python27/Lib/site-packages/gnome/share/fonts</dir> <dir>%(executable_dir)s/share/fonts</dir> <cachedir>%(cache_dir)s</cachedir> <alias> <family>Times</family> <default><family>Vera</family></default> </alias> <alias> <family>Helvetica</family> <default><family>Vera</family></default> </alias> <alias> <family>Courier</family> <default><family>Vera</family></default> </alias> </fontconfig>''' % { 'executable_dir': exe_dir, 'cache_dir': cachedir, }) previous_config = os.environ.get('FONTCONFIG_FILE', None) os.environ['FONTCONFIG_FILE'] = config try: win = Window() gtk.main() finally: if previous_config is None: del os.environ['FONTCONFIG_FILE'] else: os.environ['FONTCONFIG_FILE'] = previous_config finally: shutil.rmtree(tmpdir)
def update(args=[], notification_delay=3, notification_duration=3): '''Update fontconfig cache by calling fc-cache.exe manually. The function will block until fc-cache.exe has finished. If the update takes more than <notification_delay> seconds, a notification window will be shown for at least <notification_duration> seconds. ''' cmd = [fc_cache_exe] cmd.extend(args) proc = process.popen(cmd, stdout=process.NULL) notif_time = time.time() + notification_delay end_time = notif_time + notification_duration i18n.install_gettext() import pygtk pygtk.require('2.0') import gtk, gobject gobject.threads_init() class Window(gtk.Window): def __init__(self): super(Window, self).__init__() self.set_title('MComix') self.set_border_width(10) self.set_wmclass('MComix', 'MComix') self.set_resizable(False) self.set_deletable(False) self._displayed = False vbox = gtk.VBox(spacing=5) label = gtk.Label(_('Updating font cache. This may take a few minutes.')) vbox.pack_start(label) self._spinner = gtk.Spinner() vbox.pack_start(self._spinner, expand=False, fill=False) vbox.show_all() self.add(vbox) self.set_geometry_hints(vbox) gobject.timeout_add(200, self._on_ping) def _on_ping(self): now = time.time() returncode = proc.poll() if returncode is None: # Process is still running. if now <= notif_time: # Not enough time elapsed, do not show dialog yet. return True else: # Process has terminated. if not notif_time < now < end_time: # Dialog is not being shown or it has already # been displayed for the required amount of time. gtk.main_quit() return False if not self._displayed: # Show dialog. self.show() self._spinner.start() self._displayed = True return True # Create a very simple fontconfig configuration, # with a temporary cache directory, and only a few fonts. tmpdir = tempfile.mkdtemp(suffix='-mcomix-fc_cache') try: cachedir = os.path.join(tmpdir, 'cache') os.mkdir(cachedir) config = os.path.join(tmpdir, 'fonts.conf') exe_dir = os.path.dirname(os.path.abspath(sys.argv[0])) with open(config, 'w') as f: f.write('''<?xml version="1.0"?> <!DOCTYPE fontconfig SYSTEM "fonts.dtd"> <fontconfig> <dir>c:/Python27/Lib/site-packages/gnome/share/fonts</dir> <dir>%(executable_dir)s/share/fonts</dir> <cachedir>%(cache_dir)s</cachedir> <alias> <family>Times</family> <default><family>Vera</family></default> </alias> <alias> <family>Helvetica</family> <default><family>Vera</family></default> </alias> <alias> <family>Courier</family> <default><family>Vera</family></default> </alias> </fontconfig>''' % { 'executable_dir': exe_dir, 'cache_dir': cachedir, }) previous_config = os.environ.get('FONTCONFIG_FILE', None) os.environ['FONTCONFIG_FILE'] = config try: win = Window() gtk.main() finally: if previous_config is None: del os.environ['FONTCONFIG_FILE'] else: os.environ['FONTCONFIG_FILE'] = previous_config finally: shutil.rmtree(tmpdir)