[comp.sys.mac] Missing deactivate events

lipsett@inmet.UUCP (10/09/87)

I am writing an application that requires/allows multiple windows with
similar contents.  While a window is active, I want to maintain the
contents of the window in a data structure that is appropriate for
various data manipulations.  However, that form takes a lot of space,
so when the window is inactive, I want to compress the data structure
until the window is reactivated.  So, I use the refcon field in each
window to hold its compressed data.  Activate events extract and
uncompress the data; deactivate events compress the data and save it
in the refcon field.

This works fine in general.  However, when I throw an alert box up on
the screen, deactivate events either are not generated for the windows
covered by the alert box or else the alert box toolbox routine eats
them.  As a result, when the alert box is dismissed, the resulting
activate and update events lose badly, and either the windows are
displayed wrong or I get a bomb of one kind or another.

Either I am missing something obvious, or I have to call my deactivate
routine explicitly before calling NoteAlert, or I am just trying to be
too fancy with my refcon's, or...???

Thanks,
Roger Lipsett
{ihnp4,mirror}!inmet!lipsett

lippin@spam (tom lippincott) (10/12/87)

In article <127200007@inmet> lipsett@inmet.UUCP writes:
>However, when I throw an alert box up on
>the screen, deactivate events either are not generated for the windows
>covered by the alert box or else the alert box toolbox routine eats
>them.  As a result, when the alert box is dismissed, the resulting
>activate and update events lose badly, and either the windows are
>displayed wrong or I get a bomb of one kind or another.

I don't know what happens to those events, but it doesn't really matter --
they're not going to show up.  Even if they did show up, they would
be worthless because they couldn't be processed until the alert (actually
any modal dialog) went away, and they'd be just before the activate event.
The simple solution is to hang a flag off the refcon which tells whether
the window is active.  If it is, don't activate it again.

					May the Source be with you,
						--Tom Lippincott
						..ucbvax!bosco!lippin

     "Mr. Spock does NOT say `eat hot plasma death, klingon scumbags!'"
					--Berke Breathed

lsr@apple.UUCP (Larry Rosenstein) (10/12/87)

In article <127200007@inmet> lipsett@inmet.UUCP writes:
>
>This works fine in general.  However, when I throw an alert box up on
>the screen, deactivate events either are not generated for the windows
>covered by the alert box or else the alert box toolbox routine eats
>them.  As a result, when the alert box is dismissed, the resulting
>activate and update events lose badly, and either the windows are
>displayed wrong or I get a bomb of one kind or another.

The problem will appear with any modal dialog.  In a modal dialog, the
Dialog Manager is in control and receives the events.  If an event is
intended for a dialog window it can do something with it.  

If the event is for a non-dialog window, then it throws it away.  The
deactivate event for your window is such an event.  There's really not much
else it can do with such an event.  When the modal dialog goes away, your
application starts receiving events again, and one of the first it will get
is an activate event for its window

In MacApp, we took the approach someone else suggested, which is to keep
track of whether your application's window is already activated, and ignore
the "extra" activate.

If you want, you can catch the deactivate event by passing a filter proc to
the Alert or Modal Dialog call.  In the filter proc, you can call
IsDialogEvent, and if it returns FALSE (not a dialog event) pass the event
to your normal event handling code.

The only problem is that some calls to Alert/Modal Dialog don't come from
your application, which means you can't pass a filter proc.  You can,
however, create a global patch for the Modal Dialog trap which always passes
your filter proc in as a parameter.  (You will have to call the original
filter proc, if it exists.)

I did this once (a while ago), and it seemed to work.  I will try to dig up
the code, but I am not sure if it is around any longer.

-- 
Larry Rosenstein

Object Specialist
Apple Computer

AppleLink: Rosenstein1
UUCP:  {sun, voder, nsc, mtxinu, dual}!apple!lsr
CSNET: lsr@Apple.com

brian@ut-sally.UUCP (Brian H. Powell) (10/13/87)

In article <127200007@inmet>, lipsett@inmet.UUCP writes:
> Either I am missing something obvious, or I have to call my deactivate
> routine explicitly before calling NoteAlert, or I am just trying to be
> too fancy with my refcon's, or...???

     The various Alerts (and ModalDialog, by the way) swallow all the events
that occur while the Alert window is brought up.  That's why you're missing
the deactivate events.  They call HiliteWindow (indirectly) themselves, and
your code for deactivation never gets called.
     For your code, just do a deactivate (really a fake deactivate, see below)
before you call an Alert.  Dialogs don't cause this problem because the
activate/deactivate events are generated by [Get]NewDialog and not by
ModalDialog.  There are exceptions to this, such as SFGetFile and SFPutFile.
Those guys handle their "own" events, so you need to do a fake deactivate
before calling them.
     You also run into this problem with desk accessories.  Some DAs may
choose to put up an Alert or a standard file dialog.  DAs cause other problems
as well; you can't do a real deactivate because a DA might not bring up a
window.  (It might just install a menu item, for instance.)  This is why I
said you should do a "fake" deactivate.

     I had this problem with a TextEdit-based application where I had globals
that pertained to the frontmost (i.e., active) window.  When I got a
deactivate, I stored them in a record pointed to by the refCon field in the
window record.  I couldn't call TEDeactivate for these fake deactivates since
a DA without a window would leave one of my windows in front that was Hilited,
but without an active TE record, so I didn't have an insertion point or
selection range.

     Depending on what you're doing, you might not have to do a so-called
"fake" deactivate.  I had to fake it because I didn't want to call
TEDeactivate unnecessarily.  You might be able to call your real deactivate
routine.  This leads to your next problem...
     One of the features of my TE application was that it didn't hurt to copy
those globals to the refCon record twice (once for a fake deactivate and once
for a real deactivate, in case I got a real one in the case of a DA.)  In your
case, you can only compress once, so you have to be careful about not
recompressing compressed data.  With your code, you know exactly when you
won't be getting the deactivates.  With DAs, you won't know and you can't find
out.  Either don't allow DAs (a travesty in some peoples' minds) or leave a
flag around telling you whether the data has been compressed or not.  I think
you should do the latter.  Perhaps there are other solutions besides the two
that I have mentioned.

     Good luck.

Brian H. Powell
		UUCP:	...!uunet!ut-sally!brian
		ARPA:	brian@sally.UTEXAS.EDU

   _Work_					 _Not Work_
  Department of Computer Sciences		P.O. Box 5899
  Taylor Hall 2.124				Austin, TX 78763-5899
  The University of Texas at Austin		(512) 346-0835
  Austin, TX 78712-1188
  (512) 471-9536

denbeste@bgsuvax.UUCP (William C. DenBesten) (10/13/87)

How about setting the refcon to NILL (NUL) when ever you don't have
compressed data hooked to it.  Then when you go to decompress, check
to make sure that it is non-NILL and then do the decompression.  If it
was NILL, the stuff is allready compressed.

-bill

lsr@apple.UUCP (Larry Rosenstein) (10/15/87)

In article <9262@ut-sally.UUCP> brian@ut-sally.UUCP (Brian H. Powell) writes:
>
>     For your code, just do a deactivate (really a fake deactivate, see below)
>before you call an Alert.  Dialogs don't cause this problem because the
>activate/deactivate events are generated by [Get]NewDialog and not by
>ModalDialog.  There are exceptions to this, such as SFGetFile and SFPutFile.
>Those guys handle their "own" events, so you need to do a fake deactivate
>before calling them.

Dialogs are not completely immune from this problem.

The action of making a new window (dialog or not) frontmost will schedule a
pair of deactivate and activate events.  The next call to GetNextEvent will
return a deactivate event, and the following one an activate event.  

If ModalDialog makes the first call to GetNextEvent, it will throw away the
deactive, since it won't be directed to a dialog window.  If your code makes
the call, you can process the event normally.

In the case of alerts or Std File, it is not possible to run any of your
code between bringing up the dialog and calling ModalDialog.  In these
cases, you can use an event filter proc to catch the event.

-- 
Larry Rosenstein

Object Specialist
Apple Computer

AppleLink: Rosenstein1
UUCP:  {sun, voder, nsc, mtxinu, dual}!apple!lsr
CSNET: lsr@Apple.com