@@ -6,16 +6,23 @@ import checkForZenUpdates, {
66 createWindowUpdateAnimation ,
77} from "chrome://browser/content/ZenUpdates.mjs" ;
88
9+ const ZEN_MACOS_APP_ICON_VARIANT_PREF = "zen.widget.macos.app-icon-variant" ;
10+ const ZEN_MACOS_APP_ICON_URLS = {
11+ alternate : "chrome://browser/content/zen-images/app-icons/alternate.png" ,
12+ } ;
13+
914class ZenStartup {
1015 #watermarkIgnoreElements = [ "zen-toast-container" ] ;
1116 #hasInitializedLayout = false ;
17+ #macOSAppIconDataURLs = new Map ( ) ;
1218
1319 isReady = false ;
1420 promiseInitialized = new Promise ( resolve => {
1521 this . promiseInitializedResolve = resolve ;
1622 } ) ;
1723
1824 init ( ) {
25+ this . #initMacOSAppIcon( ) ;
1926 this . openWatermark ( ) ;
2027 this . #zenInitBrowserLayout( ) ;
2128 }
@@ -69,15 +76,84 @@ class ZenStartup {
6976 }
7077 }
7178
72- observe ( aSubject , aTopic ) {
79+ observe ( aSubject , aTopic , aData ) {
7380 // This nsIObserver method allows us to defer initialization until after
7481 // this window has finished painting and starting up.
7582 if ( aTopic == "browser-delayed-startup-finished" && aSubject == window ) {
7683 Services . obs . removeObserver ( this , "browser-delayed-startup-finished" ) ;
7784 this . delayedStartupFinished ( ) ;
85+ return ;
86+ }
87+
88+ if ( aTopic == "nsPref:changed" ) {
89+ if ( aData == ZEN_MACOS_APP_ICON_VARIANT_PREF ) {
90+ void this . #applyMacOSAppIconVariant( ) ;
91+ }
7892 }
7993 }
8094
95+ #initMacOSAppIcon( ) {
96+ if ( Services . appinfo . OS != "Darwin" ) {
97+ return ;
98+ }
99+
100+ Services . prefs . addObserver ( ZEN_MACOS_APP_ICON_VARIANT_PREF , this ) ;
101+ window . addEventListener (
102+ "unload" ,
103+ ( ) => {
104+ Services . prefs . removeObserver ( ZEN_MACOS_APP_ICON_VARIANT_PREF , this ) ;
105+ } ,
106+ { once : true }
107+ ) ;
108+
109+ void this . #applyMacOSAppIconVariant( ) ;
110+ }
111+
112+ async #applyMacOSAppIconVariant( ) {
113+ const variant = Services . prefs . getStringPref (
114+ ZEN_MACOS_APP_ICON_VARIANT_PREF ,
115+ "default"
116+ ) ;
117+
118+ if ( variant == "default" ) {
119+ Services . zen . setMacOSAppIconData ( "" ) ;
120+ return ;
121+ }
122+
123+ const dataUrl = await this . #getMacOSAppIconDataUrl( variant ) ;
124+ Services . zen . setMacOSAppIconData ( dataUrl ) ;
125+ }
126+
127+ async #getMacOSAppIconDataUrl( variant ) {
128+ const iconUrl = ZEN_MACOS_APP_ICON_URLS [ variant ] ;
129+ if ( ! iconUrl ) {
130+ return "" ;
131+ }
132+
133+ let dataUrlPromise = this . #macOSAppIconDataURLs. get ( variant ) ;
134+ if ( ! dataUrlPromise ) {
135+ dataUrlPromise = this . #readImageAsDataUrl( iconUrl ) . catch ( error => {
136+ console . error ( "ZenStartup: failed to load macOS app icon variant" , error ) ;
137+ this . #macOSAppIconDataURLs. delete ( variant ) ;
138+ return "" ;
139+ } ) ;
140+ this . #macOSAppIconDataURLs. set ( variant , dataUrlPromise ) ;
141+ }
142+
143+ return dataUrlPromise ;
144+ }
145+
146+ async #readImageAsDataUrl( url ) {
147+ const response = await fetch ( url ) ;
148+ const blob = await response . blob ( ) ;
149+ return await new Promise ( ( resolve , reject ) => {
150+ const reader = new FileReader ( ) ;
151+ reader . addEventListener ( "loadend" , ( ) => resolve ( reader . result || "" ) ) ;
152+ reader . addEventListener ( "error" , ( ) => reject ( reader . error ) ) ;
153+ reader . readAsDataURL ( blob ) ;
154+ } ) ;
155+ }
156+
81157 delayedStartupFinished ( ) {
82158 gZenWorkspaces . promiseInitialized . then ( async ( ) => {
83159 await delayedStartupPromise ;
0 commit comments