Пример #1
0
    def test_constrains(self):
        if is_py2exe():
            self.assertEqual(is_py2exe_console(), not is_py2exe_window())
            self.assertTrue(is_windows())

        if is_windows():
            self.assertFalse(is_osx())

        if is_osx():
            self.assertFalse(is_windows())
    def test_constrains(self):
        if is_py2exe():
            self.assertEqual(is_py2exe_console(), not is_py2exe_window())
            self.assertTrue(is_windows())

        if is_windows():
            self.assertFalse(is_osx())

        if is_osx():
            self.assertFalse(is_windows())
Пример #3
0
 def test_all(self):
     self.assertTrue(isinstance(is_unity(), bool))
     self.assertTrue(isinstance(is_windows(), bool))
     self.assertTrue(isinstance(is_osx(), bool))
     self.assertTrue(isinstance(is_py2exe(), bool))
     self.assertTrue(isinstance(is_py2exe_console(), bool))
     self.assertTrue(isinstance(is_py2exe_window(), bool))
 def test_all(self):
     self.assertTrue(isinstance(is_unity(), bool))
     self.assertTrue(isinstance(is_windows(), bool))
     self.assertTrue(isinstance(is_osx(), bool))
     self.assertTrue(isinstance(is_py2exe(), bool))
     self.assertTrue(isinstance(is_py2exe_console(), bool))
     self.assertTrue(isinstance(is_py2exe_window(), bool))
Пример #5
0
def get_user_dir():
    """Place where QL saves its state, database, config etc."""

    if os.name == "nt":
        USERDIR = os.path.join(windows.get_appdata_dir(), "Quod Libet")
    elif is_osx():
        USERDIR = os.path.join(os.path.expanduser("~"), ".quodlibet")
    else:
        USERDIR = os.path.join(xdg_get_config_home(), "quodlibet")

        if not os.path.exists(USERDIR):
            tmp = os.path.join(os.path.expanduser("~"), ".quodlibet")
            if os.path.exists(tmp):
                USERDIR = tmp

    if 'QUODLIBET_USERDIR' in environ:
        USERDIR = environ['QUODLIBET_USERDIR']

    if build.BUILD_TYPE == u"windows-portable":
        USERDIR = os.path.normpath(os.path.join(
            os.path.dirname(path2fsn(sys.executable)), "..", "..", "config"))

    # XXX: users shouldn't assume the dir is there, but we currently do in
    # some places
    mkdir(USERDIR, 0o750)

    return USERDIR
Пример #6
0
def _init_python():
    if PY2 or is_release():
        MinVersions.PYTHON2.check(sys.version_info)
    else:
        # for non release builds we allow Python3
        MinVersions.PYTHON3.check(sys.version_info)

    if is_osx():
        # We build our own openssl on OSX and need to make sure that
        # our own ca file is used in all cases as the non-system openssl
        # doesn't use the system certs
        install_urllib2_ca_file()

    if is_windows():
        # Not really needed on Windows as pygi-aio seems to work fine, but
        # wine doesn't have certs which we use for testing.
        install_urllib2_ca_file()

    if is_windows() and os.sep != "\\":
        # In the MSYS2 console MSYSTEM is set, which breaks os.sep/os.path.sep
        # If you hit this do a "setup.py clean -all" to get rid of the
        # bytecode cache then start things with "MSYSTEM= ..."
        raise AssertionError("MSYSTEM is set (%r)" % environ.get("MSYSTEM"))

    if is_windows():
        # gdbm is broken under msys2, this makes shelve use another backend
        sys.modules["gdbm"] = None
        sys.modules["_gdbm"] = None

    logging.getLogger().addHandler(PrintHandler())
Пример #7
0
def _init_python():
    if PY2 or is_release():
        MinVersions.PYTHON2.check(sys.version_info)
    else:
        # for non release builds we allow Python3
        MinVersions.PYTHON3.check(sys.version_info)

    if is_osx():
        # We build our own openssl on OSX and need to make sure that
        # our own ca file is used in all cases as the non-system openssl
        # doesn't use the system certs
        install_urllib2_ca_file()

    if is_windows():
        # Not really needed on Windows as pygi-aio seems to work fine, but
        # wine doesn't have certs which we use for testing.
        install_urllib2_ca_file()

    if is_windows() and os.sep != "\\":
        # In the MSYS2 console MSYSTEM is set, which breaks os.sep/os.path.sep
        # If you hit this do a "setup.py clean -all" to get rid of the
        # bytecode cache then start things with "MSYSTEM= ..."
        raise AssertionError("MSYSTEM is set (%r)" % environ.get("MSYSTEM"))

    if is_windows():
        # gdbm is broken under msys2, this makes shelve use another backend
        sys.modules["gdbm"] = None
        sys.modules["_gdbm"] = None

    logging.getLogger().addHandler(PrintHandler())
Пример #8
0
def get_user_dir():
    """Place where QL saves its state, database, config etc."""

    if os.name == "nt":
        USERDIR = os.path.join(windows.get_appdata_dir(), "Quod Libet")
    elif is_osx():
        USERDIR = os.path.join(os.path.expanduser("~"), ".quodlibet")
    else:
        USERDIR = os.path.join(xdg_get_config_home(), "quodlibet")

        if not os.path.exists(USERDIR):
            tmp = os.path.join(os.path.expanduser("~"), ".quodlibet")
            if os.path.exists(tmp):
                USERDIR = tmp

    if 'QUODLIBET_USERDIR' in environ:
        USERDIR = environ['QUODLIBET_USERDIR']

    if build.BUILD_TYPE == u"windows-portable":
        USERDIR = os.path.normpath(
            os.path.join(os.path.dirname(path2fsn(sys.executable)), "..", "..",
                         "config"))

    # XXX: users shouldn't assume the dir is there, but we currently do in
    # some places
    mkdir(USERDIR, 0o750)

    return USERDIR
Пример #9
0
    def enabled(self):
        impl = get_indicator_impl()
        self._tray = impl()
        self._tray.set_song(app.player.song)
        self._tray.set_info_song(app.player.info)
        self._tray.set_paused(app.player.paused)

        if not is_osx() and not pconfig.getboolean("window_visible"):
            Window.prevent_inital_show(True)
Пример #10
0
    def enabled(self):
        impl = get_indicator_impl()
        self._tray = impl()
        self._tray.set_song(app.player.song)
        self._tray.set_info_song(app.player.info)
        self._tray.set_paused(app.player.paused)

        if not is_osx() and not pconfig.getboolean("window_visible"):
            Window.prevent_inital_show(True)
Пример #11
0
def _show_files_finder(dirname, *args):
    if not is_osx():
        raise BrowseError("OS X only")

    try:
        if subprocess.call(["open", "-R", dirname]) != 0:
            raise EnvironmentError("open error return status")
    except EnvironmentError as e:
        raise BrowseError(e)
Пример #12
0
def _show_files_finder(dirname, *args):
    if not is_osx():
        raise BrowseError("OS X only")

    try:
        if subprocess.call(["open", "-R", dirname]) != 0:
            raise EnvironmentError("open error return status")
    except EnvironmentError as e:
        raise BrowseError(e)
Пример #13
0
def has_locale(loc):
    if is_osx():
        return False

    try:
        with set_locale(loc):
            pass
    except locale.Error:
        return False
    else:
        return True
Пример #14
0
    def test_soup(self):
        if is_osx():
            return

        for url in self.GOOD:
            session = Soup.Session.new()
            request = session.request_http("get", url)
            request.send(None).close()

        for url in self.BAD:
            with self.assertRaises(GLib.GError):
                session = Soup.Session.new()
                request = session.request_http("get", url)
                request.send(None).close()
Пример #15
0
    def test_gio(self):
        if is_osx():
            return

        for url in self.GOOD:
            client = Gio.SocketClient.new()
            client.set_tls(True)
            client.connect_to_uri(url, 443, None).close()

        for url in self.BAD:
            with self.assertRaises(GLib.GError):
                client = Gio.SocketClient.new()
                client.set_tls(True)
                client.connect_to_uri(url, 443, None).close()
Пример #16
0
    def test_gio(self):
        if is_osx():
            return

        for url in self.GOOD:
            client = Gio.SocketClient.new()
            client.set_tls(True)
            client.connect_to_uri(url, 443, None).close()

        for url in self.BAD:
            with self.assertRaises(GLib.GError):
                client = Gio.SocketClient.new()
                client.set_tls(True)
                client.connect_to_uri(url, 443, None).close()
Пример #17
0
    def test_soup(self):
        if is_osx():
            return

        for url in self.GOOD:
            session = Soup.Session.new()
            request = session.request_http("get", url)
            request.send(None).close()

        for url in self.BAD:
            with self.assertRaises(GLib.GError):
                session = Soup.Session.new()
                request = session.request_http("get", url)
                request.send(None).close()
Пример #18
0
def init_devices():
    global devices

    load_pyc = util.is_windows() or util.is_osx()
    modules = load_dir_modules(dirname(__file__),
                               package=__package__,
                               load_compiled=load_pyc)

    for mod in modules:
        try:
            devices.extend(mod.devices)
        except AttributeError:
            print_w("%r doesn't contain any devices." % mod.__name__)

    devices.sort()
Пример #19
0
def init_devices():
    global devices

    load_pyc = util.is_windows() or util.is_osx()
    modules = load_dir_modules(dirname(__file__),
                               package=__package__,
                               load_compiled=load_pyc)

    for mod in modules:
        try:
            devices.extend(mod.devices)
        except AttributeError:
            print_w("%r doesn't contain any devices." % mod.__name__)

    devices.sort(key=lambda d: repr(d))
Пример #20
0
def init():
    """Import all browsers from this package and from the user directory.

    After this is called the global `browers` list will contain all
    classes sorted by priority.

    Can be called multiple times.
    """

    global browsers, default

    # ignore double init (for the test suite)
    if browsers:
        return

    this_dir = os.path.dirname(__file__)
    load_pyc = util.is_windows() or util.is_osx()
    modules = load_dir_modules(this_dir,
                               package=__package__,
                               load_compiled=load_pyc)

    user_dir = os.path.join(quodlibet.get_user_dir(), "browsers")
    if os.path.isdir(user_dir):
        modules += load_dir_modules(user_dir,
                                    package="quodlibet.fake.browsers",
                                    load_compiled=load_pyc)

    for browser in modules:
        try:
            browsers.extend(browser.browsers)
        except AttributeError:
            print_w("%r doesn't contain any browsers." % browser.__name__)

    def is_browser(Kind):
        return isinstance(Kind, type) and issubclass(Kind, Browser)

    browsers = list(filter(is_browser, browsers))

    if not browsers:
        raise SystemExit("No browsers found!")

    browsers.sort(key=lambda Kind: Kind.priority)

    try:
        default = get("SearchBar")
    except ValueError:
        raise SystemExit("Default browser not found!")
Пример #21
0
def _init_python():
    if PY2 or is_release():
        MinVersions.PYTHON2.check(sys.version_info)
    else:
        # for non release builds we allow Python3
        MinVersions.PYTHON3.check(sys.version_info)

    if is_osx():
        # We build our own openssl on OSX and need to make sure that
        # our own ca file is used in all cases as the non-system openssl
        # doesn't use the system certs
        util.install_urllib2_ca_file()

    if is_windows():
        # Not really needed on Windows as pygi-aio seems to work fine, but
        # wine doesn't have certs which we use for testing.
        util.install_urllib2_ca_file()
Пример #22
0
def init():
    """Load/Import all formats.

    Before this is called loading a file and unpickling will not work.
    """

    global mimes, loaders, types

    MinVersions.MUTAGEN.check(mutagen.version)

    base = util.get_module_dir()
    load_pyc = util.is_windows() or util.is_osx()
    formats = load_dir_modules(base,
                               package=__package__,
                               load_compiled=load_pyc)

    module_names = []
    for format in formats:
        name = format.__name__

        for ext in format.extensions:
            loaders[ext] = format.loader

        types.update(format.types)

        if format.extensions:
            for type_ in format.types:
                mimes.update(type_.mimes)
            module_names.append(name.split(".")[-1])

        # Migrate pre-0.16 library, which was using an undocumented "feature".
        sys.modules[name.replace(".", "/")] = format
        # Migrate old layout
        if name.startswith("quodlibet."):
            sys.modules[name.split(".", 1)[1]] = format

    # This can be used for the quodlibet.desktop file
    desktop_mime_types = "MimeType=" + \
        ";".join(sorted({m.split(";")[0] for m in mimes})) + ";"
    print_d(desktop_mime_types)

    s = ", ".join(sorted(module_names))
    print_d("Supported formats: %s" % s)

    if not loaders:
        raise SystemExit("No formats found!")
Пример #23
0
def _init_python():
    if PY2 or is_release():
        MinVersions.PYTHON2.check(sys.version_info)
    else:
        # for non release builds we allow Python3
        MinVersions.PYTHON3.check(sys.version_info)

    if is_osx():
        # We build our own openssl on OSX and need to make sure that
        # our own ca file is used in all cases as the non-system openssl
        # doesn't use the system certs
        util.install_urllib2_ca_file()

    if is_windows():
        # Not really needed on Windows as pygi-aio seems to work fine, but
        # wine doesn't have certs which we use for testing.
        util.install_urllib2_ca_file()
Пример #24
0
def init():
    """Load/Import all formats.

    Before this is called loading a file and unpickling will not work.
    """

    global mimes, loaders, types

    MinVersions.MUTAGEN.check(mutagen.version)

    base = util.get_module_dir()
    load_pyc = util.is_windows() or util.is_osx()
    formats = load_dir_modules(base,
                               package=__package__,
                               load_compiled=load_pyc)

    module_names = []
    for format in formats:
        name = format.__name__

        for ext in format.extensions:
            loaders[ext] = format.loader

        types.update(format.types)

        if format.extensions:
            for type_ in format.types:
                mimes.update(type_.mimes)
            module_names.append(name.split(".")[-1])

        # Migrate pre-0.16 library, which was using an undocumented "feature".
        sys.modules[name.replace(".", "/")] = format
        # Migrate old layout
        if name.startswith("quodlibet."):
            sys.modules[name.split(".", 1)[1]] = format

    # This can be used for the quodlibet.desktop file
    desktop_mime_types = "MimeType=" + \
        ";".join(sorted({m.split(";")[0] for m in mimes})) + ";"
    print_d(desktop_mime_types)

    s = ", ".join(sorted(module_names))
    print_d("Supported formats: %s" % s)

    if not loaders:
        raise SystemExit("No formats found!")
Пример #25
0
def init():
    """Import all browsers from this package and from the user directory.

    After this is called the global `browers` list will contain all
    classes sorted by priority.

    Can be called multiple times.
    """

    global browsers, default

    # ignore double init (for the test suite)
    if browsers:
        return

    this_dir = os.path.dirname(__file__)
    load_pyc = util.is_windows() or util.is_osx()
    modules = load_dir_modules(this_dir,
                               package=__package__,
                               load_compiled=load_pyc)

    user_dir = os.path.join(quodlibet.get_user_dir(), "browsers")
    if os.path.isdir(user_dir):
        modules += load_dir_modules(user_dir,
                                    package="quodlibet.fake.browsers",
                                    load_compiled=load_pyc)

    for browser in modules:
        try:
            browsers.extend(browser.browsers)
        except AttributeError:
            print_w("%r doesn't contain any browsers." % browser.__name__)

    def is_browser(Kind):
        return isinstance(Kind, type) and issubclass(Kind, Browser)
    browsers = filter(is_browser, browsers)

    if not browsers:
        raise SystemExit("No browsers found!")

    browsers.sort(key=lambda Kind: Kind.priority)

    try:
        default = get("SearchBar")
    except ValueError:
        raise SystemExit("Default browser not found!")
Пример #26
0
def init():
    global mimes, _infos, modules, names, _extensions

    import mutagen

    MinVersions.MUTAGEN.check(mutagen.version)

    base = os.path.dirname(__file__)
    load_pyc = util.is_windows() or util.is_osx()
    formats = load_dir_modules(base,
                               package=__package__,
                               load_compiled=load_pyc)

    for format in formats:
        name = format.__name__

        for ext in format.extensions:
            _infos[ext] = format.info

        types.extend(format.types)

        if format.extensions:
            for type_ in format.types:
                mimes.update(type_.mimes)
                names.append(type_.format)
            modules.append(name.split(".")[-1])

        # Migrate pre-0.16 library, which was using an undocumented "feature".
        sys.modules[name.replace(".", "/")] = format
        # Migrate old layout
        if name.startswith("quodlibet."):
            sys.modules[name.split(".", 1)[1]] = format

    modules.sort()
    names.sort()

    # This can be used for the quodlibet.desktop file
    desktop_mime_types = "MimeType=" + \
        ";".join(sorted({m.split(";")[0] for m in mimes})) + ";"
    print_d(desktop_mime_types)

    if not _infos:
        raise SystemExit("No formats found!")

    _extensions = tuple(_infos.keys())
Пример #27
0
def init():
    global mimes, _infos, modules, names

    import mutagen
    if mutagen.version < MinVersions.MUTAGEN:
        raise ImportError(
            "Mutagen %s required. %s found." %
            (MinVersions.MUTAGEN, mutagen.version_string))

    base = os.path.dirname(__file__)
    load_pyc = util.is_windows() or util.is_osx()
    formats = load_dir_modules(base,
                               package=__package__,
                               load_compiled=load_pyc)

    for format in formats:
        name = format.__name__

        for ext in format.extensions:
            _infos[ext] = format.info

        types.extend(format.types)

        if format.extensions:
            for type_ in format.types:
                mimes.update(type_.mimes)
                names.append(type_.format)
            modules.append(name.split(".")[-1])

        # Migrate pre-0.16 library, which was using an undocumented "feature".
        sys.modules[name.replace(".", "/")] = format
        # Migrate old layout
        if name.startswith("quodlibet."):
            sys.modules[name.split(".", 1)[1]] = format

    modules.sort()
    names.sort()

    # This can be used for the quodlibet.desktop file
    desktop_mime_types = "MimeType=" + \
        ";".join(sorted({m.split(";")[0] for m in mimes})) + ";"
    print_d(desktop_mime_types)

    if not _infos:
        raise SystemExit("No formats found!")
Пример #28
0
def _init_dbus():
    """Setup dbus mainloop integration. Call before using dbus"""

    # To make GDBus fail early and we don't have to wait for a timeout
    if is_osx() or is_windows():
        os.environ["DBUS_SYSTEM_BUS_ADDRESS"] = "something-invalid"
        os.environ["DBUS_SESSION_BUS_ADDRESS"] = "something-invalid"

    try:
        from dbus.mainloop.glib import DBusGMainLoop, threads_init
    except ImportError:
        try:
            import dbus.glib
            dbus.glib
        except ImportError:
            return
    else:
        threads_init()
        DBusGMainLoop(set_as_default=True)
Пример #29
0
def show_uri(label, uri):
    """Shows a uri. The uri can be anything handled by GIO or a quodlibet
    specific one.

    Currently handled quodlibet uris:
        - quodlibet:///prefs/plugins/<plugin id>

    Args:
        label (str)
        uri (str) the uri to show
    Returns:
        True on success, False on error
    """

    parsed = urlparse(uri)
    if parsed.scheme == "quodlibet":
        if parsed.netloc != "":
            print_w("Unknown QuodLibet URL format (%s)" % uri)
            return False
        else:
            return __show_quodlibet_uri(parsed)
    elif parsed.scheme == "file" and (is_windows() or is_osx()):
        # Gio on non-Linux can't handle file URIs for some reason,
        # fall back to our own implementation for now
        from quodlibet.qltk.showfiles import show_files

        try:
            filepath = uri2fsn(uri)
        except ValueError:
            return False
        else:
            return show_files(filepath, [])
    else:
        # Gtk.show_uri_on_window exists since 3.22
        try:
            if hasattr(Gtk, "show_uri_on_window"):
                from quodlibet.qltk import get_top_parent
                return Gtk.show_uri_on_window(get_top_parent(label), uri, 0)
            else:
                return Gtk.show_uri(None, uri, 0)
        except GLib.Error:
            return False
Пример #30
0
def show_files(dirname, entries=[]):
    """Shows the directory in the default file browser and if passed
    a list of directory entries will highlight those.

    Depending on the system/platform this might highlight all files passed,
    or only one of them, or none at all.

    Args:
        dirname (fsnative): Path to the directory
        entries (List[fsnative]): List of (relative) filenames in the directory
        entries (List[fsnative]): List of (relative) filenames in the directory
    Returns:
        bool: if the action was successful or not
    """

    assert isinstance(dirname, fsnative)
    assert all(isinstance(e, fsnative) and os.path.basename(e) == e
               for e in entries)

    dirname = os.path.abspath(dirname)

    if is_windows():
        implementations = [_show_files_win32]
    elif is_osx():
        implementations = [_show_files_finder]
    else:
        implementations = [
            _show_files_fdo,
            _show_files_thunar,
            _show_files_xdg_open,
            _show_files_gnome_open,
        ]

    for impl in implementations:
        try:
            impl(dirname, entries)
        except BrowseError as e:
            print_d("Couldn't show files with %s (%s), ignoring." % (impl, e))
            continue
        else:
            return True
    return False
Пример #31
0
def show_uri(label, uri):
    """Shows a uri. The uri can be anything handled by GIO or a quodlibet
    specific one.

    Currently handled quodlibet uris:
        - quodlibet:///prefs/plugins/<plugin id>

    Args:
        label (str)
        uri (str) the uri to show
    Returns:
        True on success, False on error
    """

    parsed = urlparse(uri)
    if parsed.scheme == "quodlibet":
        if parsed.netloc != "":
            print_w("Unknown QuodLibet URL format (%s)" % uri)
            return False
        else:
            return __show_quodlibet_uri(parsed)
    elif parsed.scheme == "file" and (is_windows() or is_osx()):
        # Gio on non-Linux can't handle file URIs for some reason,
        # fall back to our own implementation for now
        from quodlibet.qltk.showfiles import show_files

        try:
            filepath = uri2fsn(uri)
        except ValueError:
            return False
        else:
            return show_files(filepath, [])
    else:
        # Gtk.show_uri_on_window exists since 3.22
        try:
            if hasattr(Gtk, "show_uri_on_window"):
                from quodlibet.qltk import get_top_parent
                return Gtk.show_uri_on_window(get_top_parent(label), uri, 0)
            else:
                return Gtk.show_uri(None, uri, 0)
        except GLib.Error:
            return False
Пример #32
0
def show_files(dirname, entries=[]):
    """Shows the directory in the default file browser and if passed
    a list of directory entries will highlight those.

    Depending on the system/platform this might highlight all files passed,
    or only one of them, or none at all.

    Args:
        dirname (fsnative): Path to the directory
        entries (List[fsnative]): List of (relative) filenames in the directory
        entries (List[fsnative]): List of (relative) filenames in the directory
    Returns:
        bool: if the action was successful or not
    """

    assert isinstance(dirname, fsnative)
    assert all(isinstance(e, fsnative) and os.path.basename(e) == e
               for e in entries)

    dirname = os.path.abspath(dirname)

    if is_windows():
        implementations = [_show_files_win32]
    elif is_osx():
        implementations = [_show_files_finder]
    else:
        implementations = [
            _show_files_fdo,
            _show_files_thunar,
            _show_files_xdg_open,
            _show_files_gnome_open,
        ]

    for impl in implementations:
        try:
            impl(dirname, entries)
        except BrowseError:
            continue
        else:
            return True
    return False
Пример #33
0
 def test_is_accel_primary(self):
     e = Gdk.Event.new(Gdk.EventType.KEY_PRESS)
     e.keyval = Gdk.KEY_Return
     e.state = Gdk.ModifierType.CONTROL_MASK
     if not util.is_osx():
         self.assertTrue(qltk.is_accel(e, "<Primary>Return"))
Пример #34
0
import threading
from xml.dom import minidom
from urllib.parse import quote
import queue

from quodlibet import _, print_d
from quodlibet.plugins.gui import UserInterfacePlugin
from quodlibet.util import gi_require_versions, is_windows, is_osx
from quodlibet.plugins.events import EventPlugin
from quodlibet.plugins import (PluginImportException, PluginConfig, ConfProp,
    BoolConfProp, FloatConfProp, PluginNotSupportedError)

try:
    gi_require_versions("WebKit2", ["4.0", "3.0"])
except ValueError as e:
    if is_windows() or is_osx():
        raise PluginNotSupportedError
    raise PluginImportException("GObject Introspection: " + str(e))

from gi.repository import WebKit2, Gtk, GLib

from quodlibet import qltk
from quodlibet.util import escape, cached_property, connect_obj
from quodlibet.qltk import Icons, Align
from quodlibet.qltk.entry import UndoEntry
from quodlibet.pattern import URLFromPattern
from quodlibet.util.urllib import urlopen


# for the mobile version
USER_AGENT = ("Mozilla/5.0 (Linux; Android 5.1.1; Nexus 5 Build/LMY48B; wv) "
Пример #35
0
def _init_gtk():
    """Call before using Gtk/Gdk"""

    import gi

    # pygiaio 3.14rev16 switched to fontconfig for PangoCairo. As this results
    # in 100% CPU under win7 revert it. Maybe we need to update the
    # cache in the windows installer for it to work... but for now revert.
    if is_windows():
        environ['PANGOCAIRO_BACKEND'] = 'win32'
        environ["GTK_CSD"] = "0"

    # disable for consistency and trigger events seem a bit flaky here
    if is_osx():
        environ["GTK_OVERLAY_SCROLLING"] = "0"

    try:
        # not sure if this is available under Windows
        gi.require_version("GdkX11", "3.0")
        from gi.repository import GdkX11
        GdkX11
    except (ValueError, ImportError):
        pass

    gi.require_version("Gtk", "3.0")
    gi.require_version("Gdk", "3.0")
    gi.require_version("Pango", "1.0")
    gi.require_version('Soup', '2.4')

    from gi.repository import Gtk
    from quodlibet.qltk import ThemeOverrider, gtk_version

    # PyGObject doesn't fail anymore when init fails, so do it ourself
    initialized, argv[:] = Gtk.init_check(argv)
    if not initialized:
        raise SystemExit("Gtk.init failed")

    # include our own icon theme directory
    theme = Gtk.IconTheme.get_default()
    theme_search_path = get_image_dir()
    assert os.path.exists(theme_search_path)
    theme.append_search_path(theme_search_path)

    # Force menu/button image related settings. We might show too many atm
    # but this makes sure we don't miss cases where we forgot to force them
    # per widget.
    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # some day... but not now
    warnings.filterwarnings('ignore', '.*Stock items are deprecated.*',
                            Warning)
    warnings.filterwarnings('ignore', '.*:use-stock.*', Warning)
    warnings.filterwarnings(
        'ignore', '.*The property GtkAlignment:[^\s]+ is deprecated.*',
        Warning)

    settings = Gtk.Settings.get_default()
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        settings.set_property("gtk-button-images", True)
        settings.set_property("gtk-menu-images", True)
    if hasattr(settings.props, "gtk_primary_button_warps_slider"):
        # https://bugzilla.gnome.org/show_bug.cgi?id=737843
        settings.set_property("gtk-primary-button-warps-slider", True)

    # Make sure PyGObject includes support for foreign cairo structs
    try:
        gi.require_foreign("cairo")
    except ImportError:
        print_e("PyGObject is missing cairo support")
        exit(1)

    css_override = ThemeOverrider()

    if sys.platform == "darwin":
        # fix duplicated shadows for popups with Gtk+3.14
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            GtkWindow {
                box-shadow: none;
            }
            .tooltip {
                border-radius: 0;
                padding: 0;
            }
            .tooltip.background {
                background-clip: border-box;
            }
            """)
        css_override.register_provider("", style_provider)

    if gtk_version[:2] >= (3, 20):
        # https://bugzilla.gnome.org/show_bug.cgi?id=761435
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            spinbutton, button {
                min-height: 1.8rem;
            }

            .view button {
                min-height: 2.0rem;
            }

            entry {
                min-height: 2.4rem;
            }

            entry.cell {
                min-height: 0;
            }
        """)
        css_override.register_provider("Adwaita", style_provider)
        css_override.register_provider("HighContrast", style_provider)

        # https://github.com/quodlibet/quodlibet/issues/2541
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            treeview.view.separator {
                min-height: 2px;
                color: @borders;
            }
        """)
        css_override.register_provider("Ambiance", style_provider)
        css_override.register_provider("Radiance", style_provider)

    if gtk_version[:2] >= (3, 18):
        # Hack to get some grab handle like thing for panes
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            GtkPaned.vertical, paned.vertical >separator {
                -gtk-icon-source: -gtk-icontheme("view-more-symbolic");
                -gtk-icon-transform: rotate(90deg) scaleX(0.1) scaleY(3);
            }

            GtkPaned.horizontal, paned.horizontal >separator {
                -gtk-icon-source: -gtk-icontheme("view-more-symbolic");
                -gtk-icon-transform: rotate(0deg) scaleX(0.1) scaleY(3);
            }
        """)
        css_override.register_provider("", style_provider)

    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # blacklist some modules, simply loading can cause segfaults
    sys.modules["gtk"] = None
    sys.modules["gpod"] = None
    sys.modules["gnome"] = None

    from quodlibet.qltk import pygobject_version, gtk_version

    MinVersions.GTK.check(gtk_version)
    MinVersions.PYGOBJECT.check(pygobject_version)
Пример #36
0
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

from gi.repository import Gtk
from senf import fsnative, getcwd

from quodlibet.qltk.chooser import choose_files, get_current_dir, \
    set_current_dir, choose_folders, create_chooser_filter, \
    choose_target_file, choose_target_folder, with_response
from quodlibet.qltk import gtk_version
from quodlibet.util import is_osx

from . import TestCase, skipIf


@skipIf(gtk_version < (3, 16, 0) or is_osx(), "crashy on older gtk+ and macOS")
class Tchooser(TestCase):

    def test_choose_files(self):
        w = Gtk.Window()
        with with_response(Gtk.ResponseType.CANCEL):
            assert choose_files(w, u"title", u"action") == []

    def test_choose_folders(self):
        w = Gtk.Window()
        with with_response(Gtk.ResponseType.CANCEL):
            assert choose_folders(w, u"title", u"action") == []

    def test_choose_filter(self):
        cf = create_chooser_filter(u"filter", ["*.txt"])
        assert isinstance(cf, Gtk.FileFilter)
Пример #37
0
        # osx implementation might be buggy so let users disable it
        "disable_mmkeys": "false",

        # the UI language to use, empty means system default
        "language": "",

        # the pattern for the main window title
        "window_title_pattern": "~title~version~~people",

        # the format of the timestamps in DateColumn
        "datecolumn_timestamp_format": "",

        # scrollbar does not fade out when inactive
        "scrollbar_always_visible":
            "true" if (is_osx() or is_windows()) else "false",
    },

    "rename": {
        "spaces": "false",
        "windows": "true",
        "ascii": "false",
        "move_art": "false",
        "move_art_overwrite": "false",
        "remove_empty_dirs": "false",
    },

    "tagsfrompath": {
        "underscores": "false",
        "titlecase": "false",
        "split": "false",
Пример #38
0
class TWindows(TestCase):
    def test_on_first_map(self):
        w = Window()

        calls = []

        def foo(*args):
            calls.append(args)

        on_first_map(w, foo, 1)
        w.show()
        self.assertEqual(calls, [(1, )])
        on_first_map(w, foo, 2)
        self.assertEqual(calls, [(1, ), (2, )])
        w.destroy()

    def test_ctr(self):
        Window().destroy()

    def test_instance_tracking(self):
        class SomeWindow(Window, InstanceTracker):
            def __init__(self):
                super().__init__()
                self._register_instance()

        self.assertFalse(SomeWindow.windows)
        other = Window()
        a = SomeWindow()
        self.assertTrue(a in SomeWindow.windows)
        self.assertTrue(a in SomeWindow.instances())
        a.destroy()
        self.assertFalse(SomeWindow.instances())
        self.assertTrue(SomeWindow.windows)
        other.destroy()
        self.assertFalse(SomeWindow.windows)

    def test_show_maybe(self):
        Window.prevent_inital_show(True)
        w = Window()
        w.show_maybe()
        self.assertFalse(w.get_visible())
        Window.prevent_inital_show(False)
        w.show_maybe()
        self.assertTrue(w.get_visible())
        w.destroy()

    def test_use_header_bar(self):
        w = Window(title="foo")
        w.use_header_bar()
        self.assertEqual(w.get_title(), "foo")
        w.destroy()

        w = Window()
        w.use_header_bar()
        self.assertEqual(w.get_title(), None)
        w.destroy()

    @skipIf(is_osx(), "crashes on 10.13")
    def test_toggle_fullscreen(self):
        w = Window(title="foo")
        w.toggle_fullscreen()
        with realized(w):
            w.toggle_fullscreen()
            w.toggle_fullscreen()
        w.destroy()
Пример #39
0
from xml.dom import minidom
from urllib.parse import quote
import queue

from quodlibet import _, print_d
from quodlibet.plugins.gui import UserInterfacePlugin
from quodlibet.util import gi_require_versions, is_windows, is_osx
from quodlibet.plugins.events import EventPlugin
from quodlibet.plugins import (PluginImportException, PluginConfig, ConfProp,
                               BoolConfProp, FloatConfProp,
                               PluginNotSupportedError)

try:
    gi_require_versions("WebKit2", ["4.0", "3.0"])
except ValueError as e:
    if is_windows() or is_osx():
        raise PluginNotSupportedError
    raise PluginImportException("GObject Introspection: " + str(e))

from gi.repository import WebKit2, Gtk, GLib

from quodlibet import qltk
from quodlibet.util import escape, cached_property, connect_obj
from quodlibet.qltk import Icons, Align
from quodlibet.qltk.entry import UndoEntry
from quodlibet.pattern import URLFromPattern
from quodlibet.util.urllib import urlopen

# for the mobile version
USER_AGENT = ("Mozilla/5.0 (Linux; Android 5.1.1; Nexus 5 Build/LMY48B; wv) "
              "AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0"
Пример #40
0
# published by the Free Software Foundation

from quodlibet import _
from quodlibet import app
from quodlibet.plugins.events import EventPlugin
from quodlibet.qltk import is_wayland, Icons
from quodlibet.qltk.window import Window
from quodlibet.util import (is_unity, is_osx, is_plasma, is_enlightenment,
                            print_exc, print_w, print_d)

from .prefs import Preferences
from .util import pconfig
from .systemtray import SystemTray


if is_osx():
    # Works, but not without problems:
    # https://github.com/quodlibet/quodlibet/issues/1870
    # The dock menu is more useful so disable.
    from quodlibet.plugins import PluginNotSupportedError
    raise PluginNotSupportedError


def get_indicator_impl():
    """Returns a BaseIndicator implementation depending on the environ"""

    use_app_indicator = (is_unity() or is_wayland() or is_plasma() or
                         is_enlightenment())

    print_d("use app indicator: %s" % use_app_indicator)
    if not use_app_indicator:
Пример #41
0
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

from gi.repository import Gtk
from senf import fsnative, getcwd

from quodlibet.qltk.chooser import choose_files, get_current_dir, \
    set_current_dir, choose_folders, create_chooser_filter, \
    choose_target_file, choose_target_folder, with_response
from quodlibet.qltk import gtk_version
from quodlibet.util import is_osx

from . import TestCase, skipIf


@skipIf(gtk_version < (3, 16, 0) or is_osx(), "crashy on older gtk+ and macOS")
class Tchooser(TestCase):

    def test_choose_files(self):
        w = Gtk.Window()
        with with_response(Gtk.ResponseType.CANCEL):
            assert choose_files(w, u"title", u"action") == []

    def test_choose_folders(self):
        w = Gtk.Window()
        with with_response(Gtk.ResponseType.CANCEL):
            assert choose_folders(w, u"title", u"action") == []

    def test_choose_filter(self):
        cf = create_chooser_filter(u"filter", ["*.txt"])
        assert isinstance(cf, Gtk.FileFilter)
Пример #42
0
    def test_constrains(self):
        if is_windows():
            self.assertFalse(is_osx())

        if is_osx():
            self.assertFalse(is_windows())
Пример #43
0
    import configparser as ConfigParser
from os.path import dirname, basename
from quodlibet.util.dprint import print_d, print_w

from gi.repository import GObject
from quodlibet.util.path import xdg_get_system_data_dirs

import quodlibet
from quodlibet import util
from quodlibet.devices import _udev as udev
from quodlibet.util.importhelper import load_dir_modules

try:
    import dbus
except ImportError:
    if not util.is_osx() and not util.is_windows():
        print_w(_("Could not import %s, which is needed for "
            "device support.") % "dbus-python")
    dbus = None


devices = []


def init_devices():
    global devices

    load_pyc = util.is_windows() or util.is_osx()
    modules = load_dir_modules(dirname(__file__),
                               package=__package__,
                               load_compiled=load_pyc)
Пример #44
0
def _init_gtk():
    """Call before using Gtk/Gdk"""

    import gi

    # pygiaio 3.14rev16 switched to fontconfig for PangoCairo. As this results
    # in 100% CPU under win7 revert it. Maybe we need to update the
    # cache in the windows installer for it to work... but for now revert.
    if is_windows():
        os.environ['PANGOCAIRO_BACKEND'] = 'win32'

    # disable for consistency and trigger events seem a bit flaky here
    if is_osx():
        os.environ["GTK_OVERLAY_SCROLLING"] = "0"

    # make sure GdkX11 doesn't get used under Windows
    if os.name == "nt":
        sys.modules["gi.repository.GdkX11"] = None

    try:
        # not sure if this is available under Windows
        gi.require_version("GdkX11", "3.0")
        from gi.repository import GdkX11
        GdkX11
    except (ValueError, ImportError):
        pass

    gi.require_version("Gtk", "3.0")
    gi.require_version("Gdk", "3.0")
    gi.require_version("Pango", "1.0")
    gi.require_version('Soup', '2.4')

    from gi.repository import Gtk, Gdk

    # PyGObject doesn't fail anymore when init fails, so do it ourself
    initialized, argv = Gtk.init_check(sys.argv)
    if not initialized:
        raise SystemExit("Gtk.init failed")
    sys.argv = list(argv)

    # add Gtk.TreePath.__getitem__/__len__ for PyGObject 3.2
    try:
        Gtk.TreePath()[0]
    except TypeError:
        Gtk.TreePath.__getitem__ = lambda self, index: list(self)[index]
        Gtk.TreePath.__len__ = lambda self: self.get_depth()

    # GTK+ 3.4+ constants
    if not hasattr(Gdk, "BUTTON_PRIMARY"):
        Gdk.BUTTON_PRIMARY = 1
        Gdk.BUTTON_MIDDLE = 2
        Gdk.BUTTON_SECONDARY = 3

    if not hasattr(Gdk, "EVENT_PROPAGATE"):
        Gdk.EVENT_PROPAGATE = 0
        Gdk.EVENT_STOP = 1

    # include our own icon theme directory
    theme = Gtk.IconTheme.get_default()
    theme_search_path = get_image_dir()
    assert os.path.exists(theme_search_path)
    theme.append_search_path(theme_search_path)

    # Force menu/button image related settings. We might show too many atm
    # but this makes sure we don't miss cases where we forgot to force them
    # per widget.
    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # some day... but not now
    warnings.filterwarnings(
        'ignore', '.*Stock items are deprecated.*', Warning)
    warnings.filterwarnings(
        'ignore', '.*:use-stock.*', Warning)
    warnings.filterwarnings(
        'ignore', '.*The property GtkAlignment:[^\s]+ is deprecated.*',
        Warning)

    settings = Gtk.Settings.get_default()
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        settings.set_property("gtk-button-images", True)
        settings.set_property("gtk-menu-images", True)
    if hasattr(settings.props, "gtk_primary_button_warps_slider"):
        # https://bugzilla.gnome.org/show_bug.cgi?id=737843
        settings.set_property("gtk-primary-button-warps-slider", True)

    # Make sure PyGObject includes support for foreign cairo structs
    try:
        gi.require_foreign("cairo")
    except AttributeError:
        # older pygobject
        pass
    except ImportError:
        print_e("PyGObject is missing cairo support")
        exit(1)

    # CSS overrides
    if os.name == "nt":
        # somehow borders are missing under Windows & Gtk+3.14
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data("""
            .menu {
                border: 1px solid @borders;
            }
        """)
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(),
            style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

    if sys.platform == "darwin":
        # fix duplicated shadows for popups with Gtk+3.14
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data("""
            GtkWindow {
                box-shadow: none;
            }
            .tooltip {
                border-radius: 0;
                padding: 0;
            }
            .tooltip.background {
                background-clip: border-box;
            }
            """)
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(),
            style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # blacklist some modules, simply loading can cause segfaults
    sys.modules["gtk"] = None
    sys.modules["gpod"] = None
    sys.modules["gnome"] = None

    from quodlibet.qltk import pygobject_version, gtk_version

    MinVersions.GTK.check(gtk_version)
    MinVersions.PYGOBJECT.check(pygobject_version)
Пример #45
0
def run(window, before_quit=None):
    print_d("Entering quodlibet.main")
    from gi.repository import Gtk, Gdk, GLib
    from quodlibet._init import is_init

    assert is_init()

    def quit_gtk(window):

        if before_quit is not None:
            before_quit()

        # disable plugins
        import quodlibet.plugins
        quodlibet.plugins.quit()

        # for debug: this will list active copools
        from quodlibet.util import copool
        copool.pause_all()

        # See which browser windows are open and save their names
        # so we can restore them on start
        from quodlibet.qltk.browser import LibraryBrowser
        LibraryBrowser.save()

        # destroy all open windows so they hide immediately on close:
        # destroying all top level windows doesn't work (weird errors),
        # so we hide them all and only destroy our tracked instances
        # (browser windows, tag editors, pref window etc.)
        from quodlibet.qltk import Window
        for toplevel in Gtk.Window.list_toplevels():
            toplevel.hide()

        for window in Window.windows:
            window.destroy()

        Gtk.main_quit()

        print_d("Quit GTK: done.")

    window.connect('destroy', quit_gtk)

    if sys.platform == "darwin":
        _main_setup_osx(window)

    if not window.show_maybe():
        # if we don't show a window, startup isn't completed, so call manually
        Gdk.notify_startup_complete()

    from quodlibet.errorreport import faulthandling

    # gtk+ on osx is just too crashy
    if not is_osx():
        try:
            faulthandling.enable(os.path.join(get_user_dir(), "faultdump"))
        except IOError:
            util.print_exc()
        else:
            GLib.idle_add(faulthandling.raise_and_clear_error)

    # set QUODLIBET_START_PERF to measure startup time until the
    # windows is first shown.
    if "QUODLIBET_START_PERF" in environ:
        window.connect("draw", Gtk.main_quit)
        Gtk.main()
        sys.exit()
    else:
        Gtk.main()

    print_d("Gtk.main() done.")
Пример #46
0
def _gtk_init():
    """Call before using Gtk/Gdk"""

    import gi

    # disable for consistency and trigger events seem a bit flaky here
    if is_osx():
        os.environ["GTK_OVERLAY_SCROLLING"] = "0"

    # make sure GdkX11 doesn't get used under Windows
    if os.name == "nt":
        sys.modules["gi.repository.GdkX11"] = None

    try:
        # not sure if this is available under Windows
        gi.require_version("GdkX11", "3.0")
        from gi.repository import GdkX11
        GdkX11
    except (ValueError, ImportError):
        pass

    gi.require_version("GLib", "2.0")
    gi.require_version("Gtk", "3.0")
    gi.require_version("Gdk", "3.0")
    gi.require_version("GObject", "2.0")
    gi.require_version("Pango", "1.0")
    gi.require_version("GdkPixbuf", "2.0")
    gi.require_version("Gio", "2.0")

    from gi.repository import Gtk, GObject, Gdk, GdkPixbuf

    # add Gtk.TreePath.__getitem__/__len__ for PyGObject 3.2
    try:
        Gtk.TreePath()[0]
    except TypeError:
        Gtk.TreePath.__getitem__ = lambda self, index: list(self)[index]
        Gtk.TreePath.__len__ = lambda self: self.get_depth()

    # GTK+ 3.4+ constants
    if not hasattr(Gdk, "BUTTON_PRIMARY"):
        Gdk.BUTTON_PRIMARY = 1
        Gdk.BUTTON_MIDDLE = 2
        Gdk.BUTTON_SECONDARY = 3

    if not hasattr(Gdk, "EVENT_PROPAGATE"):
        Gdk.EVENT_PROPAGATE = 0
        Gdk.EVENT_STOP = 1

    # On windows the default variants only do ANSI paths, so replace them.
    # In some typelibs they are replaced by default, in some don't..
    if os.name == "nt":
        for name in ["new_from_file_at_scale", "new_from_file_at_size",
                     "new_from_file"]:
            cls = GdkPixbuf.Pixbuf
            setattr(cls, name, getattr(cls, name + "_utf8", name))

    # https://bugzilla.gnome.org/show_bug.cgi?id=670372
    if not hasattr(GdkPixbuf.Pixbuf, "savev"):
        GdkPixbuf.Pixbuf.savev = GdkPixbuf.Pixbuf.save

    # Force menu/button image related settings. We might show too many atm
    # but this makes sure we don't miss cases where we forgot to force them
    # per widget.
    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # some day... but not now
    warnings.filterwarnings(
        'ignore', '.*Stock items are deprecated.*', Warning)
    warnings.filterwarnings(
        'ignore', '.*:use-stock.*', Warning)
    warnings.filterwarnings(
        'ignore', '.*The property GtkAlignment:[^\s]+ is deprecated.*',
        Warning)

    # Newer glib is noisy regarding deprecated signals/properties
    # even with stable releases.
    if is_release():
        warnings.filterwarnings(
            'ignore', '.* It will be removed in a future version.',
            Warning)

    settings = Gtk.Settings.get_default()
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        settings.set_property("gtk-button-images", True)
        settings.set_property("gtk-menu-images", True)
    if hasattr(settings.props, "gtk_primary_button_warps_slider"):
        settings.set_property("gtk-primary-button-warps-slider", True)

    # Make sure PyGObject includes support for foreign cairo structs
    try:
        gi.require_foreign("cairo")
    except AttributeError:
        # older pygobject
        pass
    except ImportError:
        print_e("PyGObject is missing cairo support")
        exit(1)

    # CSS overrides
    if os.name == "nt":
        # somehow borders are missing under Windows & Gtk+3.14
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data("""
            .menu {
                border: 1px solid @borders;
            }
        """)
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(),
            style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

    if sys.platform == "darwin":
        # fix duplicated shadows for popups with Gtk+3.14
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data("""
            GtkWindow {
                box-shadow: none;
            }
            .tooltip {
                border-radius: 0;
                padding: 0;
            }
            .tooltip.background {
                background-clip: border-box;
            }
            """)
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(),
            style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
        )

    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # blacklist some modules, simply loading can cause segfaults
    sys.modules["gtk"] = None
    sys.modules["gpod"] = None
    sys.modules["glib"] = None
    sys.modules["gobject"] = None
    sys.modules["gnome"] = None

    from quodlibet.qltk import pygobject_version
    if pygobject_version < (3, 9):
        GObject.threads_init()
Пример #47
0
# -*- coding: utf-8 -*-
# Copyright 2016 Christoph Reiter
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.

from tests import TestCase, skipUnless

from gi.repository import Gio, Soup

from quodlibet.util import is_osx, is_windows
from quodlibet.compat import urlopen


@skipUnless(is_osx() or is_windows(), "not on linux")
class Thttps(TestCase):
    """For Windows/OSX to check if we can create a TLS connection
    using both openssl and whatever backend soup/gio uses.
    """

    URI = "https://www.google.com"

    def test_urllib(self):
        if is_windows():
            # FXIME
            return
        urlopen(self.URI).close()

    def test_gio(self):
        if is_osx():
Пример #48
0
 def test_gio(self):
     if is_osx():
         return
     client = Gio.SocketClient.new()
     client.set_tls(True)
     client.connect_to_uri(self.URI, 443, None).close()
Пример #49
0
 def test_soup(self):
     if is_osx():
         return
     session = Soup.Session.new()
     request = session.request_http("get", self.URI)
     request.send(None).close()
Пример #50
0
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

from quodlibet import _
from quodlibet import app
from quodlibet.plugins.events import EventPlugin
from quodlibet.qltk import Icons
from quodlibet.util import (is_linux, is_osx, print_w, print_d)
from quodlibet.util.environment import dbus_name_owned

from .prefs import Preferences
from .systemtray import SystemTray


if is_osx():
    # Works, but not without problems:
    # https://github.com/quodlibet/quodlibet/issues/1870
    # The dock menu is more useful so disable.
    from quodlibet.plugins import PluginNotSupportedError
    raise PluginNotSupportedError


def get_indicator_impl():
    """Returns a BaseIndicator implementation depending on the environ"""

    use_app_indicator = (
        is_linux() and dbus_name_owned("org.kde.StatusNotifierWatcher"))

    print_d("use app indicator: %s" % use_app_indicator)
    if not use_app_indicator:
Пример #51
0
        # osx implementation might be buggy so let users disable it
        "disable_mmkeys": "false",

        # the UI language to use, empty means system default
        "language": "",

        # the pattern for the main window title
        "window_title_pattern": "~title~version~~people",

        # the format of the timestamps in DateColumn
        "datecolumn_timestamp_format": "",

        # scrollbar does not fade out when inactive
        "scrollbar_always_visible": "true" if
        (is_osx() or is_windows()) else "false",

        # Force fontconfig as PangoCairo backend
        "pangocairo_force_fontconfig": "false",

        # Whether the plugin window appears on top of others
        "plugins_window_on_top": "false",

        # search bar font style (#3647)
        "monospace_query": "false",

        # size to apply to query box, in any Pango CSS units (e.g. '100%', '1rem')
        "query_font_size": "100%",

        # Amount of colour to apply to validating text entries
        # (0.0 = no colour, 1.0 = full colour)
Пример #52
0
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.

import os

from tests import TestCase, skipUnless

from gi.repository import Gio, Soup

from quodlibet.util import is_osx, is_windows
from quodlibet.compat import urlopen


# this is fixed in 3.6, but we currently still use 3.5 bundles on travis
if is_osx():
    glib_net_fixed = "GTLS_SYSTEM_CA_FILE" in os.environ
else:
    glib_net_fixed = True


@skipUnless(is_osx() or is_windows())
class Thttps(TestCase):
    """For Windows/OSX to check if we can create a TLS connection
    using both openssl and whatever backend soup/gio uses.
    """

    URI = "https://www.google.com"

    def test_urllib(self):
        if is_windows():
Пример #53
0
 def test_is_accel_primary(self):
     e = Gdk.Event.new(Gdk.EventType.KEY_PRESS)
     e.keyval = Gdk.KEY_Return
     e.state = Gdk.ModifierType.CONTROL_MASK
     if not util.is_osx():
         self.assertTrue(qltk.is_accel(e, "<Primary>Return"))
Пример #54
0
def _init_gtk():
    """Call before using Gtk/Gdk"""

    import gi

    # pygiaio 3.14rev16 switched to fontconfig for PangoCairo. As this results
    # in 100% CPU under win7 revert it. Maybe we need to update the
    # cache in the windows installer for it to work... but for now revert.
    if is_windows():
        environ['PANGOCAIRO_BACKEND'] = 'win32'
        environ["GTK_CSD"] = "0"

    # disable for consistency and trigger events seem a bit flaky here
    if is_osx():
        environ["GTK_OVERLAY_SCROLLING"] = "0"

    # make sure GdkX11 doesn't get used under Windows
    if os.name == "nt":
        sys.modules["gi.repository.GdkX11"] = None

    try:
        # not sure if this is available under Windows
        gi.require_version("GdkX11", "3.0")
        from gi.repository import GdkX11
        GdkX11
    except (ValueError, ImportError):
        pass

    gi.require_version("Gtk", "3.0")
    gi.require_version("Gdk", "3.0")
    gi.require_version("Pango", "1.0")
    gi.require_version('Soup', '2.4')

    from gi.repository import Gtk, Soup
    from quodlibet.qltk import ThemeOverrider, gtk_version

    # Work around missing annotation in older libsoup (Ubuntu 14.04 at least)
    message = Soup.Message()
    try:
        message.set_request(None, Soup.MemoryUse.COPY, b"")
    except TypeError:
        orig = Soup.Message.set_request

        def new_set_request(self, content_type, req_use, req_body):
            return orig(self, content_type, req_use, req_body, len(req_body))

        Soup.Message.set_request = new_set_request

    # PyGObject doesn't fail anymore when init fails, so do it ourself
    initialized, argv[:] = Gtk.init_check(argv)
    if not initialized:
        raise SystemExit("Gtk.init failed")

    # include our own icon theme directory
    theme = Gtk.IconTheme.get_default()
    theme_search_path = get_image_dir()
    assert os.path.exists(theme_search_path)
    theme.append_search_path(theme_search_path)

    # Force menu/button image related settings. We might show too many atm
    # but this makes sure we don't miss cases where we forgot to force them
    # per widget.
    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # some day... but not now
    warnings.filterwarnings(
        'ignore', '.*Stock items are deprecated.*', Warning)
    warnings.filterwarnings(
        'ignore', '.*:use-stock.*', Warning)
    warnings.filterwarnings(
        'ignore', '.*The property GtkAlignment:[^\s]+ is deprecated.*',
        Warning)

    settings = Gtk.Settings.get_default()
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        settings.set_property("gtk-button-images", True)
        settings.set_property("gtk-menu-images", True)
    if hasattr(settings.props, "gtk_primary_button_warps_slider"):
        # https://bugzilla.gnome.org/show_bug.cgi?id=737843
        settings.set_property("gtk-primary-button-warps-slider", True)

    # Make sure PyGObject includes support for foreign cairo structs
    try:
        gi.require_foreign("cairo")
    except AttributeError:
        # older pygobject
        pass
    except ImportError:
        print_e("PyGObject is missing cairo support")
        exit(1)

    css_override = ThemeOverrider()

    # CSS overrides
    if os.name == "nt":
        # somehow borders are missing under Windows & Gtk+3.14
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            .menu {
                border: 1px solid @borders;
            }
        """)
        css_override.register_provider("", style_provider)

    if sys.platform == "darwin":
        # fix duplicated shadows for popups with Gtk+3.14
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            GtkWindow {
                box-shadow: none;
            }
            .tooltip {
                border-radius: 0;
                padding: 0;
            }
            .tooltip.background {
                background-clip: border-box;
            }
            """)
        css_override.register_provider("", style_provider)

    if gtk_version[:2] >= (3, 20):
        # https://bugzilla.gnome.org/show_bug.cgi?id=761435
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            spinbutton, button {
                min-height: 1.8rem;
            }

            .view button {
                min-height: 2.0rem;
            }

            entry {
                min-height: 2.4rem;
            }

            entry.cell {
                min-height: 0;
            }
        """)
        css_override.register_provider("Adwaita", style_provider)
        css_override.register_provider("HighContrast", style_provider)

    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # blacklist some modules, simply loading can cause segfaults
    sys.modules["gtk"] = None
    sys.modules["gpod"] = None
    sys.modules["gnome"] = None

    from quodlibet.qltk import pygobject_version, gtk_version

    MinVersions.GTK.check(gtk_version)
    MinVersions.PYGOBJECT.check(pygobject_version)
Пример #55
0
def _init_gtk():
    """Call before using Gtk/Gdk"""

    import gi

    # pygiaio 3.14rev16 switched to fontconfig for PangoCairo. As this results
    # in 100% CPU under win7 revert it. Maybe we need to update the
    # cache in the windows installer for it to work... but for now revert.
    if is_windows():
        os.environ['PANGOCAIRO_BACKEND'] = 'win32'
        os.environ["GTK_CSD"] = "0"

    # disable for consistency and trigger events seem a bit flaky here
    if is_osx():
        os.environ["GTK_OVERLAY_SCROLLING"] = "0"

    # make sure GdkX11 doesn't get used under Windows
    if os.name == "nt":
        sys.modules["gi.repository.GdkX11"] = None

    try:
        # not sure if this is available under Windows
        gi.require_version("GdkX11", "3.0")
        from gi.repository import GdkX11
        GdkX11
    except (ValueError, ImportError):
        pass

    gi.require_version("Gtk", "3.0")
    gi.require_version("Gdk", "3.0")
    gi.require_version("Pango", "1.0")
    gi.require_version('Soup', '2.4')

    from gi.repository import Gtk, Soup
    from quodlibet.qltk import ThemeOverrider, gtk_version

    # Work around missing annotation in older libsoup (Ubuntu 14.04 at least)
    message = Soup.Message()
    try:
        message.set_request(None, Soup.MemoryUse.COPY, b"")
    except TypeError:
        orig = Soup.Message.set_request

        def new_set_request(self, content_type, req_use, req_body):
            return orig(self, content_type, req_use, req_body, len(req_body))

        Soup.Message.set_request = new_set_request

    # PyGObject doesn't fail anymore when init fails, so do it ourself
    initialized, argv = Gtk.init_check(sys.argv)
    if not initialized:
        raise SystemExit("Gtk.init failed")
    sys.argv = list(argv)

    # include our own icon theme directory
    theme = Gtk.IconTheme.get_default()
    theme_search_path = get_image_dir()
    assert os.path.exists(theme_search_path)
    theme.append_search_path(theme_search_path)

    # Force menu/button image related settings. We might show too many atm
    # but this makes sure we don't miss cases where we forgot to force them
    # per widget.
    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # some day... but not now
    warnings.filterwarnings(
        'ignore', '.*Stock items are deprecated.*', Warning)
    warnings.filterwarnings(
        'ignore', '.*:use-stock.*', Warning)
    warnings.filterwarnings(
        'ignore', '.*The property GtkAlignment:[^\s]+ is deprecated.*',
        Warning)

    settings = Gtk.Settings.get_default()
    with warnings.catch_warnings():
        warnings.simplefilter("ignore")
        settings.set_property("gtk-button-images", True)
        settings.set_property("gtk-menu-images", True)
    if hasattr(settings.props, "gtk_primary_button_warps_slider"):
        # https://bugzilla.gnome.org/show_bug.cgi?id=737843
        settings.set_property("gtk-primary-button-warps-slider", True)

    # Make sure PyGObject includes support for foreign cairo structs
    try:
        gi.require_foreign("cairo")
    except AttributeError:
        # older pygobject
        pass
    except ImportError:
        print_e("PyGObject is missing cairo support")
        exit(1)

    css_override = ThemeOverrider()

    # CSS overrides
    if os.name == "nt":
        # somehow borders are missing under Windows & Gtk+3.14
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            .menu {
                border: 1px solid @borders;
            }
        """)
        css_override.register_provider("", style_provider)

    if sys.platform == "darwin":
        # fix duplicated shadows for popups with Gtk+3.14
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            GtkWindow {
                box-shadow: none;
            }
            .tooltip {
                border-radius: 0;
                padding: 0;
            }
            .tooltip.background {
                background-clip: border-box;
            }
            """)
        css_override.register_provider("", style_provider)

    if gtk_version[:2] >= (3, 20):
        # https://bugzilla.gnome.org/show_bug.cgi?id=761435
        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b"""
            spinbutton, button {
                min-height: 1.8rem;
            }

            .view button {
                min-height: 2.0rem;
            }

            entry {
                min-height: 2.4rem;
            }
        """)
        css_override.register_provider("Adwaita", style_provider)
        css_override.register_provider("HighContrast", style_provider)

    # https://bugzilla.gnome.org/show_bug.cgi?id=708676
    warnings.filterwarnings('ignore', '.*g_value_get_int.*', Warning)

    # blacklist some modules, simply loading can cause segfaults
    sys.modules["gtk"] = None
    sys.modules["gpod"] = None
    sys.modules["gnome"] = None

    from quodlibet.qltk import pygobject_version, gtk_version

    MinVersions.GTK.check(gtk_version)
    MinVersions.PYGOBJECT.check(pygobject_version)
Пример #56
0
def run(window, before_quit=None):
    print_d("Entering quodlibet.main")
    from gi.repository import Gtk, Gdk, GLib
    from quodlibet._init import is_init

    assert is_init()

    def quit_gtk(window):

        if before_quit is not None:
            before_quit()

        # disable plugins
        import quodlibet.plugins
        quodlibet.plugins.quit()

        # for debug: this will list active copools
        from quodlibet.util import copool
        copool.pause_all()

        # See which browser windows are open and save their names
        # so we can restore them on start
        from quodlibet.qltk.browser import LibraryBrowser
        LibraryBrowser.save()

        # destroy all open windows so they hide immediately on close:
        # destroying all top level windows doesn't work (weird errors),
        # so we hide them all and only destroy our tracked instances
        # (browser windows, tag editors, pref window etc.)
        from quodlibet.qltk import Window
        for toplevel in Gtk.Window.list_toplevels():
            toplevel.hide()

        for window in Window.windows:
            window.destroy()

        Gtk.main_quit()

        print_d("Quit GTK: done.")

    window.connect('destroy', quit_gtk)

    if sys.platform == "darwin":
        _main_setup_osx(window)

    if not window.show_maybe():
        # if we don't show a window, startup isn't completed, so call manually
        Gdk.notify_startup_complete()

    from quodlibet.errorreport import faulthandling

    # gtk+ on osx is just too crashy
    if not is_osx():
        try:
            faulthandling.enable(os.path.join(get_user_dir(), "faultdump"))
        except IOError:
            util.print_exc()
        else:
            GLib.idle_add(faulthandling.raise_and_clear_error)

    # set QUODLIBET_START_PERF to measure startup time until the
    # windows is first shown.
    if "QUODLIBET_START_PERF" in environ:
        window.connect("draw", Gtk.main_quit)
        Gtk.main()
        sys.exit()
    else:
        Gtk.main()

    print_d("Gtk.main() done.")
Пример #57
0
class TIRFile(TestCase):
    def setUp(self):
        self.s = IRFile("http://foo.bar")

    def test_website(self):
        self.s["website"] = "abc"
        self.assertEqual(self.s.get("artist"), "abc")
        self.assertEqual(self.s("artist"), "abc")
        self.assertEqual(self.s.list("artist"), ["abc"])

    def test_organisation(self):
        self.s["organization"] = "foo"
        self.assertEqual(self.s("title"), "foo")
        self.assertEqual(self.s.get("title"), "foo")

    def test_title_split_stream(self):
        self.assertFalse(self.s("artist"))
        self.s["title"] = "artist - title"
        self.s.multisong = False
        self.assertEqual(self.s("title"), "title")
        self.assertEqual(self.s.get("title"), "title")
        self.assertEqual(self.s("artist"), "artist")
        self.assertEqual(self.s.get("artist"), "artist")

    def test_title_split(self):
        self.assertTrue(self.s.multisong)
        self.s["title"] = "artist - title"
        self.assertEqual(self.s("title"), self.s["title"])

    def test_format(self):
        self.assertEqual(self.s("~format"), self.s.format)
        self.s["audio-codec"] = "SomeCodec"
        self.assertTrue("SomeCodec" in self.s("~format"))
        self.assertTrue(self.s.format in self.s("~format"))

    def test_people(self):
        self.s["title"] = "artist - title"
        self.s.multisong = False
        self.assertEqual(self.s("~people"), "artist")
        self.assertEqual(self.s("~~people~foo"), "artist")

    def testcan_write(self):
        self.failUnless(self.s.can_change("title"))
        self.s.streamsong = True
        self.failIf(self.s.can_change("title"))

    def test_dump_to_file(self):
        self.s["title"] = "artist - title"
        self.s.multisong = False
        dump = self.s.to_dump()
        new = AudioFile()
        new.from_dump(dump)
        self.assertEqual(new["title"], "title")
        self.assertEqual(new["artist"], "artist")

        del self.s["title"]
        dump = self.s.to_dump()
        new = AudioFile()
        new.from_dump(dump)
        self.assertTrue("title" not in new)
        self.assertTrue("artist" not in new)

    @skipIf(is_windows() or is_osx(), "Don't need to test all the time")
    def test_download_tags(self):
        self.received = []
        # TODO: parameterise this, spin up a local HTTP server, inject this.
        url = STATION_LIST_URL

        def cb(data):
            assert data
            self.received += data

        ret = list(download_taglist(cb, None))
        run_loop()
        assert all(ret)
        assert self.received, "No stations received from %s" % url
        assert len(self.received) > 100