Vincent Gable’s Blog

May 13, 2008

Fixing Blurry Images

Filed under: Bug Bite,MacOSX,Programming
― Vincent Gable on May 13, 2008

I had an issue today where an image (A .png at 72 DPI with transparency, inside an NSImageView — if that makes any difference) in a window was blurry. The image was perfectly sharp in Interface Builder’s library panel, but when I placed it in a window, it turned blurry. Maddening!

A (mysterious) workaround: put the image where you want it. Then move it, then hit undo. When it snaps back to where you want it, it should be sharp.

I have absolutely no idea why this worked, or why the images were blurred by Interface Builder/XCode in the first place. (And yes, the images were blurry when the application was built and run. It wasn’t just a display bug in Interface Builder). It was purely coincidence that I stumbled across this “solution”.

May 4, 2008

Getting Mac OS X Version Information

Filed under: MacOSX,Objective-C,Programming,Sample Code,UNIX | , ,
― Vincent Gable on May 4, 2008

Cocoa

For a human-readable string, use [[NSProcessInfo processInfo] operatingSystemVersionString]. It looks like “Version 10.5 (Build 9A581)”, but that format might change in the future. NSProcessInfo.h explicitly warns against using it for parsing. It will always be human-readable though.

For machine-friendly numbers, use the Gestalt function, with one of the selectors:
gestaltSystemVersionMajor (in 10.4.17 this would be the decimal value 10)
gestaltSystemVersionMinor (in 10.4.17 this would be the decimal value 4)
gestaltSystemVersionBugFix (in 10.4.17 this would be the decimal value 17)
Do not use gestaltSystemVersion unless your code needs to run on OS X 10.2 or earlier. It’s a legacy function that can’t report minor/bugfix versions > 9; meaning it can’t distinguish between 10.4.9 and 10.4.11. The CocoaDev wiki has example code that works in 10.0 if you need to go that route.

Here’s a simpler example of using Gestalt:

- (BOOL) usingLeopard {
  long minorVersion, majorVersion;
  Gestalt(gestaltSystemVersionMajor, &majorVersion);
  Gestalt(gestaltSystemVersionMinor, &minorVersion);
  return majorVersion == 10 && minorVersion == 5;
}

Scripts

For scripts and command-line work, there is the sw_vers command.
$ sw_vers
ProductName: Mac OS X
ProductVersion: 10.5
BuildVersion: 9A581
$ sw_vers -productName
Mac OS X
$ sw_vers -productVersion
10.5
$ sw_vers -buildVersion
9A581

Java

Check the value of:

System.getProperty("os.name");
System.getProperty("os.version");

Fallback

Finally, if you must, you can parse /System/Library/CoreServices/SystemVersion.plist — but I don’t like the idea of doing that. There’s a chance that the file could have been corrupted or maliciously altered. It seems safer, and less complicated, to directly ask the operating system it’s version.

Minimum OS Requirements

To enforce a minimum OS requirement for your application, you can set the LSMinimumSystemVersion key in the Info.plist file. Big Nerd Ranch has a more robust, user-friendly, but complicated solution for older legacy systems.

April 28, 2008

Hardware is a Commodity. Software is not.

Filed under: Design,Programming,Tips
― Vincent Gable on April 28, 2008

…it’s easy for software to commoditize hardware (you just write a little hardware abstraction layer, like Windows NT’s HAL, which is a tiny piece of code), but it’s incredibly hard for hardware to commoditize software. Software is not interchangeable, as the StarOffice marketing team is learning. Even when the price is zero, the cost of switching from Microsoft Office is non-zero. Until the switching cost becomes zero, desktop office software is not truly a commodity. And even the smallest differences can make two software packages a pain to switch between. Despite the fact that Mozilla has all the features I want and I’d love to use it if only to avoid the whack-a-mole pop-up-ad game, I’m too used to hitting Alt+D to go to the address bar. So sue me. One tiny difference and you lose your commodity status. But I’ve pulled hard drives out of IBM computers and slammed them into Dell computers and, boom, the system comes up perfectly and runs as if it were still in the old computer.

Joel on Software

April 23, 2008

Printing a FourCharCode

Filed under: Bug Bite,C++,Cocoa,MacOSX,Programming,Sample Code,Tips | , , , ,
― Vincent Gable on April 23, 2008

A lot of Macintosh APIs take or return a 32-bit value that is supposed to be interpreted as a four character long string. (Anything using one of the types FourCharCode, OSStatus, OSType, ResType, ScriptCode, UInt32, CodecType probably does this.) The idea is that the value 1952999795 tells you less, and is harder to remember, then 'this'.

It’s a good idea, unfortunately there isn’t a simple way to print integers as character strings. So you have to write your own code to print them out correctly, and since it has to print correctly on both big endian and little endian machines this is tricker then it should be. I’ve done it incorrectly before, but more importantly so has Apple’s own sample code!

Here are the best solutions I’ve found. Please let me know if you have a better way, or if you find any bugs. (The code is public-domain, so use it any way you please.)

FourCharCode to NSString:
use NSString *NSFileTypeForHFSTypeCode(OSType code);
Results are developer-readable and look like: @"'this'", but Apple says “The format of the string is a private implementation detail”, so don’t write code that depends on the format.

FourCharCode to a C-string (char*):
use the C-macro

#define FourCC2Str(code) (char[5]){(code >> 24) & 0xFF, (code >> 16) & 0xFF, (code >> 8) & 0xFF, code & 0xFF, 0}
(requires -std=c99; credit to Joachim Bengtsson). Note that the resulting C-string is statically allocated on the stack, not dynamically allocated on the heap; do not return it from a function.
If you want a value on the heap, try:


void fourByteCodeString (UInt32 code, char* str){
  sprintf(str, "'%c%c%c%c'",
    (code >> 24) & 0xFF, (code >> 16) & 0xFF,
    (code >> 8) & 0xFF, code & 0xFF);
}

In GDB, you can print a number as characters like so:

(gdb) print/T 1936746868
$4 = 'spit'

(via Borkware’s GDB tips)

If you do end up rolling your own FourCharCode printer (and I don’t recommend it!), then be sure to use arithmetic/shifting to extract character values from the integer. You can not rely on the layout of the integer in memory, because it will change on different machines. Even if you are certain that you’re code will only run on an x86 machine, it’s still a bad idea. It limits the robustness and reusability of your code. It sets you up for an unexpected bug if you ever do port your code. And things change unexpectedly in this business.

Printing a FourCharCode is harder then it should be. Experienced developers who should know better have been bitten by it (and so have I). The best solution is probably a %format for printf/NSLog that prints integers as character strings. Unfortunately, it doesn’t look like we’ll be seeing that anytime soon.

April 18, 2008

Shifflett Happens

Filed under: Design,Programming,Tips
― Vincent Gable on April 18, 2008

To show that nonuniform distributions occur in real life, consider Americans with the uncommon last name of Shifflett. The 1997 Manhattan telephone directory, with over one million names, contains exactly five Shiffletts. So how many Shiffletts should there be in a small city of 50,000 people? Figure 2-4 shows a small portion of the two and a half pages of Shiffletts in Charlottesville, Virginia telephone book.

The Algorithm Design Manual, page 39.

April 11, 2008

NSWindow setResizable:

Filed under: Cocoa,MacOSX,Objective-C,Programming,Sample Code | ,
― Vincent Gable on April 11, 2008

-[NSWindow setResizable:(BOOL)] does not exist. But, here is a way to get that effect as long as the window was resizable when created. (I don’t know of a way to make a window resizeable if it was first created unresizeable).

The basic idea is to show/hide the resizing controls, and implement delegate functions that prevent the window from being resized when the resizing controls are hidden.

//show or hide hide the window's resizing controls:
[[window standardWindowButton:NSWindowZoomButton] setHidden:!resizable];
[window setShowsResizeIndicator:resizable];

Note that setShowsResizeIndicator: only shows/hides the resize-indicator in the lower-right of the window. It will not make the window non-resizeable.

To keep the window from being resized when showsResizeIndicator is false, implement the delegate methods:

- (NSSize)windowWillResize:(NSWindow *) window toSize:(NSSize)newSize
{
	if([window showsResizeIndicator])
		return newSize; //resize happens
	else
		return [window frame].size; //no change
}

- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame
{
	//let the zoom happen iff showsResizeIndicator is YES
	return [window showsResizeIndicator];
}

No Delegate Hack

Finally, there is a hack that avoids using delegate methods, although I don’t recommend it.

[[window standardWindowButton:NSWindowZoomButton] setHidden:!resizable];
[window setShowsResizeIndicator:resizable];
CGFloat resizeIncrements = resizable ? 1 : MAXFLOAT;
[window setResizeIncrements:NSMakeSize(resizeIncrements, resizeIncrements)];

setResizeIncrements “Restricts the user’s ability to resize the receiver so the width and height change by multiples of width and height increments.” So setting it to MAXFLOAT x MAXFLOAT means that the user can’t resize the window, because they won’t have a big enough screen. Note that this won’t disable the “zoom” function, although the user probably couldn’t use it with the zoom button hidden.

This approach uses slightly fewer lines of code, but it is more brittle and indirect, since it depends on the screen-size, not if the window is (visibly) resizeable. I wouldn’t use it over delegates. But here it is.

April 7, 2008

foreach For The Win

Filed under: C++,Cocoa,Design,Objective-C,Programming,Research
― Vincent Gable on April 7, 2008

I love foreach. What I really mean is that I really like dead-simple ways to iterate over the items in a container, one at a time. It goes beyond syntactic sugar; making errors harder to write, and easier to spot.

I’m using the term “foreach”, because the first time I realized the utility of simple iteration was seeing Michael Tsai’s foreach macro. I instantly fell in love with the ‘keyword’, because it greatly simplifies iterating over items in a Cocoa container. My reaction was so strong, because the (then current) Cocoa iteration idiom I was using was so bad. As Jonathan ‘Wolf’ Rentzsch says:

I have a number of issues with enumeration in Cocoa/ObjC. Indeed, I have a problem with every one of the three lines necessary in the standard idiom. It even goes beyond that — I have an problem with the very fact it’s three lines of code versus one.

Objective-C 2.0 (Leopard and later) introduced Fast Enumeration. It’s a better way of handling enumeration then Michael Tsai’s macro, but if you are stuck using Objective-C 1.0, then I highly recommend using his foreach macro.

I do not like the C++ stl for_each idiom. It’s not simple enough.

To explain what’s wrong with for_each I should explain what a “foreach” should look like. It should be a two-argument construct: “foreach (item, container)“, and no more. container should be evaluated only once. Syntax details aren’t terribly important, as long as they make sense.
foreach(child, naughtyList)
iterate(child, naughtyList)
ForEach(String child, naughtyList)
for child in naughyList:
for(NSString *child in naughtyList)
Are all fine constructs.

The most obvious benefits of a foreach is that it’s less code, easier to write, and less work to read. Implemented correctly, it also makes bugs harder to write — mostly because it minimizes side effects in the loop construct. For example, do you see the bug in the following code?

for( list<shared_ptr<const Media> >::iterator it = selectedMedias->selectedMediaList().begin(); it != selectedMedias->selectedMediaList().end(); ++it )

I didn’t; and it’s kind of a trick question. ->selectedMediaList() isn’t an accessor function — it constructs a new list every time it is called. So selectedMediaList() != selectedMediaList() because it returns a different list each time. The loop never terminates because it will never equal end(), since it is the end of a different list. But you have no way of knowing this without knowing details of what selectedMediaList() does.

Using BOOST_FOREACH avoids the problem:
BOOST_FOREACH(shared_ptr<const CSMediaLib::Media> media, selectedMedias->selectedMediaList())
works regardless of how selectedMediaList() is implemented, because it is only evaluated once. It’s also easier to write, and to read. I haven’t used BOOST_FOREACH much, but it’s been totally positive so far. (Yes, the name is ugly, but that’s not important).

Loops are a staple of programming. Simplifying and error-proofing the most common kind of loop is a huge productivity win. foreach regardless of it’s flavor, is worth a try.

April 6, 2008

Yes

Filed under: Design,Programming,Research,Usability | , ,
― Vincent Gable on April 6, 2008

Just a curiosity, but it happens that in a yes-no binary response test, the reaction time to select “no” is longer than for “yes.”

Source

I haven’t taken the time to verify this, or see if anyone has quantified the difference in response times.

UPDATE 2009-12-18: The technical term for this is Acquiescence Response Bias — the tendency to agree with any assertion, regardless of its content.

March 31, 2008

Resolution Independence

Filed under: Accessibility,Design,MacOSX,Programming,Research,Usability | , , ,
― Vincent Gable on March 31, 2008

Displays are getting sharper all the time. Sharpness is very important, because things don’t just look better on high-resolution displays; they are measurably faster to use.

according to Jakob Nielsen:

Low-resolution monitors (including all computer screens until now) have poor readability: people read about 25% slower from computer screens than from printed paper. Experimental 300 (PPI) displays (costing $30,000 (in 1998)) have been measured to have the same reading speed as print, so we will get better screens in the future.

The resolution of a display is measured in PPI, Pixels Per Inch, the number of pixels used to draw a one inch long, one pixel thick, line. A higher PPI means smaller pixels, and clearer images. You can calculate the PPI of your screen by

PPI ≅ sqrt(pixels_across^2 + pixels_down^2) / diagonal_inches

I am writing this article on an iMac with a 24″ screen, showing 1920 x 1200 pixels, so my PPI ≅ sqrt(1920*1920+1200*1200)/24 ≅ 93 PPI.

The resolution of a printer is measured in DPI, or Dots Per Inch. Unfortunately, DPI is often used as another term for PPI. That is technically inaccurate, but even Microsoft does it. SPI, Scans Per Inch, is another term that is used instead of PPI, but fortunately is correct when describing digital displays.

Bitmapped images are smaller on high-resolution displays, because the pixels the picture is made of are smaller. This can be a big problem for interface elements.

For example, today Apple’s interface guidelines say “The standard Help button is 20 pixels in diameter and should be placed at least 12 pixels from other interface elements.” On my iMac, a 20-pixel wide circle is about 0.21″ in diameter — roughly 1/3rd the diameter of a Dime. help_button_today.png But on a 300 PPI display, it would be 0.07″ in diameter — roughly as thick as three pieces of mechanical pencil lead help_button_300ppi.png. As you can see, it’s way too small to comfortably click!

Just scaling bitmapped images, so a 20-pixel wide picture is always drawn 0.21″ wide, isn’t a good work around. It’s just emulating a low-definition, low-readability, display on a more expensive high-definition display. Another problem is that it looks terrible when everything else on the system is crystal clear.

help_button_300_scaled_up.png

It gets more ugly when the scaling-factor is higher, say for a display that matched the print fidelity of the tawdry magazines you see in the grocery check-out isle.

A resolution independent interface can be usably, and pleasantly, displayed on high-definition or standard-definition screens. There are two ways to build a resolution-independent display.

You can use vector images, which can be resized without problems. SVG and PDF are two popular formats. This sounds like an elegant “design once, show anywhere” solution. But in practice today building a vector image of the same quality as a bitmapped image can be very difficult, especially with complex images. This will change in time. Today designers create bitmap images by embellishing a vector image with bitmap-effects. As vector-imiging tools improve, they will be able to perform equivalent effects, but in a resolution-independent way.

Alternately, your app can carry-around a set of bitmapped images and draw the one that most-closly matches the current resolution. If you only have to support a handful of well-definied resolutions, this might be the best choice with today’s tools. The only caveat is that all signs point to vector-images being the future. Loading one vector image is also easier the selecting one of many bitmapped images to load. (And theoretically a vector image won’t have to be tweaked if we suddenly get one million PPI displays).

Already Solved

I think it’s important to note that Fonts have been facing an even more severe resolution-independence problem for decades, and have mostly solved it. The same font can be rendered well on a 1200 DPI printer, and a 72 PPI display. That’s a much bigger resolution disparity then a computer interface will ever have to deal with, because by the time a screen close to the resolution of a 1200 DPI printer is common, nobody will be using 72 PPI displays anymore (they aren’t even sold today).

Early fonts were bitmap fonts — a collection of bitmaps of what the font should look like at a particular scaling. But today vector fonts have replaced bitmapped fonts on the desktop, and even the iPhone. Vector fonts let us do amazing things with scaling (font specific stuff starts at 1:18). Vector fonts have been such an unqualified success, that it’s hard to imagine vector images not replacing bitmapped images for interface elements.

When Will It Happen

Jeff Atwood “did some research to document how far we’ve come in display resolution over the last twenty years.”


Year

Model

Resolution
Size DPI
1984
Original Macintosh
512 x 342 9″ (8.5″) 72
1984

IBM PC AT

640 x 350 13″ (12.3″) 60
1994
Apple Multiple Scan 17 Display
1024 x 768 17″ (16.1″) 80
2004

Apple Cinema HD display

2560 x 1600 30″ 100

I used the Tag studios Monitor DPI calculator to arrive at the DPI numbers in the above table. I couldn’t quite figure out what the actual displayable area of those early CRT monitors were, so I estimated about 5% non-displayable area based on the diagonal measurement.

Regardless, it’s sobering to consider that the resolution of computer displays has increased by less than a factor of two over the last twenty years. Sure, displays have gotten larger– much larger– but actual display resolution in terms of pixels per inch has only gone up by a factor of about 1.6.

I can’t think of any other piece of computer hardware that has improved so little since 1984.

It certainly doesn’t not look like we will get 300 PPI displays anytime soon! At the present rate, it will be decades before a $2000 display matches the clarity of a $20 printer.

However today’s smarphones and small-devices have much sharper screens then computers. The first generation iPhone is 160 PPI, the Kindle is 167 PPI. Now these are much smaller screens then full-sized computers use, and I don’t know how cost-effective it is to scale the screens up from 3.5″ to 30″. But I do know that significantly higher resolution displays are being produced in increasing volume today for smartphone. So we may be fortunate enough to have, say 180 PPI, displays many years sooner then Atwood’s data suggests.

UPDATE 2009-02-11: Wikipedia’s list of devices by PPI lists some very high PPI devices. The Sony Ericsson X1
phone has broken the 300 PPI “readability threshold”
. The Fujitsu Lifebook U820 has a 270 PPI display. But the screen is only slightly bigger then the Osborne 1 “portable” computer of 1981. Still, if history is any indicator, once better technology is actually sold, it catches on very quickly.

March 18, 2008

Finding your laptop’s location with a shell command

Filed under: MacOSX,Programming,Sample Code,Tips,UNIX | ,
― Vincent Gable on March 18, 2008

Every wireless access point has a MAC address — a 48 bit number that uniquely identifies it. By checking the MAC address of the wireless access point your computer is connected to, you can figure out if it is being used at home, in your office, etc.

You can read this value from the shell with the command:
arp `ipconfig getoption en1 router`
Here’s how it works. The command ipconfig getoption en1 router gets the IP address of the router for the interface en1, which is the name of the Airport interface. If you want to get the router connected to the ethernet port use en0. The output of the command looks like:
128.62.96.1

arp prints information about the IP address, including the MAC address. arp is a little tricky in that it needs to take the address as an argument, you can’t pipe the output from ipconfig into it — that’s why ipconfig getoption en1 router is surrounded in “. Output from arp 128.62.96.1 looks like:
cisco-128-62-96-1.public.utexas.edu (128.62.96.1) at 0:12:44:f:5f:0 on en1 [ethernet]

The MAC address is in there, but you may need to use a regular expression to get at it. Here is an example of a perl script which prints just the MAC address of the wireless access point, or an error message.

if (qx{arp `ipconfig getoption en1 router`} =~ /([0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2})/){
   print "$1\n";
} else {
   print "Error; wireless internet is most likely unavailable\n";
}

This is essentially how IMLocation determines location.

In summary: Using the shell commands: arp `ipconfig getoption en1 router`, and the regular expression ([0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}:[0-9A-Fa-f]{1,2}) on it’s output, you can get the MAC-address of the wireless access point your computer is using. This gives you the computer’s location in about a 150 foot radius.

EDITED TO ADD: Another way to get this information is to use the private tool: /System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport
-s gives a list of surrounding networks; -I gives information about the current network.
Try /System/Library/PrivateFrameworks/Apple80211.framework/Resources/airport --help for more information.

You can even get the MAC address of all visible base-stations this way. Unfortunately, any system update could change the Apple80211.framework enough to break your code.

« Newer PostsOlder Posts »

Powered by WordPress