fwextensions / QuicKey

Jump between recent tabs in Chrome via keyboard shortcuts or a most recently used (MRU) menu.
https://fwextensions.github.io/QuicKey
219 stars 23 forks source link

Feature request: option to display UI in the middle of the page #32

Open infokiller opened 4 years ago

infokiller commented 4 years ago

Currently, the main UI is opened close to the extension bar, which may require some eye movement. It would be nice to have an option to render it in the middle of the page, similar to the Vomnibar in vimium-c:

image

I also opened https://github.com/gdh1995/vimium-c/issues/169 to support QuicKey's matching.

fwextensions commented 4 years ago

Rendering a UI within the page requires the extension to have full access to every page you visit, which I want to avoid since extensions with that permission sometimes do nefarious things with it. I suppose it could be an optional permission, that would only be asked for if the user enables the in-page UI.

The other issue is that there are some pages that extensions can't inject code into, like chrome://extensions/. I assume Vimium doesn't work on that page, for instance, while QuicKey has no problem opening on top of it:

image

infokiller commented 4 years ago

Yes, you're spot on about the complexity of this change: it needs to be an optional permission, and it will have to fall back to the current UI in special pages.

fwextensions commented 4 years ago

I created a new branch that renders the UI in a separate window, instead of in the menu. It's centered on the current window, so it doesn't require you to shift focus, but it also doesn't try to render within the web page itself, so it sidesteps all those issues. One drawback is that it's not as snappy in opening as the menu.

Let me know if you want to try it out and need pointers on loading unpacked extensions.

infokiller commented 4 years ago

Hey, sorry for the late response. I checked out the branch and tried building the extension with npm install && npm run build. However, the second step generated errors:

> QuicKey@0.0.0 build:popup /home/infokiller/src/config/QuicKey
> node build/scripts/build-popup.js

/home/infokiller/src/config/QuicKey/src/js/background/constants.js:10
        const primaryLanguage = navigator.languages[0];
                                                   ^

TypeError: Cannot read property '0' of undefined
    at /home/infokiller/src/config/QuicKey/src/js/background/constants.js:10:45

Not sure if it's related, but I'm using Linux, and I saw in a few places in the code that the assumption is either Windows or Mac. I tried to fix that error by just setting const primaryLanguage = 'en';, but then I got another error:

> QuicKey@0.0.0 build:popup /home/infokiller/src/config/QuicKey
> node build/scripts/build-popup.js

undefined:113
                        cp.windows.getCurrent()
                                   ^

TypeError: cp.windows.getCurrent is not a function
    at Object.getInitialState (eval at req.exec (/home/infokiller/src/config/QuicKey/node_modules/requirejs/bin/r.js:2620:16), <anonymous>:113:15)
fwextensions commented 4 years ago

Thanks for the detailed bug report! I guess I haven't tried running build:popup in awhile, which is only needed if something about the search box changes. The script renders the React code to a string of markup for the built extension, sort of a poor man's server-side rendering pipeline for the client. The errors you saw are because I need to add some things to the mock browser that the code accesses while rendering.

Anyway, you don't need to build anything to load the extension. Just point Chrome at the src/ directory and it should load fine, thanks to old-school RequireJS. I need to add instructions about that to the the readme.

I haven't tested on Linux or ChromeOS at all, but it seems like it works. Let me know if you see any issues. The platform-specific stuff is really just for Mac, and Windows/Linux/ChromeOS should work the same.

For the branch, you'll need to add a keyboard shortcut for the new "Open menu in popup window" option in chrome://extensions/shortcuts. That will render the UI in a popup centered on the current window. It's actually much faster than rendering the drop-down, since it's just moving the window on screen, so I think this is a fruitful direction.

infokiller commented 4 years ago

Thanks, loading from src works indeed! I'm running into issues with the pop up window, but they're probably related to my specific setup, using a tiling window manager on Linux. The window isn't really hidden, and it also refuses to be resized.

fwextensions commented 4 years ago

The not resizing is intentional for now, as the toolbar dropdown window isn't resizable, so I never handled it before.

There's no way to hide an extension window other than by minimizing it, which is quite slow on Mac. Even on Windows, there's a slight animation. But moving the window off/on-screen is instantaneous. Unfortunately, Chrome sometimes prevents the off-screen move, limiting it to 0,0. I haven't figured out the reason yet. So it may be that you're running into that bug rather than it being a window manager issue. Which WM are you using?

infokiller commented 4 years ago

i3wm

fwextensions commented 4 years ago

@infokiller I've updated the popup window branch with a new option to "hide" the popup as a tab, instead of off-screen. It's a bit slower to move it from a tab to a popup on Windows, though on a Mac, it's quite fast. Not sure how it'll be on your window manager.

When the popup is hidden, it tries to stick the tab in an unfocused Chrome window. If you only have one Chrome window, you will see the tab get removed when the popup opens, and then reinserted when it closes. But it at least won't be stuck on-screen, and it won't be left in the alt-tab stack.

image

infokiller commented 4 years ago

Thanks for following up on this! I will definitely test it once I have a chance and will report back

fwextensions commented 4 years ago

@infokiller I've made a bunch of updates to the popup window branch. There are now 4 options for hiding the popup:

image

"Hiding" the popup behind the current window works okay, and avoids the issues with trying to move windows off-screen on macOS and at least some window managers. I also brought back the option to hide it by minimizing it. One advantage is it puts the popup at the bottom of the alt-tab stack, though the minimize/unminimize animations on macOS are painfully slow, and a little slow on Windows. Not sure about your window manager.

I fixed the build issues you ran into earlier, but now it's stuck on the RequireJS packager choking on object spread syntax. I'll need to either remove those or figure out some other approach to building it.

infokiller commented 4 years ago

Thanks @fwextensions that's cool! I use QuicKey a lot and will definitely check it out.

infokiller commented 4 years ago

Just tested the updated branch. I'm supposed to use the "Open in alt-tab-style popup" keybinding, right?

One issue I ran into is that the popup window is too large and the QuicKey list is not responsive to that, which looks like this:

image

For some reason, I also can't resize the popup window: after I resize it, it automatically resizes itself back to a preset size.

I was able to work around that issue by using rules in my window manager.

The bigger issue is that non of the hiding options work well with i3:

i3 has native mechanisms to hide a window (moving it to the i3 scratchpad), which does work as with any window, but the problem is that using the "Open in alt-tab-style popup" doesn't work here. I'll try to look into it.

fwextensions commented 4 years ago

Thanks for trying it out! Yes, the "open in popup" binding opens it with the first tab focused, so you can just release the modifier key and switch to the most recent tab. The "search in popup" opens it with the search box focused. You could then press the same shortcut to move down the list.

When the popup is created, it specifies a size of 500x488. If that's not the inner size after it opens, it adjusts its size and remembers those deltas for next time. (This is because the size of the window chrome depends on the OS, UI scaling, etc.) It then remembers the outer dimensions and snaps back to those when it gets a resize event. I haven't gotten around to making it responsive since it never could be when it was in the drop-down menu.

Why it opens at twice the width, I don't know. I assume i3 is forcing it to be that size when it opens and doesn't let it resize itself. Then that size is locked in even if you try to manually resize it. Is the UI part of the popup (ignoring the blank part on the right) centered on the window where you invoked it? (Glad to see the dark mode working, though.)

In a tab: sometimes switches focus to another window

I suspect that may be due to line 265 in src/js/background/popup-window.js. You could try commenting out that if block. Could be that the extra windows.update() call is interacting badly with i3.

All the others: don't hide the window at all. It's not surprising, because i3 is a tiling window manager, and these are all options that pertain to stacking/floating WMs.

Yeah, if i3 doesn't let windows stack, then I'm not sure there's much I could do to work around it.

the problem is that using the "Open in alt-tab-style popup" doesn't work here.

You mean, once you move the popup to the scratchpad, pressing the open popup shortcut again doesn't re-show the popup? I'm guessing that i3 is overriding any window move actions by Chrome and only lets the window out if you manually move it out of the scratchpad.

infokiller commented 4 years ago

Thanks for trying it out! Yes, the "open in popup" binding opens it with the first tab focused, so you can just release the modifier key and switch to the most recent tab. The "search in popup" opens it with the search box focused. You could then press the same shortcut to move down the list.

When the popup is created, it specifies a size of 500x488. If that's not the inner size after it opens, it adjusts its size and remembers those deltas for next time. (This is because the size of the window chrome depends on the OS, UI scaling, etc.) It then remembers the outer dimensions and snaps back to those when it gets a resize event. I haven't gotten around to making it responsive since it never could be when it was in the drop-down menu.

Why it opens at twice the width, I don't know. I assume i3 is forcing it to be that size when it opens and doesn't let it resize itself. Then that size is locked in even if you try to manually resize it. Is the UI part of the popup (ignoring the blank part on the right) centered on the window where you invoked it? (Glad to see the dark mode working, though.)

I think it was centered, but I'll check again when I have more time to test it.

In a tab: sometimes switches focus to another window

I suspect that may be due to line 265 in src/js/background/popup-window.js. You could try commenting out that if block. Could be that the extra windows.update() call is interacting badly with i3.

All the others: don't hide the window at all. It's not surprising, because i3 is a tiling window manager, and these are all options that pertain to stacking/floating WMs.

Yeah, if i3 doesn't let windows stack, then I'm not sure there's much I could do to work around it.

i3 does support floating and stacking windows, but that's not the default.

the problem is that using the "Open in alt-tab-style popup" doesn't work here.

You mean, once you move the popup to the scratchpad, pressing the open popup shortcut again doesn't re-show the popup? I'm guessing that i3 is overriding any window move actions by Chrome and only lets the window out if you manually move it out of the scratchpad.

Yes, exactly, it doesn't re-show the popup. I looked into the code a bit and it seemed like it was doing the right thing (using chrome.windows to make it the focused window). I'll try to debug it to see why it doesn't work. I suspect it's related to that window being in the scratchpad which is a kind of a hidden workspace (as opposed to a regular workspace).