Looking at the existing
[...GState DPS...] methods and comparing them to the Core Graphics functions, it looked like implementing the backend will be as much of a cakewalk as I originally presumed.
Turns out it is not meant to be.
(Today’s text is a report as much as it is a way for me to contemplate next steps. It’s a noisy stream of thoughts. Sorry about that.)
All is drawn, but nothing is seen (a.k.a. doublebuffering)
The Cairo backend contains code intended to render into a backing store and then draw the content on screen when requested to do so by X. (Presumably, also to blit the content when it updates.) Theoretically, it should be trivial to add this functionality: add a new
CGBitmapContext, redirect all drawing into this new context, and then blit this content on screen when requested.
When creating the surface that targets the screen, one gets a
gswindow_device_t* that describes the X11 window. To tell the rest of the
gnustep-back that this surface can handle its doublebuffering (although it really can’t), we set this
self, and we add flags
GDriverHandlesBacking to its
gdriverProtocol bitmask. This is done only if the surface is not
(From the above description one would think by default, backing stores would be already handled elsewhere in
gnustep-back. Unfortunately, although it seems like
gnustep-back might be trying to handle the case where the surface does not handle X11’s
Expose event nor does it handle having the backing store, it does not do so, at least not properly.)
So, I’ve tried to do it. All drawing is redirected to a
CGBitmapContext, and then in
-handleExpose I’m trying to blit the content on the X11-backed Opal surface. It seems that Opal currently has some issues with the following code (i.e. I get everything drawn in pale yellow):
- (void) handleExposeRect: (NSRect)rect
CGRect cgRect = CGRectMake(rect.origin.x, rect.origin.y,
CGImageRef backingImage = CGBitmapContextCreateImage(_backingCGContext);
CGContextDrawImage(_x11CGContext, cgRect, backingImage);
Debug output from Opal suggest it’s going through all the expected dance moves: creating that image, converting it into destination context’s colorspace, et al. I’ll poke Eric to see if he has a better idea of what’s going wrong.
An interesting behavior is that if I simply don’t redirect drawing to the bitmap context, then I get some content on screen. Despite not having an actual backing store. Maybe
GDriverHandlesBacking has side effects? I’ll have to dig in more.
gotShmCompletion methods seemed like they might be related. No change if I implement them.)
Everything is flipped
When I first got some content on the screen, it turned out that GNUstep’s zero-zero seems to be based on top-left corner of the drawable — opposite from what Opal expects.
So as a first attempt I went in and implemented matrix functions. While things don’t get drawn in the appropriate place yet, it seems like I’m on the right track. The thing that worries me is that I’m not sure what’s the orientation of DPS matrix as opposed to the orientation of the CG matrix. Also, I’m now overriding DPS methods and not calling
super, yet there’s a bunch of code in
GSGState‘s implementation that makes me think this is not such a good idea. DPS functions seem to be maintaining matrix state; hopefully they don’t ever use it directly. If they don’t, then it might be safe to simply override the getter for the matrix.
To be able to reset the Opal matrix to the identity (or, near-identity, considering it’s also flipping the coordinate system), I’ve also added a method to Opal that allows this precise operation. This is an extension over what Apple provides: Apple provides absolutely no way to set the
CTM (presumably, this stands for current transform matrix) directly, which makes only a little bit of sense. I don’t see a good reason this functionality is not provided to developers. (I can think of one that’s just a tiny little bit good.)
Menus have a single item
Now all I get in a menu window is a single menu item. Drawn in place of the menu window’s title.
Meaning, drawn on a completely incorrect place. I’m not really sure if this is a menu item drawn in an incorrect place, or if this is caused by the fact that
-compositeGState:..., which seems to permit blitting one
GState‘s backing surface’s content on top of another
GState‘s content, is not implemented.
If this is so, this may prove very troublesome to implement without adding further hacks into Opal. Core Graphics seems to provide no real way to copy a portion of a context on top of another context, apart from using
Fonts. Oooh, boy.
Cairo backend does a lot of stuff when it comes fonts. A lot, lot of stuff. I wonder why most of that is not exposed to the rest of
gnustep-back, so I’ll probably be moving that out of the Cairo backend and into an additional module within
fonts, or something like that. Or perhaps even into the existing
Just taking a quick look,
art backend seems to be supporting just fonts with the
.nfont extension (explaining
Helvetica.nfont), but I may be wrong. Taking a quick look at
xlib backend, and it seems to be doing something similar to the
It’s going to be a pain to implement fonts, especially to do it properly. I’ll have to think about how to deal with refactoring this — cairo backend is popular and accidentally breaking it won’t be looked at kindly by the community. Still, it’ll be worth it.
Unless it turns out I should have dealt with Opal. In which case Cairo backend’s implementation will stay Cairo backend’s implementation, and Opal backend will leverage Opal for its text needs.
Yes — just as the title of this section implies, I’m not sure what I’m talking about.
Other upcoming steps
Among other things, I’ll look into getting image painting to work. GNUstep does a lot of things with images, so seeing the images might help me figure out what’s going on more easily.