diff --git a/prefs/zen/sync.yaml b/prefs/zen/sync.yaml
deleted file mode 100644
index dff75e481..000000000
--- a/prefs/zen/sync.yaml
+++ /dev/null
@@ -1,12 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-- name: services.sync.engine.spaces
- value: true
- condition: "@IS_TWILIGHT@"
-
-- name: services.sync.engine.spaces
- value: false
- locked: true
- condition: "!@IS_TWILIGHT@"
diff --git a/prefs/zen/workspaces.yaml b/prefs/zen/workspaces.yaml
index dfa8b7d6c..24aaf887c 100644
--- a/prefs/zen/workspaces.yaml
+++ b/prefs/zen/workspaces.yaml
@@ -32,6 +32,9 @@
- name: zen.workspaces.scroll-modifier-key
value: ctrl
+- name: services.sync.engine.workspaces
+ value: false
+
- name: zen.workspaces.separate-essentials
value: true
diff --git a/src/browser/components/preferences/config/account-sync-mjs.patch b/src/browser/components/preferences/config/account-sync-mjs.patch
deleted file mode 100644
index ce14b3e05..000000000
--- a/src/browser/components/preferences/config/account-sync-mjs.patch
+++ /dev/null
@@ -1,20 +0,0 @@
-diff --git a/browser/components/preferences/config/account-sync.mjs b/browser/components/preferences/config/account-sync.mjs
-index b503987a08e2ce64bfc01c4e3a21e5e19ef834f0..b1c03a0b219fd3eddd93c1deaeb18ab79c85f168 100644
---- a/browser/components/preferences/config/account-sync.mjs
-+++ b/browser/components/preferences/config/account-sync.mjs
-@@ -42,6 +42,7 @@ Preferences.addAll([
- { id: "services.sync.engine.creditcards", type: "bool" },
- { id: "services.sync.engine.addons", type: "bool" },
- { id: "services.sync.engine.prefs", type: "bool" },
-+ { id: "services.sync.engine.spaces", type: "bool" },
- ]);
-
- /**
-@@ -546,6 +547,7 @@ const SYNC_ENGINE_SETTINGS = [
- type: "payments",
- },
- { id: "syncAddons", pref: "services.sync.engine.addons", type: "addons" },
-+ { id: "syncSpaces", pref: "services.sync.engine.spaces", type: "workspaces" },
- { id: "syncSettings", pref: "services.sync.engine.prefs", type: "settings" },
- ];
-
diff --git a/src/browser/components/preferences/dialogs/syncChooseWhatToSync-js.patch b/src/browser/components/preferences/dialogs/syncChooseWhatToSync-js.patch
index da89f90fb..e066aca21 100644
--- a/src/browser/components/preferences/dialogs/syncChooseWhatToSync-js.patch
+++ b/src/browser/components/preferences/dialogs/syncChooseWhatToSync-js.patch
@@ -6,7 +6,7 @@ index 64aa0d98a0622c01f3dcfff1a04bfcda368354d2..2013e04b0881ad2295d6897b91e1573c
{ id: "services.sync.engine.passwords", type: "bool" },
{ id: "services.sync.engine.addresses", type: "bool" },
{ id: "services.sync.engine.creditcards", type: "bool" },
-+ { id: "services.sync.engine.spaces", type: "bool" },
++ { id: "services.sync.engine.workspaces", type: "bool" },
]);
let gSyncChooseWhatToSync = {
diff --git a/src/browser/components/preferences/dialogs/syncChooseWhatToSync-xhtml.patch b/src/browser/components/preferences/dialogs/syncChooseWhatToSync-xhtml.patch
index 0ebce7576..3b0ab370d 100644
--- a/src/browser/components/preferences/dialogs/syncChooseWhatToSync-xhtml.patch
+++ b/src/browser/components/preferences/dialogs/syncChooseWhatToSync-xhtml.patch
@@ -20,7 +20,7 @@ index a893c5ec3d007820d98f5d92dd039640faa2c181..9cbd00102e44ccf98b37845474d92d57
+
+
+
diff --git a/src/browser/components/preferences/sync-inc-xhtml.patch b/src/browser/components/preferences/sync-inc-xhtml.patch
index 4b6e6306d..06944335a 100644
--- a/src/browser/components/preferences/sync-inc-xhtml.patch
+++ b/src/browser/components/preferences/sync-inc-xhtml.patch
@@ -6,7 +6,7 @@ index c379e1a5f82692406a92d9fcd3bca2769dfac5b2..af037dd3d995813d966524ac44a3795d
-+
++
+
+
+
diff --git a/src/external-patches/firefox/allow_backdrop_to_work_on_transparency.patch b/src/external-patches/firefox/allow_backdrop_to_work_on_transparency.patch
deleted file mode 100644
index 20ebb535c..000000000
--- a/src/external-patches/firefox/allow_backdrop_to_work_on_transparency.patch
+++ /dev/null
@@ -1,167 +0,0 @@
-diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp
---- a/gfx/webrender_bindings/WebRenderAPI.cpp
-+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
-@@ -298,11 +298,13 @@
- panic_on_gl_error, picTileWidth, picTileHeight,
- gfx::gfxVars::WebRenderRequiresHardwareDriver(),
- StaticPrefs::gfx_webrender_low_quality_pinch_zoom_AtStartup(),
- StaticPrefs::gfx_webrender_max_shared_surface_size_AtStartup(),
- StaticPrefs::gfx_webrender_enable_subpixel_aa_AtStartup(),
-- compositor->ShouldUseLayerCompositor())) {
-+ compositor->ShouldUseLayerCompositor(),
-+ StaticPrefs::
-+ gfx_webrender_opaque_backdrop_fallback_AtStartup())) {
- // wr_window_new puts a message into gfxCriticalNote if it returns
- // false
- MOZ_ASSERT(errorMessage);
- error.AssignASCII(errorMessage);
- wr_api_free_error_msg(errorMessage);
-diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs
---- a/gfx/webrender_bindings/src/bindings.rs
-+++ b/gfx/webrender_bindings/src/bindings.rs
-@@ -1998,10 +1998,11 @@
- reject_software_rasterizer: bool,
- low_quality_pinch_zoom: bool,
- max_shared_surface_size: i32,
- enable_subpixel_aa: bool,
- use_layer_compositor: bool,
-+ opaque_backdrop_fallback: bool,
- ) -> bool {
- assert!(unsafe { is_in_render_thread() });
-
- // Ensure the WR profiler callbacks are hooked up to the Gecko profiler.
- set_profiler_hooks(Some(&PROFILER_HOOKS));
-@@ -2164,10 +2165,11 @@
- texture_cache_config,
- reject_software_rasterizer,
- low_quality_pinch_zoom,
- max_shared_surface_size,
- enable_dithering,
-+ opaque_backdrop_fallback,
- ..Default::default()
- };
-
- let window_size = DeviceIntSize::new(window_width, window_height);
- let notifier = Box::new(CppNotifier { window_id });
-diff --git a/gfx/wr/webrender/src/device/gl.rs b/gfx/wr/webrender/src/device/gl.rs
---- a/gfx/wr/webrender/src/device/gl.rs
-+++ b/gfx/wr/webrender/src/device/gl.rs
-@@ -3982,10 +3982,14 @@
-
- pub fn disable_color_write(&self) {
- self.gl.color_mask(false, false, false, false);
- }
-
-+ pub fn set_color_mask(&self, r: bool, g: bool, b: bool, a: bool) {
-+ self.gl.color_mask(r, g, b, a);
-+ }
-+
- pub fn set_blend(&mut self, enable: bool) {
- if enable {
- self.gl.enable(gl::BLEND);
- } else {
- self.gl.disable(gl::BLEND);
-diff --git a/gfx/wr/webrender/src/renderer/init.rs b/gfx/wr/webrender/src/renderer/init.rs
---- a/gfx/wr/webrender/src/renderer/init.rs
-+++ b/gfx/wr/webrender/src/renderer/init.rs
-@@ -204,6 +204,8 @@
- pub low_quality_pinch_zoom: bool,
- pub max_shared_surface_size: i32,
- /// If true, open a debug socket to listen for remote debugger.
- /// Relies on `debugger` cargo feature being enabled.
- pub enable_debugger: bool,
-+ /// See explanation of `gfx.webrender.opaque-backdrop-fallback`.
-+ pub opaque_backdrop_fallback: bool,
- }
-@@ -277,9 +279,10 @@
- enable_instancing: true,
- reject_software_rasterizer: false,
- low_quality_pinch_zoom: false,
- max_shared_surface_size: 2048,
- enable_debugger: true,
-+ opaque_backdrop_fallback: false,
- }
- }
- }
-
-@@ -802,10 +805,11 @@
- allocated_native_surfaces: FastHashSet::default(),
- debug_overlay_state: DebugOverlayState::new(),
- buffer_damage_tracker: BufferDamageTracker::default(),
- max_primitive_instance_count,
- enable_instancing: options.enable_instancing,
-+ opaque_backdrop_fallback: options.opaque_backdrop_fallback,
- consecutive_oom_frames: 0,
- target_frame_publish_id: None,
- pending_result_msg: None,
- layer_compositor_frame_state_in_prev_frame: None,
- external_composite_debug_items: Vec::new(),
-diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
---- a/gfx/wr/webrender/src/renderer/mod.rs
-+++ b/gfx/wr/webrender/src/renderer/mod.rs
-@@ -867,10 +867,12 @@
- buffer_damage_tracker: BufferDamageTracker,
-
- max_primitive_instance_count: usize,
- enable_instancing: bool,
-
-+ opaque_backdrop_fallback: bool,
-+
- /// Count consecutive oom frames to detectif we are stuck unable to render
- /// in a loop.
- consecutive_oom_frames: u32,
-
- /// update() defers processing of ResultMsg, if frame_publish_id of
-@@ -2787,18 +2789,29 @@
- let read_target = ReadTarget::from_texture(cache_texture);
-
- // Should always be drawing to picture cache tiles or off-screen surface!
- debug_assert!(!draw_target.is_default());
- let device_to_framebuffer = Scale::new(1i32);
-+ let dest_fb_rect = dest * device_to_framebuffer;
-
- self.device.blit_render_target(
- read_target,
- src * device_to_framebuffer,
- draw_target,
-- dest * device_to_framebuffer,
-+ dest_fb_rect,
- TextureFilter::Linear,
- );
-+
-+ if self.opaque_backdrop_fallback {
-+ self.device.set_color_mask(false, false, false, true);
-+ self.device.clear_target(
-+ Some([0.0, 0.0, 0.0, 1.0]),
-+ None,
-+ Some(dest_fb_rect),
-+ );
-+ self.device.set_color_mask(true, true, true, true);
-+ }
- }
- }
- }
-
- fn draw_picture_cache_target(
-diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
---- a/modules/libpref/init/StaticPrefList.yaml
-+++ b/modules/libpref/init/StaticPrefList.yaml
-@@ -8439,10 +8439,17 @@
- #else
- value: false
- #endif
- mirror: once
-
-+# Make backdrop-filter treat its captured backdrop as if it had been
-+# composited over an opaque-black background. (See bug 2036640)
-+- name: gfx.webrender.opaque-backdrop-fallback
-+ type: bool
-+ value: true
-+ mirror: once
-+
- # Disable wait of GPU execution completion
- - name: gfx.webrender.wait-gpu-finished.disabled
- type: bool
- value: false
- mirror: once
-
diff --git a/src/services/sync/modules/service-sys-mjs.patch b/src/services/sync/modules/service-sys-mjs.patch
deleted file mode 100644
index daf57720d..000000000
--- a/src/services/sync/modules/service-sys-mjs.patch
+++ /dev/null
@@ -1,15 +0,0 @@
-diff --git a/services/sync/modules/service.sys.mjs b/services/sync/modules/service.sys.mjs
-index 4f4efe572909441abdd81909282936702c225621..81ab06a9414ed656b644a21b40b683f06a4f8dbf 100644
---- a/services/sync/modules/service.sys.mjs
-+++ b/services/sync/modules/service.sys.mjs
-@@ -99,6 +99,10 @@ function getEngineModules() {
- whenTrue: "ExtensionStorageEngineKinto",
- whenFalse: "ExtensionStorageEngineBridge",
- };
-+ result.Spaces = {
-+ module: "resource:///modules/zen/ZenWorkspacesSync.sys.mjs",
-+ symbol: "ZenWorkspacesEngine",
-+ };
- return result;
- }
-
diff --git a/src/toolkit/components/contextualidentity/ContextualIdentityService-sys-mjs.patch b/src/toolkit/components/contextualidentity/ContextualIdentityService-sys-mjs.patch
deleted file mode 100644
index 1b108254d..000000000
--- a/src/toolkit/components/contextualidentity/ContextualIdentityService-sys-mjs.patch
+++ /dev/null
@@ -1,37 +0,0 @@
-diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs b/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs
-index 5702ff28cc22206f5ce16584dac8a78d816562ce..3d08ecc97ce5995b30d8a4af0c33df329b428008 100644
---- a/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs
-+++ b/toolkit/components/contextualidentity/ContextualIdentityService.sys.mjs
-@@ -270,11 +270,29 @@ _ContextualIdentityService.prototype = {
- });
- },
-
-- create(name, icon, color) {
-+ create(name, icon, color, id = null) {
- this.ensureDataReady();
-
-- // Retrieve the next userContextId available.
-- let userContextId = ++this._lastUserContextId;
-+ if (id !== null) {
-+ id = typeof id == "string" ? Number(id) : id;
-+ if (!Number.isSafeInteger(id) || id <= 0) {
-+ throw new Error(`Invalid userContextId '${id}'`);
-+ }
-+ }
-+
-+ let userContextId;
-+ if (
-+ id !== null &&
-+ !this._identities.some(identity => identity.userContextId === id)
-+ ) {
-+ userContextId = id;
-+ this._lastUserContextId = Math.max(
-+ this._lastUserContextId,
-+ userContextId
-+ );
-+ } else {
-+ userContextId = ++this._lastUserContextId;
-+ }
-
- // Throw an error if the next userContextId available is invalid (the one associated to
- // MAX_USER_CONTEXT_ID is already reserved to "userContextIdInternal.webextStorageLocal", which
diff --git a/src/zen/moz.build b/src/zen/moz.build
index 4e3e80ecb..8b1426065 100644
--- a/src/zen/moz.build
+++ b/src/zen/moz.build
@@ -20,5 +20,4 @@ DIRS += [
"share",
"spaces",
"space-routing",
- "sync",
]
diff --git a/src/zen/sessionstore/ZenSessionManager.sys.mjs b/src/zen/sessionstore/ZenSessionManager.sys.mjs
index bccec81c6..39f2d0eb2 100644
--- a/src/zen/sessionstore/ZenSessionManager.sys.mjs
+++ b/src/zen/sessionstore/ZenSessionManager.sys.mjs
@@ -10,7 +10,6 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ZenLiveFoldersManager:
"resource:///modules/zen/ZenLiveFoldersManager.sys.mjs",
- ZenSyncStore: "resource:///modules/zen/ZenSyncManager.sys.mjs",
PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs",
SessionStore: "resource:///modules/sessionstore/SessionStore.sys.mjs",
SessionStartup: "resource:///modules/sessionstore/SessionStartup.sys.mjs",
@@ -610,7 +609,6 @@ export class nsZenSessionManager {
}
);
this.#collectWindowData(windows);
- lazy.ZenSyncStore.notifyAboutChanges();
// This would save the data to disk asynchronously or when quitting the app.
let sidebar = this.#sidebarWithoutCloning;
this.#file.data = sidebar;
@@ -624,15 +622,6 @@ export class nsZenSessionManager {
this.log(`Saving Zen session data with ${sidebar.tabs?.length || 0} tabs`);
}
- /**
- * Returns the sidebar data object.
- *
- * @returns {object}
- */
- getSidebarData() {
- return this.#sidebarWithoutCloning;
- }
-
/**
* Called when the last known backup should be deleted and a new one
* created. This uses the #deferredBackupTask to debounce clusters of
diff --git a/src/zen/spaces/ZenSpaceManager.mjs b/src/zen/spaces/ZenSpaceManager.mjs
index 78d990899..beae4b055 100644
--- a/src/zen/spaces/ZenSpaceManager.mjs
+++ b/src/zen/spaces/ZenSpaceManager.mjs
@@ -11,7 +11,6 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
- ZenSyncStore: "resource:///modules/zen/ZenSyncManager.sys.mjs",
});
ChromeUtils.defineLazyGetter(lazy, "browserBackgroundElement", () => {
@@ -149,7 +148,7 @@ class nsZenWorkspaces {
if (!this.privateWindowOrDisabled) {
const observerFunction = async () => {
delete this._workspaceBookmarksCache;
- await this.#initializeWorkspaceBookmarks();
+ await this.workspaceBookmarks();
this._invalidateBookmarkContainers();
};
Services.obs.addObserver(observerFunction, "workspace-bookmarks-updated");
@@ -169,63 +168,6 @@ class nsZenWorkspaces {
}
}
- /**
- * Applies live sync changes: updates workspace cache, removes deleted items,
- * then creates/updates pulled items.
- *
- * @param {{ spaces: Array}} pulled Reconcile-pulled items.
- * @param {{ spaces: Array}} removals Items to remove.
- */
- async _applySyncChanges(pulled, removals = {}) {
- if (!this.shouldHaveWorkspaces || this.privateWindowOrDisabled) {
- return;
- }
- await this.promiseInitialized;
-
- // 1. Update workspace cache (remove deleted, merge pulled)
- const removedSpaceIds = new Set((removals.spaces || []).map(s => s.uuid));
- if (removedSpaceIds.size || pulled.spaces?.length) {
- const localMap = new Map(
- this.getWorkspaces()
- .filter(w => !removedSpaceIds.has(w.uuid))
- .map(w => [w.uuid, w])
- );
- for (const space of pulled.spaces || []) {
- if (!space?.uuid) {
- continue;
- }
- const existing = localMap.get(space.uuid);
- localMap.set(space.uuid, existing ? { ...existing, ...space } : space);
- }
- await this.propagateWorkspaces(
- this.#getOrderedWorkspacesByPosition(Array.from(localMap.values()))
- );
- this.#propagateWorkspaceData();
- }
- }
-
- #getOrderedWorkspacesByPosition(workspaces) {
- return [...workspaces]
- .map((workspace, index) => ({ workspace, index }))
- .sort((a, b) => {
- const aPosition =
- typeof a.workspace.position === "number"
- ? a.workspace.position
- : a.index;
- const bPosition =
- typeof b.workspace.position === "number"
- ? b.workspace.position
- : b.index;
- return aPosition - bPosition || a.index - b.index;
- })
- .map(({ workspace }) => {
- // strip the position property that comes from pulled workspaces
- const rest = { ...workspace };
- delete rest.position;
- return rest;
- });
- }
-
#afterLoadInit() {
const onResize = (...args) => {
requestAnimationFrame(() => {
@@ -752,17 +694,17 @@ class nsZenWorkspaces {
return spacesForSS;
}
- async #initializeWorkspaceBookmarks() {
+ async workspaceBookmarks() {
if (this.privateWindowOrDisabled) {
this._workspaceBookmarksCache = {
bookmarks: [],
lastChangeTimestamp: 0,
};
- return;
+ return this._workspaceBookmarksCache;
}
if (this._workspaceBookmarksCache) {
- return;
+ return this._workspaceBookmarksCache;
}
const [bookmarks, lastChangeTimestamp] = await Promise.all([
@@ -771,6 +713,8 @@ class nsZenWorkspaces {
]);
this._workspaceBookmarksCache = { bookmarks, lastChangeTimestamp };
+
+ return this._workspaceCache;
}
restoreWorkspacesFromSessionStore(aWinData = {}) {
@@ -830,7 +774,7 @@ class nsZenWorkspaces {
return (async () => {
await this.#waitForPromises();
this.#afterLoadInit();
- await this.#initializeWorkspaceBookmarks();
+ await this.workspaceBookmarks();
await this.changeWorkspace(activeWorkspace, { onInit: true });
this.#fixTabPositions();
this.onWindowResize();
@@ -856,13 +800,6 @@ class nsZenWorkspaces {
})();
}
- #markWorkspaceChanged(workspaceId) {
- lazy.ZenSyncStore.markItemChanged({
- type: "space",
- id: workspaceId,
- });
- }
-
async selectStartPage() {
if (!this.workspaceEnabled || gZenUIManager.testingEnabled) {
return;
@@ -1283,19 +1220,12 @@ class nsZenWorkspaces {
} else {
workspacesData.push(workspaceData);
}
- // mark item as changed for sync
- this.#markWorkspaceChanged(workspaceData.uuid);
-
this.#propagateWorkspaceData();
}
removeWorkspace(windowID) {
let { promise, resolve } = Promise.withResolvers();
this.#deleteWorkspaceOwnedTabs(windowID);
-
- // mark item as changed for sync
- this.#markWorkspaceChanged(windowID);
-
let workspacesData = this.getWorkspaces();
// Remove the workspace from the cache
workspacesData = workspacesData.filter(
@@ -1427,50 +1357,30 @@ class nsZenWorkspaces {
if (this.privateWindowOrDisabled) {
return;
}
- const workspaces = this.getWorkspaces();
- // Track previous positions so we only notify observers for workspaces whose
- // position changed during the reorder.
- const previousPositions = new Map(
- workspaces.map((workspace, index) => [workspace.uuid, index])
- );
-
+ const workspaces = this._workspaceCache;
const workspace = workspaces.find(w => w.uuid === id);
if (!workspace) {
console.warn(`Workspace with ID ${id} not found for reordering.`);
return;
}
-
// Remove the workspace from its current position
const currentIndex = workspaces.indexOf(workspace);
if (currentIndex === -1) {
console.warn(`Workspace with ID ${id} not found in the list.`);
return;
}
-
+ workspaces.splice(currentIndex, 1);
// Insert the workspace at the new position
- if (newPosition < 0 || newPosition >= workspaces.length) {
+ if (newPosition < 0 || newPosition > workspaces.length) {
console.warn(
`Invalid position ${newPosition} for reordering workspace with ID ${id}.`
);
return;
}
-
- workspaces.splice(currentIndex, 1);
workspaces.splice(newPosition, 0, workspace);
-
// Propagate the changes if the order has changed
if (currentIndex !== newPosition) {
- this._workspaceCache = workspaces;
-
- for (const [i, ws] of workspaces.entries()) {
- if (previousPositions.get(ws.uuid) === i) {
- continue;
- }
- // mark item as changed for sync
- this.#markWorkspaceChanged(ws.uuid);
- }
-
- this.#propagateWorkspaceData(workspaces);
+ this.#propagateWorkspaceData();
}
}
@@ -2443,7 +2353,7 @@ class nsZenWorkspaces {
for (const tab of gBrowser.tabs) {
if (
!tab.hasAttribute("zen-workspace-id") &&
- !tab.hasAttribute("zen-essential")
+ !tab.hasAttribute("zen-workspace-id")
) {
tab.setAttribute("zen-workspace-id", workspace.uuid);
}
diff --git a/src/zen/sync/ZenSyncManager.sys.mjs b/src/zen/sync/ZenSyncManager.sys.mjs
deleted file mode 100644
index 1b454da81..000000000
--- a/src/zen/sync/ZenSyncManager.sys.mjs
+++ /dev/null
@@ -1,160 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-const lazy = {};
-
-ChromeUtils.defineESModuleGetters(lazy, {
- ZenSessionStore: "resource:///modules/zen/ZenSessionManager.sys.mjs",
- ContextualIdentityService:
- "resource://gre/modules/ContextualIdentityService.sys.mjs",
- ZenWindowSync: "resource:///modules/zen/ZenWindowSync.sys.mjs",
-});
-
-function normalizeUserContextId(value) {
- const normalized = typeof value === "string" ? Number(value) : value;
- if (!Number.isSafeInteger(normalized) || normalized <= 0) {
- return null;
- }
- return normalized;
-}
-
-class ZenSyncManager {
- getSidebarData() {
- return lazy.ZenSessionStore.getSidebarData();
- }
-
- /**
- * Whether to ignore changes to items. This is used to prevent
- * infinite loops when applying incoming sync changes.
- *
- * @type {boolean}
- */
- #ignoreChanges = false;
-
- #changedItems = new Map();
-
- markItemChanged(item) {
- if (item.type && item.id && !this.#ignoreChanges) {
- const key = `${item.type}~${item.id}`;
- this.#changedItems.set(key, { type: item.type, id: item.id });
- }
- }
-
- #getChangedItems() {
- return Array.from(this.#changedItems.values());
- }
-
- #clearChangedItems() {
- this.#changedItems.clear();
- }
-
- notifyAboutChanges() {
- const changedItems = this.#getChangedItems();
-
- for (const item of changedItems) {
- Services.obs.notifyObservers(
- { wrappedJSObject: item },
- "zen-workspace-item-changed"
- );
- }
- this.#clearChangedItems();
- }
-
- async applyIncomingBatch(pulled, removals) {
- try {
- this.#ignoreChanges = true;
- this.#applyIncomingContainers(
- pulled.containers || [],
- removals.containers || []
- );
-
- const win = lazy.ZenWindowSync.firstSyncedWindow;
- if (win?.gZenWorkspaces) {
- await win.gZenWorkspaces._applySyncChanges(pulled, removals);
- }
- } catch (e) {
- console.error("ZenSyncManager: Failed to apply incoming sync data:", e);
- throw e;
- } finally {
- this.#ignoreChanges = false;
- }
- }
-
- #applyIncomingContainers(pulledContainers, removedContainers) {
- const localContainersById = new Map(
- lazy.ContextualIdentityService.getPublicIdentities().map(container => [
- container.userContextId,
- container,
- ])
- );
-
- for (const container of pulledContainers) {
- if (!container.name) {
- continue;
- }
-
- const userContextId = normalizeUserContextId(container.userContextId);
- if (userContextId === null) {
- console.warn(
- "ZenSyncManager: Ignoring incoming container with invalid userContextId",
- { container }
- );
- continue;
- }
-
- const existsLocally = localContainersById.has(userContextId);
-
- if (existsLocally) {
- lazy.ContextualIdentityService.update(
- userContextId,
- container.name,
- container.icon,
- container.color
- );
- continue;
- }
-
- const createdIdentity = lazy.ContextualIdentityService.create(
- container.name,
- container.icon,
- container.color,
- userContextId
- );
- if (createdIdentity) {
- localContainersById.set(createdIdentity.userContextId, createdIdentity);
- }
- if (createdIdentity && createdIdentity.userContextId !== userContextId) {
- console.warn("ZenSyncManager: Container sync created unexpected ID", {
- requestedId: userContextId,
- createdId: createdIdentity.userContextId,
- name: container.name,
- });
- }
- }
-
- for (const container of removedContainers) {
- const userContextId = normalizeUserContextId(container.userContextId);
- if (userContextId === null) {
- console.warn(
- "ZenSyncManager: Ignoring container removal with invalid userContextId",
- { container }
- );
- continue;
- }
-
- if (!localContainersById.has(userContextId)) {
- continue;
- }
-
- try {
- lazy.ContextualIdentityService.remove(userContextId);
- localContainersById.delete(userContextId);
- } catch {
- // Container may already be gone locally.
- }
- }
- }
-}
-
-export const ZenSyncStore = new ZenSyncManager();
diff --git a/src/zen/sync/ZenWorkspacesSync.sys.mjs b/src/zen/sync/ZenWorkspacesSync.sys.mjs
deleted file mode 100644
index 0b0946ed4..000000000
--- a/src/zen/sync/ZenWorkspacesSync.sys.mjs
+++ /dev/null
@@ -1,404 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-import {
- Store,
- SyncEngine,
- Tracker,
-} from "resource://services-sync/engines.sys.mjs";
-import { CryptoWrapper } from "resource://services-sync/record.sys.mjs";
-import { SCORE_INCREMENT_XLARGE } from "resource://services-sync/constants.sys.mjs";
-
-const lazy = {};
-
-ChromeUtils.defineESModuleGetters(lazy, {
- ZenSyncStore: "resource:///modules/zen/ZenSyncManager.sys.mjs",
- ContextualIdentityService:
- "resource://gre/modules/ContextualIdentityService.sys.mjs",
-});
-
-const RECORD_ID_PREFIX_BY_TYPE = Object.freeze({
- space: "s",
- container: "c",
-});
-
-const RECORD_TYPE_BY_PREFIX = Object.freeze({
- s: "space",
- c: "container",
-});
-
-/**
- * Sync record wrapper for workspace and container items stored in the
- * Workspaces engine collection.
- */
-export class ZenWorkspacesRecord extends CryptoWrapper {
- _logName = "Sync.Record.ZenSpaces";
-}
-
-ZenWorkspacesRecord.prototype.type = "spaces";
-
-function parseRecordId(id) {
- const sep = id.indexOf("~");
- if (sep === -1) {
- return null;
- }
- const prefix = id.slice(0, sep);
- const key = id.slice(sep + 1);
- return { type: RECORD_TYPE_BY_PREFIX[prefix] || prefix, key };
-}
-
-function createRecordId(type, id) {
- const prefix = RECORD_ID_PREFIX_BY_TYPE[type];
- if (!prefix) {
- throw new Error(`Unknown Spaces Sync record type: ${type}`);
- }
- return `${prefix}~${id}`;
-}
-
-function normalizeUserContextId(value) {
- const normalized = typeof value === "string" ? Number(value) : value;
- if (!Number.isSafeInteger(normalized) || normalized <= 0) {
- return null;
- }
- return normalized;
-}
-
-/**
- * Strips the sync-envelope fields (`id` and `type`) from incoming record data
- * and restores the item's real identity key where needed
- *
- * @param {object} data
- */
-function stripSyncFields(data) {
- const rest = { ...data };
- delete rest.id;
- delete rest.type;
- return rest;
-}
-
-/**
- * Sync store implementation that serializes local workspace and container
- * state into records and applies incoming remote changes.
- */
-class ZenWorkspacesStore extends Store {
- constructor(name, engine) {
- super(name, engine);
- }
-
- async getAllIDs() {
- const ids = {};
- const sidebar = lazy.ZenSyncStore.getSidebarData();
-
- for (const space of sidebar.spaces || []) {
- if (space.uuid) {
- ids[createRecordId("space", space.uuid)] = true;
- }
- }
-
- for (const c of lazy.ContextualIdentityService.getPublicIdentities()) {
- ids[createRecordId("container", c.userContextId)] = true;
- }
-
- return ids;
- }
-
- async itemExists(id) {
- const parsed = parseRecordId(id);
- if (!parsed) {
- return false;
- }
- const sidebar = lazy.ZenSyncStore.getSidebarData();
-
- switch (parsed.type) {
- case "space":
- return (sidebar.spaces || []).some(s => s.uuid === parsed.key);
- case "container":
- return lazy.ContextualIdentityService.getPublicIdentities().some(
- c => String(c.userContextId) === parsed.key
- );
- default:
- return false;
- }
- }
-
- async createRecord(id, collection) {
- const record = new ZenWorkspacesRecord(collection, id);
- const parsed = parseRecordId(id);
- if (!parsed) {
- record.deleted = true;
- return record;
- }
-
- const sidebar = lazy.ZenSyncStore.getSidebarData();
-
- switch (parsed.type) {
- case "space": {
- const spaces = sidebar.spaces || [];
- const idx = spaces.findIndex(s => s.uuid === parsed.key);
- if (idx === -1) {
- record.deleted = true;
- return record;
- }
- const rest = { ...spaces[idx] };
- delete rest.syncStatus;
- record.cleartext = { id, type: "space", ...rest, position: idx };
- break;
- }
-
- case "container": {
- const container =
- lazy.ContextualIdentityService.getPublicIdentities().find(
- c => String(c.userContextId) === parsed.key
- );
- if (!container) {
- record.deleted = true;
- return record;
- }
- record.cleartext = {
- id,
- type: "container",
- userContextId: container.userContextId,
- name: container.name,
- icon: container.icon,
- color: container.color,
- };
- break;
- }
-
- default:
- record.deleted = true;
- }
-
- return record;
- }
-
- async applyIncomingBatch(records, _countTelemetry) {
- const pulled = { spaces: [], containers: [] };
- const removals = { spaces: [], containers: [] };
-
- for (const record of records) {
- if (record.deleted) {
- this._collectRemoval(record.id, removals);
- continue;
- }
- const data = record.cleartext;
- if (!data?.type) {
- continue;
- }
- const clean = stripSyncFields(data);
- switch (data.type) {
- case "space":
- pulled.spaces.push(clean);
- break;
- case "container":
- pulled.containers.push(clean);
- break;
- }
- }
-
- // Suppress change tracking while applying incoming data to prevent
- // feedback loops where applied items get re-uploaded immediately.
- this.engine._tracker.ignoreAll = true;
- try {
- await lazy.ZenSyncStore.applyIncomingBatch(pulled, removals);
- } finally {
- this.engine._tracker.ignoreAll = false;
- }
- return [];
- }
-
- _collectRemoval(id, removals) {
- const parsed = parseRecordId(id);
- if (!parsed) {
- return;
- }
- switch (parsed.type) {
- case "space":
- removals.spaces.push({ uuid: parsed.key });
- break;
- case "container": {
- const userContextId = normalizeUserContextId(parsed.key);
- if (userContextId === null) {
- console.warn(
- "ZenWorkspacesStore: Ignoring container removal with invalid userContextId",
- { id }
- );
- break;
- }
- removals.containers.push({ userContextId });
- break;
- }
- }
- }
-
- async create(record) {
- await this._applySingle(record);
- }
-
- async update(record) {
- await this._applySingle(record);
- }
-
- async _applySingle(record) {
- this.engine._tracker.ignoreAll = true;
- try {
- if (record.deleted) {
- const removals = { spaces: [], containers: [] };
- this._collectRemoval(record.id, removals);
- await lazy.ZenSyncStore.applyIncomingBatch(
- { spaces: [], containers: [] },
- removals
- );
- return;
- }
- const data = record.cleartext;
- if (!data?.type) {
- return;
- }
- const clean = stripSyncFields(data);
- const pulled = { spaces: [], containers: [] };
- switch (data.type) {
- case "space":
- pulled.spaces.push(clean);
- break;
- case "container":
- pulled.containers.push(clean);
- break;
- }
- await lazy.ZenSyncStore.applyIncomingBatch(pulled, {
- spaces: [],
- containers: [],
- });
- } finally {
- this.engine._tracker.ignoreAll = false;
- }
- }
-
- async remove() {
- // No-op: never delete user data on wipe
- }
-
- async wipe() {
- // No-op: never delete user data on wipe
- }
-
- changeItemID() {
- // No-op
- }
-}
-
-/**
- * Sync tracker that watches workspace and contextual identity observers and
- * marks the corresponding record IDs as changed.
- */
-class ZenWorkspacesTracker extends Tracker {
- #changedIDs = {};
- #ignoreAll = false;
-
- get ignoreAll() {
- return this.#ignoreAll;
- }
-
- set ignoreAll(value) {
- this.#ignoreAll = value;
- }
-
- onStart() {
- Services.obs.addObserver(this, "zen-workspace-item-changed");
- Services.obs.addObserver(this, "contextual-identity-created");
- Services.obs.addObserver(this, "contextual-identity-updated");
- Services.obs.addObserver(this, "contextual-identity-deleted");
- }
-
- onStop() {
- Services.obs.removeObserver(this, "zen-workspace-item-changed");
- Services.obs.removeObserver(this, "contextual-identity-created");
- Services.obs.removeObserver(this, "contextual-identity-updated");
- Services.obs.removeObserver(this, "contextual-identity-deleted");
- }
-
- observe(subject, topic, _data) {
- if (this.#ignoreAll) {
- return;
- }
- if (topic === "zen-workspace-item-changed") {
- const type = subject?.wrappedJSObject?.type;
- const id = subject?.wrappedJSObject?.id;
- if (type && id) {
- this._trackChange({ type, id });
- }
- } else if (topic.startsWith("contextual-identity-")) {
- const id = subject?.wrappedJSObject?.userContextId;
- if (id && normalizeUserContextId(id) !== null) {
- this._trackChange({ type: "container", id });
- }
- }
- }
-
- _trackChange(data) {
- if (data.type && data.id) {
- const id = createRecordId(data.type, data.id);
- this.#changedIDs[id] = Date.now() / 1000;
- this.score += SCORE_INCREMENT_XLARGE;
- }
- }
-
- async getChangedIDs() {
- return { ...this.#changedIDs };
- }
-
- async addChangedID(id, when) {
- this.#changedIDs[id] = when;
- return true;
- }
-
- async removeChangedID(...ids) {
- for (const id of ids) {
- delete this.#changedIDs[id];
- }
- return true;
- }
-
- clearChangedIDs() {
- this.#changedIDs = {};
- }
-}
-
-/**
- * Sync engine entrypoint that wires the Workspaces record, store, and tracker
- * implementations into Firefox Sync.
- */
-export class ZenWorkspacesEngine extends SyncEngine {
- static get name() {
- return "Spaces";
- }
-
- constructor(service) {
- super("Spaces", service);
- }
-
- get _storeObj() {
- return ZenWorkspacesStore;
- }
-
- get _trackerObj() {
- return ZenWorkspacesTracker;
- }
-
- get _recordObj() {
- return ZenWorkspacesRecord;
- }
-
- get version() {
- return 2;
- }
-
- get syncPriority() {
- return 8;
- }
-
- get allowSkippedRecord() {
- return false;
- }
-}
diff --git a/src/zen/sync/moz.build b/src/zen/sync/moz.build
deleted file mode 100644
index d10ad7a19..000000000
--- a/src/zen/sync/moz.build
+++ /dev/null
@@ -1,8 +0,0 @@
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-EXTRA_JS_MODULES.zen += [
- "ZenSyncManager.sys.mjs",
- "ZenWorkspacesSync.sys.mjs",
-]
diff --git a/tools/ffprefs/src/main.rs b/tools/ffprefs/src/main.rs
index 20724730d..ac11c8e5b 100644
--- a/tools/ffprefs/src/main.rs
+++ b/tools/ffprefs/src/main.rs
@@ -346,17 +346,6 @@ fn expand_pref_values(prefs: &mut [Preference]) {
}
pref.value = new_value.clone();
}
- // Also change the condition if it contains placeholders
- if let Some(condition) = &pref.condition {
- let mut new_condition = condition.clone();
- for (key, value) in &env_values {
- let placeholder = format!("@{}@", key);
- if new_condition.contains(&placeholder) {
- new_condition = new_condition.replace(&placeholder, if *value { "1" } else { "0" });
- }
- pref.condition = Some(new_condition.clone());
- }
- }
}
}