[comp.sys.mac.programmer] A couple of problems a beginner is having. . .

adams.e@oxy.edu (Erik Adams) (06/28/89)

Howdy!

     I'm not new to programming, but I am new to programming the
Macintosh.  I am having a couple of problems that look like they
have very simple solutions, but I just can't see them.

     1.)  If I move an application window on top of a system
window (the control panel, for example), and then move it away,
the system window is _not_ updated.  Where the application window
was is now a white outline in the system window.  This seems to
occur with all desk accessories.  Currently I am not handling
updateEvents for any windows, but when I tried putting in
BeginUpdate and EndUpdate, the problem was still there.  Any
ideas?

     2.)  I can not get a scroll bar in a modal dialog to work.
Here is what I am currently doing:  I pass to ModalDialog a
pointer to a FilterProcedure.  The Filterprocedure checks to see
where theEvent is.  If theEvent is in the scroll bar, I call
TrackControl, passing it an ActionProcedure. I get, at various
times with various combinations:  nothing at all; a scroll bar
that highlights correctly but does not change its value; a scroll
bar that both hightlights and moves, but only when you mouseDown
about 16 pixels to the left; and more system crashes of varying
sorts than I care to enumerate.  The problem seem to be with
my figuring out whether or not theEvent is in the scroll bar,
but there appears to be more than just that.

     I am using LSC 2.01 on a Mac 512ke, using older (pre-6.0)
versions of the Finder and System.  (Yes I know there are newer
versions of LSC, but I can not compile when I use them:
everytime I try I get "Out of Memory" messages from LSC).

    If enough folk want, I will post my source code.
I didn't this time because, as I indicated, these look to
me like stupid mistakes which someone has probably run into
before and will know how to fix.

     Thank you in advance.

     Erik Adams
     adams.e@oxy.edu

tim@hoptoad.uucp (Tim Maroney) (07/01/89)

In article <42687@tiger.oxy.edu> adams.e@oxy.edu (Erik Adams) writes:
>     1.)  If I move an application window on top of a system
>window (the control panel, for example), and then move it away,
>the system window is _not_ updated.  Where the application window
>was is now a white outline in the system window.

The only thing I can think of is that you're calling GetOSEvent rather
than GetNextEvent or WaitNextEvent.  If you call GetNextEvent or
WaitNextEvent, SystemEvent is called by the OS to handle (among other
things) update events for desk accessory windows.  Don't use
GetOSEvent, as it is incompatible with MultiFinder.  If you *are*
using GetNextEvent, I admit bafflement.

>     2.)  I can not get a scroll bar in a modal dialog to work.
>Here is what I am currently doing:  I pass to ModalDialog a
>pointer to a FilterProcedure.  The Filterprocedure checks to see
>where theEvent is.  If theEvent is in the scroll bar, I call
>TrackControl, passing it an ActionProcedure. I get, at various
>times with various combinations:  nothing at all; a scroll bar
>that highlights correctly but does not change its value; a scroll
>bar that both hightlights and moves, but only when you mouseDown
>about 16 pixels to the left; and more system crashes of varying
>sorts than I care to enumerate.  The problem seem to be with
>my figuring out whether or not theEvent is in the scroll bar,
>but there appears to be more than just that.

This is a pretty advanced task for a beginning Mac programmer.  I think
there are probably a few problems.  First, the scroll bar should be
completely enclosed by a userItem, or declared as a CNTL item.  If you
don't do this, then you will have updating problems.  Second, make sure
you understand the difference between local and global coordinates.
When you get an event, the where field will be in global coordinates.
You need to convert to local coordinates before determining where it
falls in your dialog.  To do this, you need to be sure the current port
is the dialog window, then call GlobalToLocal.  Third, it is generally
better *not* to do this directly; instead, pass the point to FindWindow
and then to FindControl.  This should take care of determining whether
the mouse click is in the control or not, and if so, in which part.
Fourth, you may be having clipping problems; it shouldn't hurt to do
a "ClipRect(&dialog->portRect);" before doing anything with the scroll
bars.

Fifth, it is generally better to have a bunch of different action
procedures, one for each part.  Here's a tracking routine I use a lot.
Obviously, you don't have all the context for this, and this controls
both vertical and horizontal scroll bars, but it ought to give you the
idea.  Note that FindWindow and FindControl have already been called,
and the "where" parameter is in local coordinates.

void
ScrollClick(window, extra, ch, where, part)
WindowPtr window;
WindowExtra **extra;
ControlHandle ch;
Point where;
short part;
{
	ControlHandle new;
	
	ClipRect(&window->portRect);
	
	switch (part) {
	case inUpButton:
		if (ch == (*extra)->vScroll)
			TrackControl(ch, where, ScrollVUp);
		else	TrackControl(ch, where, ScrollHUp);
		break;

	case inDownButton:
		if (ch == (*extra)->vScroll)
			TrackControl(ch, where, ScrollVDown);
		else	TrackControl(ch, where, ScrollHDown);
		break;

	case inPageUp:
		do {
			if (ch == (*extra)->vScroll)
				ScrollVPgUp(ch, part);
			else	ScrollHPgUp(ch, part);
			GetMouse(&where);
		} while (StillDown()
			 && FindControl(where, window, &new) == part
			 && ch == new);
		break;

	case inPageDown:
		do {
			if (ch == (*extra)->vScroll)
				ScrollVPgDn(ch, part);
			else	ScrollHPgDn(ch, part);
			GetMouse(&where);
		} while (StillDown()
			 && FindControl(where, window, &new) == part
			 && ch == new);
		break;

	case inThumb:
		if (TrackControl(ch, where, 0)) ScrollThumb(window, ch);
		break;
	}
}

>     I am using LSC 2.01 on a Mac 512ke, using older (pre-6.0)
>versions of the Finder and System.

Get more memory.  The Dove upgrades are excellent -- reliable, easy to
install, and cheap.  A develoment system needs at least one megabyte
and preferably at least 2.5 Megs.  You also need to use the latest
System and Finder and the latest development system.  You're dancing
with the devil in the pale moonlight if you don't.

Hoep this helps!
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com
Postal: 424 Tehama, SF CA 94103; Phone: (415) 495-2934

"The Diabolonian position is new to the London playgoer of today, but not to
 lovers of serious literature.  From Prometheus to the Wagnerian Siegfried,
 some enemy of the gods, unterrified champion of those oppressed by them, has
 always towered among the heroes of the loftiest poetry."
    - Shaw, "On Diabolonian Ethics"

oster@dewey.soe.berkeley.edu (David Phillip Oster) (07/01/89)

In article <42687@tiger.oxy.edu> adams.e@oxy.edu (Erik Adams) writes:
>     1.)  If I move an application window on top of a system
>window (the control panel, for example), and then move it away,
>the system window is _not_ updated. 
You mousedown handleer should look like this:


/* GoMouseDown - dispatch on the mousedown
 */
private void GoMouseDown(theEvent)EventRecord *theEvent;{
    WindowPtr whichWindow;
    Integer i;

    i = FindWindow(theEvent->where, &whichWindow);
    switch(i){
        case inMenuBar:        GoMenuBar(theEvent);                    break;
        case inGoAway:        GoAway(theEvent, whichWindow);            break;
        case inGrow:        GoGrow(theEvent, whichWindow);            break;
        case inContent:        GoContent(theEvent, whichWindow);        break;
        case inSysWindow:    SystemClick(theEvent, whichWindow);        break;
        case inDrag:        GoDrag(theEvent, whichWindow);            break;
        case inZoomOut:
        case inZoomIn:        GoZoom(theEvent, whichWindow, i);        break;
    }
}

It is clear that you forgot the "inSysWindow" case.

>     2.)  I can not get a scroll bar in a modal dialog to work.
>Here is what I am currently doing:  I pass to ModalDialog a
>pointer to a FilterProcedure.  The Filterprocedure checks to see
>where theEvent is.  If theEvent is in the scroll bar, I call
>TrackControl, passing it an ActionProcedure.

you are basically doing the right thing. The biggest thing you are
forgetting  is that the filter procedure sees the mouse in global
coordinates.  Here is how I handle this. (Note: this is a fragment. I
stick a pointer to an array of procedure pointers in the refCon of the
control, to do the actual work of the scroll bar. All procs but the thumb
proc are responsible for doing a SetCtlValue() to set the control to a new
value.)

/* ModifyFilter - the dialog event filter
 */
private pascal Boolean ModifyFilter(dp, event, itemp)
	DialogPtr dp;EventRecord *event;Integer *itemp;{

	GrafPtr savePort;
	Point where;

	GetPort(&savePort);
	SetPort(dp);
	if(event->what == mouseDown){
		where = event->where;
		GlobalToLocal(&where);
		if(PtInRect(where, &(**GetCIHandle(SLIDER)).contrlRect) &&
TrackScroll(where)){
			event->what = nullEvent;
		}
	}
	SetPort(savePort);
	return FALSE;
}

/* ControlProc - return the appropriate Pascal procedure
 */

ProcPtr ControlProc(theControl, part)ControlHandle theControl;Integer part;{
	Integer i;
	ProcPtr *p;
	switch(part){
		case inUpButton:	i = UPPROC;			break;
		case inDownButton:	i = DOWNPROC;		break;
		case inPageUp:		i = PAGEUPPROC;		break;
		case inPageDown:	i = PAGEDOWNPROC;	break;
		case inThumb:		i = THUMBPROC;		break;
	}
	if(NIL == (p = (ProcPtr *) GetCRefCon(theControl))){
		return NIL;
	}
	return (ProcPtr) p[i];
}


/* TrackScroll - track a scroll bar. takes a pointer to a vector of
 * procedures in the refcon of the scroll bar, and calls the appropriate
 * one repeatedly, as appropriate.
 */
Boolean TrackScroll(where)Point where;{
	ControlHandle theControl;
	Integer part, oldVal;
	ProcPtr ControlProc();
	SubrPtr *p;

	if(0 != (part = FindControl(where, thePort, &theControl)) ){
		if(inThumb == part){
			oldVal = GetCtlValue(theControl);
			p = (SubrPtr *) GetCRefCon(theControl);
			(*p[THUMBINITPROC])(theControl);
		}
		if(inThumb == TrackControl(theControl, where, ControlProc(theControl, part))){
			p = (SubrPtr *) GetCRefCon(theControl);
			(*p[THUMBDONEPROC])(theControl, oldVal);
		}
		return TRUE;
	}else
		return FALSE;
}



--- David Phillip Oster            --When you asked me to live in sin with you
Arpa: oster@dewey.soe.berkeley.edu --I didn't know you meant sloth.
Uucp: {uwvax,decvax}!ucbvax!oster%dewey.soe.berkeley.edu

tim@hoptoad.uucp (Tim Maroney) (07/04/89)

In article <42687@tiger.oxy.edu> adams.e@oxy.edu (Erik Adams) writes:
>     1.)  If I move an application window on top of a system
>window (the control panel, for example), and then move it away,
>the system window is _not_ updated. 

In article <29911@ucbvax.BERKELEY.EDU> oster@dewey.soe.berkeley.edu.UUCP
(David Phillip Oster) writes:
>It is clear that you forgot the "inSysWindow" case.

Uh, David, how could leaving a clause out of mouse down event handling
have anything to do with update events?  SystemClick definitely is not
in charge of system updates....

My idea was that he was using GetOSEvent, which wouldn't call
SystemEvent.  However, another possibility I realized later was that he
might be passing an invalid event mask, one without the updateMask bit
set.  This is similar to the error you pointed out recently in that
flawed security scheme.  A beginner could easily mistake the event
type codes for the event mask bit values.  This would not only prevent
the application from receiving update events, it would prevents them
being passed to SystemEvent from inside GetNextEvent.
-- 
Tim Maroney, Mac Software Consultant, sun!hoptoad!tim, tim@toad.com
Postal: 424 Tehama, SF CA 94103; Phone: (415) 495-2934

"Do what you wanna, do what you will;
 Just don't mess up your neighbor's thrill.
 And when you pay the bill, kindly leave a little tip
 To help the next poor sucker on his one-way trip."
    - Frank Zappa, "You Are What You Is"