Couldn’t seep again last night, so I hacked on CASMSIM some more. I hope this doesn’t get to be a habit. I like hacking in my spare time, but I don’t normally consider the time I want to spend sleeping as spare time.
I found the docs on pkg-config and on GtkLabels not having a background. I changed the code to create the button “empty” and set its background color, then add the label with a foreground color, and that did what I wanted.
However, I’ve since thrown that code away (still in the Subversion source repository as csim.c rev 114) because I’ve switched to using a photo of the actual calculator. I use gdk_new_pixbuf_from_file to load a JPEG image, and gtk_image_new_from_pixbuf to create a background widget.
The next hurdle was that now I want the buttons to be transparent. I couldn’t figure out any way to make that happen. In principle I could do away with button widgets, and capture mouse down and up events in the window, and find and track virtual buttons myself. But this seemed like a huge waste when the GtkButton widget does *almost* exactly what I want.
Then it occurred to me that I could use the button widget, but inside the button put a GtkImage of the actual button. Of course, I don’t want to have a bunch of separate image files for each button. So I started looking at the GdkPixbuf functions for copying blocks of pixels around. At first I thought I’d create new pixbufs, then copy into them using gdk_pixbuf_copy_area. But then I found gdk_pixbuf_new_subpixbuf(), which does exactly what I needed in one operation without actually duplicating pixels.
At this point I had all the button stuff working, in terms of catching the events, but they just print press and release messages to standard out. I hadn’t yet integrated the simulator again.
In the xlib version, I used setitimer and SIGINT to get an interrupt 100 times per second, and on each one simulate 35 microinstructions, so that it runs at the same rate as the real calculator (3500 uinst/sec). The exact rate isn’t too important except when using the stopwatch mode of the HP-55 (and as an undocumented feature in the HP-45). But even when not using the stopwatch, it at least serves to keep the simulator from using much CPU time.
However, one of my goals is to get CASMSIM working on Windows without too much porting effort, and setitimer/SIGINT doesn’t seem likely to port very easily. I considered using a Gtk timer callout, but I wasn’t sure how well that would work at 1/100 second resolution.
Back in 1995 when I was working on vecsim, an Atari vector game simulator, I did an experimental port to the then-new Windows 95. I had similar problems and decided that the best thing to do was to run the actual simulation in one thread and the user interface in another. Although this worked, it was very “jerky”, because back then there was a lot less CPU power available and the schduler in Windows apparently set the time slices much longer than I wanted. These days I don’t think that should be a problem for either Windows or Linux.
I wanted to do the same thing in CASMSIM, but I was again concerned about portability. But then I discovered that glibc 2.x includes portable thread primitives. So I spent a couple of hours moving the simulation code into a separate thread, and building a clean interface to it using a mutex and two GCond variables. (Possibly should use g_async_queue instead.)
pkg-config (at least as supplied with Fedora Core 1) does not seem to know about libgthread. Even though I told pkg-config I was using glib-2.0, I had to add “-lgthread-2.0″ to the link options. Seems like a potential portability problem, which presumably is what pkg-config is supposed to avoid.
It now mostly works. I haven’t got a good LED display yet; it’s just putting a red-foreground GtkLabel in front of the calculator image. The first button press doesn’t seem to make it to the simulator. And I haven’t yet tried building it on Windows. (Since I despise Windows, I’m hoping that I can set up a cross-development environment and actually do the build under Linux.)
I just noticed that if I try to invoke the HP-45 stopwatch (RCL, ENTER), I get assertions in pango. I guess my display code has a problem. And if I try to run it under gdb, I get the same assertions as soon as I start the program. I need to figure out how to get the assertion to immediately break so I can go up the stack trace and find the problem. But it will be moot if I implement the display properly rather than as a text label.
One thing I haven’t found is whether there are any documented rules regarding overlapping widgets, such as buttons overlapping an image. Are widgets added to a container always painted in the order they were added?