MacOS: How can I activate fonts programmatically, systemwide? - macos

I'm trying to make something that behaves very similarly to a font manager, but I simply can't find any documentation on how I can, for example, add an OpenType font to the list NSFontManager provides. I see even Font Book shows fonts activated through a font manager app, so I want to understand what's happening under the hood. What libraries are being called?
Thank you!

It took me quite some time, but here's the way to go.
CTFontManagerRegisterFontURLs does exactly what I was looking for on macOS. Also, session 227 from 2019's WWDC has more info on it, albeit focused on iOS.

Apple has an old archived article entitled Mac OS X: Font locations and their purposes which has a section on manually managing fonts:
[...] You may install fonts by double-clicking them and following the on screen prompts in the Font Book application, or by manually copying or dragging font files to any of the standard Fonts folders in Mac OS X.
The folder in which a font is located determines who can access and use the font. For example: If a user manually installs a new font at ~/Library/Fonts/, the font is available only to that user. If a root or admin user installs the same font at /Network/Library/Fonts/, all network users can use the fonts (assuming that the network administrator has set up computers for this type of sharing).
Changes to fonts take effect when an application is opened or a user logs in to the account or computer on which the changes occurred. Duplicate fonts are resolved based on the order of precedence defined for the standard Fonts folders and are described from highest to lowest priority below.
I tested this using an empty font I created (Awfulcode-Regular.otf) and TextEdit and found the changes to be instant. I therefor conjecture that any delay is actually introduced by specific apps rather than macOS itself.

Function
CTFontManagerRegisterFontURLs(::::)
Declaration *
func CTFontManagerRegisterFontURLs(_ fontURLs: CFArray,
_ scope: CTFontManagerScope,
_ enabled: Bool,
_ registrationHandler: ((CFArray, Bool) -> Bool)?)

Related

how does windows deal with drawing chars not in the current font

I have an app that is trying to display U+23CE (⏎). This is a terminal app, so we are using "Consolas"/"Cascadia"/"Courier". As far as I can see, none of these fonts have this character. And yet, in Visual Studio, when I am debugging this app, it actually displays it correctly in the debugger. Also, when displayed by the new Windows Terminal, it displays correctly. But when I use the app I am working with (actually Putty), it displays the "I don't know this character" glyph.
Putty is a classic Win32 app using ExtTextOutW() to draw that text. I have checked that the correct font is bound to the HDC.
I am assuming that Visual Studio and Windows Terminal are using DirectWrite or other more modern text output logic, but ultimately they have to be getting these unknown glyphs from somewhere.
UPDATE:
I found a font with that character ("Segue UI Symbol"), and if I set Putty to use that font, it displays the missing character (woohoo). Sadly, this is a proportional font, so it looks terrible, and this is not the solution.
#dvix pointed me at a Microsoft page discussing this exact topic, but its not clear which things are done by Windows and which by an app developer. I tried linking "Courier New" (Putty's default) to "Segoe Symbol"", but it made no difference. Does the Putty code need to do all the work itself? Detect an unknown character, read the Registry, and substitute the font for that one char? That is certainly doable, but a pain.
Windows can be directed to "borrow" missing glyphs in a font from another font that carries them using font linking. This applies to both consoles and GUI apps that use GDI (DrawText, ExtTextOut) to render text in Windows 2000 and later.
For example, the following registry entry will link the Consolas font to Segoe UI Symbol (the following can be saved as a .reg file and merged into the registry, will take effect at the next logon).
REGEDIT4
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink]
"Consolas"=hex(7):53,45,47,55,49,53,59,4d,2e,54,54,46,2c,53,65,\
67,6f,65,20,55,49,20,53,79,6d,62,6f,6c,00,00
; "Consolas"=REG_MULTI_SZ:"SEGUISYM.TTF,Segoe UI Symbol"
One handy tool to explore coverage of the different fonts is BabelMap. For example this is the list of fonts that carry U+23CE (⏎) on a fairly clean Win10 system.
Another feature of BabelMap is the option to create temporary user-defined composite fonts on the fly, as opposed to the ones "statically" defined in the registry. This is presumably done using the MLang
IMLangFontLink interface, more about that in Raymond Chen's How to display a string without those ugly boxes and Michael Kaplan's Font substitution and linking #2.

Setting Default Keyboard Layout for Electron Application on Windows (Unable to copy UTF-8 text propely)

We have this problem where a Farsi UTF-8 text that is programmatically copied from an electron application, loses encoding when pasted into one specific application and is displayed as a set of ? characters. The issue persists even with manual text selection and copy command invoked via either context menu or Ctrl+C. Texts copied from other sources such as browsers or text editors are transferred just fine.
We tried clipboard API of electron. We also implemented our own helper to verify the issue is not with the clipboard itself.
We also prepended the text with UTF-8 BOM character before writing it to the clipboard.
One interesting observation was that once the text is pasted into some text editor and then recopied, target app received the text properly. We also noticed that changing the keyboard layout to target language when the electron app is focused, resolves the issue as well. In addition, we realized that Windows changes default keyboard layout to English when the application is launched.
Following on these clues, we configured NSIS bundler to set the default language to Persian so that maybe Windows detects it as default keyboard language as well. Description of the application shows Persian as the language but Windows does not respect it and reverts the language to system default upon launch.
We tried running a script on application startup to mimic a Farsi character keyboard input, creating temporary input fields, and a set of other hacks to maybe trick the Windows/application into properly handling these texts. Keep in mind we can't rely on user to perform idiotic actions on every application launch, to fix a problem that shouldn't exist in first place. That's why we need this issue to be resolved programmatically.
Right now the only solution that comes to mind is to force Windows to set the keyboard layout for our application to Persian via registry entries by some separate script that user need to run only once, or can be run after each installation. I'm not familiar with the windows registry entries. My searches came up empty and the results were focused on how to do it for the whole system, but we don't wanna mess with their whole system configurations since.
Any other suggestions regarding this issue is highly appreciated.
Other information that you might find relevant:
OS is Windows 7.
Target app is an accounting software and the vendor rejects to provide any support with the integration, so I have very little information about inner workings of that application.
html lang attribute of electron template is set to fa.
meta charset attribute is set to utf-8.
Application is bundled with electron-builder and NSIS.

Change icon of running firefox profile

I'm using Win7 but looking for a cross os solution, but this isnt even working in my Win7. I'm trying to change the icon of just the current profile. So what i did was:
I created shortcut of firefox.exe and moved it to my documents
right click on this shortcut and then changed icon
but in firefox the taskbar shows normal firefox icon and so does the top left icon (see attached image plz)
How can I change this icon?
Thanks
Here's another topic i made on ask.m.o trying to ask the same thing: https://ask.mozilla.org/question/725/custom-icon-per-profile/
As of Firefox 57, this is not possible from an extension.
WebExtensions do not permit the window icon to be changed from an extension.
Prior to Firefox 57 (or non-release versions w/ legacy add-ons)
The combination of the title of your question and the text of your question make it unclear what you desire to accomplish.
If your goal is to dynamically change the window icon of a currently running Firefox process then you will need to follow something along the lines of the second or third method listed in nmaier's answer.
If you goal is to always have a different, static icon used for the primary Firefox windows for a specific profile, that is quite easy.
You will need icon files of the appropriate format for each architecture for which you desire this to work.
The following assumes Windows, it is easily expanded to other architectures by including an icon file with the same name, but appropriate file extension and format.
Create a simple overlay, extracted extension. You will need a minimum of 2 files:
<extension-dir>instal.rdf
<extension-dir>\chrome\icons\default\main-window.ico
Example, fully functional, install.rdf:
<?xml version="1.0"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>window-icon-change#nowhere.foo</em:id>
<em:version>1.0.0</em:version>
<em:name>Window icon change</em:name>
<em:description>Change the Firefox main window icon.</em:description>
<em:creator>Makyen</em:creator>
<em:unpack>true</em:unpack>
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>3.0a1</em:minVersion>
<em:maxVersion>43.0a1</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>
NOTE: The "<extension-dir>\chrome\icons\default\" directory is different than the one in the response by nmaier. In that answer the "icons" and "default" directories reversed and will be non-functional.
You will probably want an additional file:
<extension-dir>chrome.manifest
The chrome.manifest file is not required. However, not having it may result in a single line being printed to the error/browser console (if you even have that open). If the chrome.manifest file exists, even if zero length, there will be no complaint in the console that the file could not be read.
Install the extension. The easy way to do this is to create a zip file with those three files; then change the file extension to .xpi; then drag and drop it onto a Firefox window running the profile in which you desire it to be installed.
You can expand this to include icons for whatever sub-windows you desire. You will need to determine the ID for each sub-window. The icon file name is just the window ID with the appropriate extension for an icon in the architectures you desire. "main-window" is just the ID for the main Firefox browser window.
Creating an extension to test this took less than 5 minutes. You should find it reasonably easy to accomplish.
This assumes that there is not a custom main-window icon located at (Windows, default install location):
C:\Program Files\Mozilla Firefox\browser\chrome\icons\default
as that directory is for all profiles and is searched first.
This will not work if the extension is either restartless or extractionless.
You can find a brief amount of information about window icons on MDN. nmaier mentions the docs talking about bundles. When talking about Mozilla add-ons, a bundle is your add-on package.
The icon file(s) will be at (Windows):
<profile dir>\extensions\<extension-dir>\chrome\icons\default*
Once the extension is installed, you can change it/them manually without re-installing, if desired.
Add-ons created to solve this
Based on the discussion in the comments, I created a Firefox Add-on to allow setting the window icons for the profile. It is much expanded upon the 5 minute add-on mentioned in the comments. The addition is entirely in a UI for the options dialog for selecting the icon to use and assigning it to the various different windows Firefox opens. You can get it from Mozilla Add-ons under Change Profile's Window Icons. Unfortunately, it's not possible for that add-on to function as of Firefox 48 which requires add-ons to be signed. To dynamically change the icon requires changing files which must be signed. Thus it's not possible to dynamically change the icon with add-on signing required.
Instead I created a few add-ons which statically change the window icon. You can find them on AMO.
Well, there are some ways that spring to mind, but all with their own issues:
Using Window Icons provided by an add-on you install into the profile (the docs talk about bundles, but add-on can also use this technique). The add-on must be em:unpack and have the icon(s) in chrome/default/icons exactly. It is possible that the Firefox in question has an own set of icons bundled in the $appdir/chrome/default/icons, in particular on *nix and since they are checked first, they will be used instead of the add-on provided add-ons. So while this approach works for custom add-on windows, it might not for built-in ones.
Copy and patch Firefox itself, aka. the sledgehammer approach. Different for each platform (e.g. under Windows you'd have to swap out the icon resource of the firefox.exe).
Create a tool that will switch out the icons of a running window. There is no code to do so in Firefox that would be accessible from javascript, so you need to go binary and platform-specific, e.g. WM_SETICON on Windows.
Edit 1:
Actually, thinking more about it, I'd install an add-on with some platform-specific js-ctypes code that would then switch out the icons, e.g. the already mentioned WM_SETICON on Windows.
Usually you'll need a window handle for the platform APIs, which Firefox refuses to provide to JS. But as a workaround for that:
Store the window title.
Set the window title to a new uuid.
Call a platform API to find the new uuid titled window handle (FindWindow on Windows). mintrayr uses this scheme for Windows/Gnome(GTK/GDK), also not in js-ctypes.
Restore the window title.
Load/transform the icon file to something the platform supports (HICON on windows). I once had a patch somewhere on bugzilla that enabled loading of arbitrary images as window icons FWIW, but let it slide. Should be still somewhere and could give pointers.
Switch the icon using the obtained handle. E.g. Sending two WM_SETICON for small/big icon on Windows.
Edit 2
Turns out nsIBaseWindow exposes a nativeHandle these days, as I learned from your other question. so the window-title–hack isn't needed any longer. However, nativeHandle might be an 64-bit pointer, which isn't really supported in JS land without some trickery... Better not parseInt it... Also js numbers are floats.
ctypes.voidptr_t(ctypes.UInt64(nativeHandle)) should work, though.
On Mac OS X, this Firefox plugin will do just that: https://addons.mozilla.org/en-US/firefox/addon/fosx-label/. Also on GitHub: https://github.com/jf/fosx-label. Thanks to Noitidart for pointing out this very useful plugin.
Tested on Yosemite 10.10.5 and it works perfectly!

Howto automatically open FITS images and tables with different apps from the Mac OS X Finder?

FITS files can contain several images (or more generally n-dimensional arrays) and tables.
Is there a way to automatically open images e.g. with the ds9 application and tables with the TOPCAT application when I double-click the FITS file in the Mac OS X Finder?
I'm thinking of something like FITS Explorer from AstroSoft, but free and nicely integrated into the Mac (i.e. Finder, Quicklook).
If such a thing doesn't exist, what is your workflow for browsing and opening images and tables in FITS files?
I just found QLFits which is a Mac OS X Finder QuickLook plugin that display some FITS header info and an image simply by hitting SPACE after selecting a FITS file in the Finder.
The same guy wrote FITSImporter:
a Spotlight plugin that allow you make spotlight queries against dedicated FITS header keywords. It provides also additional information in the "Get Info" panel of the Finder (⌘-I).
Both are open source (GPL licence), the code is available on github: QLFITS, FITSImporter.
They are not perfect though (e.g. I didn't see a way to get at the different extensions in a multi-extension FITS file, although the description says there is; and you can't use QLFits to browse tables) and development seems to have stopped, but still well worth a try!
Apart from recommending you QLFits, you could try to write an AppleScript application, or Automator action using any scripting language, which explored the FITS file, and sent table-based FITS to TOPCAT, and image-based FITS to DS9, and make that application the default for FITS files.

How can I delete fonts from my code, under Windows?

This article showed me how to install fonts from a script, but now I'm faced with the problem of removing them. How can I do that ? Any language is ok, I'll convert the info to what I need later.
EDIT: Okay, so I now know how to uninstall fonts ( most of the part at least ). I'm issuing calls to RemoveFontResource. After that I use SendMessage with parameters: 0xffff,0x001D,0,0 ( HWND_BROACAST,WM_FONTCHANGE ... and I forgot what the other two parameters stand for ). The thing is, this deletes the font, but in the Control Panel's Fonts entry, the font still appears there ( even though if you try to delete it from there as well, it will say it cannot read from source file or disk.
So basically, I'm deleting a font in this order:
deleting physically from the C:\Windows\Fonts
calling RemoveFontResource
calling SendMessage
What's the proper way of uninstalling?
From all the documentation I've ever seen those three lines of code are the "proper" way to do it but as we well know it doesn't quite work - as expected.
RemoveFontResource(fontPath);
DeleteFile(fontPath);
::SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
REBOOT
I executed the code above and duplicated your problem (control panel still shows the font, however the font file is gone). I then rebooted. Now the font is gone from the Fonts Control Panel applet.
Something else to note: even though control panel still showed the font as "there" applications no longer listed it in their font lists (I specifically tried Wordpad, before and after deleting webdings.ttf - without rebooting)
Yea i know - rebooting is a poor solution - especially if you need to update the Font since you can't reinstall it (via the control panel anyways - it claims the font is still installed) until you reboot after removing it (I tried).
However if all you want to do is remove the font - its not the worst solution - the font is essentially gone after you uninstall it (apps don't see it, its only visible in control panel fonts as far as i can tell) and you wouldn't need to force a reboot.
From the SDK help on RemoveFontResourceFont (which may indicate why the oddness is seen)
If there are outstanding references to
a font, the associated resource
remains loaded until no device context
is using it.
Once you find the actual filename as Havenard mentioned and using the article you mentioned you can do a
objFSO.DeleteFile(FontFilePath);
where FontFilePath is the file path of the file you want to delete.
More Info here:
technet article
A problem that you may run into, which I didn't think of until I saw your comment, is that a program may require that font for some particular item. All known system fonts are stored within the registry. If you remove a font, you should also remove the key from the registry. Registry paths are as follows
Windows 95
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Fonts]
Windows NT
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts]
The keys are as followed:
Key name = Full name of the font
Key type = REG_SZ
Key Value = name of font file
All your fonts can be found at C:\WINDOWS\Fonts\
Explorer will mask this folder to display the font names instead of the real file names, but its all there. You can edit and comment out the lines of C:\WINDOWS\Fonts\desktop.ini to disable this feature and reveal the font files (maybe you need to reopen the Explorer to take effect).

Resources