Changeset View
Changeset View
Standalone View
Standalone View
extension/extension.js
Show First 20 Lines • Show All 81 Lines • ▼ Show 20 Line(s) | |||||
82 | // System | 82 | // System | ||
83 | // ------------------------------------------------------------------------ | 83 | // ------------------------------------------------------------------------ | ||
84 | // | 84 | // | ||
85 | 85 | | |||
86 | // When connecting to native host fails (e.g. not installed), we immediately get a disconnect | 86 | // When connecting to native host fails (e.g. not installed), we immediately get a disconnect | ||
87 | // event immediately afterwards. Also avoid infinite restart loop then. | 87 | // event immediately afterwards. Also avoid infinite restart loop then. | ||
88 | var receivedMessageOnce = false; | 88 | var receivedMessageOnce = false; | ||
89 | 89 | | |||
90 | var portStatus = ""; | ||||
91 | var portLastErrorMessage = undefined; | ||||
92 | | ||||
93 | function updateBrowserAction() { | ||||
94 | let enableAction = false; | ||||
95 | if (portStatus === "UNSUPPORTED_OS" || portStatus === "STARTUP_FAILED") { | ||||
96 | chrome.browserAction.setIcon({ | ||||
97 | path: { | ||||
98 | "16": "icons/plasma-disabled-16.png", | ||||
99 | "32": "icons/plasma-disabled-32.png", | ||||
100 | "48": "icons/plasma-disabled-48.png", | ||||
101 | "128": "icons/plasma-disabled-128.png" | ||||
102 | } | ||||
103 | }); | ||||
104 | enableAction = true; | ||||
105 | } | ||||
106 | | ||||
107 | if (portLastErrorMessage) { | ||||
108 | chrome.browserAction.setBadgeText({ text: "!" }); | ||||
109 | chrome.browserAction.setBadgeBackgroundColor({ color: "#da4453" }); // breeze "negative" color | ||||
110 | enableAction = true; | ||||
111 | } else { | ||||
112 | chrome.browserAction.setBadgeText({ text: "" }); | ||||
113 | } | ||||
114 | | ||||
115 | if (enableAction) { | ||||
116 | chrome.browserAction.enable(); | ||||
117 | } else { | ||||
118 | chrome.browserAction.disable(); | ||||
119 | } | ||||
120 | } | ||||
121 | updateBrowserAction(); | ||||
122 | | ||||
90 | // Check for supported platform to avoid loading it on e.g. Windows and then failing | 123 | // Check for supported platform to avoid loading it on e.g. Windows and then failing | ||
91 | // when the extension got synced to another device and then failing | 124 | // when the extension got synced to another device and then failing | ||
92 | chrome.runtime.getPlatformInfo(function (info) { | 125 | chrome.runtime.getPlatformInfo(function (info) { | ||
93 | if (!SUPPORTED_PLATFORMS.includes(info.os)) { | 126 | if (!SUPPORTED_PLATFORMS.includes(info.os)) { | ||
94 | console.log("This extension is not supported on", info.os); | 127 | console.log("This extension is not supported on", info.os); | ||
128 | portStatus = "UNSUPPORTED_OS"; | ||||
129 | updateBrowserAction(); | ||||
95 | return; | 130 | return; | ||
96 | } | 131 | } | ||
97 | 132 | | |||
98 | connectHost(); | 133 | connectHost(); | ||
99 | }); | 134 | }); | ||
100 | 135 | | |||
101 | function connectHost() { | 136 | function connectHost() { | ||
102 | port = chrome.runtime.connectNative("org.kde.plasma.browser_integration"); | 137 | port = chrome.runtime.connectNative("org.kde.plasma.browser_integration"); | ||
103 | 138 | | |||
104 | port.onMessage.addListener(function (message) { | 139 | port.onMessage.addListener(function (message) { | ||
105 | var subsystem = message.subsystem; | 140 | var subsystem = message.subsystem; | ||
106 | var action = message.action; | 141 | var action = message.action; | ||
107 | 142 | | |||
108 | let isReply = message.hasOwnProperty("replyToSerial"); | 143 | let isReply = message.hasOwnProperty("replyToSerial"); | ||
109 | let replyToSerial = message.replyToSerial; | 144 | let replyToSerial = message.replyToSerial; | ||
110 | 145 | | |||
111 | if (!isReply && (!subsystem || !action)) { | 146 | if (!isReply && (!subsystem || !action)) { | ||
112 | return; | 147 | return; | ||
113 | } | 148 | } | ||
114 | 149 | | |||
150 | if (portStatus) { | ||||
151 | portStatus = ""; | ||||
152 | updateBrowserAction(); | ||||
153 | } | ||||
154 | | ||||
115 | receivedMessageOnce = true; | 155 | receivedMessageOnce = true; | ||
116 | 156 | | |||
117 | if (isReply) { | 157 | if (isReply) { | ||
118 | let replyResolver = pendingMessageReplyResolvers[replyToSerial]; | 158 | let replyResolver = pendingMessageReplyResolvers[replyToSerial]; | ||
119 | if (replyResolver) { | 159 | if (replyResolver) { | ||
120 | replyResolver(message.payload); | 160 | replyResolver(message.payload); | ||
121 | delete pendingMessageReplyResolvers[replyToSerial]; | 161 | delete pendingMessageReplyResolvers[replyToSerial]; | ||
122 | } else { | 162 | } else { | ||
Show All 10 Lines | |||||
133 | }); | 173 | }); | ||
134 | 174 | | |||
135 | port.onDisconnect.addListener(function() { | 175 | port.onDisconnect.addListener(function() { | ||
136 | var error = chrome.runtime.lastError; | 176 | var error = chrome.runtime.lastError; | ||
137 | 177 | | |||
138 | console.warn("Host disconnected", error); | 178 | console.warn("Host disconnected", error); | ||
139 | 179 | | |||
140 | // Remove all kde connect menu entries since they won't work without a host | 180 | // Remove all kde connect menu entries since they won't work without a host | ||
181 | try { | ||||
141 | for (let device of kdeConnectDevices) { | 182 | for (let device of kdeConnectDevices) { | ||
142 | chrome.contextMenus.remove(kdeConnectMenuIdPrefix + device); | 183 | chrome.contextMenus.remove(kdeConnectMenuIdPrefix + device); | ||
143 | } | 184 | } | ||
144 | kdeConnectDevices = []; | 185 | } catch (e) { | ||
145 | 186 | console.warn("Failed to cleanup after port disconnect", e); | |||
146 | var reason = chrome.i18n.getMessage("general_error_unknown"); | | |||
147 | if (error && error.message) { | | |||
148 | reason = error.message; | | |||
149 | } | 187 | } | ||
150 | 188 | kdeConnectDevices = []; | |||
151 | var message = receivedMessageOnce ? chrome.i18n.getMessage("general_error_port_disconnect", reason) | | |||
152 | : chrome.i18n.getMessage("general_error_port_startupfail"); | | |||
153 | | ||||
154 | chrome.notifications.create(null, { | | |||
155 | type: "basic", | | |||
156 | title: chrome.i18n.getMessage("general_error_title"), | | |||
157 | message: message, | | |||
158 | iconUrl: "icons/sad-face-128.png" | | |||
159 | }); | | |||
160 | 189 | | |||
161 | if (receivedMessageOnce) { | 190 | if (receivedMessageOnce) { | ||
191 | portLastErrorMessage = error && error.message || "UNKNOWN"; | ||||
192 | portStatus = "DISCONNECTED"; | ||||
193 | | ||||
162 | console.log("Auto-restarting it"); | 194 | console.log("Auto-restarting it"); | ||
163 | connectHost(); | 195 | connectHost(); | ||
164 | } else { | 196 | } else { | ||
197 | portLastErrorMessage = ""; | ||||
198 | portStatus = "STARTUP_FAILED"; | ||||
199 | | ||||
165 | console.warn("Not auto-restarting host as we haven't received any message from it before. Check that it's working/installed correctly"); | 200 | console.warn("Not auto-restarting host as we haven't received any message from it before. Check that it's working/installed correctly"); | ||
166 | } | 201 | } | ||
202 | updateBrowserAction(); | ||||
167 | }); | 203 | }); | ||
168 | 204 | | |||
169 | sendEnvironment(); | 205 | sendEnvironment(); | ||
170 | sendSettings(); | 206 | sendSettings(); | ||
171 | sendDownloads(); | 207 | sendDownloads(); | ||
172 | } | 208 | } | ||
173 | 209 | | |||
174 | addRuntimeCallback("settings", "changed", function () { | 210 | addRuntimeCallback("settings", "changed", function () { | ||
175 | // we could also just reload our extension :) | 211 | // we could also just reload our extension :) | ||
176 | // but this also causes the settings dialog to quit | 212 | // but this also causes the settings dialog to quit | ||
177 | //chrome.runtime.reload(); | 213 | //chrome.runtime.reload(); | ||
178 | sendSettings(); | 214 | sendSettings(); | ||
179 | }); | 215 | }); | ||
180 | 216 | | |||
181 | addRuntimeCallback("settings", "openKRunnerSettings", function () { | 217 | addRuntimeCallback("settings", "openKRunnerSettings", function () { | ||
182 | sendPortMessage("settings", "openKRunnerSettings"); | 218 | sendPortMessage("settings", "openKRunnerSettings"); | ||
183 | }); | 219 | }); | ||
184 | 220 | | |||
185 | addRuntimeCallback("settings", "getSubsystemStatus", (message, sender, action) => { | 221 | addRuntimeCallback("settings", "getSubsystemStatus", (message, sender, action) => { | ||
186 | return sendPortMessageWithReply("settings", "getSubsystemStatus"); | 222 | return sendPortMessageWithReply("settings", "getSubsystemStatus"); | ||
187 | }); | 223 | }); | ||
224 | | ||||
225 | addRuntimeCallback("browserAction", "getStatus", (message) => { | ||||
226 | let info = { | ||||
227 | portStatus, | ||||
228 | portLastErrorMessage | ||||
229 | }; | ||||
230 | | ||||
231 | return Promise.resolve(info); | ||||
232 | }); | ||||
233 | | ||||
234 | addRuntimeCallback("browserAction", "ready", () => { | ||||
235 | | ||||
236 | // HACK there's no way to tell whether the browser action popup got closed | ||||
237 | // None of onunload, onbeforeunload, onvisibilitychanged are fired. | ||||
238 | // Instead, we create a port once the browser action is ready and then | ||||
239 | // listen for the port being disconnected. | ||||
240 | | ||||
241 | let browserActionPort = chrome.runtime.connect({ | ||||
242 | name: "browserActionPort" | ||||
243 | }); | ||||
244 | browserActionPort.onDisconnect.addListener((port) => { | ||||
245 | if (port.name !== "browserActionPort") { | ||||
246 | return; | ||||
247 | } | ||||
248 | | ||||
249 | // disabling the browser action immediately when opening it | ||||
250 | // causes opening to fail on Firefox, so clear the error only when it's being closed. | ||||
251 | portLastErrorMessage = ""; | ||||
252 | updateBrowserAction(); | ||||
253 | }); | ||||
254 | }); |