Keeping references to glyph names up to date

I’m storing a bunch of data in GSGlyph.userData that reference other glyph names, and I want to keep this list up to date when the glyph names are changed. There does not seem to be a callback for when glyph is renamed or when the font is changed in general.

I thought of reading the userData in a DOCUMENTOPENED callback, saving it in a parallel tempData structure that uses GSGlyph objects, and updating the userData in a DOCUMENTWASSAVED callback, but the callback will be called after the file is saved so the userData will not be saved and triggering another save in the callback will result in an infinite loop.

Any better ideas?

Alternatively, is there a way to influence how an object is serialized to .glyphs file? I can imagine making a class, say GlyphName, that keeps reference to the GSGlyph but upon serializing it serializes only the name.

There is a class that is handling the glyph name updates: GSComponent. But most it is doing is storing the name and the glyphID (a UUID, not to be confused with the index).

You can put an NSObject that implements the method:
- (BOOL)propertyListToData:(CFMutableDataRef)data format:(int)formatVersion error:(NSError **)error;
or
- (id)propertyListValueFormat:(int)format;
into the userdata. So that object can write itself to the file. The structure has to be valid plist. The first method expects you to add the data to the data object, the second expects a plist object on return.

1 Like

I tried using GSComponent, but the user data still saves the component with old glyph name.

Thanks, I did something like this and it seems to work, but sometimes Glyphs would crash on me, so I think I’m doing something wrong:

class GlyphName:
    def __init__(self, glyph):
        self.glyph = glyph
    def propertyListValueFormat_(self, format):
        return self.glyph.name 

Your class needs to be a subclass of NSObject. Change its definition like so:

class GlyphName(NSObject):
1 Like

Thanks, I did that first but it I couldn’t do Class() style construction, and had to use Class.new() instead, but I guess I have to live with that.

This seems to do it:

class GlyphName(NSObject):
    @staticmethod
    def __new__(cls, *args, **kwargs):
        return cls.new()

    @objc.python_method
    def __init__(self, glyph):
        self.glyph = glyph

    def propertyListValueFormat_(self, formatVersion):
        return self.glyph.name

Now if I can get Glyphs to load the names to this class directly, or at least find a way not to mark the font modified when I do it manually, but it is pretty good already.

You need to check your data when the file is loaded and put your custom object in place. Didn’t we just had the problem that setting the userdata would not dirty the document? Do it the old way here.

1 Like

Good point, I did that and no longer mark the font modified (this also helps reduce the crashes I’m experiencing).

But now I have a more serious issue, when I open the font and try to save it immediately (up to a few seconds), Glyphs will immediately crash. If I wait a little bit longer it will save normally. When the font was marked modified at open, it would crash as soon as the autosave is triggered. I’m not sure how to debug this and whether I’m doing something that I shouldn’t be doing.

Can you send me your script and a sample file?

Sent to support email.

I had a look and I don’t understand what is going on. But I discovered that if I use this:

    def propertyListValueFormat_(self, formatVersion):
        NSLog("A")
        return self.glyph.name

It isn’t crashing. It is spamming the console but this is better than crashing (for now).

This made no difference for.

What python version do you have?

3.9.5 (Homebrew)

FWIW, I think something goes wrong if the file gets saved before my code processes all the glyphs e.g. if I added a log message to the __init__ method and try try to save while it is still printing output the application will crash, but if I wait until the messages stop it will not crash.

I did that logging, and it was always finished.

Yes, it started to crash again after finishing, looks like it was a mistaken observation. I’m thinking now if finding away to block any user interaction for few seconds and hope this is enough. Message() would do if there were away to close it automatically.

I played around with this a bit more. When I defined the class in ObjectivC directly, it worked fine. So it seems a strange bug in pyObjC.