Chip's Tips for Developers

Contains coding, but not narcotic.

Scoping a wait cursor in Synergy/DE

May 5th, 2008 11:23:28 am pst by Sterling Camden

On Windows, Synergy/DE provides access to the mouse cursor via the WP_CURSOR subfunction of W_PROC. Because this API is purely imperative, managing a wait cursor properly becomes a recurring problem in non-trivial applications. Typically, it begins like this (in pseudo-code):

set wait cursor
do lengthy process
clear wait cursor

But what happens if “do lengthy process” throws an exception that’s caught outside this code? You’ll skip right over “clear wait cursor” and leave the user unable to click anything. What you’d like to do is more like this:

begin
  set wait cursor
  do lengthy process
end

… and have the cursor reset whenever and however you exit the code block.

The downloadable code below demonstrates how to do this with the new object syntax in Synergy/DE version 9. The WaitCursor class sets the wait cursor in its constructor and resets it in its destructor. So you can code it like this:

begin
  data wait, @*, new WaitCursor()
  do lengthy process
end

The data statement declares a variable that has the scope of its containing begin-end block. The variable wait is declared as an object (@*). We could have more precisely declared it as @WaitCursor, but that’s just more typing (pun intended). It’s initial value is returned by the “new” expression, creating a new WaitCursor object. This invokes its constructor, setting the wait cursor. When wait goes out of scope, the last reference to the object is lost, and the destructor is invoked and the cursor is reset — no matter how you get out of the code block. If you want to preserve the cursor instead, you can just pass a reference to the object out of the block in another variable, and clear that variable when you no longer want the wait cursor.

But what happens if you have nested operations that, agnostic of each other, each want to set a wait cursor? When the inner one finishes, it will reset the cursor to normal. That’s not what you want at all. I solved this by adding a static counter to the class, so we only reset the cursor if our count of active WaitCursor objects gets back to zero.

Of course it’s possible that other code is manipulating the cursor without using our class. That could definitely interfere with our scheme, and should be avoided if possible. One common case is the set of message box routines in the UI Toolkit (U_MESSAGE, U_MSGBOX, U_WAIT). These routines always reset the cursor to the normal pointer so the user can use the mouse to click the buttons. If you want to have the cursor go back to what it was before these routines were called, then you’ll probably need to wrap them in your own version that saves off the current cursor state, calls the original, and then restores the cursor.

Posted in SynergyDE, UI Toolkit, Windows | 2 Comments » RSS 2.0 | Sphere it!

Better Tag Cloud