Commit 838c872b authored by Cédric Bellegarde's avatar Cédric Bellegarde

Better session saving, store title, atime and gtime

parent 901a1491
......@@ -503,24 +503,35 @@ class Application(Gtk.Application):
@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:
uri = view.webview.get_uri()
if uri is None:
uri = view.webview.delayed_uri
parsed = urlparse(uri)
if parsed.scheme not in ["http", "https"]:
if view.webview == current:
continue
ephemeral = view.webview.ephemeral
state = view.webview.get_session_state().serialize()
session_states.append((uri,
ephemeral,
state.get_data()))
state = get_state_for_webview(view.webview)
if state is not None:
session_states.append(state)
window_state["states"] = session_states
return window_state
......@@ -562,25 +573,30 @@ class Application(Gtk.Application):
windows = load(open(EOLIE_DATA_PATH + "/session_states.bin", "rb"))
if self.settings.get_value("remember-session"):
for window in windows:
self.get_new_window(window["size"],
window["maximized"])
new_window = self.get_new_window(window["size"],
window["maximized"])
items = []
for (uri, ephemeral, state) in window["states"]:
for (uri, title, atime,
gtime, ephemeral, state) in window["states"]:
webkit_state = WebKit2.WebViewSessionState(
GLib.Bytes.new(state))
items.append((uri, ephemeral, webkit_state))
items.append((uri, title, atime, gtime, ephemeral,
webkit_state))
if items:
self.active_window.container.add_webviews(items, True)
else:
size = (800, 600)
maximized = False
if windows:
new_window.container.add_webviews(items)
else:
new_window.container.add_webview(self.start_page,
WindowType.FOREGROUND)
elif windows:
size = windows[0]["size"]
maximized = windows[0]["maximized"]
self.get_new_window(size, maximized)
except Exception as e:
print("Application::__create_initial_windows()", e)
if not self.get_windows():
self.get_new_window(size, maximized)
if not self.active_window.container.views:
self.active_window.container.add_webview(self.start_page,
WindowType.FOREGROUND)
def __on_handle_local_options(self, app, options):
"""
......@@ -626,11 +642,11 @@ class Application(Gtk.Application):
uri = "file://%s" % uri
else:
uri = "http://%s" % uri
items.append((uri, ephemeral, None))
self.active_window.container.add_webviews(items, True)
items.append((uri, "", 0, 0, ephemeral, None))
self.active_window.container.add_webviews(items)
active_window.present_with_time(Gtk.get_current_event_time())
# Add default start page
elif self.active_window.container.current is None:
elif not self.get_windows():
self.active_window.present_with_time(Gtk.get_current_event_time())
self.active_window.container.add_webview(self.start_page,
WindowType.FOREGROUND,
......
......@@ -87,29 +87,30 @@ class Container(Gtk.Overlay):
if state is not None:
webview.restore_session_state(state)
if uri is not None:
webview.set_uri(uri)
if window_type != WindowType.OFFLOAD:
# Do not load uri until we are on screen
GLib.idle_add(webview.load_uri, uri)
else:
webview.set_delayed_uri(uri)
self.add_view(webview, window_type)
return webview
def add_webviews(self, items, first_onscreen=False):
def add_webviews(self, items):
"""
Add webviews offscreen by default
@param items as [(uri: str,
ephemeral: bool,
state: WebKit2.WebViewSessionState)]
@param first_offscreen as bool
@param items as [(uri => str,
ephemeral => bool,
state => WebKit2.WebViewSessionState)]
"""
if first_onscreen:
window_type = WindowType.FOREGROUND
else:
window_type = WindowType.OFFLOAD
if items:
(uri, ephemeral, state) = items.pop(0)
self.add_webview(uri, window_type, ephemeral, state)
(uri, title, atime, gtime, ephemeral, state) = items.pop(0)
if not self.__stack.get_children():
window_type = WindowType.FOREGROUND
else:
window_type = WindowType.OFFLOAD
webview = self.add_webview(uri, window_type, ephemeral, state)
webview.set_title(title)
webview.set_atime(atime)
webview.set_gtime(gtime)
GLib.idle_add(self.add_webviews, items)
def add_view(self, webview, window_type):
......@@ -230,14 +231,14 @@ class Container(Gtk.Overlay):
children.remove(view)
reversed_children = list(reversed(children))
children_count = len(children)
El().history.set_page_state(view.webview.get_uri())
El().history.set_page_state(view.webview.uri)
self.__window.close_popovers()
# Needed to unfocus titlebar
self.__window.set_focus(None)
was_current = view == self.__window.container.current
gtime = view.webview.gtime
El().pages_menu.add_action(view.webview.get_title(),
view.webview.get_uri(),
El().pages_menu.add_action(view.webview.title,
view.webview.uri,
view.webview.ephemeral,
view.webview.get_session_state())
view.destroy()
......
......@@ -166,9 +166,14 @@ class PagesMenu(Gio.Menu):
for i in range(0, self.__closed_section.get_n_items()):
uri_attr = self.__closed_section.get_item_attribute_value(i,
"uri")
if uri_attr is None:
title_attr = self.__closed_section.get_item_attribute_value(
i,
"label")
if uri_attr is None or title_attr is None:
continue
items.append((uri_attr.get_string(), False, None))
uri = uri_attr.get_string()
title = title_attr.get_string()
items.append((uri, title, 0, 0, False, None))
i += 1
El().active_window.container.add_webviews(items)
self.__closed_section.remove_all()
......
......@@ -32,12 +32,10 @@ class SitesMenu(Gio.Menu):
self.__window = window
Gio.Menu.__init__(self)
for view in views:
uri = view.webview.get_uri()
uri = view.webview.uri
if uri is None:
continue
title = view.webview.get_title()
if not title:
title = uri
title = view.webview.title
encoded = "SITE_" + sha256(uri.encode("utf-8")).hexdigest()
action = El().lookup_action(encoded)
if action is not None:
......@@ -91,7 +89,7 @@ class SitesMenu(Gio.Menu):
"""
if views:
from eolie.dialog_modify_ua import ModifyUADialog
dialog = ModifyUADialog(views[0].webview.get_uri(), self.__window)
dialog = ModifyUADialog(views[0].webview.uri, self.__window)
dialog.run()
def __on_action_clicked(self, action, variant, view):
......
......@@ -294,8 +294,8 @@ class PagesManager(Gtk.EventBox):
filter = self.__search_entry.get_text()
if not filter:
return True
uri = row.view.webview.get_uri()
title = row.view.webview.get_title()
uri = row.view.webview.uri
title = row.view.webview.title
if (uri is not None and uri.find(filter) != -1) or\
(title is not None and title.find(filter) != -1) or\
(filter == "private://" and row.view.webview.ephemeral):
......
......@@ -45,6 +45,8 @@ class PagesManagerChild(Gtk.FlowBoxChild):
self.__indicator_label.set_property("valign", Gtk.Align.CENTER)
self.__indicator_label.set_ellipsize(Pango.EllipsizeMode.END)
self.__indicator_label.show()
if view.webview.title:
self.__indicator_label.set_text(view.webview.title)
builder.get_object("grid").attach(self.__indicator_label, 0, 0, 1, 1)
self.__image = builder.get_object("image")
self.__close_button = builder.get_object("close_button")
......@@ -96,6 +98,11 @@ class PagesManagerChild(Gtk.FlowBoxChild):
self.__connected_signals.append(
self.__view.webview.connect("shown",
self.__on_webview_shown))
self.__set_favicon_artwork()
if self.__view.webview.uri is not None:
artwork_path = El().art.get_path(self.__view.webview.uri, "start")
if artwork_path is not None:
self.__image.set_from_file(artwork_path)
@property
def view(self):
......@@ -154,30 +161,36 @@ class PagesManagerChild(Gtk.FlowBoxChild):
event.x >= allocation.width or\
event.y <= 0 or\
event.y >= allocation.height:
if self.__view.webview.ephemeral:
return
image = self.__close_button.get_image()
if self.__favicon is not None:
image.set_from_surface(self.__favicon)
else:
uri = self.__view.webview.get_uri()
artwork = El().art.get_icon_theme_artwork(
uri,
self.view.webview.ephemeral)
if artwork is not None:
image.set_from_icon_name(artwork,
Gtk.IconSize.INVALID)
else:
favicon_path = El().art.get_favicon_path(uri)
if favicon_path is not None:
image.set_from_file(favicon_path)
else:
image.set_from_icon_name("applications-internet",
Gtk.IconSize.INVALID)
self.__set_favicon_artwork()
#######################
# PRIVATE #
#######################
def __set_favicon_artwork(self):
"""
Set favicon artwork
"""
if self.__view.webview.ephemeral:
return
image = self.__close_button.get_image()
if self.__favicon is not None:
image.set_from_surface(self.__favicon)
else:
uri = self.__view.webview.uri
artwork = El().art.get_icon_theme_artwork(
uri,
self.view.webview.ephemeral)
if artwork is not None:
image.set_from_icon_name(artwork,
Gtk.IconSize.INVALID)
else:
favicon_path = El().art.get_favicon_path(uri)
if favicon_path is not None:
image.set_from_file(favicon_path)
else:
image.set_from_icon_name("applications-internet",
Gtk.IconSize.INVALID)
def __set_snapshot(self):
"""
Set webpage preview
......@@ -212,7 +225,7 @@ class PagesManagerChild(Gtk.FlowBoxChild):
"""
text = ""
label = self.__indicator_label.get_text()
uri = self.__view.webview.get_uri()
uri = self.__view.webview.uri
# GLib.markup_escape_text
if uri is None:
text = "<b>%s</b>" % GLib.markup_escape_text(label)
......@@ -299,7 +312,7 @@ class PagesManagerChild(Gtk.FlowBoxChild):
@param webview as WebView
@param event as WebKit2.LoadEvent
"""
uri = webview.get_uri()
uri = webview.uri
if event == WebKit2.LoadEvent.STARTED:
self.__favicon = None
self.__close_button.get_image().set_from_icon_name(
......
......@@ -362,8 +362,8 @@ class Row(Gtk.ListBoxRow):
items = El().bookmarks.get_bookmarks(tag_id)
pages = []
for (bid, uri, title) in items:
pages.append((uri, False, None))
self.__window.container.add_webviews(pages, True)
pages.append((uri, "", 0, 0, False, None))
self.__window.container.add_webviews(pages)
def __on_delete_clicked(self, button):
"""
......
......@@ -55,8 +55,7 @@ class WebViewPopover(Gtk.Popover):
view.webview.connect("close", self.__on_webview_close, destroy)
view.webview.connect("title-changed", self.__on_webview_title_changed)
view.webview.connect("load-changed", self.__on_webview_load_changed)
title = view.webview.get_title()
self.__combobox.append(str(view), title)
self.__combobox.append(str(view), view.webview.title)
if position == 0:
properties = view.webview.get_window_properties()
geometry = properties.get_geometry()
......@@ -64,7 +63,7 @@ class WebViewPopover(Gtk.Popover):
self.__stack.set_size_request(geometry.width, geometry.height)
else:
self.__stack.set_size_request(width, height)
self.__label.set_text(title)
self.__label.set_text(view.webview.title)
self.__label.show()
self.__combobox.set_active_id(str(view))
self.__combobox.hide()
......
......@@ -63,9 +63,9 @@ class SitesManager(Gtk.EventBox):
Add a new view to monitor
@param view as View
"""
delayed_uri = view.webview.delayed_uri
if delayed_uri is not None:
self.__loaded_uri(view.webview, delayed_uri)
# WebView not loaded, as load-changed will not be emited, force update
if view.webview.get_uri() != view.webview.uri:
self.__loaded_uri(view.webview, view.webview.uri)
view.webview.connect("load-changed", self.__on_webview_load_changed)
view.connect("destroying", self.__on_view_destroying)
......@@ -284,8 +284,7 @@ class SitesManager(Gtk.EventBox):
"""
if event == WebKit2.LoadEvent.FINISHED:
return
uri = webview.get_uri()
self.__loaded_uri(webview, uri)
self.__loaded_uri(webview, webview.uri)
def __on_row_activated(self, listbox, child):
"""
......
......@@ -277,7 +277,7 @@ class ToolbarEnd(Gtk.Bin):
if not self.__download_button.is_visible():
builder.get_object("toolbar_items").show()
uri = self.__window.container.current.webview.get_uri()
uri = self.__window.container.current.webview.uri
if not uri:
return
parsed = urlparse(uri)
......@@ -337,7 +337,7 @@ class ToolbarEnd(Gtk.Bin):
widget = builder.get_object("widget")
webview = self.__window.container.current.webview
current = El().websettings.get_zoom(webview.get_uri())
current = El().websettings.get_zoom(webview.uri)
if current is None:
current = 100
builder.get_object("default_zoom_button").set_label(
......@@ -427,7 +427,7 @@ class ToolbarEnd(Gtk.Bin):
@param button as Gtk.Button
"""
webview = self.__window.container.current.webview
El().websettings.set_zoom(100, webview.get_uri())
El().websettings.set_zoom(100, webview.uri)
webview.update_zoom_level()
button.set_label("100 %")
......@@ -475,7 +475,7 @@ class ToolbarEnd(Gtk.Bin):
@param action as Gio.SimpleAction
@param param as GLib.Variant
"""
uri = self.__window.container.current.webview.get_uri()
uri = self.__window.container.current.webview.uri
if not uri:
return
if action == self.__adblock_exceptions:
......
......@@ -241,13 +241,13 @@ class ToolbarTitle(Gtk.Bin):
"""
Show title instead of uri
"""
self.__window.set_title(title)
# Do not show this in titlebar
parsed = urlparse(self.__uri)
if parsed.scheme in ["populars", "about"]:
self.__set_default_placeholder()
return
if title:
self.__window.set_title(title)
self.__placeholder.set_text(title)
else:
self.__placeholder.set_text(self.__uri)
......@@ -609,7 +609,7 @@ class ToolbarTitle(Gtk.Bin):
"""
if self.__indicator2_image.get_icon_name()[0] ==\
"mark-location-symbolic":
uri = self.__window.container.current.webview.get_uri()
uri = self.__window.container.current.webview.uri
El().websettings.allow_geolocation(uri, False)
if self.__window.container.current.webview.popups:
self.show_indicator(Indicator.POPUPS)
......@@ -651,17 +651,14 @@ class ToolbarTitle(Gtk.Bin):
self.__entry.delete_text(0, -1)
webview.clear_text_entry()
else:
bookmark_id = El().bookmarks.get_id(webview.get_uri())
bookmark_id = El().bookmarks.get_id(webview.uri)
if bookmark_id is None:
uri = webview.get_uri()
if not uri or uri == "about:blank":
uri = webview.uri
if uri is None or uri == "about:blank":
return
title = webview.get_title()
if not title:
title = uri
self.__action_image2.set_from_icon_name("starred-symbolic",
Gtk.IconSize.MENU)
bookmark_id = El().bookmarks.add(title,
bookmark_id = El().bookmarks.add(webview.title,
uri, None, [])
from eolie.widget_bookmark_edit import BookmarkEditWidget
widget = BookmarkEditWidget(bookmark_id, False)
......@@ -721,7 +718,7 @@ class ToolbarTitle(Gtk.Bin):
self.__placeholder.set_opacity(0.8)
self.set_text_entry("")
self.__update_secure_content_indicator()
uri = view.webview.get_uri()
uri = view.webview.uri
if uri is not None:
bookmark_id = El().bookmarks.get_id(uri)
if bookmark_id is not None:
......@@ -786,7 +783,7 @@ class ToolbarTitle(Gtk.Bin):
elif len(value) < 3:
return
for view in self.__window.container.views:
uri = view.webview.get_uri()
uri = view.webview.uri
if uri is not None:
view_parsed = urlparse(uri)
if view_parsed.netloc.find(value) != -1:
......@@ -874,7 +871,7 @@ class ToolbarTitle(Gtk.Bin):
self.__entry.delete_selection()
from eolie.widget_bookmark_edit import BookmarkEditWidget
if isinstance(popover, BookmarkEditWidget):
bookmark_id = El().bookmarks.get_id(webview.get_uri())
bookmark_id = El().bookmarks.get_id(webview.uri)
if bookmark_id is None:
self.__action_image2.set_from_icon_name("non-starred-symbolic",
Gtk.IconSize.MENU)
......
......@@ -106,7 +106,7 @@ class View(Gtk.Overlay):
width: %s}\
</style></head>" % (document_font_size,
self.get_allocated_width() / 1.5)
html += "<title>%s</title>" % self.__webview.get_title()
html += "<title>%s</title>" % self.__webview.title
html += self.__webview.readable_content
html += "</html>"
GLib.idle_add(self.__reading_view.load_html, html, None)
......
......@@ -81,7 +81,7 @@ class WebView(WebKit2.WebView):
Update zoom level
"""
try:
zoom_level = El().websettings.get_zoom(self.get_uri())
zoom_level = El().websettings.get_zoom(self.uri)
if zoom_level is None:
zoom_level = 100
if self.__related_view is None:
......@@ -107,11 +107,11 @@ class WebView(WebKit2.WebView):
Zoom in view
@return current zoom after zoom in
"""
current = El().websettings.get_zoom(self.get_uri())
current = El().websettings.get_zoom(self.uri)
if current is None:
current = 100
current += 10
El().websettings.set_zoom(current, self.get_uri())
El().websettings.set_zoom(current, self.uri)
self.update_zoom_level()
return current
......@@ -120,13 +120,13 @@ class WebView(WebKit2.WebView):
Zoom out view
@return current zoom after zoom out
"""
current = El().websettings.get_zoom(self.get_uri())
current = El().websettings.get_zoom(self.uri)
if current is None:
current = 100
current -= 10
if current == 0:
return 10
El().websettings.set_zoom(current, self.get_uri())
El().websettings.set_zoom(current, self.uri)
self.update_zoom_level()
return current
......@@ -135,33 +135,31 @@ class WebView(WebKit2.WebView):
Reset zoom level
@return current zoom after zoom out
"""
El().websettings.set_zoom(100, self.get_uri())
El().websettings.set_zoom(100, self.uri)
self.update_zoom_level()
def get_title(self):
def set_title(self, title):
"""
Get webview title
@return str
Set title, will be returned by title property until title is set
by WebView
@param title as str
"""
title = WebKit2.WebView.get_title(self)
if title is None:
title = self.__delayed_uri
return title
self._title = title
self.emit("title-changed", title)
def set_delayed_uri(self, uri):
def set_uri(self, uri):
"""
Set delayed uri
@param uri as str/None
@param uri as str
"""
self.__delayed_uri = uri
if uri is not None:
self.emit("title-changed", uri)
self._uri = uri
self.emit("uri-changed", uri)
def update_spell_checking(self):
"""
Update spell checking
"""
codes = El().websettings.get_languages(self.get_uri())
codes = El().websettings.get_languages(self.uri)
# If None, default user language
if codes is not None:
self.get_context().set_spell_checking_languages(codes)
......@@ -320,12 +318,28 @@ class WebView(WebKit2.WebView):
return self._cancelled
@property
def delayed_uri(self):
def title(self):
"""
Get title (loaded or unloaded)
@return str
"""
title = self.get_title()
if title is None:
title = self._title
if title is None:
title = self.uri
return title
@property
def uri(self):
"""
Get delayed uri (one time)
Get uri (loaded or unloaded)
@return str
"""
return self.__delayed_uri
uri = self.get_uri()
if uri is None:
uri = self._uri
return uri
@property
def ephemeral(self):
......@@ -375,7 +389,8 @@ class WebView(WebKit2.WebView):
# it from clipboard FIXME Get it from extensions
self.__selection = ""
self._readable_content = ""
self.__delayed_uri = None
self._uri = None
self._title = None
self._navigation_uri = None
self.__related_view = related_view
self.__input_source = Gdk.InputSource.MOUSE
......@@ -481,7 +496,7 @@ class WebView(WebKit2.WebView):
# Do not block if we get a click on view
elapsed = time() - related._last_click_time
popup_block = El().settings.get_value("popupblock")
parsed_related = urlparse(related.get_uri())
parsed_related = urlparse(related.uri)
exception = El().popup_exceptions.find_parsed(parsed_related) or\
elapsed < 0.5
if not exception and popup_block and\
......
......@@ -112,7 +112,7 @@ class WebViewArtwork:
# Do not cache snapshot on error
if self.error is not None:
return
uri = self.get_uri()
uri = self.uri
# We also cache initial URI
uris = [uri.rstrip("/")]
if self.initial_uri is not None and\
......
......@@ -194,10 +194,10 @@ class WebViewErrors:
self.load_html(html, uri)
return True
def __on_web_process_crashed(self, view):
def __on_web_process_crashed(self, webview):
"""
We just crashed :-(
@param view as WebKit2.WebView
@param webview as WebKit2.WebView
"""
self._error = GLib.Error()
f = Gio.File.new_for_uri("resource:///org/gnome/Eolie/error.css")
......@@ -220,5 +220,5 @@ class WebViewErrors:
"Set <b>[GTK]</b> as subject prefix."),
"suggested-action",
_("Report a bug now"))
self.load_html(html, view.get_uri())
self.load_html(html, webview.uri)
return True
......@@ -156,7 +156,7 @@ class WebViewNavigation:
if self.ephemeral:
request.deny()
else:
uri = webview.get_uri()
uri = webview.uri
self._window.toolbar.title.show_geolocation(uri, request)
elif isinstance(request, WebKit2.NotificationPermissionRequest):
# Can use Gnome Shell notification policy
......@@ -169,7 +169,8 @@ class WebViewNavigation:
@param webview as WebKit2.WebView
@param uri as GParamSpec
"""
uri = webview.get_uri()
self._uri = None
uri = webview.uri
# JS bookmark (Bookmarklet)
if not uri.startswith("javascript:"):
self.emit("uri-changed", uri)
......@@ -180,14 +181,14 @@ class WebViewNavigation:
@param webview as WebKit2.WebView
@param event as GParamSpec
"""
title = webview.get_title()
if event.name != "title" or not title:
if event.name != "title" or not webview.title:
return
self.emit("title-changed", title)
self._title = None
self.emit("title-changed", webview.title)
# Js update, force favicon caching for current uri
if not self.is_loading():
self.__initial_uri = None
self.set_favicon(self.get_uri())
self.set_favicon(self.uri)
if self.__js_timeout is not None:
GLib.source_remove(self.__js_timeout)
self.__js_timeout = GLib.timeout_add(
......@@ -201,7 +202,7 @@ class WebViewNavigation:
@param webview as WebView
@param favicon as Gparam
"""
self.set_favicon(self.get_uri())
self.set_favicon(self.uri)
def __on_js_timeout(self, path):
"""
......@@ -296,7 +297,7 @@ class WebViewNavigation:
decision.ignore()
return True
else:
El().history.set_page_state(webview.get_uri())
El().history.set_page_state(webview.uri)
decision.use()
self._error = None
return False
......@@ -311,7 +312,7 @@ class WebViewNavigation:
@param webview as WebView
@param event as WebKit2.LoadEvent
"""
uri = webview.get_uri()
uri = webview.uri
parsed = urlparse(uri)
if event == WebKit2.LoadEvent.STARTED:
self.stop_snapshot()
......
......@@ -81,9 +81,9 @@ class WebViewSignals(WebViewMenuSignals, WebViewJsSignals,
# We are offscreen
if self._window != self.get_toplevel():