Addon migration - FF Windows icon(s)

Hi,

a few years ago, I created an addon to change the windows icons of Firefox (main_window, Downloads, Places, …). Some context at the end of the post, if needed.
The addon is now flagged as legacy (on Quantum), and I need help as I really don’t know where to start to update it !
The addon hierarchy is exactly like that, no other files:

[chrome]
  [icons]
    [default]
      devtools-toolbox-window.ico
      devtools-webconsole.ico
      JSConsoleWindow.ico
      main-window.ico
      places.ico
      viewSource.ico
install.rdf
(LICENSE+README)

My “install.rdf” looks like a standard one. It has type=2, unpack=true (req. for icon files), multiprocessCompatible=true.
It doesn’t really matter that windows inside the same firefox profile may be changed, I’m using the same icon for all windows anyway, but I really need each FF profile to display its own windows icon.
What should I do to upgrade this add-on ? Or what’s the new way of doing this ?

Thanks !

Context: I wrote this addon because I’m heavily using Firefox Profiles (via firefox -p -no-remote). I have 20+ of them and rarely less than two running at the same time, each with one or several windows.
To avoid my taskbar being filled by only foxes, the addon allows for example to have an enveloppe for my “mail” profile, a TV icon for my “streaming/videos” profile, and so on. When I want to open a mailbox, I know I have to search for the enveloppe icon, not read all the FF icons.
BTW, would that be possible now to adapt the browser main_window icon to reflect the website’s favicon ? I know it was impossible before (too OS-tied IIRC). But that would be cool.

Well, first of, this is not at all supported by WebExtensions and very very most likely never will be.

That leaves you with one option: native messaging.

If you want to go down that road, I believe the easiest way to make it work is to use https://github.com/NiklasGollenstede/native-ext.

Two more things that aren’t documented very well yet:
require('browser').pid gives you the pid of the current Firefox main process which you will most likely need to use ffi = require('ffi') to use some winAPI to change the windows taskbar icons.

Well, I should have mentionned I’m no addon dev at all. I just reproduced some behaviour of a now defunct add-on (named “window-icon-changer” iirc), and packed into one.
If I get you right, I have to move from an addon with zero code to a full blown one ? Because I needed no JS files at all to make this work. An install.rdf, a few icons in a special file tree, that’s all.
Also, I’ve now read what native messaging is, but the thing is, I need the extension to talk to the -current- FF processes (multiprocessFF==several PIDs). So the listener must be FF itself.
A few questions arise:

  • wouldn’t just converting the install.rdf file to a manifest.json file wouldn’t be sufficient ? Would the icons be used ?
  • how is FF handling this “chrome->icons->default” tree, and the icons ?
  • I quote you from the readme: “WebExtensions […] can send JSON-messages […] if the target applications are explicitly designed for it”. Is FF designed to receive such messages ? If yes, where/what should I look for ?

Thanks

multiprocessFF==several PIDs

Sure. But only the main process of every instance creates (OS-level) windows. You should only need that one pid per profile.

wouldn’t just converting the install.rdf file to a manifest.json file wouldn’t be sufficient ? Would the icons be used ?

That won’t work.

I quote you from the readme: “WebExtensions […] can send JSON-messages […] if the target applications are explicitly designed for it”. Is FF designed to receive such messages ? If yes, where/what should I look for ?

Firefox is sending out the messages an extension sends and receives the reply,m but the other end of the native messaging has to be a different application.

I’m no addon dev at all

The primary part of the work, if you do it the way I suggested, wouldn’t be add-on development, but winAPI calls through node-ffi, but if you are not a programmer/developer at all, this is probably not the best project to start with.

So to sum up, create an extension that uses native-ext to connect to a node-ffi based script that does WinAPI calls to the FF process ? Do I get it right ?
I am a programmer, but not in nodejs, for now I just use it to make calls for addon signing (jpm sign).
I know javascript though, I’m a webdev and sysadmin, do you think that’s possible without a too steep learning curve ?

Jupp. That’s how I would do it and, if the necessary WinAPIs exisit, you should do fine.

If you do want to use native-ext, I’d suggest you look at how reStyle uses it.

I found WinAPI calls, even an AHK script to readily test it, but I found drawbacks.

  • Changing the icon of the main/first window works, but only changes the 1st window icon.
  • Subsequent windows (Ctrl+N) do not get their icon changed, another call must be made after window creation on that particular window.

There’s also no relation between PIDs and windows !

  • one FF profile (still on v.56, the icon works) has two windows but only one PID. Changing the icon via the PID does not work on the second window
  • one FF profile (v.57) has 4 windows but 7 PIDs. Changing the icon on the main process only changes the first window.

In the AHK script, if I use WinTitle instead of the PID, then it works.
So a few questions:

  • can you get all windows titles from an addon ?
  • can you monitor windows creations from an addon ?
  • passing the windows titles to the AHK script is enough for my needs, so i just need Native Messaging, no ? Because the new FF forces us to use the OS, this method will never be portable anyway … And I’ll have to find alternatives for my *nixes … Such a simple thing that becomes so complicated … A shame.

Thanks again

There’s also no relation between PIDs and windows!

The relation is actually pretty simple. There is only one main PID per instance which can open any number of windows. The child processes (render, GPU, extension processes) don’t open any windows themselves. You can use e.g. process hacker to see that (right-click on process > Miscellaneous > Windows).

can you monitor windows creations from an addon ?

Yes. See browser.windows.onCreated.

can you get all windows titles from an addon?

Sure, but window titles aren’t unique to a profile. The PID of the main process is. Here is an example of enumerating all windows (whose number is quite limited, even of you include the ones not shown as taskbar icons) and filtering them by PID:

You can trigger that from the browser.windows.onCreated event.

passing the windows titles to the AHK script is enough for my needs, so i just need Native Messaging, no ?

Not sure what you mean.

Because the new FF forces us to use the OS, this method will never be portable anyway … And I’ll have to find alternatives for my *nixes … Such a simple thing that becomes so complicated … A shame.

That’s WebExtensions. Quite simple for the things it is meant for, not so much for everything else.

Good to know for the PIDs and windows handling. Now I know more about multiprocess FF !
Realized it when messing with my AHK script (I use AHK for WinAPI programming). I can get all windows ID (hwnd) from the main PID. So now I can change the icon for each window. Phew.

Nevermind the titles thing as per above, but to use that AHK script, I’ll obviously only need to use Native Messaging (NM), no need for the node brick, correct ?

The addon would:

  • on FF launch, set the icons for all existing windows via a NM call to the AHK script
  • monitor windows creation and on new ones, set the icon via another NM call

The remote app (AHK/WinAPI) should:

  • load icons in memory
  • set icons to specific windows when requested by the addon via a NM call
  • (I also had to notify the shell to refresh itself in order to cancel a custom icon and re-apply the std one, as the taskbar icon wouldnt revert back)

To store the “profile<->icon path” relation in the AHK (too complicated in the addon, pre Quantum I had to create one addon per profile), I’ll have to pass the profile name too to the script, I guess that’s possible ? When launching a profile via the integrated way, the session name is not in the program command line.

Yeah (and the change raises storms on the interwebs ^^), but for this simple task, there’s really one quick fix and nice way to do it: instead of FF searching for “chrome/icons/default/” in the install/program folder only (this method exists since ages, see this link), it should do it in the profile folder first, plain and simple ! $profile_dir -> $install_dir -> (default app icons).
I know the dev teams are busy with the new APIs, but don’t you think I could request this change in a way ? This would only be a few lines to add, as all the logic exists already !

Thanks again for all the info and sorry for this long post …

NM call to the AHK script

Just keep in mind that any parameters you want to pass from the extension to the native script/program/app/… are sent and replied to via the native messaging protocol over stdio. I don’t think it is fun to implement or debug that with AHK scripts, if it is possible at all.

To store the “profile<->icon path” relation in the AHK, I’ll have to pass the profile name too to the script, I guess that’s possible ? When launching a profile via the integrated way, the session name is not in the program command line.

See above. That alternative would be an individual script with distinct name per profile. The extension could call the script belonging to the profile without any parameters.

And getting the current profile isn’t straight forward either:

Or you could use my “node brick” as a proxy that takes care of the messaging and figuring out where the current profile is located, so you could simply call your scripts with parameters or use ffi :wink: