mirror of
https://github.com/zen-browser/desktop.git
synced 2026-04-05 07:09:30 +00:00
Fix pinned tab state and favicon handling (#2853)
Fixes several issues related to pinned tab restoration and favicon display: - Ensures pinned tabs are not loaded in private windows. - Improves favicon caching and setting for pinned tabs. - Fixes an issue where the tab state was not properly restored, leading to incorrect icons and titles. - Uses base64 encoded favicon data to prevent issues with favicon loading and updates the favicon loading logic to be more robust. - Adds a call to `gBrowser._updateTabBarForPinnedTabs` to ensure the tab bar is updated correctly after restoring pinned tabs, which fixes a UI issue where the tab bar wouldn't refresh properly until interacted with. - Improves tab initialization by explicitly calling `newTab.initialize()` after restoring a pinned tab. This fixes an issue with tabs not rendering icon and label after being restored. The changes improve the reliability of pinned tab restoration and ensure that favicons are displayed correctly.
This commit is contained in:
@@ -39,7 +39,7 @@
|
||||
class ZenPinnedTabManager extends ZenPreloadedFeature {
|
||||
|
||||
init() {
|
||||
if (!this.enabled) {
|
||||
if (!this.enabled || PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
return;
|
||||
}
|
||||
this.observer = new ZenPinnedTabsObserver();
|
||||
@@ -51,7 +51,7 @@
|
||||
}
|
||||
|
||||
async initTabs() {
|
||||
if (!this.enabled) {
|
||||
if (!this.enabled || PrivateBrowsingUtils.isWindowPrivate(window)) {
|
||||
return;
|
||||
}
|
||||
await ZenPinnedTabsStorage.init();
|
||||
@@ -81,10 +81,10 @@
|
||||
// Enhance pins with favicons
|
||||
const enhancedPins = await Promise.all(pins.map(async pin => {
|
||||
try {
|
||||
const faviconData = await PlacesUtils.promiseFaviconData(pin.url);
|
||||
const image = await this.getFaviconAsBase64(pin.url);
|
||||
return {
|
||||
...pin,
|
||||
iconUrl: faviconData?.uri?.spec || null
|
||||
iconUrl: image || null
|
||||
};
|
||||
} catch(ex) {
|
||||
// If favicon fetch fails, continue without icon
|
||||
@@ -142,23 +142,30 @@
|
||||
continue; // Skip pins that already have tabs
|
||||
}
|
||||
|
||||
let newTab = gBrowser.addTrustedTab(pin.url, {
|
||||
let params = {
|
||||
skipAnimation: true,
|
||||
userContextId: pin.containerTabId || 0,
|
||||
allowInheritPrincipal: false,
|
||||
skipBackgroundNotify: true,
|
||||
userContextId: pin.containerTabId || 0,
|
||||
createLazyBrowser: true,
|
||||
skipLoad: true,
|
||||
});
|
||||
noInitialLabel: false
|
||||
};
|
||||
|
||||
// Set the favicon from cache
|
||||
if (!!pin.iconUrl) {
|
||||
// TODO: Figure out if there is a better way -
|
||||
// calling gBrowser.setIcon messes shit up and should be avoided. I think this works for now.
|
||||
newTab.setAttribute("image", pin.iconUrl);
|
||||
// Create and initialize the tab
|
||||
let newTab = gBrowser.addTrustedTab(pin.url, params);
|
||||
|
||||
// Set initial label/title
|
||||
if (pin.title) {
|
||||
gBrowser.setInitialTabTitle(newTab, pin.title);
|
||||
}
|
||||
|
||||
// Set the icon if we have it cached
|
||||
if (pin.iconUrl) {
|
||||
gBrowser.setIcon(newTab, pin.iconUrl);
|
||||
}
|
||||
|
||||
newTab.setAttribute("zen-pin-id", pin.uuid);
|
||||
gBrowser.setInitialTabTitle(newTab, pin.title);
|
||||
|
||||
if (pin.workspaceUuid) {
|
||||
newTab.setAttribute("zen-workspace-id", pin.workspaceUuid);
|
||||
@@ -168,13 +175,32 @@
|
||||
newTab.setAttribute("zen-essential", "true");
|
||||
}
|
||||
|
||||
// Initialize browser state if needed
|
||||
if (!newTab.linkedBrowser._remoteAutoRemoved) {
|
||||
let state = {
|
||||
entries: [{
|
||||
url: pin.url,
|
||||
title: pin.title,
|
||||
triggeringPrincipal_base64: E10SUtils.SERIALIZED_SYSTEMPRINCIPAL
|
||||
}],
|
||||
userContextId: pin.containerTabId || 0,
|
||||
image: pin.iconUrl
|
||||
};
|
||||
|
||||
SessionStore.setTabState(newTab, state);
|
||||
}
|
||||
|
||||
gBrowser.pinTab(newTab);
|
||||
|
||||
newTab.initialize();
|
||||
}
|
||||
|
||||
// Restore active tab
|
||||
if (!activeTab.closing) {
|
||||
gBrowser.selectedTab = activeTab;
|
||||
}
|
||||
|
||||
gBrowser._updateTabBarForPinnedTabs();
|
||||
}
|
||||
|
||||
_onPinnedTabEvent(action, event) {
|
||||
@@ -370,36 +396,51 @@
|
||||
|
||||
async _resetTabToStoredState(tab) {
|
||||
const id = tab.getAttribute("zen-pin-id");
|
||||
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pin = this._pinsCache.find(pin => pin.uuid === id);
|
||||
if (!pin) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pin) {
|
||||
const tabState = SessionStore.getTabState(tab);
|
||||
const state = JSON.parse(tabState);
|
||||
let icon = undefined;
|
||||
try {
|
||||
icon = await PlacesUtils.promiseFaviconData(pin.url);
|
||||
} catch (e) {
|
||||
console.warn("Error trying to get favicon for pinned tab", e);
|
||||
}
|
||||
const tabState = SessionStore.getTabState(tab);
|
||||
const state = JSON.parse(tabState);
|
||||
|
||||
state.entries = [{
|
||||
url: pin.url,
|
||||
title: pin.title,
|
||||
triggeringPrincipal_base64: lazy.E10SUtils.SERIALIZED_SYSTEMPRINCIPAL
|
||||
}];
|
||||
if (icon instanceof Ci.nsIURI || typeof icon === "string") {
|
||||
state.image = icon;
|
||||
} else {
|
||||
state.image = null;
|
||||
}
|
||||
state.index = 0;
|
||||
state.entries = [{
|
||||
url: pin.url,
|
||||
title: pin.title,
|
||||
triggeringPrincipal_base64: lazy.E10SUtils.SERIALIZED_SYSTEMPRINCIPAL
|
||||
}];
|
||||
|
||||
SessionStore.setTabState(tab, state);
|
||||
state.image = pin.iconUrl || null;
|
||||
state.index = 0;
|
||||
|
||||
SessionStore.setTabState(tab, state);
|
||||
}
|
||||
|
||||
async getFaviconAsBase64(pageUrl) {
|
||||
try {
|
||||
// Get the favicon data
|
||||
const faviconData = await PlacesUtils.promiseFaviconData(pageUrl);
|
||||
|
||||
// The data comes as an array buffer, we need to convert it to base64
|
||||
// First create a byte array from the data
|
||||
const array = new Uint8Array(faviconData.data);
|
||||
|
||||
// Convert to base64
|
||||
const base64String = btoa(
|
||||
Array.from(array)
|
||||
.map(b => String.fromCharCode(b))
|
||||
.join('')
|
||||
);
|
||||
|
||||
// Return as a proper data URL
|
||||
return `data:${faviconData.mimeType};base64,${base64String}`;
|
||||
} catch (ex) {
|
||||
console.error("Failed to get favicon:", ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user