Beispiel #1
0
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()
Beispiel #2
0
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()
Beispiel #3
0
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()
Beispiel #4
0
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()
Beispiel #5
0
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)
Beispiel #6
0
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)
Beispiel #7
0
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()