Slider FKEY
Volume Number: 6
Issue Number: 1
Column Tag: Pascal Procedures
Related Info: Quickdraw Window Manager
Slider FKEY
By Bill Johnson, Ron Duritsch, Cincinnati, OH
Note: Source code files accompanying article are located on MacTech CD-ROM or
source code disks.
[Bill Johnson is an Architect who gave up the good life to become a Macintosh
developer. He has written several architectural utilities for the Macintosh, and
recently finished Retriever™, a database desk accessory for managing lists of
information. Ron Duritsch is an Economist who can’t afford to give up the good life.
Except evenings and weekends.]
Sliding Around The Guidelines
Direct interaction by users with the Macintosh screen, in the form of choosing or
selecting objects they are interested in, is an important feature of the Mac’s graphical
user interface. This general form of user action is described in Apple’s Human
Interface Guidelines as noun-then-verb.
User selection of “objects”, or the nouns, includes many items such as icons,
text, graphics, and others. One important function of the Macintosh Finder is managing
icons in windows and on the desktop. Users can select an icon, or group of icons, and
move them about to better manage applications and documents in a window or on the
desktop.
One at a Time, Please
With the advent of larger and multiple screen use on the Mac has come a
realization that objects the user can select in multiples do not include windows. Only
one window can be selected or moved at any given time. We feel a simple extension of
the definition of objects to include windows should be considered. Just as groups of
icons can be moved for better placement on the desktop, moving groups of windows on a
large screen can be just as useful. Slider is an FKEY that implements one method of
doing just that.
Let It Slide
When Slider is invoked the cursor is changed to give the user feedback. The
cursor takes the form of a hand (the familiar MacPaint “grabber”) over the outline of
a window. At this point multiple windows can be grabbed by shift-clicking on any part
of any individual window. The term “grabbed” is used here to avoid confusion with
normal window “selection”, using the SelectWindow toolbox call. As each window is
grabbed, it’s outline is displayed in the same manner as when clicking in it’s drag
region. When the user clicks in a window using Slider, the outline of all windows
currently chosen is drawn, and a sound that is correctly named and placed in the
System folder is played. This group of windows can then be dragged to any position on
the screen. The movement does not effect the ordering of windows from front to back.
Slider can be used effectively in any application under MultiFinder or UniFinder.
Under MultiFinder, only windows in the current layer can be grabbed and moved. This
is analogous to the current interface guidelines of only allowing users to select and
move icons or objects in one window at any time. Slider defaults to moving all windows
in the current if any one window is clicked in and immediately dragged. This provides
for a very fast method of moving all windows in the current layer out of the way to
expose a clearer view of windows in other layers under MultiFinder, or simply a bare
desktop under UniFinder. Holding the shift key down while clicking in successive
windows grabs them and adds them to a group that can be dragged. After any window or
group of windows is moved beyond its initial location, Slider drops out, the pointer
cursor reappears, and control is passed back to the current application.
A few other features were included to provide additional functionality. Holding the
option key down while clicking in a single window grabs that window and any windows
behind it in the current layer. This is useful in allowing the user to grab and drag a
particular subset of windows out of view while leaving the screen position and
ordering of the windows above it undisturbed.
Slider can be useful with both single and multiple screens. In default mode,
dragging windows to the extreme left, right or bottom will result in at least 20 pixels
of each window’s drag bar remaining on the main screen. This is to ensure that
windows are not completely lost from view on a single screen. In this case, some
windows that are moved must lose their positions relative to one another. Holding the
command key down pr events the loss of relative window positions. In multiple screen
use, holding the command key down will allow windows to be dragged to an alternate
display (although we haven’t been able to test that feature). With a single screen, some
windows may be lost completely from view if the command key is held down. In this
case, windows out of view can be retrieved by grabbing all windows in the current
layer. In all cases, dragging windows to the extreme top will leave windows positioned
just below the menu bar.
Uses Of Slider
So who would need or want Slider’s features? We are guessing that more than
just of few of us are annoyed at the clutter of windows that can accumulate on the
desktop, e specially when using several applications under MultiFinder. Moving
windows one at a time is slow. Repositioning singularly moved windows to conform to
their previous relative positions takes even more time. Slider provides for a very
quick and efficient way to get windows out of the way all while keeping their relative
positions.
The advantages of moving entire groups of windows are readily noticeable in a
multiple display environment. An entire layer of windows can be quickly moved to an
alternate display screen while holding on to relative window positions. Even with a
minimal configuration, such as in UniFinder with a nine inch screen, the added
functionality afforded by Slider’s features is useful.
Abuses Of Slider
In its current configuration Slider will move literally any window. This includes
modal dialogs and windows that were meant to always be stationary. The movement of
modal dialogs is not apparent to us as being useful. Usually, when a modal dialog is
moved, the screen area behind it is not refreshed until the dialog is dismissed. We left
this feature in for two reasons. First off, it doesn’t hurt the performance of any
application that we know of. Secondly, you may find it useful where we haven’t. We
invite you to recode the FKEY to bypass modal dialogs if you wish. This could be
accomplished by checking the WindowKind field of the window record for inappropriate
window types, although some applications use dBoxProc windows for things other than
modal dialogs.
Moving an application or document window that was programmed never to be
moved is a much more serious issue. In fact, it’s quite rude! You’ll find that most
applications won’t care because they draw to the window’s port and only in response to
update events. If the programmer of the application has followed these two rules,
which are recommended by Inside Macintosh, there should be no problems. But let’s
face it. Most of us break the rules from time to time. Some drawing applications use a
global coordinate system, since the drawing surface (they thought) would remain
stationary. Some applications will react very strangely to the movement of otherwise
stationary windows. And that’s exactly why we left this feature in!
That’s Not A Virus, That’s A Feature
We found some applications to respond in fascinating ways. The command line of
an excellent Mac spreadsheet application is actually made up of three windows. The
part of the command line that the user types into is actually a ghost window and is not
found in the window list. Surprisingly, these windows still operate correctly when
moved to other screen locations.
In others, we discovered hidden windows left in for debugging purposes and
who-knows-what. An easy three-dimensional drawing program that was written in an
implementation of Forth has a drawing surface that appears not to be a window at all.
After moving this surface with Slider, a drag region appears from under the menu bar
to show that, indeed, the drawing surface is a window with a title bar. Right off the top
left of this window a small white rectangle appears with a slight hint of a grow box.
Expanding the grow box reveals a window with an “ok ?” prompt. Apparently this
window was left in for debugging purposes and responds to different user actions.
The palettes and pattern areas of a super painting application reveal themselves
to be a single inverted L-shaped window. After moving this window, however, the
palette is unusable since it uses fixed global coordinates to detect mouse hits. We like
to think of these not as Slider bugs, but features! You too can surprise and amuse your
friends as you tear apart the windows of some of the most beloved Mac applications.
If It Ain’t Broke, Fix It
Moving otherwise stationary windows is rude if their locations are hard-coded,
but occasionally it can be useful from the standpoint of adding functionality to a user
interface, as in the case of unmovable tool palettes. However if you do move these, you
do so at your own risk, since at times moving stationary windows will bomb an
application. Any version of MacPaint, for instance, will allow you only a little fun
before breaking. We found this to be rare but this is the price you are sure to pay,
e specially with applications that bypass normal toolbox calls or IM recommendations.
At present we know of no clean way of leaving stationary windows alone, aside from
simply not attempting to move them. We invite you to try and write the code that says
“if the window is meant to be stationary, then don’t move it”. As a favorite professor
used to say when caught in a similar dilemma, “this is left as an exercise for the
reader”.
Variables and Data Structures
Before we get into the code, we need to look at the data structure that is used to
store the pointers to the windows that are individually chosen with a shift-click. The
variable ‘WPtrArray’ is an array of 32 window pointers, and the integer variable
‘NumWSel’ is the number of windows currently selected. Simple enough. Every time a
window is clicked in, if its pointer isn’t already in the array the pointer is added to the
array and ‘NumWSel’ is incremented by one. However, when we drag shift-clicked
windows around the screen, we want to avoid drawing over windows that are in front of
the windows being dragged. In order to do that we need to know which window is the
frontmost out of our collection of shift-clicked windows. We can then call ‘ClipAbove’
using the pointer to that window to achieve this effect.
We could use a separate variable to store the pointer to the frontmost chosen
window. Instead we structure the information we have by adding one more
characteristic to our array of pointers; of all the pointers in the array, the one
nearest the front should always be stored in the first position in the array
(WPtrArray[1]). All that is required to maintain this property when inserting
pointers into the pointer array is to walk down the window list starting with the
pointer you want to insert. If you encounter the window pointed to by ‘WPtrArray[1]’,
then the new window is above the current ‘highest’ window and belongs in
‘WPtrArray[1]’. All of these gory details are handled in the function ‘InsertWPtr’
(see below).
One last note. The toolbox call ‘ClipAbove’ is only called when ‘WPtrArray[1]’ is
not equal to ‘TopWindPtr’, since there is no need to clip if the front window is being
dragged. So we can kill two birds with one stone by initializing ‘WPtrArray[1]’ to
‘TopWindPtr’. If the user clicks in the menubar or desktop before any windows have