Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Pinned tab state and favicon handling #2853

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 76 additions & 35 deletions src/browser/base/zen-components/ZenPinnedTabManager.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
class ZenPinnedTabManager extends ZenPreloadedFeature {

init() {
if (!this.enabled) {
if (!this.enabled || PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
}
this.observer = new ZenPinnedTabsObserver();
Expand All @@ -51,7 +51,7 @@
}

async initTabs() {
if (!this.enabled) {
if (!this.enabled || PrivateBrowsingUtils.isWindowPrivate(window)) {
return;
}
await ZenPinnedTabsStorage.init();
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
};

// Create and initialize the tab
let newTab = gBrowser.addTrustedTab(pin.url, params);

// 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);
// 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);
Expand All @@ -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) {
Expand Down Expand Up @@ -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
}];

state.image = pin.iconUrl || null;
state.index = 0;

SessionStore.setTabState(tab, state);
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;
}
}

Expand Down
Loading