[comp.sys.mac.programmer] A *** SERIOUS ***

jmunkki@kampi.hut.fi (Juri Munkki) (08/09/89)

I just discovered that I had wasted several weeks hunting down a bug in
my source code, when it actually wasn't there. The problem was that somehow
the system was using grafports that didn't exist.

I always use the sequence:
	GetPort(&saved);
	SetPort(someport);
	...
	SetPort(saved);

This means that when InitWindows sets the port to the window manager port,
it usually remains that way for the rest of my program. I verified this
with a debugger.

I then proceeded to start with Suitcase II (v 1.2.2) enabled and the
behavior changed. Whenever I opened a desk accessory, the port would
change to that window. The problem is that when the desk accessory is
closed, the port (thePort for you programmers) stays in that now
defunct window.

You might say that this does not matter, because everyone calls SetPort
before doing any _drawing_. The problem arises when some programs
create regions or pictures and just assume that it's fine to use any
port (in a storm?). The Blast FKEY is a good example, since the source
code was published in MacTutor. Even the window manager might do this,
but I haven't checked this.

This bug might affect any really well behaved application. Imagine my
anger when I discovered that I follow all the apple guidelines and even
a few of my own and that my software has a problem with desk accessories!

The first fix that came to my mind was to change ports every time one of
windows is activated or deactivated. This doesn't solve the problem when
there are no windows open. Any bright suggestions? I don't want to call
SetPort every time I go through the event loop, but I just might have to
do that...Suitcase is too popular to be ignored.

Please check your own source code. Even if you don't restore your grafports,
it is possible (although highly unlikely) that your code will crash in some
situations.

I would really like to get some feedback on this. If you do not want to post,
please feel free to mail me. (If jmunkki@hut.fi doesn't work, try mcvax!santra!
jmunkki)

_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

jmunkki@kampi.hut.fi (Juri Munkki) (08/09/89)

This is a followup to my original article. At that time I still hadn't
thought of a reasonable fix to the problem. Here's what I decided to
do:

StartSetup();	/* This calls InitWindows among other things.	*/
GetPort(&WindowManagerPort);

do /* my main event loop */
{	/*	The following line fixes a bug in Suitcase:	*/
	if(thePort != WindowManagerPort)	SetPort(WindowManagerPort);
...

Can anyone think of a reason why this wouldn't work? I wanted to optimize
things, so I use thePort instead of calling GetPort. Usually I avoid this
kind programming, but this time I think it can't hurt to use a global.

_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

mystone@caen.engin.umich.edu (Dean Yu) (08/09/89)

In article <24320@santra.UUCP> jmunkki@kampi.hut.fi (Juri Munkki) writes:
>I just discovered that I had wasted several weeks hunting down a bug in
>my source code, when it actually wasn't there. The problem was that somehow
>the system was using grafports that didn't exist.
>
>I always use the sequence:
>	GetPort(&saved);
>	SetPort(someport);
>	...
>	SetPort(saved);
>
>This means that when InitWindows sets the port to the window manager port,
>it usually remains that way for the rest of my program. I verified this
>with a debugger.
>
>I then proceeded to start with Suitcase II (v 1.2.2) enabled and the
>behavior changed. Whenever I opened a desk accessory, the port would
>change to that window. The problem is that when the desk accessory is
>closed, the port (thePort for you programmers) stays in that now
>defunct window.
>

  This isn't a bug in Suitcase, but a problem with some DAs.  It's fairly
well known that some older DAs don't restore the grafPort when they close
or get switched out.

_______________________________________________________________________________
Dean Yu                            | E-mail: mystone@{sol,caen}.engin.umich.edu
University of Michigan             | Real-mail: Dean Yu
Computer Aided Engineering Network |            909 Church St
                                   |            Apt C
===================================|            Ann Arbor, MI 48104
                                   | Phone: Given on a need to know basis, and
"I am the Merit Host.  I speak for |        only if you're going to offer me a
 the bitstream."  (In other words, |        job...
 these are my very own opinions;   | 
 my employer wants to have nothing |===========================================
 to do with them, or me.)          |       This space available for rent
-------------------------------------------------------------------------------

mystone@caen.engin.umich.edu (Dean Yu) (08/09/89)

In article <24321@santra.UUCP> jmunkki@kampi.hut.fi (Juri Munkki) writes:
>This is a followup to my original article. At that time I still hadn't
>thought of a reasonable fix to the problem. Here's what I decided to
>do:
>
>StartSetup();	/* This calls InitWindows among other things.	*/
>GetPort(&WindowManagerPort);
>
>do /* my main event loop */
>{	/*	The following line fixes a bug in Suitcase:	*/
>	if(thePort != WindowManagerPort)	SetPort(WindowManagerPort);
>...
>
>Can anyone think of a reason why this wouldn't work? I wanted to optimize
>things, so I use thePort instead of calling GetPort. Usually I avoid this
>kind programming, but this time I think it can't hurt to use a global.
>

  It works, but i wouldn't call it optimizing.  If you're setting the port
to the Window Manager port every time the current port isn't the Window
Manager's port, you're going to have to set the port to a window's grafPort
every time you want to do any drawing.  If you're going to do that anyway, the
conditional seems to be excess baggage.  (And you shouldn't be drawing to the
Window Manager port anyway, if you are...)

_______________________________________________________________________________
Dean Yu                            | E-mail: mystone@{sol,caen}.engin.umich.edu
University of Michigan             | Real-mail: Dean Yu
Computer Aided Engineering Network |            909 Church St
                                   |            Apt C
===================================|            Ann Arbor, MI 48104
                                   | Phone: Given on a need to know basis, and
"I am the Merit Host.  I speak for |        only if you're going to offer me a
 the bitstream."  (In other words, |        job...
 these are my very own opinions;   | 
 my employer wants to have nothing |===========================================
 to do with them, or me.)          |       This space available for rent
-------------------------------------------------------------------------------

earleh@eleazar.dartmouth.edu (Earle R. Horton) (08/10/89)

...
>windows is activated or deactivated. This doesn't solve the problem when
>there are no windows open. Any bright suggestions? I don't want to call
>SetPort every time I go through the event loop, but I just might have to

     Do it.  It's the paranoid way, and it's the only way to be sure some
nasty little code-snippet doesn't ever change thePort behind your back.

Earle R. Horton

jmunkki@kampi.hut.fi (Juri Munkki) (08/10/89)

In <44ed4fee.19c13@locust.engin.umich.edu> mystone@sol.engin.umich.edu writes:
>In article <24321@santra.UUCP> jmunkki@kampi.hut.fi (Juri Munkki) writes:
>>StartSetup();	/* This calls InitWindows among other things.	*/
>>GetPort(&WindowManagerPort);
>>
>>do /* my main event loop */
>>{	/*	The following line fixes a bug in Suitcase:	*/
>>	if(thePort != WindowManagerPort)	SetPort(WindowManagerPort);
>>...
>
>  It works, but i wouldn't call it optimizing.  If you're setting the port
>to the Window Manager port every time the current port isn't the Window
>Manager's port, you're going to have to set the port to a window's grafPort
>every time you want to do any drawing.  If you're going to do that anyway, the
>conditional seems to be excess baggage.  (And you shouldn't be drawing to the
>Window Manager port anyway, if you are...)

The SetPort only happens when a DA or Suitcase (or something else) changes
thePort. My own routines always use GetPort/SetPort/Draw/SetPort. That's
why the bug was causing me so much trouble (a crash/week).

I'm not doing any drawing in the window manager port. I'm not even using
the window manager port. I just set thePort to point to that so that some
buggy DAs/FKEYs/... can have a grafport to play with (to create regions for
example). My own program always calls SetPort before drawing anything.
The alternative to the code above would have been to call SetPort every
time through the event loop.

Why do I have to call SetPort every time I want to draw something? If
DAs can change thePort, then I can't rely that my port setting will
remain when I call GetNextEvent/SystemTask.

_._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._._
|     Juri Munkki jmunkki@hut.fi  jmunkki@fingate.bitnet        I Want   Ne   |
|     Helsinki University of Technology Computing Centre        My Own   XT   |
^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^~^

dolf@janus.UUCP (Dolf Starreveld) (08/10/89)

jmunkki@kampi.hut.fi (Juri Munkki) writes:

>I just discovered that I had wasted several weeks hunting down a bug in
>my source code, when it actually wasn't there. The problem was that somehow
>the system was using grafports that didn't exist.
>	.... Trimmed ....

>I then proceeded to start with Suitcase II (v 1.2.2) enabled and the
>behavior changed. Whenever I opened a desk accessory, the port would
>change to that window. The problem is that when the desk accessory is
>closed, the port (thePort for you programmers) stays in that now
>defunct window.
Correct, this could even happen before Suitcase ever existed, because not
all DA programmers were doing what you are doing and restoring the original
port on exit. I don't have the docs handy right now, but it says somewhere
in IM-I that you should preserve the current port across calls to DAs (or
was it in a Tech Note, I'm not sure, but this info is very old). The confusing
thing is that IM also says that the desk manager preserves the current port
for you, but it doesn't.
> ... Trimmed ...
As far as I can see, preserving "thePort" whenever you call desk accessories
or anything else that might pop up windows in unexpected ways (read something
that is beyond your own control), or might change the current port, will
solve your problems.

--dolf

-- 
Dolf Starreveld  Phone: +31 20 592 5056/+31 20 592 5022, TELEX: 10262 HEF NL
EMAIL:           dolf@fwi.uva.nl (dolf%fwi.uva.nl@hp4nl.nluug.nl)
SNAIL:           Dept. of Math. and Computing Science, University of Amsterdam,
                 Kruislaan 409, NL-1098 SJ  Amsterdam, The Netherlands