From: pottier@clipper.ens.fr (Francois Pottier) Subject: csmp-digest-v3-055 Date: Thu, 8 Sep 1994 18:50:13 +0200 (MET DST) C.S.M.P. Digest Thu, 08 Sep 94 Volume 3 : Issue 55 Today's Topics: Clover+. interrupt?~ Standard C Libraries: use them? Summary of 'Safe Save' problem - IM:Files flawed! What Happens in the Resource Fork Why does NewGWorld do this? Won't strange windows come in my layer? The Comp.Sys.Mac.Programmer Digest is moderated by Francois Pottier (pottier@clipper.ens.fr). The digest is a collection of article threads from the internet newsgroup comp.sys.mac.programmer. It is designed for people who read c.s.m.p. semi- regularly and want an archive of the discussions. If you don't know what a newsgroup is, you probably don't have access to it. Ask your systems administrator(s) for details. If you don't have access to news, you may still be able to post messages to the group by using a mail server like anon.penet.fi (mail help@anon.penet.fi for more information). Each issue of the digest contains one or more sets of articles (called threads), with each set corresponding to a 'discussion' of a particular subject. The articles are not edited; all articles included in this digest are in their original posted form (as received by our news server at nef.ens.fr). Article threads are not added to the digest until the last article added to the thread is at least two weeks old (this is to ensure that the thread is dead before adding it to the digest). Article threads that consist of only one message are generally not included in the digest. The digest is officially distributed by two means, by email and ftp. If you want to receive the digest by mail, send email to listserv@ens.fr with no subject and one of the following commands as body: help Sends you a summary of commands subscribe csmp-digest Your Name Adds you to the mailing list signoff csmp-digest Removes you from the list Once you have subscribed, you will automatically receive each new issue as it is created. The official ftp info is //ftp.dartmouth.edu/pub/csmp-digest. Questions related to the ftp site should be directed to scott.silver@dartmouth.edu. Currently no previous volumes of the CSMP digest are available there. Also, the digests are available to WAIS users. To search back issues with WAIS, use comp.sys.mac.programmer.src. With Mosaic, use http://www.wais.com/wais-dbs/comp.sys.mac.programmer.html. ------------------------------------------------------- >From arthur_babitz@mentorg.com (Arthur Babitz) Subject: Clover+. interrupt? Date: Tue, 23 Aug 1994 13:51:08 -0800 Organization: Mentor Graphics Corp., Wilsonville, OR., USA I've been trying unsuccessfully to implement a "clover+." interrupt for a compute intensive part of an application. I won't bore you with a list of things I've tried which don't work, but can someone point me in the right direction? Seems like there must be a standard, simple solution to this problem. Thanks! +++++++++++++++++++++++++++ >From timothys@hood.uucp (Timothy Sherburne) Date: 24 Aug 94 16:19:46 GMT Organization: University of Portland arthur_babitz@mentorg.com (Arthur Babitz) writes: >I've been trying unsuccessfully to implement a "clover+." interrupt for a >compute intensive part of an application. I won't bore you with a list of >things I've tried which don't work, but can someone point me in the right >direction? Seems like there must be a standard, simple solution to this >problem. >Thanks! The trick is to check for a cmd-. (the "clover" key is usually called the command key) in your event loop. Or you could implement a GetKeys filter. Here's a snippet using WaitNextEvent that returns a "true" if cmd-. is detected: Boolean CheckForCmdPeriod (void) { EventRecord theEvent; char key; Boolean result = false; // Wait for an event... if (WaitNextEvent (keyDownMask, &theEvent, kMaxSleep, nil)) { // Get the ASCII value of the key from the event record... key = theEvent.message & charCodeMask; // If the key value is equal to that of the period key and // the command modifier key is also being held down, then // set result to true... if ((theEvent.modifiers & cmdKey) && key == '.') // cmd-. result = true; } return result; } Here's a snippet using the "GetKeys" toolbox call: Boolean CheckForCmdPeriod (void) { KeyMap keys; // Check to see if the user has pressed command-period keys... GetKeys (keys); if(keys [1] & 0x00800000) // command { GetKeys (keys); if(keys[1] & 0x00008000) // . (period) { FlushEvents (mDownMask + mUpMask, 0); return true; } } else return false; } The GetKeys call will catch cmd-. that is intended for anyone, so use it sparingly. It will also not filter the cmd-. Don't Panic, t -- | Timothy Sherburne | Software Engineer | | Internet: timothys@uofport.edu | Prometheus Products, Inc. | | AppleLink: D6164@applelink.apple.com | 1-800-477-3473 | *All comments are my own and in no way represent those of Prometheus Products* +++++++++++++++++++++++++++ >From dshayer@netcom.com (David Shayer) Date: Wed, 24 Aug 1994 18:04:50 GMT Organization: NETCOM On-line Communication Services (408 261-4700 guest) Arthur Babitz (arthur_babitz@mentorg.com) wrote: : I've been trying unsuccessfully to implement a "clover+." interrupt for a : compute intensive part of an application. I won't bore you with a list of : things I've tried which don't work, but can someone point me in the right : direction? Seems like there must be a standard, simple solution to this : problem. The simplest solution is to simply call WaitNextEvent every so often, checking for keydown events of cmd-period. This is polling, not interrupt based. But that's the correct way to do it on a Mac. David +++++++++++++++++++++++++++ >From rhn@waltz.engr.sgi.com (Ron Nicholson) Date: Thu, 25 Aug 1994 02:02:12 GMT Organization: Silicon Graphics, Inc., Mountain View, CA In article , Timothy Sherburne wrote: >arthur_babitz@mentorg.com (Arthur Babitz) writes: > >>I've been trying unsuccessfully to implement a "clover+." interrupt for a >>compute intensive part of an application. I won't bore you with a list of >>things I've tried which don't work, but can someone point me in the right >>direction? Seems like there must be a standard, simple solution to this >>problem. (snip) >Here's a snippet using WaitNextEvent that returns a "true" if cmd-. ... > (snip) A program has to call WaitNextEvent to cleanly check for a keyboard abort (command-period). I tried this in an inner loop of a compute intensive application and it slowed down the computation noticeably. I had to figure out a way to poll often enough to not make the user interface seem sluggish, while slowing calculation down minimally. What I now do is to is this: First I install a VBL task whose only function is to increment a global variable. That gives me a tickcount variable that can be read without a function call. You can also use the TickCount() access function. (Or you can just use the lowmem global Ticks at $016A if you aren't strictly following Apple's guidelines. Would I do that? :-) In my inner loop I have code similar to: /* in pseudo code */ int ComputeIntensiveFunction(parameters ...) { ... volatile long int *myTickCountPtr; long int CheckNow; int LocalCounter; /* a local variable */ myTickCountPtr = &some_tickcount_global; /* point at tickcount */ CheckNow = *myTickCountPtr + 6; /* every 10th of a second */ LocalCounter = 25; ... for (i=1,i<1000000000;i++) { ... /* compute intensive inner loop stuff that goes on forever */ if (--LocalCounter <= 0) { if (*myTickCountPtr >= CheckNow) { flag = CheckForAbortEvent(); /* wrapper for WaitNextEvent */ if (flag) return(kSomeErrorCode); /* abort calculation */ /* or alternatively just break */ else CheckNow = *myTickCountPtr + 6; } LocalCounter = 25; /* or some such value */ } } ... return(kFinishedCalculating); } Every time through the loop, the code does one local variable decrement and compare. Every 25th time, the code does one global variable (probably uncached and thus slower) load and compare. Every 10th of a second, the code polls the event queue for abort, application switches, etc. The "6" and "25" are just example values. You might want to choose the initial loop counter value based on application tuning and the processor speed of the Mac on which the application is running. - - Ronald H. Nicholson, Jr. rhn@engr.sgi.com, rhn@netcom.com, N6YWU #include // I speak only for myself, etc. +++++++++++++++++++++++++++ >From radixinc@aol.com (RadixInc) Date: 25 Aug 1994 01:11:10 -0400 Organization: America Online, Inc. (1-800-827-6364) In article , rhn@waltz.engr.sgi.com (Ron Nicholson) writes: << A program has to call WaitNextEvent to cleanly check for a keyboard abort (command-period). I tried this in an inner loop of a compute intensive application and it slowed down the computation noticeably. I had to figure out a way to poll often enough to not make the user interface seem sluggish, while slowing calculation down minimally. >> A program has to call WaitNextEvent to cleanly do a lot of things. If you aren't checking events you are hogging the machine and not letting other apps have time. And what do you mean "not make the user interface seem sluggish?" What user interface do you have when you aren't checking for events? << First I install a VBL task whose only function is to increment a global variable. That gives me a tickcount variable that can be read without a function call. You can also use the TickCount() access function. (Or you can just use the lowmem global Ticks at $016A if you aren't strictly following Apple's guidelines. Would I do that? :-) >> This is silly. Just call TickCount(), or if you have to, just look at Ticks. You are overly worried about performance, yet you install a VBL task that does the same thing as an existing VBL task (how do you think Ticks gets updated in the first place?). You can use any DOCUMENTED low-memory globals, like Ticks, without getting in trouble. Certainly given the choice between that and installing a VBL, DTS would advise the former. As for the code sample, why not call EventAvail periodically with an event mask that ignores events you don't care about? That way you won't end up with an event loop inside your compute-intensive loop and (presumably) another one in your main program. (DTS will certainly frown on calling WaitNextEvent from more than one place in your program). And rather than using Ticks and the local counter, use a modulo calculation on your loop variable; e.g. check for an event every 10,000 iterations or so. Make it work first, optimize the slow parts later [after identifying the slow parts]. Gregory Jorgensen Radix Consulting Inc. +++++++++++++++++++++++++++ >From rhn@waltz.engr.sgi.com (Ron Nicholson) Date: Thu, 25 Aug 1994 17:31:16 GMT Organization: Silicon Graphics, Inc., Mountain View, CA In article <33h95e$ekn@search01.news.aol.com>, RadixInc wrote: > >As for the code sample, why not call EventAvail periodically with an event >mask that ignores events you don't care about? That way you won't end up >with an event loop inside your compute-intensive loop and (presumably) >another one in your main program. (DTS will certainly frown on calling >WaitNextEvent from more than one place in your program). And rather than >using Ticks and the local counter, use a modulo calculation on your loop >variable; e.g. check for an event every 10,000 iterations or so. > You're right, EventAvail is a better choice for polling. But what's wrong with calling WNE from more than one place? WNE has an eventmask also. I just get the events that I want to abort my loop, allow WNE to put the program in the background, etc. Using a modula on the loop count is very bad. The difference in speed between a Plus and a 8100/80 is enormous, especially on FP stuff. Either you will poll much to seldom on slow machines. Or waste a lot of time in WNE on fast machines. That's assuming that the time through the loop is deterministic. If it isn't, the Mac GUI could get jerky suddenly if the modulo is set wrong on any machine. My goal was to poll WNE at the same rate on slow and fast machines so that the Mac GUI never feels jerky (menus drop promptly, etc.). Around the neighborhood of 15 times a second feels about right. This works for me and doesn't slow down a program that spends a lot of time doing FFT's more than 1%. - - Ronald H. Nicholson, Jr. rhn@engr.sgi.com, rhn@netcom.com, N6YWU #include // I speak only for myself, etc. +++++++++++++++++++++++++++ >From radixinc@aol.com (RadixInc) Date: 25 Aug 1994 15:29:10 -0400 Organization: America Online, Inc. (1-800-827-6364) I understand that the overhead of making the WNE toolbox call and polling for events is time consuming, especially if you are trying to squeeze the most performance out of a loop. Lots of programs just put up the "watch" cursor and ignore all events while they do their computation. This is considered bad etiquette, because WNE does more than just feed events to your app. It is the only way to let other processes have time. Those other processes may just be apps sitting there waiting for user input, in which case it doesn't matter, but they may be important background processes, such as network software or background printing. Because so many programs are rude about giving up time with WNE, some developers have gone the route of installing VBL or Time Manager tasks to make sure they get time, and this is even worse. If your method of calling WNE every 10 ticks works, and you can live with the potential problems of having two WNE calls in your program, great. I still think you'd be better off calling EventAvail with an event mask, so if an event does show up you can exit your loop and let your "main" even loop handle the event (EventAvail doesn't dequeue the event). You can use a mask to just look for keyboard events, so mouse events and so on are ignored (but remain in the even queue). Also keep in mind that, depending on the speed of the Mac you are running on, events don't live all that long. The event queue only holds 20 events, and if you aren't removing them with WNE the old events will be lost. That means you have to poll for events fast enough to catch them before they are lost. User-interface events will happen much less frequently than every 10 ticks, but network events may happen very fast on certain Macs. Gregory Jorgensen Radix Consulting Inc. +++++++++++++++++++++++++++ >From wilkins@jarthur.cs.hmc.edu (Mark Wilkins) Date: 25 Aug 1994 21:03:07 GMT Organization: Harvey Mudd College, Claremont CA In article <33ire6$s4i@search01.news.aol.com>, RadixInc wrote: >If your method of calling WNE every 10 ticks works, and you can live with >the potential problems of having two WNE calls in your program, great. I >still think you'd be better off calling EventAvail with an event mask... What possible problems could be caused by having multiple calls to WaitNextEvent in an application, especially if the purpose is to check for interruption of a time-consuming process? An application which doesn't try to do nifty things like threading will usually limit user input during a time-consuming processing task to that which could interrupt the task or that which needs to be passed on to the OS such as a click in another app's window. In other words, why should I care if I'm throwing away events which don't consist of a command period or mouse click when those are the only two forms of interaction my application will entertain when it's chugging away? That is, assuming I'm only throwing away events directed at my application... I'm just not sure I see the issue. -- Mark Wilkins +++++++++++++++++++++++++++ >From radixinc@aol.com (RadixInc) Date: 26 Aug 1994 00:11:08 -0400 Organization: America Online, Inc. (1-800-827-6364) In article <33j0ub$eip@jaws.cs.hmc.edu>, wilkins@jarthur.cs.hmc.edu (Mark Wilkins) writes: <> It's mostly a matter of style, and of course it is generic Mac programming advice to have only one place in your code call WNE. It sounds like you know what you are doing, and perhaps this is the best way to handle it. The complication of calling WNE from more than one place is that you have to (or at least should) handle ALL events you get. In your case you are going to ignore all events except the ones that can terminate your loop. It's most important that you call WNE periodically (and often), for the reasons mentioned in my previous post, even if you don't handle all of the events. Besides the key and mouse events, there are other events you may get. You can't really get switched out if you ignore mouse clicks outside of your window, but another process could do something that causes an update event in one of your windows. Or a high-level event could get passed to you (if your program accepts them). If you call WNE but can't respond to these events in your computation loop, your window won't be updated and you won't be able to process Apple Events. In your case maybe this is not a big deal. There is no "hard" reason to have only one WNE call in your program, as long as you know that you may lose events. Gregory Jorgensen Radix Consulting Inc. +++++++++++++++++++++++++++ >From kluev@jonathan.srcc.msu.su (Kluev) Date: Sun, 28 Aug 94 18:13:09 +0400 Organization: (none) In article <33h95e$ekn@search01.news.aol.com> radixinc@aol.com (RadixInc) wrote: > In article , rhn@waltz.engr.sgi.com (Ron > Nicholson) writes: > << > First I install a VBL task whose only function is to increment a global > variable. That gives me a tickcount variable that can be read without > a function call. You can also use the TickCount() access function. > (Or you can just use the lowmem global Ticks at $016A if you aren't > strictly following Apple's guidelines. Would I do that? :-) > >> > This is silly. Just call TickCount(), or if you have to, just look at > Ticks. You are overly worried about performance, yet you install a VBL > task that does the same thing as an existing VBL task (how do you think > Ticks gets updated in the first place?). First: There is no special VBL task that increments Ticks. Second: Installing VBLTask that increments global variable gives you much less accuracy than looking into Ticks (TickCount). This inaccuracy will heavily depend on machine load and may rise up to several "real" ticks against one "your" tick. Ticks is guaranteed to be incremented every tick, but your VBLTask (which contains 1 in vblCount) is not guaranteed to be called every tick. > WaitNextEvent from more than one place in your program). And rather than > using Ticks and the local counter, use a modulo calculation on your loop > variable; e.g. check for an event every 10,000 iterations or so. This is bad practice. If "10,000" is hard-coded you will get different response time on different machines. It may be computed at start-time. But think: machine load (VBLs for example) may vary during program execution. Processor cache may be turned on/off. All this and more will invalidate this "10,000" estimate. Ticks is better. Michael Kluev. +++++++++++++++++++++++++++ >From radixinc@aol.com (RadixInc) Date: 29 Aug 1994 02:13:04 -0400 Organization: America Online, Inc. (1-800-827-6364) In article <584486046668@jonathan.srcc.msu.su>, kluev@jonathan.srcc.msu.su (Kluev) writes: <> Not on newer Macs, no. Ticks used to get updated by a VBL task, but now it is synthesized. It doesn't matter how it gets updated; the point is that it is better to get the value of Ticks, either by function call or reading the global directly. If you use the Universal Headers you can read the Ticks global and stay compatible by using LMGetTicks(). For historical reasons it's easier to pretend that Ticks is incremented at VBL time, even though on most Macs it isn't actually done that way. I apologize if anyone was confused or misled by my statement, but it really makes no difference how Ticks gets incremented, and by design it appears that it is done at VBL time. <> Obviously, but you are misreading my message. I wasn't suggesting hard-coding the number 10,000, or any other number--I was suggesting a modulo calculation based on SOME modulus. The actual number used could be any value, and could be calculated in advance to account for differences among machines. 10,000 was simply an illustrative example, and that's why I wrote "e.g. check for an event every 10,000 iterations or so." "e.g." is an abbrevation for "exempli gratia," meaning "for example," not to be confused with "i.e.," (id est), meaning "that is." This should be self-evident to anyone capable of writing a VBL task in the first place, and therefore I didn't see any reason to exhaustively explain what I was suggesting. Quod erat demonstrandum. <> I agree, but the original post, and my response, were discussing other approaches. My suggestion, which was followed up by email, was to simply read the value of Ticks and be done with it. Done correctly the modulus method is a legitimate way to handle the problem, if for some reason the programmer doesn't want to use Ticks. Gregory Jorgensen Radix Consulting Inc. +++++++++++++++++++++++++++ >From besbris@jeeves.ucsd.edu (David Besbris) Date: 29 Aug 1994 10:25:39 GMT Organization: The Avant-Garde of the Now, Ltd. Kluev (kluev@jonathan.srcc.msu.su) wrote: (snip) : First: There is no special VBL task that increments Ticks. : Second: Installing VBLTask that increments global variable gives you : much less accuracy than looking into Ticks (TickCount). This inaccuracy : will heavily depend on machine load and may rise up to several "real" : ticks against one "your" tick. Ticks is guaranteed to be incremented : every tick, but your VBLTask (which contains 1 in vblCount) is not : guaranteed to be called every tick. (snip) : This is bad practice. If "10,000" is hard-coded you will get different : response time on different machines. It may be computed at start-time. : But think: machine load (VBLs for example) may vary during program : execution. Processor cache may be turned on/off. All this and more : will invalidate this "10,000" estimate. Ticks is better. : Michael Kluev. Ticks is INDEED incremented by a system-installed VBL task, and is NOT guaranteed to be inceremented exactly once evey tick. (for the reasons that you mention about the inaccuracy of using a VBL task.) I'm curious, why do you say otherwise? -Dave One of the last Mac Pascal programmers... besbris@jeeves.ucsd.edu +++++++++++++++++++++++++++ >From kluev@jonathan.srcc.msu.su (Kluev) Date: Tue, 30 Aug 94 16:42:18 +0400 Organization: (none) In article <33sd33$4lh@network.ucsd.edu> besbris@jeeves.ucsd.edu (David Besbris) wrote: > Kluev (kluev@jonathan.srcc.msu.su) wrote: > (snip) > > : First: There is no special VBL task that increments Ticks. > : Second: Installing VBLTask that increments global variable gives you > : much less accuracy than looking into Ticks (TickCount). This inaccuracy > : will heavily depend on machine load and may rise up to several "real" > : ticks against one "your" tick. Ticks is guaranteed to be incremented > : every tick, but your VBLTask (which contains 1 in vblCount) is not > : guaranteed to be called every tick. > > : Michael Kluev. > > Ticks is INDEED incremented by a system-installed VBL task, and is NOT > guaranteed to be inceremented exactly once evey tick. (for the reasons that > you mention about the inaccuracy of using a VBL task.) I'm curious, why do > you say otherwise? > > -Dave Here's the story on how VBL mechanism work, at least as I understand it. Ticks is updated by "VBL mechanism", *not* by system-installed VBL task. The first thing that is done by VBL mechanism is incrementing Ticks variable. Then it gets sure that it is not already running (by looking in VBLQueue). If it is already running, there is nothing to do, just return. If it is not running, mechanism decrements vblCounts of VBL tasks, and calls those, which have zero in vblCount. While VBL task is getting called, VBL mechanism may be entered again. (This is another story, how is it getting called: is it real video card interrupt, or is it triggered VIA interrupt. For now it is important only, that mechanism is getting called every 1/60 sec or so.) In this case the only thing it does is incrementing Ticks variable. So Ticks *is guaranteed* (if we aren't talking about situations when interrupts are disabled for a long time, e. g. diskette formatting) to be incremented every tick, but VBL task that has 1 in vblCount *is not guaranteed* to be called every tick. As far as I know all Macs since 1984 share this scheme. If you don't believe me, disassemble a few bytes of ROM above the code that calls your VBL task (on my machine it starts at "_VRemove+16". You will see: +0014 RTS ; Starting point of "VBL mechanics" +0016 ADDQ.L #$1, Ticks; increments Ticks global +001A ..... +0020 BSET #$06, VBLQueue; test if it is already running +0026 BNE _VRemove+0014; nothing can do - return. If you still don't believe me, write a small test. Install VBL task that does the following: ... Task-> vblCount = 1; // reinstalls itself MyTicks++; // increments global Delay(10, &L); // degrades machine performance, // (emulates Mac Plus or so) // You may try to use this "for" loop instead of Delay // for (i = 0; i < 1000000L; i++); ... In your main write: ... VInstall(...); // installs VBL task with 1 in vblCount MyOldTicks = MyTicks; // saves old timers OldTicks = TickCount(); Delay(60*10); // waits 10 seconds MyNewTicks = MyTicks; NewTicks = TickCount(); // gets new timers NumToString(MyNewTicks - MyOldTicks, String); DebugStr(String); NumToString(NewTicks - OldTicks, String); DebugStr(String); // makes things obvious ...You will notice a big difference. As someone else pointed, for more exact and/or long-term measurements it is better to use other mechanisms instead of Ticks (e. g. Time Manager or GetDateTime). Michael Kluev. +++++++++++++++++++++++++++ >From kluev@jonathan.srcc.msu.su (Kluev) Date: Fri, 2 Sep 94 21:33:30 +0400 Organization: (none) In article <33ire6$s4i@search01.news.aol.com> radixinc@aol.com (RadixInc) wrote: > I understand that the overhead of making the WNE toolbox call and polling > for events is time consuming, especially if you are trying to squeeze the > most performance out of a loop. Lots of programs just put up the "watch" > cursor and ignore all events while they do their computation. This is > considered bad etiquette, because WNE does more than just feed events to > your app. It is the only way to let other processes have time. EventAvail and GetNextEvent also allow other processes to work. Their "time consuming" is approximately the same as of WaitNextEvent. > Also keep in mind that, depending on the speed of the Mac you are running > on, events don't live all that long. The event queue only holds 20 events, > and if you aren't removing them with WNE the old events will be lost. That > means you have to poll for events fast enough to catch them before they > are lost. User-interface events will happen much less frequently than > every 10 ticks, but network events may happen very fast on certain Macs. Do you use those cool "network" events? This is not recommended practice. Michael Kluev. +++++++++++++++++++++++++++ >From radixinc@aol.com (RadixInc) Date: 25 Aug 1994 01:11:10 -0400 Organization: America Online, Inc. (1-800-827-6364) In article , rhn@waltz.engr.sgi.com (Ron Nicholson) writes: << A program has to call WaitNextEvent to cleanly check for a keyboard abort (command-period). I tried this in an inner loop of a compute intensive application and it slowed down the computation noticeably. I had to figure out a way to poll often enough to not make the user interface seem sluggish, while slowing calculation down minimally. >> A program has to call WaitNextEvent to cleanly do a lot of things. If you aren't checking events you are hogging the machine and not letting other apps have time. And what do you mean "not make the user interface seem sluggish?" What user interface do you have when you aren't checking for events? << First I install a VBL task whose only function is to increment a global variable. That gives me a tickcount variable that can be read without a function call. You can also use the TickCount() access function. (Or you can just use the lowmem global Ticks at $016A if you aren't strictly following Apple's guidelines. Would I do that? :-) >> This is silly. Just call TickCount(), or if you have to, just look at Ticks. You are overly worried about performance, yet you install a VBL task that does the same thing as an existing VBL task (how do you think Ticks gets updated in the first place?). You can use any DOCUMENTED low-memory globals, like Ticks, without getting in trouble. Certainly given the choice between that and installing a VBL, DTS would advise the former. As for the code sample, why not call EventAvail periodically with an event mask that ignores events you don't care about? That way you won't end up with an event loop inside your compute-intensive loop and (presumably) another one in your main program. (DTS will certainly frown on calling WaitNextEvent from more than one place in your program). And rather than using Ticks and the local counter, use a modulo calculation on your loop variable; e.g. check for an event every 10,000 iterations or so. Make it work first, optimize the slow parts later [after identifying the slow parts]. Gregory Jorgensen Radix Consulting Inc. --------------------------- >From dlopez@sailsun (Dean Lopez) Subject: Standard C Libraries: use them? Date: 12 Aug 1994 18:46:29 GMT Organization: NASA Johnson Space Center, Houston, TX, USA I am wondering about the 'legitimacy' of using the Standard C Libraries in my Mac applications. As a C programmer on other systems, I've become quite fond of the Standard C libraries - stdio.h in particular. The problem with using them on the Mac, as I'm sure you all know, is the way files are reference via FILE* 'ers compared with the File Manager's file reference numbers. If I use the File Manager, I don't see how I can use the stdio.h functions which require a FILE*. And if I use the stdio.h functions, I can't use some of the File Manager's goodies. Has anybody figured out how to convert the FILE structure info into the FSSpec structure? (I mean written the routines already, I really don't have the time right now to attempt it myself). I'd just like to be able to interchange how I reference a file right now, in the same way on say, a Data General system using AOS will let me reference a file either with the stdio or Unix calls. Is there a reason NOT to try to use either/or? Any and all advice welcome. NOTE: if you e-mail me, see my email addresses below, don't use what's in my reply-to field. Its messed up somehow. -- +---------------------------------------+-----------------------------+ | Dean Lopez | | | SAIL DPS Engineer | dlopez@sailsun.jsc.nasa.gov | | Rockwell Space Operations Co. | deanlopez@aol.com | | JSC Shuttle Avionics Integration Lab | dean_lopez@maclair.cld9.com | +---------------------------------------+-----------------------------+ #include /* The opinions expressed are all mine. RSOC doesn't speak for me and I don't speak for RSOC After all, I'm only an engineer - what do I know? */ +++++++++++++++++++++++++++ >From rollin@newton.apple.com (Keith Rollin) Date: Thu, 18 Aug 1994 04:26:36 -0800 Organization: Apple ][ -> Mac -> Taligent -> Newton -> Windows? In article <32gg25$of9@pendragon.jsc.nasa.gov>, dlopez@sailsun (Dean Lopez) wrote: >I am wondering about the 'legitimacy' of using the Standard C Libraries >in my Mac applications. As a C programmer on other systems, I've become >quite fond of the Standard C libraries - stdio.h in particular. The >problem with using them on the Mac, as I'm sure you all know, is the way >files are reference via FILE* 'ers compared with the File Manager's >file reference numbers. If I use the File Manager, I don't see how I >can use the stdio.h functions which require a FILE*. And if I use the >stdio.h functions, I can't use some of the File Manager's goodies. > >Has anybody figured out how to convert the FILE structure info into the >FSSpec structure? (I mean written the routines already, I really don't >have the time right now to attempt it myself). >I'd just like to be able to interchange how I reference a file right >now, in the same way on say, a Data General system using AOS will let >me reference a file either with the stdio or Unix calls. > >Is there a reason NOT to try to use either/or? Check the Mac Technotes: "Frequently, developers want to use both Macintosh file I/O and C file I/O. Developers who do this must keep in mind that they are combining two distinct file representations (the Macintosh and ANSI C). The only limitation on mixing HFS and C I/O functions is that they cannot be mixed on the same open file. There are three reasons why this cannot be done. "First, there is no routine that maps between a C FILE struct (returned by fopen()) to an HFS fRefNum (needed to call HFS functions). Similarly, there is no call to create a FILE struct given an fRefNum returned by FSOpen(). Thus, there is no way that the information from an fopen() call could be used to do a FSRead(). "Second, even if the first problem were solved, the C libraries eventually call the HFS file system, but keep some internal state information. So, if you call HFS directly (say, SetFPos()), the C file system has no way of knowing a call was made and, therefore, doesn¹t update its state information. "Similarly, there is no mechanism for synchronizing the C library¹s buffers. For example, you perform an fwrite() with some number of characters which get put into a buffer without flushing it. Then you perform an FSWrite() with something else. Neither the C library nor HFS are aware that the other has written to the file. "Simply put, you cannot make HFS calls on a file opened with fopen() or fdopen(); you cannot use C library I/O on a file opened under HFS." - -------------------------------------------------------------------------- Keith Rollin --- Phantom Programmer --- Apple Computer, Inc. --- Team Newton +++++++++++++++++++++++++++ >From cjsmith@nwu.edu (Jeremy Smith) Date: 18 Aug 1994 15:37:49 GMT Organization: Northwestern University, Evanston, IL USA I'm not sure, what exactly you're trying to do, but if you have a copy of Think Reference, go to misc. topics/Code Example Orphans/Printing a Text File and look at the GotATextFile procedure. This uses a medly of toolbox and ANSI file routines. Good luck, Jeremy Smith cjsmith@nwu.edu +++++++++++++++++++++++++++ >From phils@bedford.symantec.com (Phil Shapiro) Date: Mon, 22 Aug 1994 14:37:27 -0400 Organization: Symantec Corp. In article , rollin@newton.apple.com (Keith Rollin) wrote: | In article <32gg25$of9@pendragon.jsc.nasa.gov>, dlopez@sailsun (Dean | Lopez) wrote: | | >I am wondering about the 'legitimacy' of using the Standard C Libraries | >in my Mac applications. As a C programmer on other systems, I've become | >quite fond of the Standard C libraries - stdio.h in particular. The | >problem with using them on the Mac, as I'm sure you all know, is the way | >files are reference via FILE* 'ers compared with the File Manager's | >file reference numbers. If I use the File Manager, I don't see how I | >can use the stdio.h functions which require a FILE*. And if I use the | >stdio.h functions, I can't use some of the File Manager's goodies. | > | >Is there a reason NOT to try to use either/or? | | Check the Mac Technotes: | | "First, there is no routine that maps between a C FILE struct (returned by | fopen()) to an HFS fRefNum (needed to call HFS functions). Similarly, | there is no call to create a FILE struct given an fRefNum returned by | FSOpen(). Thus, there is no way that the information from an fopen() call | could be used to do a FSRead(). The Mac Technotes have always assumed that everyone is using the MPW development system. If you're using THINK, you *can* get the refnum for an open FILE. It's stored in the field called "refnum". You could also write a stdio routine that builds a FILE* from an open file, since the THINK libraries ship with full source. But that's a fair amount of work just because you happen to like ANSI I/O. You will only be able to use the code in THINK, too. Unless you're porting a lot of code that already uses ANSI I/O, you're much better off going with straight Mac I/O. -phil +++++++++++++++++++++++++++ >From nagle@netcom.com (John Nagle) Date: Tue, 23 Aug 1994 02:02:25 GMT Organization: NETCOM On-line Communication Services (408 261-4700 guest) phils@bedford.symantec.com (Phil Shapiro) writes: >In article , >rollin@newton.apple.com (Keith Rollin) wrote: >| In article <32gg25$of9@pendragon.jsc.nasa.gov>, dlopez@sailsun (Dean >| Lopez) wrote: >| >I am wondering about the 'legitimacy' of using the Standard C Libraries >| >in my Mac applications. As a C programmer on other systems, I've become >| >quite fond of the Standard C libraries - stdio.h in particular. >The Mac Technotes have always assumed that everyone is using the MPW >development system. If you're using THINK, you *can* get the refnum for an >open FILE. >Unless you're porting a lot of code that already uses ANSI I/O, you're >much better off going with straight Mac I/O. Of course, then you have to try to read a text file with the Toolbox calls, a difficult, slow, and badly documented operation. Anybody have the obscure tech note reference on doing that? John Nagle +++++++++++++++++++++++++++ >From zstern@adobe.com (Zalman Stern) Date: Tue, 23 Aug 1994 05:51:49 GMT Organization: Adobe Systems Incorporated That the Mac API prevents the use of stdio in many cases is just a bug. Any reasonable UNIX system provides functions to map a FILE * to a file descriptor (the moral equivalent of a Mac file reference number) and to open a FILE * from a file descriptor. (They're called fileno and fdopen respectively.) The conventions for switching between system call level I/O and stdio are a bit arcane but workable for most uses of this functionality. (The fdopen call is necessary because UNIX has a unified model of stream I/O which a large number of things obey. There are many ways to get a file descriptor, but once you have one it behaves according to this model and turning it into a stdio stream is very useful.) I've seen a number of posts recently that express the attitude that there is no point in using portable API's for Macintosh programming because Mac applications are inherently non-portable. (Or perhaps these posters feel a program isn't a good Macintosh application unless its non-portable.) People who feel this way are quickly becoming economic roadkill, and deservedly so. One writes non-portable code because less than ideal circumstances forces one to, not because it is desirable. -- Zalman Stern zalman@adobe.com (415) 962 3824 Adobe Systems, 1585 Charleston Rd., POB 7900, Mountain View, CA 94039-7900 Please do not change color while I am talking to you -- MC 900 Ft Jesus. +++++++++++++++++++++++++++ >From tree@bedford.symantec.com (Tom Emerson) Date: Tue, 23 Aug 1994 06:33:54 -0500 Organization: Symantec Development Tools Group > >Unless you're porting a lot of code that already uses ANSI I/O, you're > >much better off going with straight Mac I/O. > > Of course, then you have to try to read a text file with the > Toolbox calls, a difficult, slow, and badly documented operation. > Anybody have the obscure tech note reference on doing that? IM: Files, p. 2-90 & 2-122. -tre -- Tom Emerson Software Engineer Development Tools Group Symantec Corporation tree@bedford.symantec.com "I dreamed I had to take a test, in a Dairy Queen, on another planet." +++++++++++++++++++++++++++ >From quinn@cs.uwa.edu.au (Quinn "The Eskimo!") Date: Thu, 25 Aug 1994 11:40:13 +0800 Organization: Department of Computer Science, The University of Western Australia In article <1994Aug23.055149.5764@adobe.com>, zstern@adobe.com (Zalman Stern) wrote: >That the Mac API prevents the use of stdio in many cases is just a bug. I disagree with this. Any API that promotes the use of full paths to denote files is fundamentally broken for use on a Mac, mainly because multiple volumes can have the same name. Of course you can work around this problem but there comes a point where you've got to decide whether your workaround is worth the effort. -- Quinn "The Eskimo!" "Scout in a can. Simple, cheap, easy to use and it's expendable!" +++++++++++++++++++++++++++ >From zstern@adobe.com (Zalman Stern) Date: Thu, 25 Aug 1994 07:10:14 GMT Organization: Adobe Systems Incorporated Quinn "The Eskimo!" writes > In article <1994Aug23.055149.5764@adobe.com>, zstern@adobe.com (Zalman > Stern) wrote: > >That the Mac API prevents the use of stdio in many cases is just a bug. > > I disagree with this. Any API that promotes the use of full paths to > denote files is fundamentally broken for use on a Mac, mainly because > multiple volumes can have the same name. Of course you can work around > this problem but there comes a point where you've got to decide whether > your workaround is worth the effort. Fine write a function like so: FILE * FSfopen(FSSpec *fileSpec, char *mode); or perhaps a function that pops up a standard file dialog and opens a file that way. Then you can write the file processing routines in a portable fashion. The other alternative is to write your own stream library and ensure that it is portable, but that is fraught with problems. (E.g. the MacApp stream implementation which does no buffering.) I prefer not to re-invent the wheel unless I have to. My original point is that with a little work in the stdio implementation one can go back and forth easily. My use of "The Mac API" is wrong. I meant the standard C library implementation combined with the toolbox requirements. Obviously the C library implementation is a better choice to change. -- Zalman Stern zalman@adobe.com (415) 962 3824 Adobe Systems, 1585 Charleston Rd., POB 7900, Mountain View, CA 94039-7900 Please do not change color while I am talking to you -- MC 900 Ft Jesus. --------------------------- >From redial Subject: Summary of 'Safe Save' problem - IM:Files flawed! Date: Thu, 25 Aug 1994 04:29:12 GMT Organization: NETCOM On-line Communication Services (408 261-4700 guest) Netters - Awhile ago I posted a request for help with a problem I was having implementing the 'Safe Save' routine outlined in Inside Macintosh:Files, pp. 1-25,26. A 'safe save' is a save routine which creates a temporary file on disk, saves the data to it, and - if no error occurs - swaps the the directory information for the two files, and then deletes the temporary file. The advantage over a 'direct save' to the existing file is that if an error were to occur, the existing file could be damaged and its data erased or corrupted. The IM example code is in Pascal (naturally), but since I am working in C I attempted to translate it to that language. The problem I ran into was that after the directory swap between the files, I would get a 'file busy' error when I attempted to delete the temporary file. This was quite puzzling since the code clearly executes a command to close the temporary file immediately before the delete command. Scott Bronson pointed out that the swap command, FSpExchangeFiles, swaps the FCBs too, and recommended closing both files before swapping. However, a comment line in the original pascal example directed that the data fork of the existing file be opened and left open! I wondered why, but Scott thought this was just another example of how inaccurate the code examples in IM can be. The bugginess of the 'Safe Save' routine certainly attests to this fact! Further snooping led to several bits of info about the two files which enabled Troy Gaul to correctly diagnose that the IM example code called for a resource to be written to the original file BEFORE the swap. Thus, it contained the resource and the old data, while the temporary file contained only the new data. AFTER the swap, the original file then contained only the new data while the temporary file contained the resource and the old data. Troy also pointed out that since FSpExchangeFiles also swaps the FCBs if either or both files are open, the FSClose routine needs to use the path reference number of the _original_ file in order to actually close the temporary file! This means that future references to the original file will require the use of the temporary file's path refnum, so it must be saved. Yet another error was discovered by Jens-Uwe Mager. The IM:Files example used the FSClose routine to close the resource fork of the original file, but this did not cause the resource data to actually be flushed to the disk. He correctly suggested the use of CloseResFile, which (contrary to my initial response to him) does work exactly like it should. The first part of the fix is to move the resource creating code from the DoSaveAsCmd routine to the DoWriteFile routine. However, you must continue to allow the DoSaveAsCmd routine to open the original file's data fork and leave it open. This is important because of the interplay between the 'Save' and the 'Save As...' file menu commands. The first time the user saves his file, the DoSaveAsCmd routine is going to be executed regardless of which command was chosen. Thereafter, each time the user selects the 'Save' command, the DoSaveAsCmd routine is bypassed and flow goes directly to DoWriteData. You could allow DoWriteData to open the original file's data fork, but then you'd also have to close it again before leaving the routine. Putting just one call to open the data fork in the DoSaveAsCmd is more efficient. The second part of the fix is to make the DoWriteFile routine create the temporary file, copy the resource to its resource fork, and close the resource fork with CloseResFile. Then the routine should open the temp file's data fork, write the current data to it, and leave it open also. Do the swap using FSpExchangeFiles. NOW the path reference numbers of the two files, which locate their data in memory, are reversed, but their FSSpecs are not. Close the temp file by calling FSClose with the _original_ file's path reference number. Save the _temporary_ file's path reference number for future use with the file, and then delete the temp file by calling FSpDelete with the temporary file's FSSpec. Sorry to be so long winded. If anyone wishes to see the final code, drop me an email. And sincere thanks to all who helped. =============================================================== | Ron Goebel | | | G & V Systems | Whatdya mean 'I don't get it?' | | Internet: redial@netcom.com | | =============================================================== --------------------------- >From redcon@xmission.com (Dan Eldridge) Subject: What Happens in the Resource Fork Date: 18 Aug 1994 14:23:26 GMT Organization: Redcon Hi Here's A general question, that I'm sure someone can answer, What happens in the Resource Fork if a program significantly and often changes the size of one of the resources, does the fork get fragmented, or does the whole file get rewritten so that the forks are all contiguous? Just Wondering -- Dan Redcon *** insert favorite corn dog joke here *** +++++++++++++++++++++++++++ >From mclow@san_marcos.csusm.edu (Marshall Clow) Date: Thu, 18 Aug 1994 09:26:20 -0800 Organization: Aladdin Systems In article , redcon@xmission.com (Dan Eldridge) wrote: > Hi > > Here's A general question, that I'm sure someone can answer, > What happens in the Resource Fork if a program significantly and often > changes the size of one of the resources, does the fork get fragmented, or > does the whole file get rewritten so that the forks are all contiguous? > My experience has been that if you make resources smaller (or possibly delete them), the extra space in the file is left unused, but if you add a resource or make one larger, then it is added at the end and the file is compacted in UpdateResFile. (which is called from CloseResFile) -- Marshall -- Marshall Clow Aladdin Systems mclow@san_marcos.csusm.edu +++++++++++++++++++++++++++ >From Jens Alfke Date: Wed, 24 Aug 1994 17:53:54 GMT Organization: Apple Computer Dan Eldridge, redcon@xmission.com writes: > What happens in the Resource Fork if a program significantly and often > changes the size of one of the resources, does the fork get fragmented, or > does the whole file get rewritten so that the forks are all contiguous? When you call UpdateResFile or CloseResFile, all the data gets shuffled around on disk until it's contiguous. Needless to say this can be very slow. Remember those long delays you sometimes get when you close the Monitors control panel or use some utility to update the desktop pattern? That's the cause; the System file is rather large, esp. pre-7.1 systems that had all the fonts in the System file itself. And the best part is, if you decide your system's hung and reboot, you've just destroyed your system file! That's the major reason we made Wallpaper not store its desktop pattern in the System file. All the more reason why (let's all chant it together) "The Resource Manager is not a database!" --Jens Alfke jens_alfke@powertalk.apple.com "A man, a plan, a yam, a can of Spam ... Bananama!" +++++++++++++++++++++++++++ >From kluev@jonathan.srcc.msu.su (Kluev) Date: Thu, 25 Aug 94 20:58:39 +0400 Organization: (none) In article <1994Aug24.175354.27836@gallant.apple.com> Jens Alfke wrote: > Dan Eldridge, redcon@xmission.com writes: > > What happens in the Resource Fork if a program significantly and often > > changes the size of one of the resources, does the fork get fragmented, or > > does the whole file get rewritten so that the forks are all contiguous? > > When you call UpdateResFile or CloseResFile, all the data gets shuffled > around on disk until it's contiguous. Needless to say this can be very slow. This data compacting occurred in "logical" space of fork instead of "physical". Compacting removes empty space in fork (not on disk) created when a resource was removed, made smaller, or larger. "Physically", file can be shuffled around all the disk. So the answer is: Yes, the fork get fragmented. Michael Kluev. --------------------------- >From schwarz@kodak.com (Doug Schwarz) Subject: Why does NewGWorld do this? Date: Tue, 23 Aug 1994 20:07:42 GMT Organization: Eastman Kodak Company, Rochester, NY I am trying to create multiple offscreen graphics worlds. QDErr err1, err2; PixMapHandle pixBase1, pixBase2; GWorldPtr theGWorld1, theGWorld2; CGrafPtr currentPort; GDHandle currentDevice; Rect boundsRect; GetGWorld(¤tPort, ¤tDevice); err1 = NewGWorld(&theGWorld1, 32, &boundsRect, NULL, NULL, 0); pixBase1 = GetGWorldPixMap(theGWorld1); SetGWorld(currentPort, currentDevice); GetGWorld(¤tPort, ¤tDevice); err2 = NewGWorld(&theGWorld2, 32, &boundsRect, NULL, NULL, 0); pixBase2 = GetGWorldPixMap(theGWorld2); SetGWorld(currentPort, currentDevice); In the code fragment above, theGWorld1 gets allocated just fine (and pixBase1 looks ok), but theGWorld2 is NULL (and pixBase2 is not valid). Both err1 and err2 are zero. What is going on/what am I doing wrong? There is no mention in IM VI what a zero GWorldPtr means. I had assumed that it would mean that there wasn't enough memory to allocate the pixel maps, but the pixel maps aren't very large and I have the memory partition for the app set plenty large. Thanks for any help you can give me. Doug Schwarz Eastman Kodak Company schwarz@kodak.com +++++++++++++++++++++++++++ >From python@world.std.com (Steven J. Bushell) Date: Wed, 24 Aug 1994 11:48:59 -0500 Organization: Kodak Electronic Printing Systems, Inc. In article , schwarz@kodak.com (Doug Schwarz) wrote: [ code deleted ] > In the code fragment above, theGWorld1 gets allocated just fine (and pixBase1 > looks ok), but theGWorld2 is NULL (and pixBase2 is not valid). Both err1 > and err2 are zero. What is going on/what am I doing wrong? There is no > mention in IM VI what a zero GWorldPtr means. I had assumed that it would > mean that there wasn't enough memory to allocate the pixel maps, but the pixel > maps aren't very large and I have the memory partition for the app set plenty > large. Thanks for any help you can give me. > > Doug Schwarz > Eastman Kodak Company > schwarz@kodak.com It's an undocumented feature of NewGWorld that it returns no error when it has insufficient memory to allocate the GWorld. You should ALWAYS check the GWorldPtr to determine if the call was successful. The only time you get errors back from NewGWorld is when you pass ridiculous parameters to it. I've never seen any other errors come back from it. Considering this, plus the fact that the first call to NewGWorld was successful, you can pretty safely assume that you are short on memory. Double-check your boundsRect, and make sure your heap isn't fragmented too. A quick way to confirm that it is a memory problem would be to cut the boundsRect in half and see if both calls succeed. If they don't, check to make sure your heap's okay. - Steve ////////// // // Steve Bushell // python@world.std.com // // "It's always the quiet ones." // ////////// +++++++++++++++++++++++++++ >From dab@zork.tiac.net (Dana Basken) Date: 24 Aug 1994 16:41:23 GMT Organization: Rockland Software In article python@world.std.com (Steven J. Bushell) writes: > It's an undocumented feature of NewGWorld that it returns no error when it > has insufficient memory to allocate the GWorld. You should ALWAYS check > the GWorldPtr to determine if the call was successful. The only time you > get errors back from NewGWorld is when you pass ridiculous parameters to > it. I've never seen any other errors come back from it. It's odd that you have never seen any other errors return from NewGWorld. If and when I try to create a GWorld using NewGWorld that is too large to fit into memory, I get a result code of -108 (memFullErr) every time. In my experience, I've never seen NewGWorld not create a GWorld and pass back noErr. I would look for some other reason in the failure of the allocation of your GWorld. - Dana - - Dana Basken dab@mote.tiac.net Rockland Software +++++++++++++++++++++++++++ >From tg3@u.washington.edu (Thurman Gillespy III) Date: Wed, 24 Aug 1994 11:55:51 -0800 Organization: Dept of Radiology, Univ of Washington In article , schwarz@kodak.com (Doug Schwarz) wrote: > I am trying to create multiple offscreen graphics worlds. > > QDErr err1, err2; > PixMapHandle pixBase1, pixBase2; > GWorldPtr theGWorld1, theGWorld2; > CGrafPtr currentPort; > GDHandle currentDevice; > Rect boundsRect; > > GetGWorld(¤tPort, ¤tDevice); > err1 = NewGWorld(&theGWorld1, 32, &boundsRect, NULL, NULL, 0); > pixBase1 = GetGWorldPixMap(theGWorld1); > SetGWorld(currentPort, currentDevice); > > GetGWorld(¤tPort, ¤tDevice); > err2 = NewGWorld(&theGWorld2, 32, &boundsRect, NULL, NULL, 0); > pixBase2 = GetGWorldPixMap(theGWorld2); > SetGWorld(currentPort, currentDevice); > Err, you HAVE defined boundsRect further, havn't you? -- Thurman Gillespy III | tg3@u.washington.edu Department of Radiology, SB-05 | voice (206)543-3320 University of Washington | fax (206)543-6317 Seattle, WA 98195 | +++++++++++++++++++++++++++ >From snozer@cats.ucsc.edu (Daniel Craig Jalkut) Date: 24 Aug 1994 21:21:31 GMT Organization: University of California, Santa Cruz In schwarz@kodak.com (Doug Schwarz) writes: >I am trying to create multiple offscreen graphics worlds. > QDErr err1, err2; > PixMapHandle pixBase1, pixBase2; > GWorldPtr theGWorld1, theGWorld2; > CGrafPtr currentPort; > GDHandle currentDevice; > Rect boundsRect; > GetGWorld(¤tPort, ¤tDevice); > err1 = NewGWorld(&theGWorld1, 32, &boundsRect, NULL, NULL, 0); > pixBase1 = GetGWorldPixMap(theGWorld1); > SetGWorld(currentPort, currentDevice); > GetGWorld(¤tPort, ¤tDevice); > err2 = NewGWorld(&theGWorld2, 32, &boundsRect, NULL, NULL, 0); > pixBase2 = GetGWorldPixMap(theGWorld2); > SetGWorld(currentPort, currentDevice); >In the code fragment above, theGWorld1 gets allocated just fine (and pixBase1 >looks ok), but theGWorld2 is NULL (and pixBase2 is not valid). Both err1 >and err2 are zero. What is going on/what am I doing wrong? There is no >mention in IM VI what a zero GWorldPtr means. I had assumed that it would >mean that there wasn't enough memory to allocate the pixel maps, but the pixel >maps aren't very large and I have the memory partition for the app set plenty >large. Thanks for any help you can give me. >Doug Schwarz >Eastman Kodak Company >schwarz@kodak.com Any GWorld references I've read have always insisted that you check both the return value being noErr, *and* the GworldPtr being != NULL. Probably you are somehow passing NewGWorld parameters that seem ok, and it does it's job ok, but doesn't put the results where you expect it to. I can't see from your example code anything that looks wrong in the NewGWorld calls. It is weird that you call GetGWorld and SetGWorld before and after your NewGWorld calls, though. I may be wrong, but I don't think NewGWorld does any modification to the active GrafPort or GDevice. You only need to Get/SaveGworld before and after you do any drawing to the GWorld(just like a GrafPort, in fact I've seen it recommended that if you use GWorlds at all your just use Get/SaveGWorld in *lieu* of Get/SavePort. The main problem I ran into when learning GWorlds was running out of memory, and it did return the proper error code. I concur with the other person who said that they have never had NewGWorld return noErr in reaction to an out of memory error. If you use GWorlds or anything else that is memory intensive, you will probably have to change the default heap size of your application from whatever compiler you use. -- ____ / /\ \ Daniel Craig Jalkut "All I know is that I don't know nothing, -/--\- snozer@cats.ucsc.edu and that's FINE" -- Operation Ivy X____X UNIX, coffee, politics, punk-rock, Mac, women, food, and more. +++++++++++++++++++++++++++ >From Darrin Cardani Date: Wed, 24 Aug 1994 19:34:38 GMT Organization: AT&T Global Information Solutions, Atlanta >In article <33ft7j$llk@sundog.tiac.net> Dana Basken writes: >In article >python@world.std.com (Steven J. Bushell) writes: > >> It's an undocumented feature of NewGWorld that it returns no error when it >> has insufficient memory to allocate the GWorld. You should ALWAYS check >> the GWorldPtr to determine if the call was successful. The only time you >> get errors back from NewGWorld is when you pass ridiculous parameters to >> it. I've never seen any other errors come back from it. > >It's odd that you have never seen any other errors return from >NewGWorld. If and when I try to create a GWorld using NewGWorld that >is too large to fit into memory, I get a result code of -108 >(memFullErr) every time. In my experience, I've never seen NewGWorld >not create a GWorld and pass back noErr. I too have seen the noErr, but no memory problem. Is there maybe more to it than those 2 factors? (Maybe, there's enough mem., but it's too fragmented or something wacko like that?) Darrin +++++++++++++++++++++++++++ >From schwarz@kodak.com (Doug Schwarz) Date: Wed, 24 Aug 1994 20:26:47 GMT Organization: Eastman Kodak Company, Rochester, NY In article <33ft7j$llk@sundog.tiac.net>, dab@zork.tiac.net (Dana Basken) wrote: > It's odd that you have never seen any other errors return from > NewGWorld. If and when I try to create a GWorld using NewGWorld that > is too large to fit into memory, I get a result code of -108 > (memFullErr) every time. In my experience, I've never seen NewGWorld > not create a GWorld and pass back noErr. > > I would look for some other reason in the failure of the allocation of > your GWorld. > > - Dana I wrote a small application containing little more than my original code fragment and I also get a result of -108 when there is not enough memory. It never returns a null GWorld and a zero error. So, it seems that I need to give a more complete description of my original problem. I am using THINK C 7.0.3 and the TCL 1.1.3. The allocation of the GWorlds is done in the initialization method for a class. I create two instances of my class and initialize them like so: SetRect(&bounds, ...); instance1 = new(COffscreenPixMap); instance1->IOffscreenPixMap(bounds); instance2 = new(COffscreenPixMap); instance2->IOffscreenPixMap(bounds); where, IOffscreenPixMap() is something like: class COffscreenPixMap : CObject { private: CGrafPtr currentPort; GDHandle currentDevice; GWorldPtr theGWorld; public: void IOffscreenPixMap(Rect); }; void COffscreenPixMap::IOffscreenPixMap(Rect boundsRect) { QDErr err, qderr; PixMapHandle pixBase; GetGWorld(¤tPort, ¤tDevice); err = NewGWorld(&theGWorld, 32, &boundsRect, NULL, NULL, 0); qderr = QDError(); pixBase = GetGWorldPixMap(theGWorld); SetGWorld(currentPort, currentDevice); return; } When I step through the program using the source level debugger, everything works fine with instance1. When I get to NewGWorld for instance2, I get err = 0, theGWorld = NULL and qderr = 0. If I purposely set the memory partition for the app too low, I never return from NewGWorld, but I get a dialog from the TCL telling me that there is not enough memory. (This I also do not understand). The app never really recovers from this and I have to enter MacsBug and do an ES. I don't really care about that right now, I just want to be able to allocate my second GWorld. Please note: I definitely have enough memory to allocate these two GWorlds. They each take a little over 1 MB and I have the memory partition for the app set to 23 MB (the machine has 32M). All of this stuff is right at the beginning of IApplication() so no other large objects have been created. Thanks for all the help so far! Does anybody know what is going on? Doug Schwarz Eastman Kodak Company schwarz@kodak.com +++++++++++++++++++++++++++ >From Jaeger@fquest.com (Brian Stern) Date: 25 Aug 1994 05:25:14 GMT Organization: The University of Texas at Austin, Austin, Texas In article , schwarz@kodak.com (Doug Schwarz) wrote: > I wrote a small application containing little more than my original code > fragment and I also get a result of -108 when there is not enough memory. > It never returns a null GWorld and a zero error. So, it seems that I need > to give a more complete description of my original problem. > > When I step through the program using the source level debugger, > everything works fine with instance1. When I get to NewGWorld for > instance2, I get > err = 0, theGWorld = NULL and qderr = 0. If I purposely set the memory > partition for the app too low, I never return from NewGWorld, but I get a > dialog from the TCL telling me that there is not enough memory. (This I > also do not understand). The app never really recovers from this and I > have to enter MacsBug and do an ES. I don't really care about that right > now, I just want to be able to allocate my second GWorld. > > Please note: I definitely have enough memory to allocate these two > GWorlds. They each take a little over 1 MB and I have the memory > partition for the app set to 23 MB (the machine has 32M). All of this > stuff is right at the beginning of IApplication() so no other large > objects have been created. > > Thanks for all the help so far! Does anybody know what is going on? > > Doug Schwarz > Eastman Kodak Company > schwarz@kodak.com Hi Doug, Guess what. You are successfully creating two GWorlds. That's why your return values are err = 0, and qderr = 0. The problem is that the GWorldPtr isn't going where you think it is. In TCL 1.1.3 objects are handles and your instance variables can move when you call a toolbox routine that can move memory, like NewGWorld. You have two choices. Use local variables when you need to pass by reference and copy the result to your instance variables or else lock the object using the utility routine 'Lock'. The problem you mention with the TCL not enough mem error msg is because TCL has a GrowZone proc. If it can't free up enough mem to satisfy the request it throws an exception. This includes a longjump out of the trap that was requesting memory. I think that this can screw up everything, as you discovered. -- Brian Stern :-{)} Jaeger@fquest.com +++++++++++++++++++++++++++ >From python@world.std.com (Steven J. Bushell) Date: Thu, 25 Aug 1994 11:44:02 -0500 Organization: Kodak Electronic Printing Systems, Inc. In article , schwarz@kodak.com (Doug Schwarz) wrote: > void COffscreenPixMap::IOffscreenPixMap(Rect boundsRect) > { > QDErr err, qderr; > PixMapHandle pixBase; > > GetGWorld(¤tPort, ¤tDevice); > err = NewGWorld(&theGWorld, 32, &boundsRect, NULL, NULL, 0); > qderr = QDError(); > pixBase = GetGWorldPixMap(theGWorld); > SetGWorld(currentPort, currentDevice); > return; > } > Thanks for all the help so far! Does anybody know what is going on? Have you tried locking your object before creating the GWorld? If you don't, the address of 'theGWorld' can become invalid if memory moves around (i.e., when creating a new GWorld), and the pointer to the GWorld will be stored in some random place in memory. Remember, TCL 1.1.3 is still handle-based so you have to watch out when using addresses of instance vars; TCL 2.0 is pointer based so you can avoid these problems if you use a newer TCL. - Steve ////////// // // Steve Bushell // python@world.std.com // // "It's always the quiet ones." // ////////// +++++++++++++++++++++++++++ >From schwarz@kodak.com (Doug Schwarz) Date: Thu, 25 Aug 1994 17:26:03 GMT Organization: Eastman Kodak Company, Rochester, NY In article , Jaeger@fquest.com (Brian Stern) wrote: > Guess what. You are successfully creating two GWorlds. That's why your > return values are err = 0, and qderr = 0. The problem is that the > GWorldPtr isn't going where you think it is. In TCL 1.1.3 objects are > handles and your instance variables can move when you call a toolbox > routine that can move memory, like NewGWorld. You have two choices. Use > local variables when you need to pass by reference and copy the result to > your instance variables or else lock the object using the utility routine > 'Lock'. > > The problem you mention with the TCL not enough mem error msg is because > TCL has a GrowZone proc. If it can't free up enough mem to satisfy the > request it throws an exception. This includes a longjump out of the trap > that was requesting memory. I think that this can screw up everything, as > you discovered. > > -- > Brian Stern :-{)} > Jaeger@fquest.com In article , python@world.std.com (Steven J. Bushell) wrote: > Have you tried locking your object before creating the GWorld? If you > don't, the address of 'theGWorld' can become invalid if memory moves > around (i.e., when creating a new GWorld), and the pointer to the GWorld > will be stored in some random place in memory. Remember, TCL 1.1.3 is > still handle-based so you have to watch out when using addresses of > instance vars; TCL 2.0 is pointer based so you can avoid these problems if > you use a newer TCL. > > - Steve > > // Steve Bushell > // python@world.std.com Yes! Brian and Steve are correct. I replaced err = NewGWorld(&theGWorld, 32, &boundsRect, NULL, NULL, 0); where theGWorld is an instance variable, with GWorldPtr tempGWorld; err = NewGWorld(&tempGWorld, 32, &boundsRect, NULL, NULL, 0); theGWorld = tempGWorld; where tempGWorld is a local variable and it works just fine. I was also able to make some other simplifications once *that* was working (thanks to some other helpful suggestions). So, THANK YOU EVERYBODY and especially Brian and Steve! Doug Schwarz Eastman Kodak Company schwarz@kodak.com --------------------------- >From partingt@fwi.uva.nl (Vincent Partington) Subject: Won't strange windows come in my layer? Date: 23 Aug 1994 11:09:43 GMT Organization: FWI, University of Amsterdam Hi everyone, I'm investigating putting a pointer to an object in the refCon of a windowPtr to call a virtual function (C++) through it. I was wondering: Can I be sure I'll only get events for my own windows? Can I be sure the refCon value doesn't contain garbage? I know under System 6 DA's would invade your window list but they can be recognized by looking at the windowKind (or something). It's it ok for my app to break if somebody makes an INIT that puts windows in my layer? Thanks, Vincent -- appel peer banaan baksteen ||| The Fingerware Project: schelp zon zand rolstoel ||| Put your code snippets in your .plan! groen wit geel flatgebouw ||| If you want to know more boer postbode bouwvakker roos ||| finger partingt@gene.fwi.uva.nl +++++++++++++++++++++++++++ >From Jaeger@fquest.com (Brian Stern) Date: 23 Aug 1994 16:44:50 GMT Organization: The University of Texas at Austin, Austin, Texas In article <33cldn$ncd@hermes.fwi.uva.nl>, partingt@fwi.uva.nl (Vincent Partington) wrote: > Hi everyone, > > I'm investigating putting a pointer to an object in the refCon of a windowPtr > to call a virtual function (C++) through it. I was wondering: > Can I be sure I'll only get events for my own windows? Can I be sure the > refCon value doesn't contain garbage? > I know under System 6 DA's would invade your window list but they can be > recognized by looking at the windowKind (or something). It's it ok for my > app to break if somebody makes an INIT that puts windows in my layer? > > Thanks, Vincent > -- > appel peer banaan baksteen ||| The Fingerware Project: > schelp zon zand rolstoel ||| Put your code snippets in your .plan! > groen wit geel flatgebouw ||| If you want to know more > boer postbode bouwvakker roos ||| finger partingt@gene.fwi.uva.nl Vincent, You should set the WindowKind of any window when you create it; choose values that are not among the already defined values (> 8 I think). Then when you receive window events you check the windowkind first and then act accordingly. You can put anything you like in the refcon, including object references. If you do this then presumably you wouldn't do anything for a windowkind that your app doesn't know about. I wouldn't worry about an INIT putting windows in your layer. If I was writing an INIT to do such a thing I'd be sure to steal any window events related to that window before your app ever saw them. -- Brian Stern :-{)} Jaeger@fquest.com +++++++++++++++++++++++++++ >From jonasw@lysator.liu.se (Jonas Wallden) Date: 23 Aug 1994 21:02:05 GMT Organization: (none) Jaeger@fquest.com (Brian Stern) writes: >In article <33cldn$ncd@hermes.fwi.uva.nl>, partingt@fwi.uva.nl (Vincent >Partington) wrote: >> Hi everyone, >> >> I'm investigating putting a pointer to an object in the refCon of a windowPtr >> to call a virtual function (C++) through it. I was wondering: >> Can I be sure I'll only get events for my own windows? Can I be sure the >> refCon value doesn't contain garbage? >> I know under System 6 DA's would invade your window list but they can be >> recognized by looking at the windowKind (or something). It's it ok for my >> app to break if somebody makes an INIT that puts windows in my layer? >> >> Thanks, Vincent >> -- >> appel peer banaan baksteen ||| The Fingerware Project: >> schelp zon zand rolstoel ||| Put your code snippets in your .plan! >> groen wit geel flatgebouw ||| If you want to know more >> boer postbode bouwvakker roos ||| finger partingt@gene.fwi.uva.nl > >Vincent, > >You should set the WindowKind of any window when you create it; choose >values that are not among the already defined values (> 8 I think). Then >when you receive window events you check the windowkind first and then act >accordingly. You can put anything you like in the refcon, including >object references. If you do this then presumably you wouldn't do >anything for a windowkind that your app doesn't know about. > >I wouldn't worry about an INIT putting windows in your layer. If I was >writing an INIT to do such a thing I'd be sure to steal any window events >related to that window before your app ever saw them. > >Brian Stern :-{)} A great way to extend WindowRecords is to declare your own data type with a WindowRecord as the first item. E.g., struct tMyWinData { // This must come first! WindowRecord winRec; // Additional window-specific data here... Handle aHandle; Ptr aPtr; }; typedef struct tMyWinData tMyWinData; typedef tMyWinData *tMyWinPtr; The trick now is that you can typecast any window pointer to tMyWinPtr (and back) and access your window-specific data fields. You might want to place your application's unique creator code in the WindowRecord refCon field and check it first to be sure you have a window that belongs to your program. I use this all the time and it is useful in many other places where the system gives you a pointer to an object (VBL tasks, ParamBlocks, ...) and you need to store extra data. No need to use any globals for this stuff! -- `.`. Jonas Wallden `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. `.`.`. Internet: jonasw@lysator.liu.se `.`.`.`.`.`.`.`.`.`.`.`.`.`.`.`. `.`.`.`. AppleLink: sw1369 `.`.`.`.`.`.`.`.`.`.`.`.`.`.`. +++++++++++++++++++++++++++ >From benh@fdn.org (Benjamin Herrenschmidt) Date: Tue, 23 Aug 94 17:24:09 +0100 Organization: (none) In article <33cldn$ncd@hermes.fwi.uva.nl> (comp.sys.mac.programmer), partingt@fwi.uva.nl (Vincent Partington) writes: >I'm investigating putting a pointer to an object in the refCon of a windowPtr >to call a virtual function (C++) through it. I was wondering: >Can I be sure I'll only get events for my own windows? Can I be sure the >refCon value doesn't contain garbage? >I know under System 6 DA's would invade your window list but they can be >recognized by looking at the windowKind (or something). It's it ok for my >app to break if somebody makes an INIT that puts windows in my layer? I think you should have somewhere a list of YOUR windows, so you can check it's one of yours before using it's refcon. Another way to do so is to use a custom windowKind and check for it (that's what PowerPlant does) but you are not protected against someone using the same windowKind (there is no way to register them). BenH. +++++++++++++++++++++++++++ >From lsr@taligent.com (Larry Rosenstein) Date: Tue, 23 Aug 1994 23:04:25 GMT Organization: Taligent, Inc. In article <33cldn$ncd@hermes.fwi.uva.nl>, partingt@fwi.uva.nl (Vincent Partington) wrote: > Can I be sure I'll only get events for my own windows? Can I be sure the > refCon value doesn't contain garbage? No. For example, there's a program called PacerForum (a BBS app) that can pop up notification windows inside your application's space. It makes the windows look like DAs (negative windowKind) so if you handle those properly you should be OK. -- Larry Rosenstein Taligent, Inc. lsr@taligent.com +++++++++++++++++++++++++++ >From h+@nada.kth.se (Jon W{tte) Date: Wed, 24 Aug 1994 10:23:51 +0200 Organization: Royal Institute of Something or other In article <33cldn$ncd@hermes.fwi.uva.nl>, partingt@fwi.uva.nl (Vincent Partington) wrote: >It's it ok for my >app to break if somebody makes an INIT that puts windows in my layer? Yes; PowerPlant, TCL and MacApp all put object pointers in the refCon. To be really safe, set the windowKind of windows you create to something >8, like 11147, and test for that first. Also test that the object pointer is not 0 (and if you're paranoid; not odd and above your heap start and below your stack base) Cheers, / h+ -- Jon Wätte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden "Don't use the Layer Manager" +++++++++++++++++++++++++++ >From h+@nada.kth.se (Jon W{tte) Date: Wed, 24 Aug 1994 23:10:45 +0200 Organization: Royal Institute of Something or other In article <01050105.7vo9pz@tatooine.fdn.org>, benh@fdn.org (Benjamin Herrenschmidt) wrote: >I think you should have somewhere a list of YOUR windows, so you can >check it's one of yours before using it's refcon. Another way to do >so is to use a custom windowKind and check for it (that's what PowerPlant >does) but you are not protected against someone using the same windowKind >(there is no way to register them). No, but there is simply NO WAY that someone elses window gets into your window list, unless that's a DA/system window, in which case the windowKind will be negative. Using a separate list is just a lot of trouble to avoid something which won't happen; sort of lugging around a portable bomb shelter in case a meteorite would hit you... Cheers, / h+ -- Jon Wätte (h+@nada.kth.se), Hagagatan 1, 113 48 Stockholm, Sweden "Don't use the Layer Manager" +++++++++++++++++++++++++++ >From sigurasg@plusplus.is (Sigurdur Asgeirsson) Date: 25 Aug 1994 09:03:27 GMT Organization: Plusplus Inc. h+@nada.kth.se (Jon W{tte) writes: >In article <01050105.7vo9pz@tatooine.fdn.org>, >benh@fdn.org (Benjamin Herrenschmidt) wrote: >>I think you should have somewhere a list of YOUR windows, so you can [snip] >No, but there is simply NO WAY that someone elses window gets >into your window list, unless that's a DA/system window, in >which case the windowKind will be negative. Using a separate >list is just a lot of trouble to avoid something which won't >happen; sort of lugging around a portable bomb shelter in case >a meteorite would hit you... Uhm, hate to rain on your parade, but what about CTB windows? CTB tools are allowed to put up windows (just about anytime if I remember correctly), AND they use the RefCon for their own purposes, so if you're using the CTB beware... -- Sigurdur Asgeirsson | "Well you know, C isn't that hard, void (*(*f[])())() Kambasel 26 | for instance declares f as an array of unspecified 109 Reykjavik, Iceland | size, of pointers to functions that return pointers to sigurasg@plusplus.is | functions that return void... I think" --------------------------- End of C.S.M.P. Digest **********************