Monday 10 May 2010

It must have been a long day...


I've managed to fix a few of the problems with the graph layouts that were all caused by "d'oh, I'm so dumb" errors:
  • the backwards graph-edge layout in the tree-graph-pane (the middle one) were caused by a simple '- rather than +' error in the edge layout code.
  • the pixmaps for the control buttons were incorrectly positioned because the medium transform was applied twice (once by draw-image and once by do-copy-pixmap).
Now those are sorted, the graphs look much better.

There's still (obviously) an issue with the control buttons, which are supposed to look like a box with a + in and a box with a - in depending on whether the button is to expand or contract the adjacent node.

Initially I thought this was to do with incorrect native drawables being associated to mediums but after looking at the code again I'm not so sure. I did manage to come up with what I think is a more elegant solution to the general problem of getting the correct drawable though; instead of squirreling away the sheet that was initially attached to the medium during attach-medium, I instead just find the mirror for the sheet (which the previous attempt did anyway on its way to finding a widget object) and take the drawable of that mirror. It does basically the same thing as yesterday's solution but doesn't require a slot. I can't at the moment imagine a scenario where this won't be acceptable and I'm keeping my fingers crossed that I don't come up with one any time soon.

That leaves a bit of a puzzle with respect to the control buttons though. Using the buttons in the "simple graphics" ui test (for that test's test image) works; the icon is displayed. Using the buttons in the graph layouts doesn't work; GTK "renders" a bunch of random memory onto the screen. This is true even if the simple graphics pane is wrapped in a scroller, so the problem isn't anything to do with scrollers as far as I can tell. I'll just have to keep digging at this and put off some potentially more interesting work to another day.

Sunday 9 May 2010

Trucking along...

Removing all the references (and comments referring to) DEFINE-DYLAN-CLASS has now been completed. There were more of them than I remembered (even with a revision control system I tend to prefer to comment things out rather than remove them altogether), but there are a lot of classes defined by DUIM. At least they're gone now.

Defining :default-initargs properly resolved a few issues with the scrolling; in the hopes that the lack of scrolling was preventing tree + graph controls from being displayed (they're both displayed in scrollers) I added a <gtk-viewport> type built on GtkLayout to contain the scrolled sheet. Now this is in place, scrolling "seems" to behave itself, more or less. is a little like a cross between a <gtk-fixed> in that in can contain child widgets, and <gtk-drawing-area> in that it provides a drawable surface. It offers a couple of other facilities too (like being able to attach scroll bars to it) but for now I'm going to punt and let DUIM deal with all of that.

Unfortunately fixing scrolling didn't help with tree + graph controls, which still weren't being displayed. After much fun and games, it turns out that these controls end up drawing to the "wrong" drawable. The issue here is that when mediums are attached to sheets, those sheets are not yet mapped and there are no (x) drawables so the code ends up associated a null drawable to the medium. Whenever an attempt is made to draw to the medium the code checks that the drawable is non-null and if it is null, again attempts to set the drawable for the medium.
The problem in all this is two-fold:
  • The sheet being drawn to is not necessarily the one that the medium was initially attached to (child sheets can use the medium of a parent, and DUIM rebinds the medium-sheet to be the sheet where drawing "should go" so that transforms etc. don't lose)
  • The drawable for everything comes from the GTK widget->window pointer, except for GtkLayout where it comes from layout->bin_window instead.
In most cases (because the same X window is referred to by widget->window) it doesn't matter which sheet's drawable gets hooked up to the medium. In the case of GtkLayout though, it does matter because the widget->window value of the sheet that is contained in the layout does not match layout->bin_window and the code ends up attempting to draw onto a drawable which is obscured by the layout->bin_window drawable.
At the point we first have a non-null native drawable, we've very possibly lost the reference to the sheet to which the medium was attached (i.e. we are drawing to a child sheet of the sheet the medium was attached to). In the case of viewports the drawable needs to come from the original sheet.
I've fixed this by keeping track of the sheet the medium is attached to in a slot in <gtk-medium>, but I don't really like the solution. I'll try to come up with a better one.

With all that done, tree and graph controls appear on screen, at last:


Hrm. There's still a few issues with tree + graph drawing, apparently... I'm pretty sure what the problem is with the control-buttons, and that is the pixmaps that they are drawn into are created on the "wrong" drawable which at least should now be relatively easy to fix (that is, it's the same problem I've already solved for viewport children).

At least I have some clear problems to overcome now with these controls, and a couple more issues can be knocked off the "major stuff to do" list and be moved onto the "stuff that really needs cleaning up" list.

Wednesday 5 May 2010

Default initargs and object instantiation

Whilst running through the gui tests for DUIM I was puzzled by the behaviour of dialog boxes. As far as I could tell, most of them should have been running modally, but they were all running modelessly (well, all apart from the "standard dialogs" which use a completely different create/map/event loop process to everything else).

What to do, apart from to examine the code?

It turns out that the <dialog-frame> classes (which inherit from <basic-frame>) all contain Dylan "keyword" slots. I had assumed (even after reading the relevant sections of the DRM) that this was a straightforward shorthand for specifying a slot with a keyword initarg, but after looking in detail at the frame creation code on <basic-frame> and re-reading the DRM it becomes apparent that these are not slots at all, but rather Dylan's way of specifying CL's :default-initargs class option.

After changing these "slots" to be :default-initargs, things run much better (i.e. more like I expected them to run). The initialize-instance method on <basic-frame> is now passed the initargs it needs to construct frames properly (barring further errors on my part). This also resolves a couple of the issues with scrolling that I've been having.

Unfortunately the DEFINE-DYLAN-CLASS macro I wrote (and that is still used by other macros, such as DEFINE-FRAME) doesn't deal with "keyword" slots properly. I spent some time a while ago making most classes just use DEFCLASS instead of my Dylan "compatability" macro -- it would seem the time has come to port the remaining uses over to DEFCLASS and to rewrite some of those macros. At least I know what I'll be doing this evening given the opportunity.

Monday 3 May 2010

Another year...

More than a year since the last post, where does the time go? I put DUIM down for a while whilst a few other things took my interest, but after a bit of a break I'm back to hacking it again.

Things appear to be coming together a little more:-


Finally colours are working, as is (the easy bit) of text rendering. Quite a few of the gadgets that didn't used to work properly have been fixed, and I've added code for image drawing / double buffering / bitblting etc.

I've decided not to write native (= GTK+) toolkit wrappers for the remaining pane types. There are still several things that aren't working properly (most notably scrollers and graph panes) and I suspect the easiest way to get them going will be to just wrap as many native panes as possible -- but if I can't get user-defined panes working on top of DUIM, what hope does any other unfortunate who uses it got? This is the main reason I went with the DUIM-supplied spin-box pane (visible as the "thickness" control on the random rectangles test in the screenshot above) is the DUIM-supplied pane rather than a GtkSpinButton.

Once everything works "as it should" I intend to migrate the few remaining non-native widgets over to wrapped GTK+ widgets.

Fixes since last year include:

  • A bunch of gadgets have been "GTK-ified": list controls, option + combo boxes, sliders.
  • Use bordeaux-threads for threading primitives rather than hand-rolling a generic interface + implementations for different CL implementations.
  • Fixes for a couple of layout issues for top-level sheets, menu-bars, text-editor gadgets, others.
  • Drawing implementations for basic text drawing, drawing in colour, images + pixmaps, clipping regions.
  • Support for key events -- basic ascii generates sensible keysyms (although the keysyms for Unicode chars etc. is likely to be ugly for the time being).
  • Support added for setting and changing the input focus.
  • Fixed radio buttons so that setting their state computationally doesn't lose. A bunch of work on (DUIM-provided) table controls.
  • Command tables now seem to work after fixing a couple of bugs in my macros.
The todo list still contains (major issues, there are many minor issues too):-
  • Resizing one of the DUIM frames doesn't lead to relayout; minimize + restore after resizing doesn't lead to redrawing.
  • When the last active DUIM frame is closed, the event loop is not exited (to be honest I'm not sure it should be, or if the user should just be prevented from closing the last frame).
  • No support for path drawing (this is likely to remain unsupported until some Cairo support is added to the back end).
  • Popup menu + dialog modality needs investigating.
  • Mouse motion event support.
  • Scrolling.
  • Mnemonics + accelerator support.
  • Clipboard handling.
I'll add the usual promise to update this blog more regularly (which I'm bound to break, so don't hold your breath waiting for it to actually happen ;)

Followers