diff --git a/re.sonny.Tangram.json b/re.sonny.Tangram.json index c4e8bc4..84dfa86 100644 --- a/re.sonny.Tangram.json +++ b/re.sonny.Tangram.json @@ -1,7 +1,7 @@ { "id": "re.sonny.Tangram", "runtime": "org.gnome.Platform", - "runtime-version": "43", + "runtime-version": "44", "sdk": "org.gnome.Sdk", "command": "re.sonny.Tangram", "finish-args": [ @@ -31,7 +31,12 @@ "name": "Tangram", "buildsystem": "meson", "builddir": true, - "sources": [{ "type": "dir", "path": "." }] + "sources": [ + { + "type": "dir", + "path": "." + } + ] } ] -} +} \ No newline at end of file diff --git a/src/AboutDialog.js b/src/AboutDialog.js index 86a77db..cf9e7e6 100644 --- a/src/AboutDialog.js +++ b/src/AboutDialog.js @@ -1,5 +1,5 @@ import Gtk from "gi://Gtk"; -import WebKit from "gi://WebKit2"; +import WebKit from "gi://WebKit"; import Soup from "gi://Soup"; import Adw from "gi://Adw"; import { gettext as _ } from "gettext"; diff --git a/src/Actions.js b/src/Actions.js index 62d5f8c..cdb7eea 100644 --- a/src/Actions.js +++ b/src/Actions.js @@ -47,16 +47,6 @@ export default function Actions({ window, application, selectTab }) { }); application.add_action(showInstanceAction); - const openURIAction = new Gio.SimpleAction({ - name: "openURI", - parameter_type: GLib.VariantType.new("s"), - }); - openURIAction.connect("activate", (self, parameters) => { - const path = parameters.unpack(); - Gio.AppInfo.launch_default_for_uri(path, null); - }); - application.add_action(openURIAction); - const quit = new Gio.SimpleAction({ name: "quit", parameter_type: null, diff --git a/src/ViewNew.js b/src/ViewNew.js index 3a40ffe..a18bc2d 100644 --- a/src/ViewNew.js +++ b/src/ViewNew.js @@ -1,4 +1,4 @@ -import WebKit2 from "gi://WebKit2"; +import WebKit2 from "gi://WebKit"; import GLib from "gi://GLib"; import GObject from "gi://GObject"; import { gettext as _ } from "gettext"; diff --git a/src/WebView.js b/src/WebView.js index fa0a8e7..de5d782 100644 --- a/src/WebView.js +++ b/src/WebView.js @@ -1,12 +1,16 @@ import Gtk from "gi://Gtk"; -import WebKit2 from "gi://WebKit2"; +import WebKit2 from "gi://WebKit"; import GLib from "gi://GLib"; import Gio from "gi://Gio"; import Gdk from "gi://Gdk"; +import { gettext as _ } from "gettext"; + +import { connect, getEnum } from "./util.js"; +import { MODES } from "./constants.js"; + +Gio._promisify(Gtk.FileDialog.prototype, "save", "save_finish"); -const { FileChooserNative, FileChooserAction, ResponseType } = Gtk; const { - WebsiteDataManager, WebContext, CookiePersistentStorage, CookieAcceptPolicy, @@ -16,54 +20,73 @@ const { UserContentManager, TLSErrorsPolicy, WebView, - ProcessModel, - DownloadError, PolicyDecisionType, } = WebKit2; const { build_filenamev, - DIR_SEPARATOR_S, get_user_special_dir, UserDirectory, - path_get_basename, - path_get_dirname, get_language_names, } = GLib; -const { Notification, AppInfo, ResourceLookupFlags, resources_open_stream } = - Gio; +const { AppInfo, ResourceLookupFlags, resources_open_stream } = Gio; -import { connect, getEnum } from "./util.js"; -import { env } from "./env.js"; -import { MODES } from "./constants.js"; +export function buildWebView({ instance, onNotification, window }) { + const { data_dir, cache_dir, url, id } = instance; + + const network_session = WebKit2.NetworkSession.new(data_dir, cache_dir); + network_session.set_tls_errors_policy(TLSErrorsPolicy.FAIL); + + // https://gjs-docs.gnome.org/webkit240~4.0_api/webkit2.webcontext#signal-download-started + network_session.connect("download-started", (self, download) => { + // Beware of https://bugs.webkit.org/show_bug.cgi?id=201868 + download.set_allow_overwrite(false); + + const request = download.get_request(); + const uri = request.get_uri(); + if (uri.startsWith("http")) { + download.cancel(); + AppInfo.launch_default_for_uri(uri, null); + return; + } + + // We cannot open blob: and file: uris in an other application + // so we download them ourselves, it's okay because they are very + // quick to download so we don't need a progress UI for them + + download.connect("failed", (self, err) => { + logError(err); + }); + + // https://webkitgtk.org/reference/webkit2gtk/stable/signal.Download.decide-destination.html + download.connect("decide-destination", (self, suggested_filename) => { + if (!suggested_filename || suggested_filename === "unknown.asc") { + suggested_filename = ""; + } -export function buildWebView({ - instance, - onNotification, - application, - window, -}) { - const { data_dir, cache_dir, url, id, name } = instance; - - // https://gjs-docs.gnome.org/webkit240~4.0_api/webkit2.websitedatamanager - const website_data_manager = new WebsiteDataManager({ - base_data_directory: data_dir, - disk_cache_directory: cache_dir, + const dest_dir = Gio.File.new_for_path( + get_user_special_dir(UserDirectory.DIRECTORY_DOWNLOAD), + ); + const dialog = new Gtk.FileDialog({ + title: _("Save File"), + initial_folder: dest_dir, + initial_name: suggested_filename, + }); + + dialog + .save(window, null) + .then((file) => { + download.set_destination(file.get_path()); + }) + .catch(logError); + + return true; + }); }); // https://gjs-docs.gnome.org/webkit240~4.0_api/webkit2.webcontext - const web_context = new WebContext({ - website_data_manager, - }); + const web_context = new WebContext(); web_context.set_spell_checking_enabled(true); web_context.set_spell_checking_languages(get_language_names()); - web_context.set_tls_errors_policy(TLSErrorsPolicy.FAIL); - web_context.set_favicon_database_directory( - build_filenamev([cache_dir, "icondatabase"]), - ); - web_context.set_process_model(ProcessModel.MULTIPLE_SECONDARY_PROCESSES); - web_context.set_sandbox_enabled(true); - web_context.add_path_to_sandbox(data_dir, true); - web_context.add_path_to_sandbox(cache_dir, true); const security_manager = web_context.get_security_manager(); @@ -76,9 +99,6 @@ export function buildWebView({ schemeRequest.finish(stream, -1, null); }); - // https://gjs-docs.gnome.org/webkit240~4.0_api/webkit2.favicondatabase - // const favicon_database = web_context.get_favicon_database(); - /* * Notifications */ @@ -93,95 +113,11 @@ export function buildWebView({ }); } - // https://gjs-docs.gnome.org/webkit240~4.0_api/webkit2.webcontext#signal-download-started - web_context.connect("download-started", (self, download) => { - // https://bugs.webkit.org/show_bug.cgi?id=201868 - // We do this because the destination is decided by the user in 'decide-destination' handler - download.set_allow_overwrite(true); - - const request = download.get_request(); - const uri = request.get_uri(); - if (uri.startsWith("http")) { - download.cancel(); - AppInfo.launch_default_for_uri(uri, null); - return; - } - - // We cannot open blob: and file: uris in an other application - // so we download them ourselves, it's okay because they are very - // quick to download so we don't need a progress UI for them - - let error; - download.connect("failed", (self, err) => { - error = err; - }); - download.connect("finished", () => { - if (error && error.code === DownloadError.CANCELLED_BY_USER) return; - - const path = download.get_destination(); - const filename = path_get_basename(path); - - const notification = new Notification(); - notification.set_title(name); - - if (error) { - notification.set_body(`“${filename}” ${error.message}`); - } else { - notification.set_body(`“${filename}”`); - if (env !== "flatpak") { - notification.set_default_action(`app.openURI('${path}')`); - notification.add_button("Open file", `app.openURI('${path}')`); - const dirname = path_get_dirname(path); - notification.add_button("Open folder", `app.openURI('${dirname}')`); - } - } - - application.send_notification(null, notification); - }); - - // https://gjs-docs.gnome.org/webkit240~4.0_api/webkit2.download#signal-decide-destination - download.connect("decide-destination", (self, suggested_filename) => { - if (!suggested_filename || suggested_filename === "unknown.asc") { - suggested_filename = ""; - } - - const dest_dir = get_user_special_dir(UserDirectory.DIRECTORY_DOWNLOAD); - const dest_name = suggested_filename.replace( - new RegExp(DIR_SEPARATOR_S, "g"), - "_", - ); - - const dialog = new FileChooserNative({ - action: FileChooserAction.SAVE, - transient_for: window, - do_overwrite_confirmation: true, - create_folders: true, - }); - // On Linux Mint XFCE 19.2 the default label is 'Open' - dialog.set_accept_label("Save"); - // dest_dir is null in sandbox - if (dest_dir) { - dialog.set_current_folder(dest_dir); - } - dialog.set_current_name(dest_name); - - if (dialog.run() !== ResponseType.ACCEPT) { - download.cancel(); - dialog.destroy(); - // TODO open issue - // return true segfaults - return; - } - - download.set_destination(dialog.get_uri()); - dialog.destroy(); - - return false; - }); - }); + const website_data_manager = network_session.get_website_data_manager(); + website_data_manager.set_favicons_enabled(true); // https://gjs-docs.gnome.org/webkit240~4.0_api/webkit2.cookiemanager - const cookieManager = website_data_manager.get_cookie_manager(); + const cookieManager = network_session.get_cookie_manager(); cookieManager.set_accept_policy(CookieAcceptPolicy.NO_THIRD_PARTY); cookieManager.set_persistent_storage( build_filenamev([data_dir, "cookies.sqlite"]), @@ -200,7 +136,6 @@ export function buildWebView({ enable_back_forward_navigation_gestures: true, enable_developer_extras: true, enable_dns_prefetching: true, - enable_plugins: false, javascript_can_open_windows_automatically: true, allow_top_navigation_to_data_urls: false, }); @@ -219,6 +154,7 @@ export function buildWebView({ web_context, user_content_manager, settings, + network_session, }); // https://gjs-docs.gnome.org/webkit240~4.0_api/webkit2.webinspector @@ -264,13 +200,12 @@ export function buildWebView({ ); if (decision_type === PolicyDecisionType.NAVIGATION_ACTION) { - const navigation_type = decision.get_navigation_type(); // https://webkitgtk.org/reference/webkit2gtk/stable/WebKitNavigationAction.html const navigation_action = decision.get_navigation_action(); const request_url = navigation_action.get_request().get_uri(); console.debug( "navigation", - getEnum(WebKit2.NavigationType, navigation_type), + getEnum(WebKit2.NavigationType), request_url, ); @@ -283,6 +218,7 @@ export function buildWebView({ return false; }, + // https://webkitgtk.org/reference/webkit2gtk/stable/signal.WebView.load-changed.html // ["load-changed"](load_event) { // console.debug("load-changed", getEnum(WebKit2.LoadEvent, load_event)); // }, diff --git a/src/main.js b/src/main.js index 0aed127..7a879c0 100644 --- a/src/main.js +++ b/src/main.js @@ -1,4 +1,4 @@ -import "gi://WebKit2?version=5.0"; +import "gi://WebKit?version=6.0"; import { programInvocationName } from "system"; import GLib from "gi://GLib"; import Gio from "gi://Gio"; diff --git a/src/utils.test.js b/src/utils.test.js index 5e4c148..cb8a771 100644 --- a/src/utils.test.js +++ b/src/utils.test.js @@ -1,4 +1,4 @@ -import "gi://WebKit2?version=5.0"; +import "gi://WebKit?version=6.0"; import { isSameSite } from "./utils.js"; diff --git a/src/webapp/test.js b/src/webapp/test.js index de93983..0000818 100644 --- a/src/webapp/test.js +++ b/src/webapp/test.js @@ -1,7 +1,5 @@ -import "gi://WebKit2?version=5.0"; - +import WebKit from "gi://WebKit?version=6.0"; import GLib from "gi://GLib"; -import WebKit from "gi://WebKit2"; import Gtk from "gi://Gtk"; import Soup from "gi://Soup?version=3.0"; import { exit } from "system"; @@ -66,8 +64,9 @@ function serve(html, manifest) { } async function test(html, manifest) { + const network_session = WebKit.NetworkSession.new_ephemeral(); const webview = new WebKit.WebView({ - is_ephemeral: true, + network_session, }); const server = await setup(webview, html, manifest); diff --git a/src/webapp/webapp.js b/src/webapp/webapp.js index 6bb2bf3..b3f0c72 100644 --- a/src/webapp/webapp.js +++ b/src/webapp/webapp.js @@ -3,13 +3,9 @@ import Gdk from "gi://Gdk"; import Soup from "gi://Soup"; import GdkPixbuf from "gi://GdkPixbuf"; -const { byteArray } = imports; - -const { pixbuf_get_from_surface } = Gdk; -const { get_tmp_dir, build_filenamev } = GLib; -const { Pixbuf } = GdkPixbuf; +import { promiseTask } from "../../troll/src/util.js"; -import { promiseTask, once } from "../../troll/src/util.js"; +const { byteArray } = imports; import { getWebAppIcon, @@ -18,21 +14,17 @@ import { getWebAppURL, } from "./ephy.js"; -export function download(webview, url, destination) { - const download = webview.download_uri(url); - download.set_allow_overwrite(true); - download.set_destination(destination); - return once(download, "finished", "failed"); -} - export function runJavaScript(webview, script) { return promiseTask( webview, - "run_javascript", - "run_javascript_finish", - script, - null, - ).then((javascriptResult) => javascriptResult?.get_js_value()); + "evaluate_javascript", + "evaluate_javascript_finish", + script, // script + -1, // length + null, // world_name + null, // source_uri + null, // cancellable + ); } // FIXME: we should use troll fetch but it doesn't support reading an InputStream @@ -132,7 +124,7 @@ async function getManifestURL(webview) { } const supported_formats = (() => { - const formats = Pixbuf.get_formats(); + const formats = GdkPixbuf.Pixbuf.get_formats(); return [].concat(...formats.map((format) => format.get_mime_types())); })(); @@ -247,21 +239,14 @@ export function getFaviconAsPixbuf(webview) { const favicon = getFavicon(webview); if (!favicon) return; - const pixbuf = pixbuf_get_from_surface( - favicon, - 0, - 0, - favicon.getWidth(), - favicon.getHeight(), - ); - return pixbuf; + return Gdk.pixbuf_get_from_texture(favicon); } export function saveFavicon(webview, instance) { const favicon = getFaviconAsPixbuf(webview); if (!favicon) return null; - const path = build_filenamev([get_tmp_dir(), instance.id]); + const path = GLib.build_filenamev([GLib.get_tmp_dir(), instance.id]); if (!favicon.savev(path, "png", [], [])) return null; return path;