From 8da862ac6f1ab395082654f8a04a208ce3e1881c Mon Sep 17 00:00:00 2001 From: Simon Lydell Date: Sat, 21 May 2022 18:08:44 +0200 Subject: [PATCH] Add hidden option for preferring windows over tabs See #54. --- src/background/Program.ts | 54 ++++++++++++++++++++++++++++++++++----- src/options/Tweakable.tsx | 23 +++++++++++++++++ src/shared/tweakable.ts | 32 ++++++++++++++++++++++- 3 files changed, 101 insertions(+), 8 deletions(-) diff --git a/src/background/Program.ts b/src/background/Program.ts index e359feb..9ba343c 100644 --- a/src/background/Program.ts +++ b/src/background/Program.ts @@ -61,7 +61,7 @@ import { TabsPerf, TimeTracker, } from "../shared/perf"; -import { tweakable, unsignedInt } from "../shared/tweakable"; +import { bool, tweakable, unsignedInt } from "../shared/tweakable"; type MessageInfo = { tabId: number; @@ -171,6 +171,11 @@ export const t = { // How long a matched/activated hint should show as highlighted. MATCH_HIGHLIGHT_DURATION: unsignedInt(200), // ms + + // For people with tiling window managers who exclusively use windows rather + // than tabs. This changes basically everything that deals with tabs to + // instead deal with windows. + PREFER_WINDOWS: bool(false), }; export const tMeta = tweakable("Background", t); @@ -686,7 +691,9 @@ export default class BackgroundProgram { case "OpenNewTabs": if (BROWSER === "firefox") { fireAndForget( - openNewTabs(info.tabId, message.urls), + t.PREFER_WINDOWS.value + ? openNewWindows(message.urls) + : openNewTabs(info.tabId, message.urls), "BackgroundProgram#onWorkerMessage->openNewTabs", message, info @@ -1195,7 +1202,18 @@ export default class BackgroundProgram { // downside of using the fake ctrl-click method in Chrome. In fact, there’s // even an upside to the ctrl-click method: The HTTP Referer header is sent, // just as if you had clicked the link for real. See: . - if (BROWSER === "chrome") { + if (t.PREFER_WINDOWS.value) { + fireAndForget( + browser.windows + .create({ + focused: foreground, + url, + }) + .then(() => undefined), + "BackgroundProgram#openNewTab (PREFER_WINDOWS)", + url + ); + } else if (BROWSER === "chrome") { this.sendWorkerMessage( { type: "OpenNewTab", @@ -2244,10 +2262,17 @@ export default class BackgroundProgram { async maybeOpenTutorial(): Promise { const { tutorialShown } = await browser.storage.local.get("tutorialShown"); if (tutorialShown !== true) { - await browser.tabs.create({ - active: true, - url: META_TUTORIAL, - }); + if (t.PREFER_WINDOWS.value) { + await browser.windows.create({ + focused: true, + url: META_TUTORIAL, + }); + } else { + await browser.tabs.create({ + active: true, + url: META_TUTORIAL, + }); + } await browser.storage.local.set({ tutorialShown: true }); } } @@ -2483,6 +2508,21 @@ async function openNewTabs(tabId: number, urls: Array): Promise { } } +// Open a bunch of windows, and then focus the first of them. +async function openNewWindows(urls: Array): Promise { + const newWindows = await Promise.all( + urls.map((url) => + browser.windows.create({ + focused: urls.length === 1, + url, + }) + ) + ); + if (newWindows.length >= 2 && newWindows[0].id !== undefined) { + await browser.windows.update(newWindows[0].id, { focused: true }); + } +} + type IconType = "disabled" | "normal"; function getIcons(type: IconType): Record { diff --git a/src/options/Tweakable.tsx b/src/options/Tweakable.tsx index a11369b..44d582d 100644 --- a/src/options/Tweakable.tsx +++ b/src/options/Tweakable.tsx @@ -142,6 +142,29 @@ function TweakableField({ }; switch (value.type) { + case "Bool": + if (defaultValue.type === "Bool") { + return ( + ( + + )} + /> + ); + } + break; + case "UnsignedInt": if (defaultValue.type === "UnsignedInt") { return ( diff --git a/src/shared/tweakable.ts b/src/shared/tweakable.ts index 2502815..711d47e 100644 --- a/src/shared/tweakable.ts +++ b/src/shared/tweakable.ts @@ -1,4 +1,11 @@ -import { array, chain, Decoder, DecoderError, string } from "tiny-decoders"; +import { + array, + boolean, + chain, + Decoder, + DecoderError, + string, +} from "tiny-decoders"; import { ElementType } from "./hints"; import { @@ -11,6 +18,11 @@ import { } from "./main"; import { DEBUG_PREFIX } from "./options"; +type Bool = { + type: "Bool"; + value: boolean; +}; + type UnsignedInt = { type: "UnsignedInt"; value: number; @@ -42,6 +54,7 @@ type Regex = { }; export type TweakableValue = + | Bool | ElementTypeSet | Regex | SelectorString @@ -60,6 +73,13 @@ export type TweakableMeta = { unlisten: () => void; }; +export function bool(value: boolean): Bool { + return { + type: "Bool", + value, + }; +} + export function unsignedInt(value: number): UnsignedInt { return { type: "UnsignedInt", @@ -132,6 +152,16 @@ export function tweakable( } switch (original.type) { + case "Bool": { + const decoded = decode(boolean, value); + mapping[key] = { + type: "Bool", + value: decoded, + }; + changed[key] = decoded !== original.value; + break; + } + case "UnsignedInt": { const decoded = decode(UnsignedInt, value); mapping[key] = {