From d5fcf5b30357e8ed46edcde0c6ad5f0bd2c9ed00 Mon Sep 17 00:00:00 2001 From: V Date: Thu, 1 Jul 2021 02:48:26 +0200 Subject: Root commit --- README.adoc | 3 + background.js | 110 +++++++++++++++++++++++++++++++ manifest.json | 18 +++++ native | 182 +++++++++++++++++++++++++++++++++++++++++++++++++++ native-manifest.json | 7 ++ 5 files changed, 320 insertions(+) create mode 100644 README.adoc create mode 100644 background.js create mode 100644 manifest.json create mode 100755 native create mode 100644 native-manifest.json diff --git a/README.adoc b/README.adoc new file mode 100644 index 0000000..326bbb2 --- /dev/null +++ b/README.adoc @@ -0,0 +1,3 @@ += Help, I'm drowning in tabs! + +HIDIT (pronounced "hide it") is […] diff --git a/background.js b/background.js new file mode 100644 index 0000000..c1be6e4 --- /dev/null +++ b/background.js @@ -0,0 +1,110 @@ +const PROTOCOL_VERSION = 0 + +const port = browser.runtime.connectNative("hidit") + +port.onDisconnect.addListener(port => { + if (port.error) { + // TODO(V): Write a more precise error message + console.error(`Disconnected due to an error: ${port.error.message}`) + // TODO(V): Do we want to restart the application here? Do we want to kill the extension? + } +}) + +function checkVersion(version) { + if (version !== PROTOCOL_VERSION) { + console.error(`Native application protocol has an incompatible version! Wanted ${PROTOCOL_VERSION}, got ${version}`) + // TODO(V): Fatal error. Ideally we would repeat this process once a second or so, and display + // an error icon in the toolbar to alert the user, along with some information on how to solve it. + } + + port.onMessage.removeListener(checkVersion) + port.onMessage.addListener(([command, args]) => { + switch (command) { + case "console:log": console.log(...args); break + case "console:error": console.error(...args); break + default: throw new Error(`Unknown command ${command}`) + } + }) + + browser.windows.onCreated.addListener(window => { + port.postMessage(["window:create", window]) + }) + + browser.windows.onFocusChanged.addListener(windowId => { + port.postMessage(["window:focus", windowId]) + }) + + browser.windows.onRemoved.addListener(windowId => { + port.postMessage(["window:destroy", windowId]) + }) + + browser.windows.getAll().then(windows => { + port.postMessage(["init:windows", windows]) + }) + + browser.tabs.onActivated.addListener(({ windowId, tabId, previousTabId }) => { + port.postMessage(["tab:activate", [windowId, tabId, previousTabId]]) + }) + + browser.tabs.onAttached.addListener((tabId, { newWindowId, newPosition }) => { + port.postMessage(["tab:attach", [tabId, newWindowId, newPosition]]) + }) + + browser.tabs.onCreated.addListener(tab => { + port.postMessage(["tab:create", tab]) + }) + + browser.tabs.onDetached.addListener((tabId, { oldWindowId, oldPosition }) => { + port.postMessage(["tab:detach", [tabId, oldWindowId, oldPosition]]) + }) + + browser.tabs.onHighlighted.addListener(({ windowId, tabIds }) => { + port.postMessage(["tab:select", [windowId, tabIds]]) + }) + + browser.tabs.onMoved.addListener((tabId, info) => { + port.postMessage(["tab:move", [tabId, info]]) + }) + + browser.tabs.onRemoved.addListener((tabId, { windowId, isWindowClosing }) => { + port.postMessage(["tab:destroy", [tabId, windowID, isWindowClosing]]) + }) + + // Note: MDN has the following to say: + // "This event may not be relevant for or supported by browsers other than Chrome." + browser.tabs.onReplaced.addListener((newTabId, oldTabId) => { + port.postMessage(["tab:replace", [oldTabId, newTabId]]) + }) + + // TODO(V): Remove the tab parameter, it shouldn't be necessary if we're doing deltas properly + browser.tabs.onUpdated.addListener((tabId, info, tab) => { + port.postMessage(["tab:update", [tabId, info, tab]]) + }) + + browser.tabs.onZoomChange.addListener(info => { + port.postMessage(["tab:zoom", info]) + }) + + browser.tabs.query({}).then(tabs => { + port.postMessage(["init:tabs", tabs]) + }) + + browser.contextualIdentities.onCreated.addListener(({ contextualIdentity }) => { + port.postMessage(["context:create", contextualIdentity]) + }) + + browser.contextualIdentities.onRemoved.addListener(({ contextualIdentity }) => { + port.postMessage(["context:destroy", contextualIdentity]) + }) + + browser.contextualIdentities.onUpdated.addListener(({ contextualIdentity }) => { + port.postMessage(["context:update", contextualIdentity]) + }) + + browser.contextualIdentities.query({}).then(contexts => { + port.postMessage(["init:contexts", contexts]) + // TODO(V): either send over the files in resource://usercontext-content/ or vendor them + }) +} +port.onMessage.addListener(checkVersion) +port.postMessage(PROTOCOL_VERSION) diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..926b1fe --- /dev/null +++ b/manifest.json @@ -0,0 +1,18 @@ +{ + "manifest_version": 2, + + "name": "Help, I'm drowning in tabs!", + "version": "0.1", + + "browser_specific_settings": { + "gecko": { + "id": "@hidit" + } + }, + + "background": { + "scripts": [ "background.js" ] + }, + + "permissions": [ "nativeMessaging", "tabs", "contextualIdentities" ] +} diff --git a/native b/native new file mode 100755 index 0000000..e64bd6e --- /dev/null +++ b/native @@ -0,0 +1,182 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i ruby -p ruby + +require 'json' + +PROTOCOL_VERSION = 0 + +WINDOW_ID_NONE = -1 +WINDOW_ID_CURRENT = -2 +TAB_ID_NONE = -1 + +module WebExtension + class < 1024*1024 + $stdout.write([ json.length ].pack('L')) + $stdout.write(json) + $stdout.flush() + end + end +end + +module API + class <