The goal of this week's POW is to update the XP drawing code in AbiWord so that we only draw focus indicators (such as selections and blinking cursors) when appropriate. Currently, they're always drawn, whether that window has the focus or not, and this leads to lots of visual annoyance and confusion. Your mission, should you choose to accept it, is to make this Just Work. scope ----- This POW shouldn't require very much code, but those changes will be fairly widely dispersed throughout the tree. In short, you'll need to: 1. introduce a new XAP/XP mechanism for focus notification 2. change the FV_View drawing logic to respond to those notifications 3. drive that mechanism from platform code (preferably XAP) Since few of us are expert on more than one platform, it's OK if you only implement #3 for your favorite platform. However, you may want to drive discussions on this list to make sure that the mechanisms you come up with are likely to work for other platforms. step 1 ------ The first step is to introduce an XP mechanism to notify views about focus changes. Ideally, we'd like to be able to use this mechanism for apps other than AbiWord, so where possible, this should be implemented in XAP code. Here's a proposed design, as outlined in an earlier post to this list: http://www.abisource.com/mailinglists/abiword-dev/00/March/0419.html Assume that any AV_View can have one of the following focus states: AV_FOCUS_HERE /* in this view */ AV_FOCUS_NEARBY /* on another window in this frame */ AV_FOCUS_NONE /* not this frame, somewhere else */ However, since views can be recreated any time the zoom factor changes, this state should actually be tracked in the XAP_Frame instead, and then forwarded to the AV_View as needed. For example, any time a frame's widgets really took or lost focus, they'd notify the frame accordingly: pFrame->focusChanged(AV_FOCUS_NEARBY); In turn, the frame could filter redundant changes and just pass the interesting ones along to its views: pView->focusChanged(AV_FOCUS_NEARBY); The AV_View implementation probably doesn't need to do much more than store the new focus state, since all the real work will get done in an app-specific subclass -- in our case, FV_View. You'll also need to make sure that whenever we rezoom a view that it gets renotified about the current focus state. step 2 ------ Change the FV_View drawing logic to honor the focus state as follows: AV_FOCUS_HERE -- draw selection or blinking cursor (if prefs allow) AV_FOCUS_NEARBY -- draw selection or unblinking cursor AV_FOCUS_NONE -- don't draw either This may take a bit of fiddling to get everything working smoothly, but it shouldn't be too bad. Cursor blinking is done in response to timer callbacks, so to stop/start that behavior you'll need to stop/start that timer, being sure to fix the display first, so there aren't any leftover artifacts from the old state. Selections should be easier, because they don't involve XORs or timers. The tricky thing here will be to make sure that you get the transitions right -- that moving between states doesn't leave any dirt on-screen. Thus, to test your logic, you may want to temporarily add a keybinding and edit method which allows you to interactively cycle focus states for a given view on cue. Once everything's working smoothly, this testing harness can easily be ripped out. In the mean time, though, you may want to #if DEBUG guard this testing code, to keep from confusing users of production builds. step 3 ------ Hook this all up to the platform-specific mechanisms for detecting focus changes. As far as an AbiWord frame is concerned, there currently aren't many places where the focus can wind up. AV_FOCUS_HERE == the frame's top-level window AV_FOCUS_NEARBY == some other window in this frame's window hierarchy, such as a menu, a focusable toolbar control, or modal dialog AV_FOCUS_NONE == outside this frame entirely Given what you know about how focus notifications get propagated on your platform, it shouldn't be too hard to figure out where to detect those changes so that you can call pFrame->focusChanged() appropriately. hints ----- 1. UT_DEBUGMSG is your friend. 2. You're best off if you figure out how to call focusChanged() from the minimum number of spots on your platform. One would be ideal, but I doubt it can be done. 3. It may be easier to make hint #2 work if you warp focus away from windows that never need it to a single common window. The work you did in step 1 to ignore redundant changes should come in handy here. 4. To test your changes, you'll probably want to spend time doing things like: - restacking windows so that cursors/selections are partially hidden - clicking on title bars to change focus - changing toolbar fields - pulling down menus - etc. 5. I've provided less guidance than usual about specific places in the code that would need to be touched. If you're having trouble finding your way around, by all means ask questions here on the list. Enjoy! Paul PS: For more background on the whole POW / ZAP / SHAZAM concept, see the following introduction: http://www.abisource.com/mailinglists/abiword-dev/99/September/0097.html
