Exemple #1
0
 def __init__(self, extension):
     """
         Connect wanted signal
         @param extension as WebKit2WebExtension
     """
     self.__settings = Settings.new()
     self.__adblock = DatabaseAdblock()
     extension.connect("page-created", self.__on_page_created)
Exemple #2
0
    def init(self):
        """
            Init main application
        """
        self.__is_fs = False
        if Gtk.get_minor_version() > 18:
            cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Eolie/application.css')
        else:
            cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Eolie/application-legacy.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        self.history = DatabaseHistory()
        self.bookmarks = DatabaseBookmarks()
        # We store cursors for main thread
        SqlCursor.add(self.history)
        SqlCursor.add(self.bookmarks)
        self.bookmarks.import_firefox()
        adblock = DatabaseAdblock()
        adblock.update()
        self.art = Art()
        self.search = Search()
        self.downloads_manager = DownloadsManager()

        shortcut_action = Gio.SimpleAction.new('shortcut',
                                               GLib.VariantType.new('s'))
        shortcut_action.connect('activate', self.__on_shortcut_action)
        self.add_action(shortcut_action)
        self.set_accels_for_action("app.shortcut::uri", ["<Control>l"])
        self.set_accels_for_action("app.shortcut::new_page", ["<Control>t"])
        self.set_accels_for_action("app.shortcut::close_page", ["<Control>w"])

        # Set some WebKit defaults
        context = WebKit2.WebContext.get_default()
        GLib.setenv('PYTHONPATH', self.__extension_dir, True)
        context.set_web_extensions_directory(self.__extension_dir)

        data_manager = WebKit2.WebsiteDataManager()
        context.new_with_website_data_manager(data_manager)
        context.set_process_model(
            WebKit2.ProcessModel.MULTIPLE_SECONDARY_PROCESSES)
        context.set_cache_model(WebKit2.CacheModel.WEB_BROWSER)
        d = Gio.File.new_for_path(self.__FAVICONS_PATH)
        if not d.query_exists():
            d.make_directory_with_parents()
        context.set_favicon_database_directory(self.__FAVICONS_PATH)
        cookie_manager = context.get_cookie_manager()
        cookie_manager.set_accept_policy(
            WebKit2.CookieAcceptPolicy.NO_THIRD_PARTY)
        cookie_manager.set_persistent_storage(
            self.__COOKIES_PATH, WebKit2.CookiePersistentStorage.SQLITE)
Exemple #3
0
 def __init__(self, extension, settings):
     """
         Connect wanted signal
         @param extension as WebKit2WebExtension
         @param settings as Settings
     """
     self.__settings = settings
     self.__adblock = DatabaseAdblock()
     self.__exceptions = DatabaseExceptions("adblock")
     extension.connect("page-created", self.__on_page_created)
Exemple #4
0
class AdblockExtension:
    """
        Handle adblocking
    """
    def __init__(self, extension):
        """
            Connect wanted signal
            @param extension as WebKit2WebExtension
        """
        self.__settings = Settings.new()
        self.__adblock = DatabaseAdblock()
        extension.connect("page-created", self.__on_page_created)

#######################
# PRIVATE             #
#######################

    def __on_page_created(self, extension, webpage):
        """
            Connect to send request
            @param extension as WebKit2WebExtension
            @param webpage as WebKit2WebExtension.WebPage
        """
        webpage.connect("send-request", self.__on_send_request)

    def __on_send_request(self, webpage, request, redirect):
        """
            Filter based on adblock db
            @param webpage as WebKit2WebExtension.WebPage
            @param request as WebKit2.URIRequest
            @param redirect as WebKit2WebExtension.URIResponse
        """
        uri = request.get_uri()
        parsed = urlparse(webpage.get_uri())
        exception = self.__adblock.is_an_exception(parsed.netloc) or\
            self.__adblock.is_an_exception(parsed.netloc + parsed.path)
        if self.__settings.get_value("adblock") and\
                not exception and\
                self.__adblock.is_blocked(uri):
            return True
        return False
Exemple #5
0
class AdblockExtension:
    """
        Handle adblocking
    """
    def __init__(self, extension, settings):
        """
            Connect wanted signal
            @param extension as WebKit2WebExtension
            @param settings as Settings
        """
        self.__settings = settings
        self.__adblock = DatabaseAdblock()
        self.__exceptions = DatabaseExceptions("adblock")
        extension.connect("page-created", self.__on_page_created)

#######################
# PRIVATE             #
#######################

    def __on_page_created(self, extension, webpage):
        """
            Connect to send request
            @param extension as WebKit2WebExtension
            @param webpage as WebKit2WebExtension.WebPage
        """
        webpage.connect("send-request", self.__on_send_request)

    def __on_send_request(self, webpage, request, redirect):
        """
            Filter based on adblock db
            @param webpage as WebKit2WebExtension.WebPage
            @param request as WebKit2.URIRequest
            @param redirect as WebKit2WebExtension.URIResponse
        """
        uri = request.get_uri()
        parsed = urlparse(webpage.get_uri())
        exception = self.__exceptions.find(parsed.netloc) or\
            self.__exceptions.find(parsed.netloc + parsed.path)
        if self.__settings.get_value("adblock") and\
                not exception and\
                self.__adblock.is_blocked(uri):
            return True
        return False
        if self.__settings.get_value("do-not-track"):
            headers = request.get_http_headers()
            if headers is not None:
                headers.append("DNT", "1")
Exemple #6
0
class Application(Gtk.Application):
    """
        Eolie application:
    """

    __COOKIES_PATH = "%s/cookies.db" % EOLIE_LOCAL_PATH
    __FAVICONS_PATH = "/tmp/eolie_%s" % getuser()

    def __init__(self, version, extension_dir):
        """
            Create application
            @param version as str
            @param extension_dir as str
        """
        self.__version = version
        # First check WebKit2 version
        if WebKit2.MINOR_VERSION < 16:
            exit("You need WebKit2GTK >= 2.16")
        Gtk.Application.__init__(
                            self,
                            application_id='org.gnome.Eolie',
                            flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
        self.set_property('register-session', True)
        # Ideally, we will be able to delete this once Flatpak has a solution
        # for SSL certificate management inside of applications.
        if GLib.file_test("/app", GLib.FileTest.EXISTS):
            paths = ["/etc/ssl/certs/ca-certificates.crt",
                     "/etc/pki/tls/cert.pem",
                     "/etc/ssl/cert.pem"]
            for path in paths:
                if GLib.file_test(path, GLib.FileTest.EXISTS):
                    GLib.setenv('SSL_CERT_FILE', path, True)
                    break
        self.sync_worker = None  # Not initialised
        self.__extension_dir = extension_dir
        self.debug = False
        self.show_tls = False
        self.cursors = {}
        GLib.set_application_name('Eolie')
        GLib.set_prgname('org.gnome.Eolie')
        self.add_main_option("debug", b'd', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Debug Eolie", None)
        self.add_main_option("private", b'p', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Add a private page",
                             None)
        self.add_main_option("new", b'n', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Add a new window",
                             None)
        self.add_main_option("disable-artwork-cache", b'a',
                             GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Do not use cache for art",
                             None)
        self.add_main_option("show-tls", b's', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Show TLS info",
                             None)
        self.connect('activate', self.__on_activate)
        self.connect("handle-local-options", self.__on_handle_local_options)
        self.connect('command-line', self.__on_command_line)
        self.register(None)
        if self.get_is_remote():
            Gdk.notify_startup_complete()
        self.__listen_to_gnome_sm()

    def get_app_menu(self):
        """
            Setup application menu
            @return menu as Gio.Menu
        """
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Eolie/Appmenu.ui")
        menu = builder.get_object("app-menu")

        report_action = Gio.SimpleAction.new("report", None)
        report_action.connect("activate", self.__on_report_activate)
        self.add_action(report_action)

        settings_action = Gio.SimpleAction.new("settings", None)
        settings_action.connect("activate", self.__on_settings_activate)
        self.add_action(settings_action)

        about_action = Gio.SimpleAction.new("about", None)
        about_action.connect("activate", self.__on_about_activate)
        self.add_action(about_action)

        show_sidebar = self.settings.get_value("show-sidebar")
        sidebar_action = Gio.SimpleAction.new_stateful(
                                       "sidebar",
                                       None,
                                       GLib.Variant.new_boolean(show_sidebar))
        sidebar_action.connect("change-state", self.__on_sidebar_change_state)
        self.add_action(sidebar_action)

        shortcuts_action = Gio.SimpleAction.new("shortcuts", None)
        shortcuts_action.connect("activate", self.__on_shortcuts_activate)
        self.add_action(shortcuts_action)

        # help_action = Gio.SimpleAction.new('help', None)
        # help_action.connect('activate', self.__on_help_activate)
        # self.add_action(help_action)

        quit_action = Gio.SimpleAction.new("quit", None)
        quit_action.connect("activate", lambda x, y: self.quit())
        self.add_action(quit_action)
        return menu

    def do_startup(self):
        """
            Init application
        """
        Gtk.Application.do_startup(self)
        if not self.get_windows():
            self.__init()
            window = self.get_new_window()
            window.container.add_webview(None,
                                         Gdk.WindowType.CHILD,
                                         False)

    def get_new_window(self):
        """
            Return a new window
            @return Window
        """
        window = Window(self)
        window.connect('delete-event', self.__on_delete_event)
        window.show()
        return window

    def set_setting(self, key, value):
        """
            Set setting for all view
            @param key as str
            @param value as GLib.Variant
        """
        for window in self.get_windows():
            for view in window.container.views:
                view.webview.set_setting(key, value)

    def quit(self, vacuum=False):
        """
            Quit application
            @param vacuum as bool
        """
        # Save webpage state
        self.__save_state()
        # Stop pending tasks
        self.download_manager.cancel()
        self.adblock.stop()
        # Clear history
        active_id = str(self.settings.get_enum("history-storage"))
        if active_id != TimeSpan.FOREVER:
            atime = time()
            if active_id != TimeSpan.NEVER:
                atime -= TimeSpanValues[active_id]/1000000
            self.history.clear_to(int(atime))
        # If sync is running, to avoid db lock, we do not vacuum
        if self.sync_worker is not None and self.sync_worker.syncing:
            self.sync_worker.stop()
            Gio.Application.quit(self)
        elif vacuum:
            task_helper = TaskHelper()
            task_helper.run(self.__vacuum,
                            (),
                            lambda x: Gio.Application.quit(self))
        else:
            Gio.Application.quit(self)

    @property
    def ephemeral_context(self):
        """
            Get default ephemral context
            @return WebKit2.WebContext
        """
        return self.__ephemeral_context

    @property
    def start_page(self):
        """
            Get start page
            @return uri as str
        """
        value = self.settings.get_value("start-page").get_string()
        if value in ["popular_hist", "popular_book"]:
            value = "populars://"
        elif value == "blank":
            value = "about:blank"
        else:
            value = self.search.uri
        return value

    @property
    def active_window(self):
        """
            Get active window
            @return Window
        """
        return self.get_windows()[0]

    @property
    def windows(self):
        """
            Get windows
            @return [Window]
        """
        return self.get_windows()

    @property
    def cookies_path(self):
        """
            Cookies sqlite db path
        """
        return self.__COOKIES_PATH

    @property
    def favicons_path(self):
        """
            Cookies sqlite db path
        """
        return self.__FAVICONS_PATH

    @property
    def extension_dir(self):
        """
            Extension dir path
            @return str
        """
        return self.__extension_dir

#######################
# PRIVATE             #
#######################
    def __init(self):
        """
            Init main application
        """
        self.settings = Settings.new()

        # Init extensions
        GLib.setenv('PYTHONPATH', self.__extension_dir, True)

        # Create favicon path
        d = Gio.File.new_for_path(self.__FAVICONS_PATH)
        if not d.query_exists():
            d.make_directory_with_parents()

        # Setup default context
        context = WebKit2.WebContext.get_default()
        Context(context)
        # Setup ephemeral context
        self.__ephemeral_context = WebKit2.WebContext.new_ephemeral()
        Context(self.__ephemeral_context)

        # Add a global DBus helper
        self.helper = DBusHelper()
        # First init sync worker
        try:
            from eolie.mozilla_sync import SyncWorker
            self.sync_worker = SyncWorker()
            # Run a first sync in 10 seconds, speed up app start
            GLib.timeout_add_seconds(10,
                                     self.sync_worker.sync,
                                     False)
            # Then run a sync every hour
            GLib.timeout_add_seconds(3600,
                                     self.sync_worker.sync,
                                     True)
        except Exception as e:
            print("Application::init():", e)
            self.sync_worker = None
        if self.prefers_app_menu():
            menu = self.get_app_menu()
            self.set_app_menu(menu)
        cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Eolie/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.history = DatabaseHistory()
        self.bookmarks = DatabaseBookmarks()
        # We store cursors for main thread
        SqlCursor.add(self.history)
        SqlCursor.add(self.bookmarks)
        self.websettings = DatabaseSettings()
        self.adblock = DatabaseAdblock()
        self.adblock.update()
        self.phishing = DatabasePhishing()
        self.adblock_exceptions = DatabaseExceptions("adblock")
        self.popup_exceptions = DatabaseExceptions("popup")
        self.image_exceptions = DatabaseExceptions("image")
        if self.settings.get_user_value("jsblock") is not None:
            self.js_exceptions = DatabaseExceptions("js")
        else:
            self.js_exceptions = None
        self.phishing.update()
        self.art = Art()
        self.search = Search()
        self.download_manager = DownloadManager()
        self.pages_menu = PagesMenu()

        shortcut_action = Gio.SimpleAction.new('shortcut',
                                               GLib.VariantType.new('s'))
        shortcut_action.connect('activate', self.__on_shortcut_action)
        self.add_action(shortcut_action)
        self.set_accels_for_action("win.shortcut::expose", ["<Alt>e"])
        self.set_accels_for_action("win.exceptions::site", ["<Control>e"])
        self.set_accels_for_action("win.shortcut::show_left_panel", ["F9"])
        self.set_accels_for_action("win.shortcut::uri",
                                   ["<Control>l", "<Control>b"])
        self.set_accels_for_action("win.shortcut::new_page", ["<Control>t"])
        self.set_accels_for_action("win.shortcut::last_page",
                                   ["<Control><Shift>t"])
        self.set_accels_for_action("app.shortcut::new_window", ["<Control>n"])
        self.set_accels_for_action("win.shortcut::private",
                                   ["<Control><Shift>p"])
        self.set_accels_for_action("win.shortcut::close_page", ["<Control>w"])
        self.set_accels_for_action("win.shortcut::quit", ["<Control>q"])
        self.set_accels_for_action("win.shortcut::save", ["<Control>s"])
        self.set_accels_for_action("win.shortcut::filter", ["<Control>i"])
        self.set_accels_for_action("win.shortcut::reload",
                                   ["<Control>r", "F5"])
        self.set_accels_for_action("win.shortcut::find", ["<Control>f"])
        self.set_accels_for_action("win.shortcut::print", ["<Control>p"])
        self.set_accels_for_action("win.shortcut::source",
                                   ["<Control><Shift>c"])
        self.set_accels_for_action("win.shortcut::history", ["<Control>h"])
        self.set_accels_for_action("win.shortcut::search", ["<Control>k"])
        self.set_accels_for_action("win.shortcut::fullscreen", ["F11"])
        self.set_accels_for_action("app.settings",
                                   ["<Control><Shift>s"])
        self.set_accels_for_action("win.shortcut::backward",
                                   ["<Alt>Left", "XF86Back"])
        self.set_accels_for_action("win.shortcut::forward",
                                   ["<Alt>Right", "XF86Forward"])
        self.set_accels_for_action("win.shortcut::next",
                                   ["<Control>Tab",
                                    "<Control>Page_Down"])
        self.set_accels_for_action("win.shortcut::previous",
                                   ["<Control><Shift>Tab",
                                    "<Control>Page_Up"])
        self.set_accels_for_action("win.shortcut::zoom_in",
                                   ["<Control>KP_Add",
                                    "<Control>plus",
                                    "<Control>equal"])
        self.set_accels_for_action("win.shortcut::zoom_out",
                                   ["<Control>KP_Subtract", "<Control>minus"])
        self.set_accels_for_action("win.shortcut::zoom_default",
                                   ["<Control>KP_0", "<Control>0"])

    def __listen_to_gnome_sm(self):
        """
            Save state on EndSession signal
        """
        try:
            bus = self.get_dbus_connection()
            bus.signal_subscribe(None,
                                 "org.gnome.SessionManager.EndSessionDialog",
                                 "ConfirmedLogout",
                                 "/org/gnome/SessionManager/EndSessionDialog",
                                 None,
                                 Gio.DBusSignalFlags.NONE,
                                 lambda a, b, c, d, e, f: self.__save_state())
        except Exception as e:
            print("Application::__listen_to_gnome_sm():", e)

    def __vacuum(self):
        """
            VACUUM DB
            @thread safe
        """
        try:
            with SqlCursor(self.bookmarks) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.history) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.adblock) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.phishing) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
        except Exception as e:
            print("Application::__vacuum(): ", e)
        self.art.vacuum()

    def __save_state(self):
        """
            Save window position and view
        """
        try:
            remember_session = self.settings.get_value("remember-session")
            session_states = []
            for window in self.get_windows():
                if not remember_session:
                    continue
                for view in window.container.views:
                    uri = view.webview.get_uri()
                    parsed = urlparse(uri)
                    if parsed.scheme not in ["http", "https"]:
                        continue
                    ephemeral = view.webview.ephemeral
                    state = view.webview.get_session_state().serialize()
                    session_states.append((uri, ephemeral, state.get_data()))
            if remember_session:
                dump(session_states,
                     open(EOLIE_LOCAL_PATH + "/session_states.bin", "wb"))
        except Exception as e:
            print("Application::__save_state()", e)

    def __restore_state(self):
        """
            Restore saved state
            @return True as bool if restored
        """
        window_type = Gdk.WindowType.CHILD
        try:
            session_states = load(open(
                                     EOLIE_LOCAL_PATH + "/session_states.bin",
                                     "rb"))
            for (uri, ephemeral, state) in session_states:
                webkit_state = WebKit2.WebViewSessionState(
                                                         GLib.Bytes.new(state))
                GLib.idle_add(self.active_window.container.add_webview,
                              uri, window_type, ephemeral,
                              None, webkit_state,
                              window_type == Gdk.WindowType.CHILD)
                window_type = Gdk.WindowType.OFFSCREEN
            dump([],
                 open(EOLIE_LOCAL_PATH + "/session_states.bin", "wb"))
        except Exception as e:
            print("Application::restore_state()", e)
        return window_type != Gdk.WindowType.CHILD

    def __on_handle_local_options(self, app, options):
        """
            Handle local options
            @param app as Gio.Application
            @param options as GLib.VariantDict
        """
        if options.contains("version"):
            print("Eolie %s" % self.__version)
            return 0
        return -1

    def __on_command_line(self, app, app_cmd_line):
        """
            Handle command line
            @param app as Gio.Application
            @param options as Gio.ApplicationCommandLine
        """
        self.__externals_count = 0
        args = app_cmd_line.get_arguments()
        options = app_cmd_line.get_options_dict()
        if options.contains("debug"):
            GLib.setenv("WEBKIT_DEBUG", "network", True)
            self.debug = True
        if options.contains("show-tls"):
            self.show_tls = True
        if options.contains("disable-artwork-cache"):
            self.art.disable_cache()
        ephemeral = options.contains("private")
        restored = False
        if self.settings.get_value("remember-session"):
            restored = self.__restore_state()
        if options.contains("new"):
            active_window = self.get_new_window()
        else:
            active_window = self.active_window
        # Open command line args
        if len(args) > 1:
            for uri in args[1:]:
                # Transform path to uri
                f = Gio.File.new_for_path(uri)
                if f.query_exists():
                    uri = f.get_uri()
                self.__new_or_load(uri, Gdk.WindowType.CHILD, ephemeral)
            active_window.present_with_time(Gtk.get_current_event_time())
        # Add default start page
        elif not restored:
            self.active_window.present_with_time(Gtk.get_current_event_time())
            self.__new_or_load(self.start_page,
                               Gdk.WindowType.CHILD,
                               ephemeral)
        if self.debug:
            WebKit2.WebContext.get_default().get_plugins(None,
                                                         self.__on_get_plugins,
                                                         None)
        return 0

    def __new_or_load(self, uri, window_type, ephemeral):
        """
            Check current webview, if uri is None, use it, else create
            a new webview
        """
        if self.active_window.container.current.webview.get_uri() is None:
            if ephemeral:
                self.active_window.container.pages_manager.try_close_view(
                                          self.active_window.container.current)
                self.active_window.container.add_webview(uri,
                                                         window_type,
                                                         ephemeral)
            else:
                self.active_window.container.current.webview.load_uri(uri)
        else:
            self.active_window.container.add_webview(uri,
                                                     window_type,
                                                     ephemeral)

    def __close_window(self, window):
        """
            Close window
        """
        if len(self.get_windows()) > 1:
            window.destroy()
        else:
            window.hide()
            self.quit(True)

    def __try_closing(self, window, views):
        """
            Try closing all views
        """
        if views:
            view = views.pop(0)
            page_id = view.webview.get_page_id()
            self.helper.call("FormsFilled",
                             GLib.Variant("(i)", (page_id,)),
                             self.__on_forms_filled, page_id, window, views)
        else:
            self.__close_window(window)

    def __on_forms_filled(self, source, result, window, views):
        """
            Ask user to close view, if ok, close view
            @param source as GObject.Object
            @param result as Gio.AsyncResult
            @param window as Window
            @param views as [View]
        """
        def on_response_id(dialog, response_id, window, views, self):
            if response_id == Gtk.ResponseType.CLOSE:
                if views:
                    self.__try_closing(window, views)
                else:
                    self.__close_window(window)
            dialog.destroy()

        def on_close(widget, dialog):
            dialog.response(Gtk.ResponseType.CLOSE)

        def on_cancel(widget, dialog):
            dialog.response(Gtk.ResponseType.CANCEL)

        try:
            result = source.call_finish(result)[0]
            if result:
                builder = Gtk.Builder()
                builder.add_from_resource("/org/gnome/Eolie/QuitDialog.ui")
                dialog = builder.get_object("dialog")
                label = builder.get_object("label")
                close = builder.get_object("close")
                cancel = builder.get_object("cancel")
                label.set_text(_("Do you really want to quit Eolie?"))
                dialog.set_transient_for(window)
                dialog.connect("response", on_response_id, window, views, self)
                close.connect("clicked", on_close, dialog)
                cancel.connect("clicked", on_cancel, dialog)
                dialog.run()
            else:
                if views:
                    self.__try_closing(window, views)
                else:
                    self.__close_window(window)
        except Exception as e:
            self.__close_window(window)
            print("Application::__on_forms_filled():", e)

    def __on_get_plugins(self, source, result, data):
        """
            Print plugins on command line
            @param source as GObject.Object
            @param result as Gio.AsyncResult
            @param data as None
        """
        plugins = source.get_plugins_finish(result)
        for plugin in plugins:
            print(plugin.get_name(),
                  plugin.get_description(),
                  plugin.get_path())

    def __on_delete_event(self, window, event):
        """
            Exit application
            @param window as Window
            @param event as Gdk.Event
        """
        # Ask for user if needed
        self.__try_closing(window, window.container.views)
        return True

    def __on_settings_activate(self, action, param):
        """
            Show settings dialog
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        dialog = SettingsDialog(self.active_window)
        dialog.show()

    def __on_report_activate(self, action, param):
        """
            Launch bug report page
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        argv = ["uname", "-a", None]
        (s, o, e, s) = GLib.spawn_sync(None,
                                       argv,
                                       None,
                                       GLib.SpawnFlags.SEARCH_PATH,
                                       None)
        if o:
            os = o.decode("utf-8")
        else:
            os = "Unknown"

        github = "https://github.com/gnumdk/eolie/issues/new?body="
        body = """
TRANSLATORS:
https://translate.zanata.org/project/view/eolie

### Environment
- Eolie version: %s
- GTK+ version: %s.%s
- Operating system: %s

### Bug/Feature
If your bug is a rendering bug or a WebKit crash, you should report it here:
https://bugs.webkit.org -> Section WebKit Gtk -> title starting with [GTK]

<Describe your bug here>""" % (
                                self.__version,
                                Gtk.get_major_version(),
                                Gtk.get_minor_version(),
                                os)
        url = github + GLib.uri_escape_string(body, "", False)
        self.active_window.container.add_webview(url,
                                                 Gdk.WindowType.CHILD,
                                                 False)

    def __on_about_activate(self, action, param):
        """
            Setup about dialog
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/AboutDialog.ui')
        about = builder.get_object('about_dialog')
        window = self.active_window
        if window is not None:
            about.set_transient_for(window)
        about.connect("response", self.__on_about_activate_response)
        about.show()

    def __on_shortcuts_activate(self, action, param):
        """
            Show help in yelp
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Eolie/Shortcuts.ui")
        shortcuts = builder.get_object("shortcuts")
        window = self.active_window
        if window is not None:
            shortcuts.set_transient_for(window)
        shortcuts.show()

    def __on_help_activate(self, action, param):
        """
            Show help in yelp
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        try:
            Gtk.show_uri(None, "help:eolie", Gtk.get_current_event_time())
        except:
            print(_("Eolie: You need to install yelp."))

    def __on_about_activate_response(self, dialog, response_id):
        """
            Destroy about dialog when closed
            @param dialog as Gtk.Dialog
            @param response id as int
        """
        dialog.destroy()

    def __on_sidebar_change_state(self, action, value):
        """
            Show/hide sidebar
            @param action as Gio.SimpleAction
            @param value as bool
        """
        action.set_state(value)
        self.settings.set_value("show-sidebar", GLib.Variant("b", value))

    def __on_activate(self, application):
        """
            Call default handler, raise last window
            @param application as Gio.Application
        """
        if self.get_windows():
            self.active_window.present_with_time(Gtk.get_current_event_time())

    def __on_shortcut_action(self, action, param):
        """
            Global shortcuts handler
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        string = param.get_string()
        if string == "new_window":
            window = self.get_new_window()
            window.container.add_webview(self.start_page,
                                         Gdk.WindowType.CHILD)
Exemple #7
0
    def __init(self):
        """
            Init main application
        """
        self.settings = Settings.new()

        # Init extensions
        GLib.setenv('PYTHONPATH', self.__extension_dir, True)

        # Create favicon path
        d = Gio.File.new_for_path(self.__FAVICONS_PATH)
        if not d.query_exists():
            d.make_directory_with_parents()

        # Setup default context
        context = WebKit2.WebContext.get_default()
        Context(context)
        # Setup ephemeral context
        self.__ephemeral_context = WebKit2.WebContext.new_ephemeral()
        Context(self.__ephemeral_context)

        # Add a global DBus helper
        self.helper = DBusHelper()
        # First init sync worker
        try:
            from eolie.mozilla_sync import SyncWorker
            self.sync_worker = SyncWorker()
            # Run a first sync in 10 seconds, speed up app start
            GLib.timeout_add_seconds(10,
                                     self.sync_worker.sync,
                                     False)
            # Then run a sync every hour
            GLib.timeout_add_seconds(3600,
                                     self.sync_worker.sync,
                                     True)
        except Exception as e:
            print("Application::init():", e)
            self.sync_worker = None
        if self.prefers_app_menu():
            menu = self.get_app_menu()
            self.set_app_menu(menu)
        cssProviderFile = Gio.File.new_for_uri(
                'resource:///org/gnome/Eolie/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.history = DatabaseHistory()
        self.bookmarks = DatabaseBookmarks()
        # We store cursors for main thread
        SqlCursor.add(self.history)
        SqlCursor.add(self.bookmarks)
        self.websettings = DatabaseSettings()
        self.adblock = DatabaseAdblock()
        self.adblock.update()
        self.phishing = DatabasePhishing()
        self.adblock_exceptions = DatabaseExceptions("adblock")
        self.popup_exceptions = DatabaseExceptions("popup")
        self.image_exceptions = DatabaseExceptions("image")
        if self.settings.get_user_value("jsblock") is not None:
            self.js_exceptions = DatabaseExceptions("js")
        else:
            self.js_exceptions = None
        self.phishing.update()
        self.art = Art()
        self.search = Search()
        self.download_manager = DownloadManager()
        self.pages_menu = PagesMenu()

        shortcut_action = Gio.SimpleAction.new('shortcut',
                                               GLib.VariantType.new('s'))
        shortcut_action.connect('activate', self.__on_shortcut_action)
        self.add_action(shortcut_action)
        self.set_accels_for_action("win.shortcut::expose", ["<Alt>e"])
        self.set_accels_for_action("win.exceptions::site", ["<Control>e"])
        self.set_accels_for_action("win.shortcut::show_left_panel", ["F9"])
        self.set_accels_for_action("win.shortcut::uri",
                                   ["<Control>l", "<Control>b"])
        self.set_accels_for_action("win.shortcut::new_page", ["<Control>t"])
        self.set_accels_for_action("win.shortcut::last_page",
                                   ["<Control><Shift>t"])
        self.set_accels_for_action("app.shortcut::new_window", ["<Control>n"])
        self.set_accels_for_action("win.shortcut::private",
                                   ["<Control><Shift>p"])
        self.set_accels_for_action("win.shortcut::close_page", ["<Control>w"])
        self.set_accels_for_action("win.shortcut::quit", ["<Control>q"])
        self.set_accels_for_action("win.shortcut::save", ["<Control>s"])
        self.set_accels_for_action("win.shortcut::filter", ["<Control>i"])
        self.set_accels_for_action("win.shortcut::reload",
                                   ["<Control>r", "F5"])
        self.set_accels_for_action("win.shortcut::find", ["<Control>f"])
        self.set_accels_for_action("win.shortcut::print", ["<Control>p"])
        self.set_accels_for_action("win.shortcut::source",
                                   ["<Control><Shift>c"])
        self.set_accels_for_action("win.shortcut::history", ["<Control>h"])
        self.set_accels_for_action("win.shortcut::search", ["<Control>k"])
        self.set_accels_for_action("win.shortcut::fullscreen", ["F11"])
        self.set_accels_for_action("app.settings",
                                   ["<Control><Shift>s"])
        self.set_accels_for_action("win.shortcut::backward",
                                   ["<Alt>Left", "XF86Back"])
        self.set_accels_for_action("win.shortcut::forward",
                                   ["<Alt>Right", "XF86Forward"])
        self.set_accels_for_action("win.shortcut::next",
                                   ["<Control>Tab",
                                    "<Control>Page_Down"])
        self.set_accels_for_action("win.shortcut::previous",
                                   ["<Control><Shift>Tab",
                                    "<Control>Page_Up"])
        self.set_accels_for_action("win.shortcut::zoom_in",
                                   ["<Control>KP_Add",
                                    "<Control>plus",
                                    "<Control>equal"])
        self.set_accels_for_action("win.shortcut::zoom_out",
                                   ["<Control>KP_Subtract", "<Control>minus"])
        self.set_accels_for_action("win.shortcut::zoom_default",
                                   ["<Control>KP_0", "<Control>0"])
Exemple #8
0
    def init(self):
        """
            Init main application
        """
        self.__is_fs = False
        self.__setup_app_menu()
        self.set_app_menu(self.__menu)
        cssProviderFile = Gio.File.new_for_uri(
            'resource:///org/gnome/Eolie/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        self.history = DatabaseHistory()
        self.bookmarks = DatabaseBookmarks()
        # We store cursors for main thread
        SqlCursor.add(self.history)
        SqlCursor.add(self.bookmarks)
        try:
            from eolie.mozilla_sync import SyncWorker
            self.sync_worker = SyncWorker()
            self.sync_worker.sync()
            GLib.timeout_add_seconds(3600, self.sync_worker.sync)
        except Exception as e:
            print("Application::init():", e)
            self.sync_worker = None
        self.adblock = DatabaseAdblock()
        self.adblock.update()
        self.art = Art()
        self.search = Search()
        self.download_manager = DownloadManager()

        shortcut_action = Gio.SimpleAction.new('shortcut',
                                               GLib.VariantType.new('s'))
        shortcut_action.connect('activate', self.__on_shortcut_action)
        self.add_action(shortcut_action)
        self.set_accels_for_action("win.shortcut::uri", ["<Control>l"])
        self.set_accels_for_action("win.shortcut::new_page", ["<Control>t"])
        self.set_accels_for_action("app.shortcut::new_window", ["<Control>n"])
        self.set_accels_for_action("win.shortcut::private",
                                   ["<Control><Shift>p"])
        self.set_accels_for_action("win.shortcut::close_page", ["<Control>w"])
        self.set_accels_for_action("win.shortcut::save", ["<Control>s"])
        self.set_accels_for_action("win.shortcut::filter", ["<Control>i"])
        self.set_accels_for_action("win.shortcut::reload", ["<Control>r"])
        self.set_accels_for_action("win.shortcut::find", ["<Control>f"])
        self.set_accels_for_action("win.shortcut::print", ["<Control>p"])
        self.set_accels_for_action("win.shortcut::settings", ["<Control>e"])
        self.set_accels_for_action("win.shortcut::backward", ["<Alt>Left"])
        self.set_accels_for_action("win.shortcut::forward", ["<Alt>Right"])
        self.set_accels_for_action("win.shortcut::next", ["<Control>Tab"])
        self.set_accels_for_action("win.shortcut::previous",
                                   ["<Control><Shift>Tab"])

        # Set some WebKit defaults
        context = WebKit2.WebContext.get_default()
        GLib.setenv('PYTHONPATH', self.__extension_dir, True)
        context.set_web_extensions_directory(self.__extension_dir)

        data_manager = WebKit2.WebsiteDataManager()
        context.new_with_website_data_manager(data_manager)
        context.set_process_model(
            WebKit2.ProcessModel.MULTIPLE_SECONDARY_PROCESSES)
        context.set_cache_model(WebKit2.CacheModel.WEB_BROWSER)
        d = Gio.File.new_for_path(self.__FAVICONS_PATH)
        if not d.query_exists():
            d.make_directory_with_parents()
        context.set_favicon_database_directory(self.__FAVICONS_PATH)
        cookie_manager = context.get_cookie_manager()
        cookie_manager.set_accept_policy(
            self.settings.get_enum("cookie-storage"))
        cookie_manager.set_persistent_storage(
            self.__COOKIES_PATH, WebKit2.CookiePersistentStorage.SQLITE)
        helper = DBusHelper()
        helper.connect(self.__on_extension_signal, None)
Exemple #9
0
class Application(Gtk.Application):
    """
        Eolie application:
    """

    if GLib.getenv("XDG_DATA_HOME") is None:
        LOCAL_PATH = GLib.get_home_dir() + "/.local/share/eolie"
    else:
        LOCAL_PATH = GLib.getenv("XDG_DATA_HOME") + "/eolie"
    __COOKIES_PATH = "%s/cookies.db" % LOCAL_PATH
    __FAVICONS_PATH = "%s/favicons" % LOCAL_PATH

    def __init__(self, extension_dir):
        """
            Create application
            @param extension_dir as str
        """
        # First check WebKit2 version
        if WebKit2.MINOR_VERSION < 16:
            exit("You need WebKit2GTK >= 2.16")
        Gtk.Application.__init__(
            self,
            application_id='org.gnome.Eolie',
            flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
        self.set_property('register-session', True)
        # Ideally, we will be able to delete this once Flatpak has a solution
        # for SSL certificate management inside of applications.
        if GLib.file_test("/app", GLib.FileTest.EXISTS):
            paths = [
                "/etc/ssl/certs/ca-certificates.crt", "/etc/pki/tls/cert.pem",
                "/etc/ssl/cert.pem"
            ]
            for path in paths:
                if GLib.file_test(path, GLib.FileTest.EXISTS):
                    GLib.setenv('SSL_CERT_FILE', path, True)
                    break
        self.__extension_dir = extension_dir
        self.__windows = []
        self.__pages_menu = PagesMenu(self)
        self.debug = False
        try:
            self.zoom_levels = load(
                open(self.LOCAL_PATH + "/zoom_levels.bin", "rb"))
        except:
            self.zoom_levels = {}
        self.cursors = {}
        GLib.set_application_name('Eolie')
        GLib.set_prgname('eolie')
        self.add_main_option("debug", b'd', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Debug Eolie", None)
        self.add_main_option("private", b'p', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Add a private page", None)
        self.connect('activate', self.__on_activate)
        self.connect('command-line', self.__on_command_line)
        self.register(None)
        if self.get_is_remote():
            Gdk.notify_startup_complete()

    def init(self):
        """
            Init main application
        """
        self.__is_fs = False
        self.__setup_app_menu()
        self.set_app_menu(self.__menu)
        cssProviderFile = Gio.File.new_for_uri(
            'resource:///org/gnome/Eolie/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        self.history = DatabaseHistory()
        self.bookmarks = DatabaseBookmarks()
        # We store cursors for main thread
        SqlCursor.add(self.history)
        SqlCursor.add(self.bookmarks)
        try:
            from eolie.mozilla_sync import SyncWorker
            self.sync_worker = SyncWorker()
            self.sync_worker.sync()
            GLib.timeout_add_seconds(3600, self.sync_worker.sync)
        except Exception as e:
            print("Application::init():", e)
            self.sync_worker = None
        self.adblock = DatabaseAdblock()
        self.adblock.update()
        self.art = Art()
        self.search = Search()
        self.download_manager = DownloadManager()

        shortcut_action = Gio.SimpleAction.new('shortcut',
                                               GLib.VariantType.new('s'))
        shortcut_action.connect('activate', self.__on_shortcut_action)
        self.add_action(shortcut_action)
        self.set_accels_for_action("win.shortcut::uri", ["<Control>l"])
        self.set_accels_for_action("win.shortcut::new_page", ["<Control>t"])
        self.set_accels_for_action("app.shortcut::new_window", ["<Control>n"])
        self.set_accels_for_action("win.shortcut::private",
                                   ["<Control><Shift>p"])
        self.set_accels_for_action("win.shortcut::close_page", ["<Control>w"])
        self.set_accels_for_action("win.shortcut::save", ["<Control>s"])
        self.set_accels_for_action("win.shortcut::filter", ["<Control>i"])
        self.set_accels_for_action("win.shortcut::reload", ["<Control>r"])
        self.set_accels_for_action("win.shortcut::find", ["<Control>f"])
        self.set_accels_for_action("win.shortcut::print", ["<Control>p"])
        self.set_accels_for_action("win.shortcut::settings", ["<Control>e"])
        self.set_accels_for_action("win.shortcut::backward", ["<Alt>Left"])
        self.set_accels_for_action("win.shortcut::forward", ["<Alt>Right"])
        self.set_accels_for_action("win.shortcut::next", ["<Control>Tab"])
        self.set_accels_for_action("win.shortcut::previous",
                                   ["<Control><Shift>Tab"])

        # Set some WebKit defaults
        context = WebKit2.WebContext.get_default()
        GLib.setenv('PYTHONPATH', self.__extension_dir, True)
        context.set_web_extensions_directory(self.__extension_dir)

        data_manager = WebKit2.WebsiteDataManager()
        context.new_with_website_data_manager(data_manager)
        context.set_process_model(
            WebKit2.ProcessModel.MULTIPLE_SECONDARY_PROCESSES)
        context.set_cache_model(WebKit2.CacheModel.WEB_BROWSER)
        d = Gio.File.new_for_path(self.__FAVICONS_PATH)
        if not d.query_exists():
            d.make_directory_with_parents()
        context.set_favicon_database_directory(self.__FAVICONS_PATH)
        cookie_manager = context.get_cookie_manager()
        cookie_manager.set_accept_policy(
            self.settings.get_enum("cookie-storage"))
        cookie_manager.set_persistent_storage(
            self.__COOKIES_PATH, WebKit2.CookiePersistentStorage.SQLITE)
        helper = DBusHelper()
        helper.connect(self.__on_extension_signal, None)

    def do_startup(self):
        """
            Init application
        """
        Gtk.Application.do_startup(self)

        if not self.__windows:
            self.init()
            self.__get_new_window()

    def set_setting(self, key, value):
        """
            Set setting for all view
            @param key as str
            @param value as GLib.Variant
        """
        for window in self.__windows:
            for view in window.container.views:
                view.webview.set_setting(key, value)

    @property
    def pages_menu(self):
        """
            Get pages menu
            @return PagesMenu
        """
        return self.__pages_menu

    @property
    def start_page(self):
        """
            Get start page
            @return uri as str
        """
        value = self.settings.get_value("start-page").get_string()
        if value == "search":
            value = self.search.uri
        elif value == "popular":
            value = "populars://"
        return value

    @property
    def active_window(self):
        """
            Get active window
            @return Window
        """
        for window in self.__windows:
            if window.is_active():
                return window
        # Fallback
        if self.__windows:
            return self.__windows[0]
        return None

    @property
    def windows(self):
        """
            Get windows
            @return [Window]
        """
        return self.__windows

    @property
    def cookies_path(self):
        """
            Cookies sqlite db path
        """
        return self.__COOKIES_PATH

    @property
    def favicons_path(self):
        """
            Cookies sqlite db path
        """
        return self.__FAVICONS_PATH + "/WebpageIcons.db"

#######################
# PRIVATE             #
#######################

    def __save_state(self):
        """
            Save window position and view
        """
        self.download_manager.cancel()
        self.adblock.stop()
        if self.sync_worker is not None:
            self.sync_worker.stop()
        try:
            remember_session = self.settings.get_value("remember-session")
            session_states = []
            for window in self.__windows:
                window.container.stop()
                if not remember_session:
                    continue
                for view in window.container.views:
                    uri = view.webview.get_uri()
                    private = view.webview.private
                    state = view.webview.get_session_state().serialize()
                    session_states.append((uri, private, state.get_data()))
            if remember_session:
                dump(session_states,
                     open(self.LOCAL_PATH + "/session_states.bin", "wb"))
                dump(self.zoom_levels,
                     open(self.LOCAL_PATH + "/zoom_levels.bin", "wb"))
        except Exception as e:
            print("Application::save_state()", e)

    def __get_new_window(self):
        """
            Return a new window
            @return Window
        """
        window = Window(self)
        window.connect('delete-event', self.__on_delete_event)
        window.show()
        self.__windows.append(window)
        return window

    def __show_plugins(self):
        """
            Show available plugins on stdout
        """
        if self.debug:
            self.active_window.container.current.webview.get_context(
            ).get_plugins(None, self.__on_get_plugins, None)

    def __restore_state(self):
        """
            Restore saved state
            @return restored pages count as int
        """
        count = 0
        try:
            session_states = load(
                open(self.LOCAL_PATH + "/session_states.bin", "rb"))
            for (uri, private, state) in session_states:
                webkit_state = WebKit2.WebViewSessionState(
                    GLib.Bytes.new(state))
                GLib.idle_add(self.active_window.container.add_web_view, uri,
                              count == 0, private, None, None, webkit_state)
                count += 1
        except Exception as e:
            print("Application::restore_state()", e)
        return count

    def __on_command_line(self, app, app_cmd_line):
        """
            Handle command line
            @param app as Gio.Application
            @param options as Gio.ApplicationCommandLine
        """
        self.__externals_count = 0
        args = app_cmd_line.get_arguments()
        options = app_cmd_line.get_options_dict()
        if options.contains("debug"):
            GLib.setenv("LIBGL_DEBUG", "verbose", True)
            GLib.setenv("WEBKIT_DEBUG", "network", True)
            GLib.setenv("GST_DEBUG", "webkit*:5", True)
            self.debug = True
        private_browsing = options.contains("private")
        if self.settings.get_value("remember-session"):
            count = self.__restore_state()
        else:
            count = 0
        active_window = self.active_window
        if len(args) > 1:
            for uri in args[1:]:
                active_window.container.add_web_view(uri, True,
                                                     private_browsing)
            active_window.present()
        elif count == 0:
            # We already have a window, open a new one
            if active_window.container.current:
                window = self.__get_new_window()
                window.container.add_web_view(self.start_page, True,
                                              private_browsing)
            else:
                active_window.container.add_web_view(self.start_page, True,
                                                     private_browsing)
        GLib.idle_add(self.__show_plugins)
        return 0

    def __on_get_plugins(self, source, result, data):
        """
            Print plugins on command line
            @param source as GObject.Object
            @param result as Gio.AsyncResult
            @param data as None
        """
        plugins = source.get_plugins_finish(result)
        for plugin in plugins:
            print(plugin.get_name(), plugin.get_description(),
                  plugin.get_path())

    def __on_delete_event(self, window, event):
        """
            Exit application
            @param window as Window
            @param event as Gdk.Event
        """
        self.__save_state()
        self.__windows.remove(window)
        window.destroy()
        if not self.__windows:
            self.quit()

    def __on_settings_activate(self, action, param):
        """
            Show settings dialog
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        dialog = SettingsDialog(self.active_window)
        dialog.show()

    def __on_about_activate(self, action, param):
        """
            Setup about dialog
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/AboutDialog.ui')
        about = builder.get_object('about_dialog')
        window = self.active_window
        if window is not None:
            about.set_transient_for(window)
        about.connect("response", self.__on_about_activate_response)
        about.show()

    def __on_shortcuts_activate(self, action, param):
        """
            Show help in yelp
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        try:
            builder = Gtk.Builder()
            builder.add_from_resource('/org/gnome/Eolie/Shortcuts.ui')
            shortcuts = builder.get_object('shortcuts')
            window = self.active_window
            if window is not None:
                shortcuts.set_transient_for(window)
            shortcuts.show()
        except:  # GTK < 3.20
            self.__on_help_activate(action, param)

    def __on_help_activate(self, action, param):
        """
            Show help in yelp
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        try:
            Gtk.show_uri(None, "help:eolie", Gtk.get_current_event_time())
        except:
            print(_("Eolie: You need to install yelp."))

    def __on_about_activate_response(self, dialog, response_id):
        """
            Destroy about dialog when closed
            @param dialog as Gtk.Dialog
            @param response id as int
        """
        dialog.destroy()

    def __setup_app_menu(self):
        """
            Setup application menu
            @return menu as Gio.Menu
        """
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/Appmenu.ui')
        self.__menu = builder.get_object('app-menu')

        settings_action = Gio.SimpleAction.new('settings', None)
        settings_action.connect('activate', self.__on_settings_activate)
        self.add_action(settings_action)

        about_action = Gio.SimpleAction.new('about', None)
        about_action.connect('activate', self.__on_about_activate)
        self.add_action(about_action)

        shortcuts_action = Gio.SimpleAction.new('shortcuts', None)
        shortcuts_action.connect('activate', self.__on_shortcuts_activate)
        self.add_action(shortcuts_action)

        help_action = Gio.SimpleAction.new('help', None)
        help_action.connect('activate', self.__on_help_activate)
        self.add_action(help_action)

        quit_action = Gio.SimpleAction.new('quit', None)
        quit_action.connect('activate', lambda x, y: self.__save_state())
        self.add_action(quit_action)

    def __on_activate(self, application):
        """
            Call default handler, raise last window
            @param application as Gio.Application
        """
        if self.__windows:
            self.__windows[-1].present()

    def __on_shortcut_action(self, action, param):
        """
            Global shortcuts handler
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        string = param.get_string()
        if string == "new_window":
            window = self.__get_new_window()
            window.container.add_web_view(self.start_page, True)

    def __on_extension_signal(self, connection, sender, path, interface,
                              signal, params, data):
        """
            Show message on wanted window
            @param connection as Gio.DBusConnection
            @param sender as str
            @param path as str
            @param interface as str
            @param signal as str
            @param parameters as GLib.Variant
            @param data
        """
        webview = self.active_window.container.current.webview
        self.active_window.toolbar.title.show_input_warning(webview)
Exemple #10
0
class Application(Gtk.Application):
    """
        Eolie application:
    """

    __COOKIES_PATH = "%s/cookies.db" % LOCAL_PATH
    __FAVICONS_PATH = "%s/favicons" % LOCAL_PATH

    def __init__(self, extension_dir):
        """
            Create application
            @param extension_dir as str
        """
        # First check WebKit2 version
        if WebKit2.MINOR_VERSION < 16:
            exit("You need WebKit2GTK >= 2.16")
        Gtk.Application.__init__(
            self,
            application_id='org.gnome.Eolie',
            flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
        self.set_property('register-session', True)
        # Ideally, we will be able to delete this once Flatpak has a solution
        # for SSL certificate management inside of applications.
        if GLib.file_test("/app", GLib.FileTest.EXISTS):
            paths = [
                "/etc/ssl/certs/ca-certificates.crt", "/etc/pki/tls/cert.pem",
                "/etc/ssl/cert.pem"
            ]
            for path in paths:
                if GLib.file_test(path, GLib.FileTest.EXISTS):
                    GLib.setenv('SSL_CERT_FILE', path, True)
                    break
        self.sync_worker = None  # Not initialised
        self.__extension_dir = extension_dir
        self.__windows = []
        self.debug = False
        self.show_tls = False
        try:
            self.zoom_levels = load(open(LOCAL_PATH + "/zoom_levels.bin",
                                         "rb"))
        except:
            self.zoom_levels = {}
        self.cursors = {}
        GLib.set_application_name('Eolie')
        GLib.set_prgname('eolie')
        self.add_main_option("debug", b'd', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Debug Eolie", None)
        self.add_main_option("private", b'p', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Add a private page", None)
        self.add_main_option("new", b'n', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Add a new window", None)
        self.add_main_option("show-tls", b's', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Show TLS info", None)
        self.connect('activate', self.__on_activate)
        self.connect('command-line', self.__on_command_line)
        self.register(None)
        if self.get_is_remote():
            Gdk.notify_startup_complete()
        self.__listen_to_gnome_sm()

    def get_app_menu(self):
        """
            Setup application menu
            @return menu as Gio.Menu
        """
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/Appmenu.ui')
        menu = builder.get_object('app-menu')

        settings_action = Gio.SimpleAction.new('settings', None)
        settings_action.connect('activate', self.__on_settings_activate)
        self.add_action(settings_action)

        about_action = Gio.SimpleAction.new('about', None)
        about_action.connect('activate', self.__on_about_activate)
        self.add_action(about_action)

        shortcuts_action = Gio.SimpleAction.new('shortcuts', None)
        shortcuts_action.connect('activate', self.__on_shortcuts_activate)
        self.add_action(shortcuts_action)

        # help_action = Gio.SimpleAction.new('help', None)
        # help_action.connect('activate', self.__on_help_activate)
        # self.add_action(help_action)

        quit_action = Gio.SimpleAction.new('quit', None)
        quit_action.connect('activate', lambda x, y: self.quit())
        self.add_action(quit_action)
        return menu

    def do_startup(self):
        """
            Init application
        """
        Gtk.Application.do_startup(self)

        if not self.__windows:
            self.__init()
            self.get_new_window()

    def get_new_window(self):
        """
            Return a new window
            @return Window
        """
        window = Window(self)
        window.connect('delete-event', self.__on_delete_event)
        window.show()
        self.__windows.append(window)
        return window

    def set_setting(self, key, value):
        """
            Set setting for all view
            @param key as str
            @param value as GLib.Variant
        """
        for window in self.__windows:
            for view in window.container.views:
                view.webview.set_setting(key, value)

    def quit(self, vacuum=False):
        """
            Quit application
            @param vacuum as bool
        """
        # Save webpage state
        self.__save_state()
        # Stop pending tasks
        self.download_manager.cancel()
        self.adblock.stop()
        # If sync is running, to avoid db lock, we do not vacuum
        if self.sync_worker is not None and self.sync_worker.syncing:
            self.sync_worker.stop()
            Gio.Application.quit(self)
        elif vacuum:
            thread = Thread(target=self.__vacuum)
            thread.daemon = True
            thread.start()
        else:
            Gio.Application.quit(self)

    @property
    def start_page(self):
        """
            Get start page
            @return uri as str
        """
        value = self.settings.get_value("start-page").get_string()
        if value == "search":
            value = self.search.uri
        elif value == "popular":
            value = "populars://"
        elif value == "blank":
            value = "about:blank"
        return value

    @property
    def active_window(self):
        """
            Get active window
            @return Window
        """
        for window in self.__windows:
            if window.is_active():
                return window
        # Fallback
        if self.__windows:
            return self.__windows[0]
        return None

    @property
    def windows(self):
        """
            Get windows
            @return [Window]
        """
        return self.__windows

    @property
    def cookies_path(self):
        """
            Cookies sqlite db path
        """
        return self.__COOKIES_PATH

    @property
    def favicons_path(self):
        """
            Cookies sqlite db path
        """
        return self.__FAVICONS_PATH + "/WebpageIcons.db"

#######################
# PRIVATE             #
#######################

    def __init(self):
        """
            Init main application
        """
        # First init sync worker
        try:
            from eolie.mozilla_sync import SyncWorker
            self.sync_worker = SyncWorker()
            self.sync_worker.sync()
            GLib.timeout_add_seconds(3600, self.sync_worker.sync)
        except Exception as e:
            print("Application::init():", e)
            self.sync_worker = None
        if self.prefers_app_menu():
            menu = self.get_app_menu()
            self.set_app_menu(menu)
        cssProviderFile = Gio.File.new_for_uri(
            'resource:///org/gnome/Eolie/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        self.history = DatabaseHistory()
        self.bookmarks = DatabaseBookmarks()
        # We store cursors for main thread
        SqlCursor.add(self.history)
        SqlCursor.add(self.bookmarks)
        self.adblock = DatabaseAdblock()
        self.adblock.update()
        self.phishing = DatabasePhishing()
        self.adblock_exceptions = DatabaseExceptions("adblock")
        self.popup_exceptions = DatabaseExceptions("popup")
        self.image_exceptions = DatabaseExceptions("image")
        self.phishing.update()
        self.art = Art()
        self.search = Search()
        self.download_manager = DownloadManager()
        self.pages_menu = PagesMenu(self)

        # Db upgrade
        db_version = self.settings.get_value("db-version").get_int32()
        upgrade = DatabaseUpgrade(db_version)
        db_version = upgrade.do_db_upgrade()
        self.settings.set_value("db-version", GLib.Variant("i", db_version))

        shortcut_action = Gio.SimpleAction.new('shortcut',
                                               GLib.VariantType.new('s'))
        shortcut_action.connect('activate', self.__on_shortcut_action)
        self.add_action(shortcut_action)
        self.set_accels_for_action("win.exceptions::site", ["<Control>e"])
        self.set_accels_for_action("win.shortcut::uri", ["<Control>l"])
        self.set_accels_for_action("win.shortcut::new_page", ["<Control>t"])
        self.set_accels_for_action("win.shortcut::last_page",
                                   ["<Control><Shift>t"])
        self.set_accels_for_action("app.shortcut::new_window", ["<Control>n"])
        self.set_accels_for_action("win.shortcut::private",
                                   ["<Control><Shift>p"])
        self.set_accels_for_action("win.shortcut::close_page", ["<Control>w"])
        self.set_accels_for_action("win.shortcut::quit", ["<Control>q"])
        self.set_accels_for_action("win.shortcut::save", ["<Control>s"])
        self.set_accels_for_action("win.shortcut::filter", ["<Control>i"])
        self.set_accels_for_action("win.shortcut::reload", ["<Control>r"])
        self.set_accels_for_action("win.shortcut::find", ["<Control>f"])
        self.set_accels_for_action("win.shortcut::print", ["<Control>p"])
        self.set_accels_for_action("win.shortcut::source",
                                   ["<Control><Shift>c"])
        self.set_accels_for_action("win.shortcut::fullscreen", ["F11"])
        self.set_accels_for_action("app.settings", ["<Control><Shift>s"])
        self.set_accels_for_action("win.shortcut::backward",
                                   ["<Alt>Left", "XF86Back"])
        self.set_accels_for_action("win.shortcut::forward",
                                   ["<Alt>Right", "XF86Forward"])
        self.set_accels_for_action("win.shortcut::next", ["<Control>Tab"])
        self.set_accels_for_action("win.shortcut::previous",
                                   ["<Control><Shift>Tab"])
        self.set_accels_for_action("win.shortcut::zoom_in",
                                   ["<Control>KP_Add", "<Control>plus"])
        self.set_accels_for_action("win.shortcut::zoom_out",
                                   ["<Control>KP_Subtract", "<Control>minus"])
        self.set_accels_for_action("win.panel_mode(0)",
                                   ["<Control><Alt>0", "<Control><Alt>KP_0"])
        self.set_accels_for_action("win.panel_mode(1)",
                                   ["<Control><Alt>1", "<Control><Alt>KP_1"])
        self.set_accels_for_action("win.panel_mode(2)",
                                   ["<Control><Alt>2", "<Control><Alt>KP_2"])

        # Set some WebKit defaults
        context = WebKit2.WebContext.get_default()
        Context(context)
        GLib.setenv('PYTHONPATH', self.__extension_dir, True)
        context.set_web_extensions_directory(self.__extension_dir)

        data_manager = WebKit2.WebsiteDataManager()
        context.new_with_website_data_manager(data_manager)
        context.set_process_model(
            WebKit2.ProcessModel.MULTIPLE_SECONDARY_PROCESSES)
        context.set_cache_model(WebKit2.CacheModel.WEB_BROWSER)
        d = Gio.File.new_for_path(self.__FAVICONS_PATH)
        if not d.query_exists():
            d.make_directory_with_parents()
        context.set_favicon_database_directory(self.__FAVICONS_PATH)
        cookie_manager = context.get_cookie_manager()
        cookie_manager.set_accept_policy(
            self.settings.get_enum("cookie-storage"))
        cookie_manager.set_persistent_storage(
            self.__COOKIES_PATH, WebKit2.CookiePersistentStorage.SQLITE)
        helper = DBusHelper()
        helper.connect("UnsecureFormFocused", self.__on_extension_signal)

    def __listen_to_gnome_sm(self):
        """
            Save state on EndSession signal
        """
        try:
            bus = self.get_dbus_connection()
            bus.signal_subscribe(None,
                                 "org.gnome.SessionManager.EndSessionDialog",
                                 "ConfirmedLogout",
                                 "/org/gnome/SessionManager/EndSessionDialog",
                                 None, Gio.DBusSignalFlags.NONE,
                                 lambda a, b, c, d, e, f: self.__save_state())
        except Exception as e:
            print("Application::__listen_to_gnome_sm():", e)

    def __vacuum(self):
        """
            VACUUM DB
            @thread safe
        """
        try:
            with SqlCursor(self.bookmarks) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.history) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.adblock) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.phishing) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
        except Exception as e:
            print("Application::__vacuum(): ", e)
        self.art.vacuum()
        GLib.idle_add(Gio.Application.quit, self)

    def __save_state(self):
        """
            Save window position and view
        """
        try:
            remember_session = self.settings.get_value("remember-session")
            session_states = []
            for window in self.__windows:
                window.container.stop()
                if not remember_session:
                    continue
                for view in window.container.views:
                    uri = view.webview.get_uri()
                    parsed = urlparse(uri)
                    if parsed.scheme not in ["http", "https"]:
                        continue
                    ephemeral = view.webview.ephemeral
                    state = view.webview.get_session_state().serialize()
                    session_states.append((uri, ephemeral, state.get_data()))
            if remember_session:
                dump(session_states,
                     open(LOCAL_PATH + "/session_states.bin", "wb"))
            dump(self.zoom_levels, open(LOCAL_PATH + "/zoom_levels.bin", "wb"))
        except Exception as e:
            print("Application::save_state()", e)

    def __show_plugins(self):
        """
            Show available plugins on stdout
        """
        if self.debug:
            self.active_window.container.current.webview.get_context(
            ).get_plugins(None, self.__on_get_plugins, None)

    def __restore_state(self):
        """
            Restore saved state
            @return True as bool if restored
        """
        window_type = Gdk.WindowType.CHILD
        try:
            session_states = load(
                open(LOCAL_PATH + "/session_states.bin", "rb"))
            for (uri, ephemeral, state) in session_states:
                webkit_state = WebKit2.WebViewSessionState(
                    GLib.Bytes.new(state))
                GLib.idle_add(self.active_window.container.add_webview, uri,
                              window_type, ephemeral, None, webkit_state,
                              window_type == Gdk.WindowType.CHILD)
                window_type = Gdk.WindowType.OFFSCREEN
        except Exception as e:
            print("Application::restore_state()", e)
        return window_type != Gdk.WindowType.CHILD

    def __on_command_line(self, app, app_cmd_line):
        """
            Handle command line
            @param app as Gio.Application
            @param options as Gio.ApplicationCommandLine
        """
        self.__externals_count = 0
        args = app_cmd_line.get_arguments()
        options = app_cmd_line.get_options_dict()
        if options.contains("debug"):
            GLib.setenv("WEBKIT_DEBUG", "network", True)
            self.debug = True
        if options.contains("show-tls"):
            self.show_tls = True
        ephemeral = options.contains("private")
        restored = False
        if self.settings.get_value("remember-session"):
            restored = self.__restore_state()
        if options.contains("new"):
            active_window = self.get_new_window()
        else:
            active_window = self.active_window
        # Open command line args
        if len(args) > 1:
            for uri in args[1:]:
                # Transform path to uri
                f = Gio.File.new_for_path(uri)
                if f.query_exists():
                    uri = f.get_uri()
                active_window.container.add_webview(uri, Gdk.WindowType.CHILD,
                                                    ephemeral)
            active_window.present_with_time(Gtk.get_current_event_time())
        # We already have a window, open a new one
        elif active_window.container.current:
            window = self.get_new_window()
            window.container.add_webview(self.start_page, Gdk.WindowType.CHILD,
                                         ephemeral)
        # Add default start page
        elif not restored:
            active_window.container.add_webview(self.start_page,
                                                Gdk.WindowType.CHILD,
                                                ephemeral)
        thread = Thread(target=self.__show_plugins)
        thread.daemon = True
        thread.start()
        return 0

    def __on_get_plugins(self, source, result, data):
        """
            Print plugins on command line
            @param source as GObject.Object
            @param result as Gio.AsyncResult
            @param data as None
        """
        plugins = source.get_plugins_finish(result)
        for plugin in plugins:
            print(plugin.get_name(), plugin.get_description(),
                  plugin.get_path())

    def __on_delete_event(self, window, event):
        """
            Exit application
            @param window as Window
            @param event as Gdk.Event
        """
        if len(self.__windows) > 1:
            self.__windows.remove(window)
            window.destroy()
        else:
            window.hide()
            self.quit(True)
        return True

    def __on_settings_activate(self, action, param):
        """
            Show settings dialog
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        dialog = SettingsDialog(self.active_window)
        dialog.show()

    def __on_about_activate(self, action, param):
        """
            Setup about dialog
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/AboutDialog.ui')
        about = builder.get_object('about_dialog')
        window = self.active_window
        if window is not None:
            about.set_transient_for(window)
        about.connect("response", self.__on_about_activate_response)
        about.show()

    def __on_shortcuts_activate(self, action, param):
        """
            Show help in yelp
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        try:
            builder = Gtk.Builder()
            builder.add_from_resource('/org/gnome/Eolie/Shortcuts.ui')
            shortcuts = builder.get_object('shortcuts')
            window = self.active_window
            if window is not None:
                shortcuts.set_transient_for(window)
            shortcuts.show()
        except:  # GTK < 3.20
            self.__on_help_activate(action, param)

    def __on_help_activate(self, action, param):
        """
            Show help in yelp
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        try:
            Gtk.show_uri(None, "help:eolie", Gtk.get_current_event_time())
        except:
            print(_("Eolie: You need to install yelp."))

    def __on_about_activate_response(self, dialog, response_id):
        """
            Destroy about dialog when closed
            @param dialog as Gtk.Dialog
            @param response id as int
        """
        dialog.destroy()

    def __on_activate(self, application):
        """
            Call default handler, raise last window
            @param application as Gio.Application
        """
        if self.__windows:
            self.__windows[-1].present_with_time(Gtk.get_current_event_time())

    def __on_shortcut_action(self, action, param):
        """
            Global shortcuts handler
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        string = param.get_string()
        if string == "new_window":
            window = self.get_new_window()
            window.container.add_webview(self.start_page, Gdk.WindowType.CHILD)

    def __on_extension_signal(self, connection, sender, path, interface,
                              signal, params, data):
        """
            Show message on wanted window
            @param connection as Gio.DBusConnection
            @param sender as str
            @param path as str
            @param interface as str
            @param signal as str
            @param parameters as GLib.Variant
            @param data
        """
        webview = self.active_window.container.current.webview
        self.active_window.toolbar.title.show_input_warning(webview)
Exemple #11
0
    def __init(self):
        """
            Init main application
        """
        # First init sync worker
        try:
            from eolie.mozilla_sync import SyncWorker
            self.sync_worker = SyncWorker()
            self.sync_worker.sync()
            GLib.timeout_add_seconds(3600, self.sync_worker.sync)
        except Exception as e:
            print("Application::init():", e)
            self.sync_worker = None
        if self.prefers_app_menu():
            menu = self.get_app_menu()
            self.set_app_menu(menu)
        cssProviderFile = Gio.File.new_for_uri(
            'resource:///org/gnome/Eolie/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.settings = Settings.new()
        self.history = DatabaseHistory()
        self.bookmarks = DatabaseBookmarks()
        # We store cursors for main thread
        SqlCursor.add(self.history)
        SqlCursor.add(self.bookmarks)
        self.adblock = DatabaseAdblock()
        self.adblock.update()
        self.phishing = DatabasePhishing()
        self.adblock_exceptions = DatabaseExceptions("adblock")
        self.popup_exceptions = DatabaseExceptions("popup")
        self.image_exceptions = DatabaseExceptions("image")
        self.phishing.update()
        self.art = Art()
        self.search = Search()
        self.download_manager = DownloadManager()
        self.pages_menu = PagesMenu(self)

        # Db upgrade
        db_version = self.settings.get_value("db-version").get_int32()
        upgrade = DatabaseUpgrade(db_version)
        db_version = upgrade.do_db_upgrade()
        self.settings.set_value("db-version", GLib.Variant("i", db_version))

        shortcut_action = Gio.SimpleAction.new('shortcut',
                                               GLib.VariantType.new('s'))
        shortcut_action.connect('activate', self.__on_shortcut_action)
        self.add_action(shortcut_action)
        self.set_accels_for_action("win.exceptions::site", ["<Control>e"])
        self.set_accels_for_action("win.shortcut::uri", ["<Control>l"])
        self.set_accels_for_action("win.shortcut::new_page", ["<Control>t"])
        self.set_accels_for_action("win.shortcut::last_page",
                                   ["<Control><Shift>t"])
        self.set_accels_for_action("app.shortcut::new_window", ["<Control>n"])
        self.set_accels_for_action("win.shortcut::private",
                                   ["<Control><Shift>p"])
        self.set_accels_for_action("win.shortcut::close_page", ["<Control>w"])
        self.set_accels_for_action("win.shortcut::quit", ["<Control>q"])
        self.set_accels_for_action("win.shortcut::save", ["<Control>s"])
        self.set_accels_for_action("win.shortcut::filter", ["<Control>i"])
        self.set_accels_for_action("win.shortcut::reload", ["<Control>r"])
        self.set_accels_for_action("win.shortcut::find", ["<Control>f"])
        self.set_accels_for_action("win.shortcut::print", ["<Control>p"])
        self.set_accels_for_action("win.shortcut::source",
                                   ["<Control><Shift>c"])
        self.set_accels_for_action("win.shortcut::fullscreen", ["F11"])
        self.set_accels_for_action("app.settings", ["<Control><Shift>s"])
        self.set_accels_for_action("win.shortcut::backward",
                                   ["<Alt>Left", "XF86Back"])
        self.set_accels_for_action("win.shortcut::forward",
                                   ["<Alt>Right", "XF86Forward"])
        self.set_accels_for_action("win.shortcut::next", ["<Control>Tab"])
        self.set_accels_for_action("win.shortcut::previous",
                                   ["<Control><Shift>Tab"])
        self.set_accels_for_action("win.shortcut::zoom_in",
                                   ["<Control>KP_Add", "<Control>plus"])
        self.set_accels_for_action("win.shortcut::zoom_out",
                                   ["<Control>KP_Subtract", "<Control>minus"])
        self.set_accels_for_action("win.panel_mode(0)",
                                   ["<Control><Alt>0", "<Control><Alt>KP_0"])
        self.set_accels_for_action("win.panel_mode(1)",
                                   ["<Control><Alt>1", "<Control><Alt>KP_1"])
        self.set_accels_for_action("win.panel_mode(2)",
                                   ["<Control><Alt>2", "<Control><Alt>KP_2"])

        # Set some WebKit defaults
        context = WebKit2.WebContext.get_default()
        Context(context)
        GLib.setenv('PYTHONPATH', self.__extension_dir, True)
        context.set_web_extensions_directory(self.__extension_dir)

        data_manager = WebKit2.WebsiteDataManager()
        context.new_with_website_data_manager(data_manager)
        context.set_process_model(
            WebKit2.ProcessModel.MULTIPLE_SECONDARY_PROCESSES)
        context.set_cache_model(WebKit2.CacheModel.WEB_BROWSER)
        d = Gio.File.new_for_path(self.__FAVICONS_PATH)
        if not d.query_exists():
            d.make_directory_with_parents()
        context.set_favicon_database_directory(self.__FAVICONS_PATH)
        cookie_manager = context.get_cookie_manager()
        cookie_manager.set_accept_policy(
            self.settings.get_enum("cookie-storage"))
        cookie_manager.set_persistent_storage(
            self.__COOKIES_PATH, WebKit2.CookiePersistentStorage.SQLITE)
        helper = DBusHelper()
        helper.connect("UnsecureFormFocused", self.__on_extension_signal)
Exemple #12
0
class Application(Gtk.Application):
    """
        Eolie application:
    """

    __FAVICONS_PATH = "/tmp/eolie_%s" % getuser()

    def __init__(self, version, extension_dir):
        """
            Create application
            @param version as str
            @param extension_dir as str
        """
        self.__version = version
        self.__state_cache = []
        # First check WebKit2 version
        if WebKit2.MINOR_VERSION < 18:
            exit("You need WebKit2GTK >= 2.18")
        Gtk.Application.__init__(
            self,
            application_id="org.gnome.Eolie",
            flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
        self.set_property("register-session", True)
        # Fix proxy for python
        proxy = GLib.environ_getenv(GLib.get_environ(), "all_proxy")
        if proxy is not None and proxy.startswith("socks://"):
            proxy = proxy.replace("socks://", "socks4://")
            from os import environ
            environ["all_proxy"] = proxy
            environ["ALL_PROXY"] = proxy
        # Ideally, we will be able to delete this once Flatpak has a solution
        # for SSL certificate management inside of applications.
        if GLib.file_test("/app", GLib.FileTest.EXISTS):
            paths = [
                "/etc/ssl/certs/ca-certificates.crt", "/etc/pki/tls/cert.pem",
                "/etc/ssl/cert.pem"
            ]
            for path in paths:
                if GLib.file_test(path, GLib.FileTest.EXISTS):
                    GLib.setenv("SSL_CERT_FILE", path, True)
                    break
        self.sync_worker = None  # Not initialised
        self.__extension_dir = extension_dir
        self.debug = False
        self.show_tls = False
        self.cursors = {}
        GLib.set_application_name('Eolie')
        GLib.set_prgname('org.gnome.Eolie')
        self.add_main_option("debug", b'd', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Debug Eolie", None)
        self.add_main_option("private", b'p', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Add a private page", None)
        self.add_main_option("new", b'n', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Add a new window", None)
        self.add_main_option("disable-artwork-cache", b'a',
                             GLib.OptionFlags.NONE, GLib.OptionArg.NONE,
                             "Do not use cache for art", None)
        self.add_main_option("show-tls", b's', GLib.OptionFlags.NONE,
                             GLib.OptionArg.NONE, "Show TLS info", None)
        self.connect('activate', self.__on_activate)
        self.connect("handle-local-options", self.__on_handle_local_options)
        self.connect('command-line', self.__on_command_line)
        self.register(None)
        if self.get_is_remote():
            Gdk.notify_startup_complete()
        self.__listen_to_gnome_sm()

    def get_app_menu(self):
        """
            Setup application menu
            @return menu as Gio.Menu
        """
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Eolie/Appmenu.ui")
        menu = builder.get_object("app-menu")

        report_action = Gio.SimpleAction.new("report", None)
        report_action.connect("activate", self.__on_report_activate)
        self.add_action(report_action)

        settings_action = Gio.SimpleAction.new("settings", None)
        settings_action.connect("activate", self.__on_settings_activate)
        self.add_action(settings_action)

        about_action = Gio.SimpleAction.new("about", None)
        about_action.connect("activate", self.__on_about_activate)
        self.add_action(about_action)

        show_sidebar = self.settings.get_value("show-sidebar")
        sidebar_action = Gio.SimpleAction.new_stateful(
            "sidebar", None, GLib.Variant.new_boolean(show_sidebar))
        sidebar_action.connect("change-state", self.__on_sidebar_change_state)
        self.add_action(sidebar_action)

        shortcuts_action = Gio.SimpleAction.new("shortcuts", None)
        shortcuts_action.connect("activate", self.__on_shortcuts_activate)
        self.add_action(shortcuts_action)

        # help_action = Gio.SimpleAction.new('help', None)
        # help_action.connect('activate', self.__on_help_activate)
        # self.add_action(help_action)

        quit_action = Gio.SimpleAction.new("quit", None)
        quit_action.connect("activate", lambda x, y: self.quit())
        self.add_action(quit_action)
        return menu

    def update_default_style_sheet(self):
        """
            Should be called on startup
        """
        rules = self.adblock.get_default_css_rules()
        self.__default_style_sheet = WebKit2.UserStyleSheet(
            rules, WebKit2.UserContentInjectedFrames.ALL_FRAMES,
            WebKit2.UserStyleLevel.USER, None, None)

    def do_startup(self):
        """
            Init application
        """
        Gtk.Application.do_startup(self)
        if not self.get_windows():
            self.__init()

    def get_new_window(self, size=None, maximized=False):
        """
            Return a new window
            @return Window
        """
        windows = self.get_windows()
        if windows and size is None:
            active_window = self.active_window
            size = active_window.get_size()
            maximized = active_window.is_maximized()
        window = Window(self, size, maximized)
        window.connect('delete-event', self.__on_delete_event)
        window.show()
        return window

    def set_setting(self, key, value):
        """
            Set setting for all view
            @param key as str
            @param value as GLib.Variant
        """
        for window in self.get_windows():
            for view in window.container.views:
                view.webview.set_setting(key, value)

    def update_unity_badge(self, fraction=None):
        """
            Update unity badge count/fraction
            @param fraction as double
        """
        if self.__unity is not None:
            if fraction is None:
                count = 0
                for window in self.get_windows():
                    count += len(window.container.pages_manager.children)
                self.__unity.set_property("count", count)
                self.__unity.set_property("count_visible", True)
            else:
                self.__unity.set_property("progress", fraction)
                self.__unity.set_property("progress_visible", fraction != 1.0)

    def set_profiles(self):
        """
            Set profiles
        """
        try:
            f = Gio.File.new_for_path(EOLIE_DATA_PATH + "/profiles.json")
            if f.query_exists():
                (status, contents, tag) = f.load_contents(None)
                self.__profiles = json.loads(contents.decode("utf-8"))
            else:
                PROFILES = {
                    "default": _("Default"),
                    "social": _("Social networks"),
                    "work": _("Work"),
                    "shopping": _("Shopping"),
                    "personal": _("Personal"),
                    "finance": _("Finance"),
                    "sport": _("Sport")
                }
                content = json.dumps(PROFILES)
                f.replace_contents(content.encode("utf-8"), None, False,
                                   Gio.FileCreateFlags.REPLACE_DESTINATION,
                                   None)
                self.__profiles = PROFILES
        except Exception as e:
            print("Application::set_profiles():", e)

    def quit(self, vacuum=False):
        """
            Quit application
            @param vacuum as bool
        """
        # Save webpage state
        self.__save_state()
        # Stop pending tasks
        self.download_manager.cancel()
        self.adblock.stop()
        # Clear history
        active_id = str(self.settings.get_enum("history-storage"))
        if active_id != TimeSpan.FOREVER:
            atime = time()
            if active_id != TimeSpan.NEVER:
                atime -= TimeSpanValues[active_id] / 1000000
            self.history.clear_to(int(atime))
        # If sync is running, to avoid db lock, we do not vacuum
        if self.sync_worker is not None and self.sync_worker.syncing:
            self.sync_worker.stop()
            Gio.Application.quit(self)
        elif vacuum:
            task_helper = TaskHelper()
            task_helper.run(self.__vacuum,
                            callback=(lambda x: Gio.Application.quit(self), ))
        else:
            Gio.Application.quit(self)

    @property
    def profiles(self):
        """
            Get profiles
            @return {}
        """
        return self.__profiles

    @property
    def start_page(self):
        """
            Get start page
            @return uri as str
        """
        value = self.settings.get_value("start-page").get_string()
        if value in ["popular_hist", "popular_book"]:
            value = "populars://"
        elif value == "blank":
            value = "about:blank"
        else:
            value = self.search.uri
        return value

    @property
    def default_style_sheet(self):
        """
            Get default style sheet
            @return WebKit2.UserStyleSheet
        """
        return self.__default_style_sheet

    @property
    def active_window(self):
        """
            Get active window
            @return Window
        """
        return self.get_active_window()

    @property
    def windows(self):
        """
            Get windows
            @return [Window]
        """
        return self.get_windows()

    @property
    def favicons_path(self):
        """
            Cookies sqlite db path
        """
        return self.__FAVICONS_PATH

    @property
    def extension_dir(self):
        """
            Extension dir path
            @return str
        """
        return self.__extension_dir

#######################
# PRIVATE             #
#######################

    def __init(self):
        """
            Init main application
        """
        self.settings = Settings.new()

        # Init extensions
        GLib.setenv("PYTHONPATH", self.__extension_dir, True)

        # Create favicon path
        if not GLib.file_test(self.__FAVICONS_PATH, GLib.FileTest.IS_DIR):
            GLib.mkdir_with_parents(self.__FAVICONS_PATH, 0o0750)

        # Add a global DBus helper
        self.helper = DBusHelper()
        # First init sync worker
        from eolie.mozilla_sync import SyncWorker
        if SyncWorker.check_modules():
            self.sync_worker = SyncWorker()
            # Run a first sync in 10 seconds, speed up app start
            GLib.timeout_add_seconds(10, self.sync_worker.sync, False)
            # Then run a sync every hour
            GLib.timeout_add_seconds(3600, self.sync_worker.sync, True)
        else:
            self.sync_worker = None
        if self.prefers_app_menu():
            menu = self.get_app_menu()
            self.set_app_menu(menu)
        cssProviderFile = Gio.File.new_for_uri(
            'resource:///org/gnome/Eolie/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.history = DatabaseHistory()
        self.bookmarks = DatabaseBookmarks()
        # We store cursors for main thread
        SqlCursor.add(self.history)
        SqlCursor.add(self.bookmarks)
        self.websettings = DatabaseSettings()
        self.adblock = DatabaseAdblock()
        self.adblock.update()
        self.phishing = DatabasePhishing()
        self.adblock_exceptions = DatabaseExceptions("adblock")
        # Do not remove this!
        self.update_default_style_sheet()
        self.popup_exceptions = DatabaseExceptions("popups")
        self.image_exceptions = DatabaseExceptions("images")
        if self.settings.get_user_value("jsblock") is not None:
            self.js_exceptions = DatabaseExceptions("js")
        else:
            self.js_exceptions = None
        self.phishing.update()
        self.art = Art()
        self.search = Search()
        self.download_manager = DownloadManager()
        self.pages_menu = PagesMenu()

        # Check MOZ_PLUGIN_PATH
        if self.settings.get_value('enable-plugins') and\
                not GLib.getenv("MOZ_PLUGIN_PATH"):
            print("You need to set MOZ_PLUGIN_PATH to use plugins")

        # https://wiki.ubuntu.com/Unity/LauncherAPI
        self.__unity = None
        if is_unity():
            try:
                gi.require_version('Unity', '7.0')
                from gi.repository import Unity
                self.__unity = Unity.LauncherEntry.get_for_desktop_id(
                    "org.gnome.Eolie.desktop")
            except:
                pass

        # Init profiles
        self.set_profiles()

        shortcut_action = Gio.SimpleAction.new('shortcut',
                                               GLib.VariantType.new('s'))
        shortcut_action.connect('activate', self.__on_shortcut_action)
        self.add_action(shortcut_action)
        self.set_accels_for_action("win.shortcut::expose", ["<Alt>e"])
        self.set_accels_for_action("win.exceptions::site", ["<Control>e"])
        self.set_accels_for_action("win.shortcut::show_left_panel", ["F9"])
        self.set_accels_for_action("win.shortcut::uri",
                                   ["<Control>l", "<Control>b"])
        self.set_accels_for_action("win.shortcut::new_page", ["<Control>t"])
        self.set_accels_for_action("win.shortcut::last_page",
                                   ["<Control><Shift>t"])
        self.set_accels_for_action("app.shortcut::new_window", ["<Control>n"])
        self.set_accels_for_action("win.shortcut::private",
                                   ["<Control><Shift>p"])
        self.set_accels_for_action("win.shortcut::close_page", ["<Control>w"])
        self.set_accels_for_action("win.shortcut::quit", ["<Control>q"])
        self.set_accels_for_action("win.shortcut::save", ["<Control><Shift>s"])
        self.set_accels_for_action("win.shortcut::filter", ["<Control>i"])
        self.set_accels_for_action("win.shortcut::reload",
                                   ["<Control>r", "F5"])
        self.set_accels_for_action("win.shortcut::home", ["<Control>Home"])
        self.set_accels_for_action("win.shortcut::find", ["<Control>f"])
        self.set_accels_for_action("win.shortcut::print", ["<Control>p"])
        self.set_accels_for_action("win.shortcut::source",
                                   ["<Control><Shift>c"])
        self.set_accels_for_action("win.shortcut::history", ["<Control>h"])
        self.set_accels_for_action("win.shortcut::search", ["<Control>k"])
        self.set_accels_for_action("win.shortcut::fullscreen", ["F11"])
        self.set_accels_for_action("app.settings", ["<Control>s"])
        self.set_accels_for_action("win.shortcut::backward",
                                   ["<Alt>Left", "XF86Back"])
        self.set_accels_for_action("win.shortcut::forward",
                                   ["<Alt>Right", "XF86Forward"])
        self.set_accels_for_action("win.shortcut::next",
                                   ["<Control>Tab", "<Control>Page_Down"])
        self.set_accels_for_action("win.shortcut::previous",
                                   ["<Control><Shift>Tab", "<Control>Page_Up"])
        self.set_accels_for_action("win.shortcut::next_site",
                                   ["<Control>twosuperior"])
        self.set_accels_for_action("win.shortcut::previous_site",
                                   ["<Control><Shift>twosuperior"])
        self.set_accels_for_action(
            "win.shortcut::zoom_in",
            ["<Control>KP_Add", "<Control>plus", "<Control>equal"])
        self.set_accels_for_action("win.shortcut::zoom_out",
                                   ["<Control>KP_Subtract", "<Control>minus"])
        self.set_accels_for_action("win.shortcut::zoom_default",
                                   ["<Control>KP_0", "<Control>0"])

    def __listen_to_gnome_sm(self):
        """
            Save state on EndSession signal
        """
        try:
            bus = self.get_dbus_connection()
            bus.signal_subscribe(None,
                                 "org.gnome.SessionManager.EndSessionDialog",
                                 "ConfirmedLogout",
                                 "/org/gnome/SessionManager/EndSessionDialog",
                                 None, Gio.DBusSignalFlags.NONE,
                                 lambda a, b, c, d, e, f: self.__save_state())
        except Exception as e:
            print("Application::__listen_to_gnome_sm():", e)

    def __vacuum(self):
        """
            VACUUM DB
            @thread safe
        """
        try:
            with SqlCursor(self.bookmarks) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.history) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.adblock) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
            with SqlCursor(self.phishing) as sql:
                sql.isolation_level = None
                sql.execute("VACUUM")
                sql.isolation_level = ""
        except Exception as e:
            print("Application::__vacuum(): ", e)
        self.art.vacuum()

    def __get_state(self, window):
        """
            Return state for window
            @param window as Window
            @return {}
        """
        def get_state_for_webview(webview):
            uri = webview.uri
            parsed = urlparse(uri)
            if parsed.scheme in ["http", "https"]:
                ephemeral = webview.ephemeral
                state = webview.get_session_state().serialize()
                return (uri, webview.title, webview.atime, webview.gtime,
                        ephemeral, state.get_data())
            else:
                return None

        window_state = {}
        window_state["id"] = str(window)
        window_state["size"] = window.get_size()
        window_state["maximized"] = window.is_maximized()
        session_states = []
        if self.settings.get_value("remember-session"):
            # Save current first, will be loaded first on restore
            current = window.container.current.webview
            state = get_state_for_webview(current)
            if state is not None:
                session_states.append(state)
            # Do not get view from container to save order
            for view in window.container.views:
                if view.webview == current or view.destroying:
                    continue
                state = get_state_for_webview(view.webview)
                if state is not None:
                    session_states.append(state)
        window_state["states"] = session_states
        return window_state

    def __save_state(self):
        """
            Save windows state
        """
        try:
            window_states = []
            for window in self.get_windows():
                window_state = self.__get_state(window)
                window_states.append(window_state)
            for window_state in self.__state_cache:
                window_states.append(window_state)
            dump(window_states,
                 open(EOLIE_DATA_PATH + "/session_states.bin", "wb"))
        except Exception as e:
            print("Application::__save_state()", e)

    def __clean_state_cache(self, window_id):
        """
            Remove window id from cache
            @param window_id as str
        """
        for state in self.__state_cache:
            if state["id"] == window_id:
                self.__state_cache.remove(state)
                break

    def __create_initial_windows(self, foreground):
        """
            Create initial windows based on saved session
            @param foreground  as bool if foreground loading allowed
        """
        size = (800, 600)
        maximized = False
        try:
            windows = load(open(EOLIE_DATA_PATH + "/session_states.bin", "rb"))
            if self.settings.get_value("remember-session"):
                for window in windows:
                    if not window["states"]:
                        continue
                    new_window = self.get_new_window(window["size"],
                                                     window["maximized"])
                    items = []
                    i = 0 if foreground else 1
                    for (uri, title, atime, gtime, ephemeral,
                         state) in window["states"]:
                        loading_type = wanted_loading_type(i)
                        webkit_state = WebKit2.WebViewSessionState(
                            GLib.Bytes.new(state))
                        items.append((uri, title, atime, gtime, ephemeral,
                                      webkit_state, loading_type))
                        i += 1
                    new_window.container.add_webviews(items)
            elif windows:
                size = windows[0]["size"]
                maximized = windows[0]["maximized"]
        except Exception as e:
            print("Application::__create_initial_windows()", e)
        if not self.get_windows():
            self.get_new_window(size, maximized)

    def __on_handle_local_options(self, app, options):
        """
            Handle local options
            @param app as Gio.Application
            @param options as GLib.VariantDict
        """
        if options.contains("version"):
            print("Eolie %s" % self.__version)
            return 0
        return -1

    def __on_command_line(self, app, app_cmd_line):
        """
            Handle command line
            @param app as Gio.Application
            @param options as Gio.ApplicationCommandLine
        """
        self.__externals_count = 0
        args = app_cmd_line.get_arguments()
        options = app_cmd_line.get_options_dict()
        if options.contains("debug"):
            GLib.setenv("WEBKIT_DEBUG", "network", True)
            self.debug = True
        if options.contains("show-tls"):
            self.show_tls = True
        if options.contains("disable-artwork-cache"):
            self.art.disable_cache()
        ephemeral = options.contains("private")
        if not self.get_windows():
            self.__create_initial_windows(len(args) < 2)
        if options.contains("new"):
            active_window = self.get_new_window()
        else:
            active_window = self.active_window
        # Open command line args
        if len(args) > 1:
            items = []
            i = 0
            for uri in args[1:]:
                # Transform path to uri
                parsed = urlparse(uri)
                if not parsed.scheme:
                    if uri.startswith('/'):
                        uri = "file://%s" % uri
                    else:
                        uri = "http://%s" % uri
                loading_type = wanted_loading_type(i)
                items.append((uri, uri, 0, 0, ephemeral, None, loading_type))
                i += 1
            active_window.container.add_webviews(items)
            active_window.present_with_time(Gtk.get_current_event_time())
        # Add default start page
        if not active_window.container.views:
            active_window.container.add_webview(self.start_page,
                                                LoadingType.FOREGROUND,
                                                ephemeral)
        if self.debug:
            WebKit2.WebContext.get_default().get_plugins(
                None, self.__on_get_plugins, None)
        return 0

    def __close_window(self, window):
        """
            Close window
        """
        if len(self.get_windows()) > 1:
            state = self.__get_state(window)
            self.__state_cache.append(state)
            GLib.timeout_add(25000, self.__clean_state_cache, state["id"])
            window.destroy()
        else:
            window.hide()
            self.quit(True)

    def __try_closing(self, window, views):
        """
            Try closing all views
        """
        if views:
            view = views.pop(0)
            page_id = view.webview.get_page_id()
            self.helper.call("FormsFilled", page_id, None,
                             self.__on_forms_filled, window, views)
        else:
            self.__close_window(window)

    def __on_forms_filled(self, source, result, window, views):
        """
            Ask user to close view, if ok, close view
            @param source as GObject.Object
            @param result as Gio.AsyncResult
            @param window as Window
            @param views as [View]
        """
        def on_response_id(dialog, response_id, window, views, self):
            if response_id == Gtk.ResponseType.CLOSE:
                if views:
                    self.__try_closing(window, views)
                else:
                    self.__close_window(window)
            dialog.destroy()

        def on_close(widget, dialog):
            dialog.response(Gtk.ResponseType.CLOSE)

        def on_cancel(widget, dialog):
            dialog.response(Gtk.ResponseType.CANCEL)

        try:
            result = source.call_finish(result)[0]
            if result:
                builder = Gtk.Builder()
                builder.add_from_resource("/org/gnome/Eolie/QuitDialog.ui")
                dialog = builder.get_object("dialog")
                label = builder.get_object("label")
                close = builder.get_object("close")
                cancel = builder.get_object("cancel")
                label.set_text(_("Do you really want to quit Eolie?"))
                dialog.set_transient_for(window)
                dialog.connect("response", on_response_id, window, views, self)
                close.connect("clicked", on_close, dialog)
                cancel.connect("clicked", on_cancel, dialog)
                dialog.run()
            else:
                if views:
                    self.__try_closing(window, views)
                else:
                    self.__close_window(window)
        except Exception as e:
            self.__close_window(window)
            print("Application::__on_forms_filled():", e)

    def __on_get_plugins(self, source, result, data):
        """
            Print plugins on command line
            @param source as GObject.Object
            @param result as Gio.AsyncResult
            @param data as None
        """
        plugins = source.get_plugins_finish(result)
        for plugin in plugins:
            print(plugin.get_name(), plugin.get_description(),
                  plugin.get_path())

    def __on_delete_event(self, window, event):
        """
            Exit application
            @param window as Window
            @param event as Gdk.Event
        """
        def on_response_id(dialog, response_id, window):
            if response_id == Gtk.ResponseType.CLOSE:
                self.__try_closing(window, window.container.views)
            dialog.destroy()

        def on_close(widget, dialog):
            dialog.response(Gtk.ResponseType.CLOSE)

        def on_cancel(widget, dialog):
            dialog.response(Gtk.ResponseType.CANCEL)

        # Ask for user if needed
        if len(self.get_windows()) == 1 and self.download_manager.active:
            builder = Gtk.Builder()
            builder.add_from_resource("/org/gnome/Eolie/QuitDialog.ui")
            dialog = builder.get_object("dialog")
            label = builder.get_object("label")
            close = builder.get_object("close")
            cancel = builder.get_object("cancel")
            label.set_text(
                _("Downloads running,"
                  " are you sure you want quit ?"))
            dialog.set_transient_for(window)
            dialog.connect("response", on_response_id, window)
            close.connect("clicked", on_close, dialog)
            cancel.connect("clicked", on_cancel, dialog)
            dialog.run()
        else:
            self.__try_closing(window, window.container.views)
        return True

    def __on_settings_activate(self, action, param):
        """
            Show settings dialog
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        dialog = SettingsDialog(self.active_window)
        dialog.show()

    def __on_report_activate(self, action, param):
        """
            Launch bug report page
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        argv = ["uname", "-a", None]
        (s, o, e, s) = GLib.spawn_sync(None, argv, None,
                                       GLib.SpawnFlags.SEARCH_PATH, None)
        if o:
            os = o.decode("utf-8")
        else:
            os = "Unknown"

        github = "https://github.com/gnumdk/eolie/issues/new?body="
        body = """
TRANSLATORS:
https://translate.zanata.org/project/view/eolie

### Environment
- Eolie version: %s
- GTK+ version: %s.%s
- Operating system: %s

### Bug/Feature
If your bug is a rendering bug or a WebKit crash, you should report it here:
https://bugs.webkit.org -> Section WebKit Gtk -> title starting with [GTK]

<Describe your bug here>""" % (self.__version, Gtk.get_major_version(),
                               Gtk.get_minor_version(), os)
        url = github + GLib.uri_escape_string(body, "", False)
        self.active_window.container.add_webview(url, LoadingType.FOREGROUND,
                                                 False)

    def __on_about_activate(self, action, param):
        """
            Setup about dialog
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        builder = Gtk.Builder()
        builder.add_from_resource('/org/gnome/Eolie/AboutDialog.ui')
        about = builder.get_object('about_dialog')
        window = self.active_window
        if window is not None:
            about.set_transient_for(window)
        about.connect("response", self.__on_about_activate_response)
        about.show()

    def __on_shortcuts_activate(self, action, param):
        """
            Show help in yelp
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        builder = Gtk.Builder()
        builder.add_from_resource("/org/gnome/Eolie/Shortcuts.ui")
        shortcuts = builder.get_object("shortcuts")
        window = self.active_window
        if window is not None:
            shortcuts.set_transient_for(window)
        shortcuts.show()

    def __on_help_activate(self, action, param):
        """
            Show help in yelp
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        try:
            Gtk.show_uri(None, "help:eolie", Gtk.get_current_event_time())
        except:
            print(_("Eolie: You need to install yelp."))

    def __on_about_activate_response(self, dialog, response_id):
        """
            Destroy about dialog when closed
            @param dialog as Gtk.Dialog
            @param response id as int
        """
        dialog.destroy()

    def __on_sidebar_change_state(self, action, value):
        """
            Show/hide sidebar
            @param action as Gio.SimpleAction
            @param value as bool
        """
        action.set_state(value)
        self.settings.set_value("show-sidebar", GLib.Variant("b", value))

    def __on_activate(self, application):
        """
            Call default handler, raise last window
            @param application as Gio.Application
        """
        if self.get_windows():
            self.active_window.present_with_time(Gtk.get_current_event_time())

    def __on_shortcut_action(self, action, param):
        """
            Global shortcuts handler
            @param action as Gio.SimpleAction
            @param param as GLib.Variant
        """
        string = param.get_string()
        if string == "new_window":
            window = self.get_new_window()
            window.container.add_webview(self.start_page,
                                         LoadingType.FOREGROUND)
Exemple #13
0
    def __init(self):
        """
            Init main application
        """
        self.settings = Settings.new()

        # Init extensions
        GLib.setenv("PYTHONPATH", self.__extension_dir, True)

        # Create favicon path
        if not GLib.file_test(self.__FAVICONS_PATH, GLib.FileTest.IS_DIR):
            GLib.mkdir_with_parents(self.__FAVICONS_PATH, 0o0750)

        # Add a global DBus helper
        self.helper = DBusHelper()
        # First init sync worker
        from eolie.mozilla_sync import SyncWorker
        if SyncWorker.check_modules():
            self.sync_worker = SyncWorker()
            # Run a first sync in 10 seconds, speed up app start
            GLib.timeout_add_seconds(10, self.sync_worker.sync, False)
            # Then run a sync every hour
            GLib.timeout_add_seconds(3600, self.sync_worker.sync, True)
        else:
            self.sync_worker = None
        if self.prefers_app_menu():
            menu = self.get_app_menu()
            self.set_app_menu(menu)
        cssProviderFile = Gio.File.new_for_uri(
            'resource:///org/gnome/Eolie/application.css')
        cssProvider = Gtk.CssProvider()
        cssProvider.load_from_file(cssProviderFile)
        screen = Gdk.Screen.get_default()
        styleContext = Gtk.StyleContext()
        styleContext.add_provider_for_screen(screen, cssProvider,
                                             Gtk.STYLE_PROVIDER_PRIORITY_USER)
        self.history = DatabaseHistory()
        self.bookmarks = DatabaseBookmarks()
        # We store cursors for main thread
        SqlCursor.add(self.history)
        SqlCursor.add(self.bookmarks)
        self.websettings = DatabaseSettings()
        self.adblock = DatabaseAdblock()
        self.adblock.update()
        self.phishing = DatabasePhishing()
        self.adblock_exceptions = DatabaseExceptions("adblock")
        # Do not remove this!
        self.update_default_style_sheet()
        self.popup_exceptions = DatabaseExceptions("popups")
        self.image_exceptions = DatabaseExceptions("images")
        if self.settings.get_user_value("jsblock") is not None:
            self.js_exceptions = DatabaseExceptions("js")
        else:
            self.js_exceptions = None
        self.phishing.update()
        self.art = Art()
        self.search = Search()
        self.download_manager = DownloadManager()
        self.pages_menu = PagesMenu()

        # Check MOZ_PLUGIN_PATH
        if self.settings.get_value('enable-plugins') and\
                not GLib.getenv("MOZ_PLUGIN_PATH"):
            print("You need to set MOZ_PLUGIN_PATH to use plugins")

        # https://wiki.ubuntu.com/Unity/LauncherAPI
        self.__unity = None
        if is_unity():
            try:
                gi.require_version('Unity', '7.0')
                from gi.repository import Unity
                self.__unity = Unity.LauncherEntry.get_for_desktop_id(
                    "org.gnome.Eolie.desktop")
            except:
                pass

        # Init profiles
        self.set_profiles()

        shortcut_action = Gio.SimpleAction.new('shortcut',
                                               GLib.VariantType.new('s'))
        shortcut_action.connect('activate', self.__on_shortcut_action)
        self.add_action(shortcut_action)
        self.set_accels_for_action("win.shortcut::expose", ["<Alt>e"])
        self.set_accels_for_action("win.exceptions::site", ["<Control>e"])
        self.set_accels_for_action("win.shortcut::show_left_panel", ["F9"])
        self.set_accels_for_action("win.shortcut::uri",
                                   ["<Control>l", "<Control>b"])
        self.set_accels_for_action("win.shortcut::new_page", ["<Control>t"])
        self.set_accels_for_action("win.shortcut::last_page",
                                   ["<Control><Shift>t"])
        self.set_accels_for_action("app.shortcut::new_window", ["<Control>n"])
        self.set_accels_for_action("win.shortcut::private",
                                   ["<Control><Shift>p"])
        self.set_accels_for_action("win.shortcut::close_page", ["<Control>w"])
        self.set_accels_for_action("win.shortcut::quit", ["<Control>q"])
        self.set_accels_for_action("win.shortcut::save", ["<Control><Shift>s"])
        self.set_accels_for_action("win.shortcut::filter", ["<Control>i"])
        self.set_accels_for_action("win.shortcut::reload",
                                   ["<Control>r", "F5"])
        self.set_accels_for_action("win.shortcut::home", ["<Control>Home"])
        self.set_accels_for_action("win.shortcut::find", ["<Control>f"])
        self.set_accels_for_action("win.shortcut::print", ["<Control>p"])
        self.set_accels_for_action("win.shortcut::source",
                                   ["<Control><Shift>c"])
        self.set_accels_for_action("win.shortcut::history", ["<Control>h"])
        self.set_accels_for_action("win.shortcut::search", ["<Control>k"])
        self.set_accels_for_action("win.shortcut::fullscreen", ["F11"])
        self.set_accels_for_action("app.settings", ["<Control>s"])
        self.set_accels_for_action("win.shortcut::backward",
                                   ["<Alt>Left", "XF86Back"])
        self.set_accels_for_action("win.shortcut::forward",
                                   ["<Alt>Right", "XF86Forward"])
        self.set_accels_for_action("win.shortcut::next",
                                   ["<Control>Tab", "<Control>Page_Down"])
        self.set_accels_for_action("win.shortcut::previous",
                                   ["<Control><Shift>Tab", "<Control>Page_Up"])
        self.set_accels_for_action("win.shortcut::next_site",
                                   ["<Control>twosuperior"])
        self.set_accels_for_action("win.shortcut::previous_site",
                                   ["<Control><Shift>twosuperior"])
        self.set_accels_for_action(
            "win.shortcut::zoom_in",
            ["<Control>KP_Add", "<Control>plus", "<Control>equal"])
        self.set_accels_for_action("win.shortcut::zoom_out",
                                   ["<Control>KP_Subtract", "<Control>minus"])
        self.set_accels_for_action("win.shortcut::zoom_default",
                                   ["<Control>KP_0", "<Control>0"])