Bladeren bron

Merge pull request #252 from AtkinsSJ/broadcasts

Add a message broadcasting system
Eric Dubé 1 jaar geleden
bovenliggende
commit
8e553b4ee0
5 gewijzigde bestanden met toevoegingen van 88 en 1 verwijderingen
  1. 3 0
      src/IPC.js
  2. 8 1
      src/helpers.js
  3. 2 0
      src/initgui.js
  4. 61 0
      src/services/BroadcastService.js
  5. 14 0
      src/services/ThemeService.js

+ 3 - 0
src/IPC.js

@@ -105,6 +105,9 @@ window.addEventListener('message', async (event) => {
             }, '*');
             delete window.child_launch_callbacks[event.data.appInstanceID];
         }
+
+        // Send any saved broadcasts to the new app
+        globalThis.services.get('broadcast').sendSavedBroadcastsTo(event.data.appInstanceID);
     }
     //-------------------------------------------------
     // windowFocused

+ 8 - 1
src/helpers.js

@@ -722,7 +722,14 @@ window.mutate_user_preferences = function(user_preferences_delta) {
 window.update_user_preferences = function(user_preferences) {
     window.user_preferences = user_preferences;
     localStorage.setItem('user_preferences', JSON.stringify(user_preferences));
-    window.locale = user_preferences.language ?? 'en';
+    const language = user_preferences.language ?? 'en';
+    window.locale = language;
+
+    // Broadcast locale change to apps
+    const broadcastService = globalThis.services.get('broadcast');
+    broadcastService.sendBroadcast('localeChanged', {
+        language: language,
+    }, { sendToNewAppInstances: true });
 }
 
 window.sendWindowWillCloseMsg = function(iframe_element) {

+ 2 - 0
src/initgui.js

@@ -36,6 +36,7 @@ import PuterDialog from './UI/PuterDialog.js';
 import determine_active_container_parent from './helpers/determine_active_container_parent.js';
 import { ThemeService } from './services/ThemeService.js';
 import UIWindowThemeDialog from './UI/UIWindowThemeDialog.js';
+import { BroadcastService } from './services/BroadcastService.js';
 
 const launch_services = async function () {
     const services_l_ = [];
@@ -49,6 +50,7 @@ const launch_services = async function () {
         services_m_[name] = instance;
     }
 
+    register('broadcast', new BroadcastService());
     register('theme', new ThemeService());
 
     for (const [_, instance] of services_l_) {

+ 61 - 0
src/services/BroadcastService.js

@@ -0,0 +1,61 @@
+/**
+ * Copyright (C) 2024 Puter Technologies Inc.
+ *
+ * This file is part of Puter.
+ *
+ * Puter is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+import { Service } from "../definitions.js";
+
+export class BroadcastService extends Service {
+    // After a new app is launched, it will receive these broadcasts
+    #broadcastsToSendToNewAppInstances = new Map(); // name -> data
+
+    async _init() {
+        // Nothing
+    }
+
+    // Send a 'broadcast' message to all open apps, with the given name and data.
+    // If sendToNewAppInstances is true, the message will be saved, and sent to any apps that are launched later.
+    // A new saved broadcast will replace an earlier one with the same name.
+    sendBroadcast(name, data, { sendToNewAppInstances = false } = {}) {
+        $('.window-app-iframe[data-appUsesSDK=true]').each((_, iframe) => {
+            iframe.contentWindow.postMessage({
+                msg: 'broadcast',
+                name: name,
+                data: data,
+            }, '*');
+        });
+
+        if (sendToNewAppInstances) {
+            this.#broadcastsToSendToNewAppInstances.set(name, data);
+        }
+    }
+
+    // Send all saved broadcast messages to the given app instance.
+    sendSavedBroadcastsTo(appInstanceID) {
+        const iframe = $(`.window[data-element_uuid="${appInstanceID}"] .window-app-iframe[data-appUsesSDK=true]`).get(0);
+        if (!iframe) {
+            console.error(`Attempted to send saved broadcasts to app instance ${appInstanceID}, which is not using the Puter SDK`);
+            return;
+        }
+        for (const [name, data] of this.#broadcastsToSendToNewAppInstances) {
+            iframe.contentWindow.postMessage({
+                msg: 'broadcast',
+                name: name,
+                data: data,
+            }, '*');
+        }
+    }
+}

+ 14 - 0
src/services/ThemeService.js

@@ -31,7 +31,11 @@ const default_values = {
 };
 
 export class ThemeService extends Service {
+    #broadcastService;
+
     async _init () {
+        this.#broadcastService = globalThis.services.get('broadcast');
+
         this.state = {
             sat: 41.18,
             hue: 210,
@@ -113,6 +117,16 @@ export class ThemeService extends Service {
         this.root.style.setProperty('--primary-saturation', s.sat + '%');
         this.root.style.setProperty('--primary-lightness', s.lig + '%');
         this.root.style.setProperty('--primary-alpha', s.alpha);
+
+        // TODO: Should we debounce this to reduce traffic?
+        this.#broadcastService.sendBroadcast('themeChanged', {
+            palette: {
+                primaryHue: s.hue,
+                primarySaturation: s.sat + '%',
+                primaryLightness: s.lig + '%',
+                primaryAlpha: s.alpha,
+            },
+        }, { sendToNewAppInstances: true });
     }
 
     save_ () {