• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

Macintosh Toolbox programming questions

PB170

Well-known member
Thanks for the links! I've been learning to program with the mac toolbox for quite a while now but I've been completely unaware of the existence of that magazine. What a wonderful resource! Programming on classic Mac OS suddenly feels like a much less disconnected endeavor :) Thanks!

Unfortunately, and surprisingly, there's not a single instance of the phrase "control strip" in any of the issues…

After my previous post, I started to download some of the Apple Developer Connection CDs, which I also learned about quite recently. The Control Strip development kit appears for the first time in the Jan '96 issue, and also in the issue from Oct '98 – with the same version, and the same technical note. One would think the problem with the slider would have been covered by then… Very odd. Perhaps I'm the first one to try it…? :) Or maybe there's something wrong with my setup, or my code. But I can't see what that would possibly be… I've tried it with System 7.1.1 , System 7.5.3 and System 7.6. All return the same negative values, and on Mac OS 9 it works just fine.

If the values were just constant, perhaps I could remap them to the actual setting. Obviously a very convoluted way of doing it, but…

Do tell me if you have any other ideas.

 

Crutch

Well-known member
Again if you want to share the relevant bits of your code, I’d be happy to take a look.

 

PB170

Well-known member
Thank you!

To reduce the potential for error to a minimum, I've gone back to the original code from Apple ("Control Strip Sample", included in the Control Strip development kit) and just added the code for the slider (and commented out Apple's code for the pop up menu).

The original project was made for MPW, and is more recent than Think C 5, so I had to make the following modifications to have it compile with Think C 5:

• Compile the ControlStripSample.r resource file with SARez so that it can be recognized by Think C 5
• Replace the "icons.h" file included with Think C 5 with the more recent one included with Think C 7

Here's an excerpt of the code, with my changes highlighted:

#ifndef  SystemSevenOrLater
#define  SystemSevenOrLater    1
#endif

#include <Memory.h>
#include <Menus.h>
#include <Quickdraw.h>
#include <Resources.h>
#include <ToolUtils.h>
#include <Types.h>
//#include <Icons.h>
#include "Icons.h"

#include "ControlStrip.h"
#include "ControlStripSample.h"

/…/

typedef struct Globals {
    Handle            lastIcon;
    Handle            firstIcon;
    Handle            secondIcon;
    Handle            thirdIcon;
    PicHandle        popupArrowPicture;
    Handle            helpStrings;
    short            helpStringIndex;
    short            whichIcon;
    MenuHandle        configMenu;
    short           sliderSetting;
} Globals;

/…/

long HandleMouseClick(Globals *gb, Rect *statusRect) {
    short            menuItem;
    long            result;

    result = 0;

    gb->sliderSetting = SBTrackSlider(statusRect, 53, gb->sliderSetting);
    

/*
    SetItemMark(gb->configMenu, gb->whichIcon, sdevMenuItemMark);

    menuItem = SBTrackPopupMenu(statusRect, gb->configMenu);

    CheckItem(gb->configMenu, gb->whichIcon, false);// uncheck the item for the previous icon

    result = 0;
    if ((menuItem > 0) && (menuItem != gb->whichIcon)) {

        gb->whichIcon = menuItem;
        GetCurrentIcon(gb);
        result = 1<<sdevNeedToSave;
    }
*/

    return(result);
}

/…/


And here's Apple's documentation about the slider routine:

SBTrackSlider.png

And finally, a .sit file with Apple's original project, and my modified version:

View attachment Control Strip test.sit

 

PB170

Well-known member
Hmm… I discovered just now that while the module with the slider that I included in the archive works more than the first time a selection is made in Mac OS 9 just like in my previous tests, it stops working after playing around with the slider for a while. However, if I change the ticksOnSlider parameter from 53 (the value I used in the file in the archive) back to 32 (which is what I've been using in my test up till now), it seems to work properly in OS 9 again.

Don't know what to make of this… Probably a good idea to have someone look at my code… :)

 
Last edited by a moderator:

Crutch

Well-known member
Are you sure that gb->sliderSetting is valid when you call SBTrackSlider()?  What happens if you always use an initial value of 0?

Are you sure that moduleRect is correct when passed into SBTrackSlider()?  (Actually this was my first thought when you mentioned issues with the popup menu also.)

Are you sure that gb->sliderSetting is actually coming back from SBTrackSlider() incorrectly — is it possible that some later point in your code is overwriting it somehow?  Not sure how you’re debugging this.  Do you know how to use Macbug?  It would be interesting to see what’s happening inside the call to SBTrackSlider().

 

PB170

Well-known member
I haven't had the time to delve into Think C's debugger or Macsbug yet so I'm currently not using them (still a beginner…), but it's definitely on the top of my list of things to learn more about.

But the code is straight from Apple's example, so I assume everything is set up properly.

Regarding your first point, I realize now that I forgot to initialize sliderSetting to 0 when I went back and modified Apple's example. It is however initialized properly in all of my previous tests, with the same result.

moduleRect is provided by the Control Strip software, so that shouldn't be a problem I think. And sliderSetting is only used where SBTrackSlider() is called.

Would you mind taking a closer look at the call to SBTrackSlider() for me, if it's not too much trouble?

By the way, as I understand it, Think C's debugger cannot be used with code resources like this, where the code is only running when called by the Control Strip software. It it easy to do with Macsbug?

 

Crutch

Well-known member
Having worked as an intern at Apple in the late ‘90s where part of my job was writing example code (for OpenDoc, but never mind that), sadly, I would not necessarily have complete faith that Apple’s example code is sacrosanct. :)  

If you can provide your entire source code somewhere, I would be happy to browse it more carefully.

Good point, yes, since you’re writing a code resource, THINK C’s debugger won’t help.  You’d want to use Macsbug.  In Macsbug, once your control strip loads, I would hit the interrupt switch and enter “ATB _ControlStripDispatch”.  This should break any time a control strip call Iike SBTrackSlider() is called.  Then, mouse down on your slider, “S” to step into the SBTrackSlider code, and see what’s going on in there and exactly what got passed to it on the stack.   You’d need to learn a bit of 68k assembly to be able to follow along if you haven’t already.  Apple’s original Macsbug Reference and Debugging Guide is terrific and may tell you most of what you’d need to know.

 

PB170

Well-known member
Wow, cool to hear that you worked at Apple in the 90's! Must have been fascinating.

Well… all I can do at this point is trust the examples provided :) although I try my best to fully understand how they work.

Thank you for the instructions on Macsbug. Very helpful, once I get started with it (have yet to install it :) ). I'm a little bit familiar with assembly and the inner workings of CPU's in general (on a broad level – haven't done any actual coding), so that shouldn't be too difficult to learn I think.

I included the full project in my post earlier ;)

Thank you for helping out!

 
Last edited by a moderator:

Crutch

Well-known member
Sorry had missed that - just looked at your code now.

I see that sliderSetting is indeed not initialized anywhere and that feels quite problematic to me, would suggest triple-checking that this problem indeed recurs once that's set properly, or even just set to 0 in the SBTrackSlider() call for test purposes.

One thing that makes me a bit uncomfortable is in main(), if you somehow get handed NIL in globs on an sdevMouseClick, you don't do any error checking -- you'll call HandleMouseClick with an uninitialized pointer in gb, then pass random stuff to SBTrackSlider().  I realize that feels unlikely and is probably not what's happening, but I would add an error check there and alert/fail gracefully somehow if that happens.

 

PB170

Well-known member
Like I said, I just missed it when I went back to Apple's example for my post here – it's been initialized properly throughout all my tests :)  It's initialized to 0 during the initialization call to the module after the global variables are allocated.

Regarding the globals, is this level of error checking necessary? Isn't it enough to check if the allocation was successful, like it's done in the program, as long as the values are initialized properly?

Would you mind having a look at what happens when SBTrackSlider() is called while the code is running? If so, I can upload a version with the proper initialization included. Otherwise, I guess this could be a good point for me to get familiar with Macsbug :) (Though I still lean towards this being a bug in the Control Strip software.)

By the way, I have had the initial value for the slider continuously set to 0 during all of my testing, since the slider won't appear when the value is less than 0.

 

Crutch

Well-known member
Yeah I can probably try to debug it this weekend.

Personally when writing a CODE resource that's handed a pointer when the system invokes it, I would always check to ensure it's not NIL before dereferencing it just in case something weird happened somewhere outside my code (or in case I allocated it in my Init... routine but then forgot to return it in some edge cases, or something!), just to prevent having to chase down weird cases where my variables hold random nonsense.  Again though I think it's unlikely this is happening.

 
Last edited by a moderator:

PB170

Well-known member
Oh, it's buggy alright  :) After having a first look at MacsBug, I played around a bit with a version of the control strip module that sets the initial value to "0" if the previously returned value is out of range (not using of MacsBug at this point) and discovered that if the module is just clicked on very quickly (without bringing up the slider (not possible every time) ), it returns the value "2". After that the slider works properly one time (positive values in the range specified). Bringing the slider up again a second time (now with a positive value passed as the initial value) makes the handle on the slider appear outside of the slider (makes sense, I guess…). Setting it to a new value makes it go back to negative values. However, if no new setting is made, the value returned appears to decrease by 2 and 3 alternately for each click, until it reaches "0". That is, unless the starting value is odd, in which case it appears to decrease by 4 the first time…

Also, if it's clicked on again after "2" is returned, it returns "−1" and then does so for all of the following clicks.

All of this seem to occur only when the initial value is positive.

Getting around this would involve patching the Control Strip software, I imagine. So odd that this bug isn't mentioned anywhere in the developer documentation… Surely, I can't be the first one to try out the slider function…?

Here's a version of the module that displays the value of the sliderSetting variable in place of the icon in Apple's example, and works as described above.

View attachment Module2.sit

 
Last edited by a moderator:

John_A

Well-known member
Oh, it's buggy alright  :) After having a first look at MacsBug, I played around a bit with a version of the control strip module that sets the initial value to "0" if the previously returned value is out of range (not using of MacsBug at this point) and discovered that if the module is just clicked on very quickly (without bringing up the slider (not possible every time) ), it returns the value "2". After that the slider works properly one time (positive values in the range specified). Bringing the slider up again a second time (now with a positive value passed as the initial value) makes the handle on the slider appear outside of the slider (makes sense, I guess…). Setting it to a new value makes it go back to negative values. However, if no new setting is made, the value returned appears to decrease by 2 and 3 alternately for each click, until it reaches "0". That is, unless the starting value is odd, in which case it appears to decrease by 4 the first time…

Also, if it's clicked on again after "2" is returned, it returns "−1" and then does so for all of the following clicks.

All of this seem to occur only when the initial value is positive.

Getting around this would involve patching the Control Strip software, I imagine. So odd that this bug isn't mentioned anywhere in the developer documentation… Surely, I can't be the first one to try out the slider function…?

Here's a version of the module that displays the value of the sliderSetting variable in place of the icon in Apple's example, and works as described above.

View attachment 33984
Would be fun to raise a ticket at Apples support site and report this as a software bug  :lol:

Interesting to see if there is anyone left with a sense of humour at Apple or if all those guys are retired by now..

Anyway, keep reporting! It's a very interesting and fun read  :cool:

 

PB170

Well-known member
Would be fun to raise a ticket at Apples support site and report this as a software bug  :lol:

Interesting to see if there is anyone left with a sense of humour at Apple or if all those guys are retired by now..

Anyway, keep reporting! It's a very interesting and fun read  :cool:
Haha  :lol: Well, while I like the thought of it, the company that brags about having having 90-ish percent of their users on their latest OS and do all they can get away with to improve that number, would probably ditch bug reports about anything older than the second latest version unless it's critical. And you know, if it's humor, it's got to be market oriented. :wink: Anyone with any thoughts about the the past in their head are probably not retired, but fired :) But maybe I'm being too pessimistic.

Anyway, glad to hear you enjoy the thread! I had a feeling maybe it was getting a bit too specific to be of general interest :)

 

Crutch

Well-known member
It looks like my suspicion was correct and your statusRect is somehow getting nuked. SBTrackControl has no idea what to do with the nonsense Rect so pukes back a negative value. Here’s the statusRect Macsbug shows you passing in. I got this by noticing that you are putting the Rect at an offset of $000C to A6 on the stack for SBTrackControl, and doing “DM A6+C Rect” in Macsbug. I’ll look at your code again later and try to figure out what’s causing this. 
 

62D25396-DF2B-49FF-BDE4-AAEA24BFEA0E.jpeg

 

Crutch

Well-known member
OK I'm pretty sure the problem is in this weird implementation of DrawCurrentIcon.  Is this really Apple sample code?

This writes over the statusRect that was passed in by MacOS.  That seems weird.  I think this code should allocate a new Rect on the stack, set its coordinates, and call PlotIconSuite/DrawPicture with that.  What happens if you try your control strip module with all the lines after "arrowHeight = ..." commented out?  I think you should avoid every modifying the statusRect that gets passed in by the system and if you need to draw things elsewhere, set up a separate Rect on the stack or that.

From the Macsbug screen above, it looks like statusRect->top is good, and everything else is nonsense.  When I run this multiple times, statusRect->left and bottom are random nonsense values; statusRect->right is always -256.

void DrawCurrentIcon(Globals *gb, Rect *statusRect) {
    short            arrowHeight;

//    draw the current icon

    statusRect->right = statusRect->left + IconWidth;
    (void) PlotIconSuite(statusRect, atNone, ttNone, gb->lastIcon);

//    draw an ‘up arrow’ to show that the module has a popup menu

    arrowHeight = (**gb->popupArrowPicture).picFrame.bottom - (**gb->popupArrowPicture).picFrame.top;
    statusRect->left = statusRect->right;
    statusRect->right += (**gb->popupArrowPicture).picFrame.right - (**gb->popupArrowPicture).picFrame.left;
    statusRect->top = (statusRect->top + statusRect->bottom - arrowHeight) >> 1;
    statusRect->bottom = statusRect->top + arrowHeight;
    DrawPicture(gb->popupArrowPicture, statusRect);
}

 

Crutch

Well-known member
Typo in the Macsbug command above, should have been "DM (A6+C)^ Rect" with the caret.

Anyway, pretty sure that was the issue.  I rebuilt your sdev with the attached code that just manipulated a new Rect on the stack instead of messing with the one pointed to by statusRect.  Seems to work in my tests?

Hope this helps!

View attachment ControlStripSample.c

 

PB170

Well-known member
Huge thanks for your effort and for looking into it!

Interesting to read about the results of your test. At first it felt like great news if the error was indeed in the code and easily fixed. However… when trying it out on my machine, the updated code doesn't change anything :( Very confusing this …

The code is indeed Apple's sample code. Moreover, it seems to work just fine on my setup. It appears that the statusRect gets restored with each new call to the module, so changing it in the meantime doesn't seem to do any harm (well, at least not on my machine …).

This far I've basically been debugging my code by simply printing any problematic variables out on the screen. Below is a video of a modified version of the module that displays 1) the result from the SBTrackSlider() function as stored in the sliderSetting variable, 2) the values of four members of the statusRect, 3) the ticks value passed to the function 4) another instance of the result from the function, stored in a local variable inside the HandleMouseClick() function (where SBTrackSlider() is called), and 5) a counter that's increased before and after the function, just to keep track of things.

The display is updated both before and after the SBTrackSlider() function is called, as well as during update calls to the module (in the DrawCurrentIcon() function). I've added two 1 second delays after the SBTrackSlider() function ends, just to be able to see the update after the function. After the first update/delay, I set all members of the rect variable to 0. As you can see, they revert to the correct values with the next call to the module.

Here's a brief description of what you see in the video:
First click: Making a setting on the slider returns a negative value (–131). After the SBTrackSlider() function ends, the statusRect values are all set to 0 in the code, and then immediately restored during the next call to the module.
Second click: Making a new setting returns another negative value. (Since the value of the sliderSetting is out of range after the first call, I reset it to 0 in the code before calling the function to have the menu appear.)
Third click: A quick click (mouse down/up) makes the SBTrackSlider() return the value '2'.
Fourth click: Now, when making a setting on the slider, the value returned is correct.
Fifth click: The value returned from the function is negative again.


View attachment Video.m4v





I also activated Macsbug and typed in the commands you used (without understanding exactly what they do or if they are applicable with my setup, at this point), and the result looks all right:

Macsbug.jpg

Any further ideas about what to make of all this…?

To me is still seems like the bug is in the Control Strip software, since the module works properly under Mac OS 9, and the few changes I made to the code seem to be okay. But I really have know idea… Very odd that we are getting different results when testing it.

I really wish I could get this to work properly.

By the way, what setup are you doing your test on?

 
Last edited by a moderator:

PB170

Well-known member
After the lack of success with fixing the slider back in May (@Crutch, or anyone else: if you have any ideas about my post above, feel free to comment), I went back to the less elegant but slightly more functional popup menu instead.

I then moved on to develop a second control strip module that displays the system voltage and allows you to see the battery voltage remaining until sleep. Naturally, this led to more issues  :) The main obstacle I've encountered is as follows (I'll include a second, minor one, in a separate post after this one):

After finishing the module, I thought it would be a natural development to extend its functionality to include other battery types. In short, Apple tackled this by developing additional routines for communicating with the Power Manager indirectly. The problem I have is that they don't seem to be supported on my system (System 7.1.1 / PowerBook 170), while according to Apple's documentation, they should.

The PowerBook 520/540 developer note (first PowerBooks with a NiMH battery) and the PowerBook 5300 developer note (first Powerbook with a LiIon battery) mentions:

"Starting with the Macintosh PowerBook 520 and 540 computers, the system software includes interface routines for program access to the Power Manager functions, so it is no longer necessary for applications to deal directly with the Power Manager’s data structures."

From what I can tell, the PowerBook 520/540 shipped with System 7.1/7.1.1.

The developer note, as well as Apple's documentation for the Power Manager also includes the following code for checking if the dispatch routines exist:
 

long pmgrAttributes;
Boolean routinesExist;

routinesExist = false;
if (! Gestalt(gestaltPowerMgrAttr, &pmgrAttributes))
if (pmgrAttributes & (1<<gestaltPMgrDispatchExists))
routinesExist = true;




However, when I run this under System 7.1.1 on my PowerBook 170, the check fails. Same thing with System 7.5 under emulation. Only with Mac OS 9 (on my PowerMac G4 Quicksilver) do I get a positive result.

Moreover, the definition of gestaltPMgrDispatchExists (4) is not supported under Think C 5. According to my research, it is included in the header file Gestalt.h, which replaces the earlier version called GestaltEqu.h. Unfortunately, all versions of Think C up to and including version 7 use the old header file, and presumable also don't include support for the new routines.

I guess it would be possible to get around the lack of support in Think C by using direct references to the power manager dispatch routines (not exactly sure about how to do that, but the function I'm interested in (GetBatteryVoltage) is listed with the routine selector $1B), but that would of course only work if the system software itself supports them.

Anyone here who can shine some light on this issue?

In return, I could share a nifty control strip module for checking the system voltage :)

Voltage_CSM_1.jpg

Voltage_CSM_2.jpg

 
Last edited by a moderator:
Top