Essays

Essays about OS X

1 year ago

Saturday, June 13, 2009

Fixing Maximize Bookmarklets in Safari 4

When Apple released the Safari 4 public beta at the end of February, I discovered an annoying bug: the little Javascript bookmarklet that I use to maximize the browser window didn’t work anymore. I find the behavior of Safari’s green zoom button extremely annoying. It doesn’t expand the browser window to fill the screen, but instead only resizes it to fit the content of the current page. This is typically some weird height and width that causes every subsequent page you view scroll vertically and horizontally.

Of course, Apple’s Human Interface Guidelines for Resizing and Zooming Windows explain that the zoom button isn’t actually supposed to expand the window to fill the screen, but toggle the window between a standard application-defined size and a user-defined size. Regardless of what the human interface guidelines say, though, I still don’t like what it does, and I’m apparently not the only person. There are hundreds of pages asking how to fix it.

In case you’re wondering, the bookmarklet is:

javascript:self.moveTo(0,0);self.resizeTo(screen.availWidth,screen.availHeight);

I simply put the bookmarklet first in my bookmark bar, which lets me maximize Safari by hitting ⌘1. I didn’t write this little snippet of Javascript, but I can’t remember where I found it and there are versions of it all over the Web.

So, back to the real story. Upon further investigation, I determined that the bookmarklet only works when the Safari window contains a single tab. If the window has more than one tab, the bookmarklet doesn’t work. I wasn’t the only one who noticed this bug, as I found the post Safari 4 breaks bookmarklets? on This Is the Green Room.

I figured the problem would be fixed when the final version of Safari 4 was released, but when that happened this past week, the problem remained. Googling a bit, I found WebKit bug 24218, which notes that the Javascript window.moveTo and resizeTo methods do not work in Safari windows with more than one tab.

Since the bug was marked unconfirmed and didn’t have any activity on it for months, I decided to download the WebKit source and try to track down the cause of the problem. I checked out the WebKit code and built it according to the instructions. After digging a bit and setting some breakpoints, I figured out that the following method in WebCore/page/DOMWindow.cpp implements window.moveTo in the Javascript engine:

void DOMWindow::moveTo(float x, float y) const
{
if (!m_frame)
return;

Page* page = m_frame->page();
if (!page)
return;

if (m_frame != page->mainFrame())
return;

FloatRect fr = page->chrome()->windowRect();
FloatRect sr = screenAvailableRect(page->mainFrame()->view());
fr.setLocation(sr.location());
FloatRect update = fr;
update.move(x, y);
// Security check (the spec talks about UniversalBrowserWrite to disable this check…)
adjustWindowRect(sr, fr, update);
page->chrome()->setWindowRect(fr);
}

This method basically does some adjustments with the screen and window rectangles, and then finally invokes Chrome::setWindowRect to perform the actual move of the window. Stepping through the method when clicking the bookmarklet with one and two tabs showed that all the rectangle calculations were resulting in the same values regardless of the number of tabs. The invocation of setWindowRect simply wasn’t moving the window when there was more than one tab.

After a bit of indirection through some other classes, Chrome::setWindowRect calls WebChromeClient::setWindowRect in mac/WebCoreSupport/WebChromeClient.mm:

void WebChromeClient::setWindowRect(const FloatRect& rect)
{
NSRect windowRect = toDeviceSpace(rect, [m_webView window]);
[[m_webView _UIDelegateForwarder] webView:m_webView setFrame:windowRect];
}

This method basically translates the rectangle coordinates between the scale used by the window and the WebView itself, and then sends setFrame:windowRect: to WebUIDelegate. This delegate is the bridge between WebKit’s Javascript engine and the actual Cocoa browser window (I think), and WebKit is passing it the correct coordinates to move the window. WebUIDelegate, though, simply doesn’t move the window as it should when there is more than one tab, which leads me to believe the bug is in Safari itself, not WebKit.

I updated the WebKit bug and filed a new bug for Safari on Radar. I thought for a moment that this behavior might actually be intentional, to prevent pages from resizing the browser window via Javascript when there are other open tabs that would be affected. But since the bookmarklet works in Safari 3, I tend to doubt this new behavior is by design as it would break a lot of existing Javascript. Scripts embedded in an actual page are similarly unable to move or resize the window when there’s more than one tab open, so the problem doesn’t have anything to do with the Javascript being in a bookmarklet.

16 Comments

2 years ago

Sunday, January 6, 2008

Furly: Full URLs to Your Clipboard

This script has been packaged alongside its URL-shortening counterpart Surly, and you can find the latest documentation for them in the Sakuzaku Goodie Basket.

A few weeks ago we offered up Surly, a pair of Applescripts to grab the URL from your default browser’s frontmost tab or window and place a shortened version on the clipboard. There’s just one little thing we’ve been meaning to finish up since…

Meet Furly, Surly’s efficacious counterpart. Furly does what its name might suggest — it grabs the full URL from your default browser’s frontmost tab or window and drops the result in your clipboard, ready for pasting. Like Surly, the script currently supports Safari, Firefox, Camino, and Opera, and is designed to work in concert with Quicksilver, but could theoretically be employed by number of similar applications or methods.

View the source: Furly — Frontmost URL to Clipboard.applescript (4 KB)

Or, grab it to go:

Installation

  1. Download the Furly script.
  2. Move the script you want to somewhere out of the way but where Quicksilver can find it. We recommend putting it in ~/Library/Scripts, which Quicksilver will index automatically if you’ve enabled the “Scripts (User)” catalog item in the “Catalog” section of your Quicksilver preferences.
  3. After a re-scan of the Quicksilver catalog (which you can force by activating QS and running ⌘+R, the appropriate scripts should be available.
  4. Activate Quicksilver and call up your script. Typing the first few letters of Furly or Copy Frontmost Browser URL should find Furly - Copy Frontmost Browser URL.scpt (if Quicksilver has figured out where you’ve stored it). Just hit Enter, and after a few seconds your full URL will be in the clipboard.
  5. Paste away!

Questions, Comments

I will modify the script to work with other browsers upon request by email. Also, don’t hesitate to send bug reports — you might get a Sakuzaku pin badge for your trouble.

Acknowledgements

Inspiration for this script, as with Surly, is owed to Dr. Drang, to whom I extend many thanks. (His much-updated and detailed post on the short- and long-URL craze is a must-read.)

Comments

2 years ago

Saturday, January 5, 2008

Two Leopard Bugs: Followup

Just about two months ago I identified two visual bugs in Leopard that were annoying me: application switcher icons were darkening, and Mail wasn’t properly changing the font color of quoted text. I’ve come up with a reproducible case for the former and a workaround for the latter.

I haven’t the faintest idea why, but if your cursor is in motion over the application switcher while it’s appearing (we’re talking fractions of a second), the application icon over which your cursor was moving will be darkened. Here’s a video demonstrating the oddity. While I hesitate to call this a 100% reproducible case, I am able to trigger the bug on my machine reliably at any time. Reports from readers such as yourself are, of course, appreciated.

And for getting properly-colored indented quotes in Mail, you have two options. First, the workaround: cut the offending text and any leading or trailing whitespace and paste to an empty text document in your favorite editor, and then cut it from there and paste back into Mail. The text will have lost whatever it is that causes the color issue. This is, admittedly, ridiculous. Thankfully, your second option works just as well and is a lot easier: just ignore it. It may display incorrectly before being sent, but once sent, the quoted text in your delivered messages will not stay uncolored, so you don’t need to worry about your recipients seeing something unexpected.

Minor offenses though they may be, attempting to find the cause of bugs like these is a valuable exercise for the developing and curious alike. We’ve filed bug reports through Apple’s Radar Bug Report system for the switcher and Mail issues: #5671975 and #5671970 respectively. Though 10.5.1 brought no cure, we can always hope for a fix in future point releases.

Comments

2 years ago

Wednesday, November 21, 2007

Surly: Shortened URLs from Multiple Browsers and Services

Update: This script has been repackaged alongside its full-URL-grabbing counterpart, Furly, and has been given a permanent home in the Sakuzaku Goodie Basket. Please head over there to get the latest documentation for it.

In response to recent well-founded worries about URL-shortening services and inspired by John Gruber’s endorsement of Metamark, Dr. Drang posted a short script for getting the URL of the frontmost Safari window (or tab, as it were), shortening it with the Metamark URL-shortening service, and storing the result in the clipboard. Even better, it can all be done with a flick of the wrist in Quicksilver.

Awesome, but I don’t use Safari. So I created some scripts to generate either a TinyURL or Metamark URL for your clipboard that works with your default browser. The scripts currently support Safari, Firefox, Camino, and Opera.

Or, grab them all in one easy-to-download package:

Installation

  1. Download the Surly & Furly collection.
  2. Move the scripts you want to somewhere out of the way, but where Quicksilver can find it. Dr. Drang recommends your home directory, but if you like to keep your directories clean, you can put it in ~/Library/Scripts, which Quicksilver will index automatically if you’ve enabled the “Scripts (User)” catalog item in the “Catalog” section of your Quicksilver preferences. After a re-scan of the Quicksilver catalog (which you can force by activating QS and running ⌘+R, the appropriate scripts should be available.
  3. Activate Quicksilver and call up your script. If you want to create a TinyURL from your browser’s frontmost URL, for example, typing TinyURL should find TinyURL.scpt (if Quicksilver has figured out where you’ve stored it). Just hit Enter, and after a few seconds your shortened URL will be in the clipboard. Note that Metamark seems to take a few seconds more than TinyURL, but you shouldn’t need to wait more than 2 or 3 seconds for either of them.
  4. Paste away!

Questions, Comments

I will modify and create scripts for other URL-shortening services and browsers upon request by email. Also, don’t hesitate to send bug reports — you might get a Sakuzaku pin badge for your trouble.

Acknowledgements

Inspiration for these scripts is owed to the aforementioned Dr. Drang, to whom I extend many thanks. (If you’re writing about webpages, Dr. Drang’s furl script for getting full URLs is a great companion to Surly.) Thanks also to Daniel Bogan of Waferbaby, who provided testing and debugging.

2 Comments

2 years ago

Saturday, November 17, 2007

Hunt and Peck: An Investigation and Proposal for Better Custom Keyboard Shortcut Management in OS X

The short story: The interface and functionality of custom keyboard shortcuts in OS X is awkward and unreliable. There are two possible direct reasons for this — Apple’s development priorities and non-standard application resource organization — and any number of underlying causes. I propose a solution.

This is the very long story. I am primarily a Camino user, but like anyone developing for the Web on a Mac, I usually have Firefox and Safari open at the same time too. My keyboard shortcut habits were formed in Firefox, though, and it’s too late to switch from ⌘+K for the search box, and ⌘+⌥+← and ⌘+⌥+→ for tab navigation. Having acquired a new laptop recently, I was reminded just how awful the process for setting up custom keyboard shortcuts is in Mac OS X.

Of Mysteries and Ellipses

If you’ve set custom keyboard shortcuts before, this interface will look familiar. In fact, it remains unchanged since OS X 10.3.

The Mac OS X 10.5 ‘Keyboard & Mouse’ preference pane.

The problems here are manifold.

First, you have to find the exact name of the menu option you want to access. This requires switching back and forth between an open application and the Keyboard & Mouse preference pane, with nowhere but your mind (or a piece of paper, or a Sticky, but come on) to store the title of the menu command, which is itself potentially buried several levels below the top-level menu options.

Safari’s “Google Search” menu option.

This is further complicated by the fact that keyboard shortcuts don’t take effect until you’ve closed the very application you were getting the menu option from. (It doesn’t say that anywhere in the interface itself; you just have to come to that conclusion by trial and error or Help when it doesn’t work immediately.) Even if you remember whether, say, that app capitalizes “to” or “from,” there’s no way to assure you’re typing the right thing. The best example of this is the ellipses, used to denote a menu option that triggers further action in a dialog box.

Can you spot the difference?

Two text boxes, one displaying three periods and one displaying an ellipsis.

Here you go:

Two text boxes, the left labeled and displaying three periods, the right labeled and displaying an ellipsis.

Apple specifies in the HIG section on Style that menu options requiring further input or confirmation should feature genuine ellipses:

Important: Be sure to create the ellipsis character using the key combination Option-; (Option-semicolon). This ensures that an assistive application can provide the correct interpretation of the character to a disabled user. If you use 3 period characters to simulate an ellipsis, many assistive applications will be unable to make sense of them. Also, 3 period characters and an ellipsis do not look the same because the periods are spaced differently than the points of an ellipsis.

But just because something’s in the HIG doesn’t mean developers will abide. Firefox is a great example. A sample custom shortcut:

Setting a keyboard shortcut for Firefox using three periods.

And sure enough, it matches up:

Proof that Firefox uses periods instead of ellipses.

This is problematic.

Of course, it’s known that third parties aren’t the only ones who don’t adhere to the HIG. The “Search Google…” menu option in Safari, pictured above, raises a few tangential questions: Does it even deserve an ellipsis? It just quietly puts focus on the Google search bar, which I didn’t notice until I’d tried selecting it a few times. The neglected HIG doesn’t account for menu items that do things like that. Hidden as it is, this menu option in Safari almost seems to exist for the sake of being custom-shortcut’d.

Assuming you do get the menu command title right, there’s no guarantee that setting the custom shortcut function is actually going to work. I spent twenty minutes trying to set keyboard shortcuts in Safari and wondering why they would show up sometimes but not others. In the end I had too many screenshots to deal with. I think this one, taken after I attempted to create a shortcut for “Private Browsing,” will suffice:

Double menu option bug in Safari. After creating a shortcut for “Private Browsing,” a duplicate menu option for it is created.

Some sort of type-ahead mechanism that would fetch the right menu command for you would solve this problem, but that brings us to why this functionality isn’t already built-in.

Not a Key Feature

Obviously, making the custom keyboard shortcuts interface eminently usable is not a priority for Apple. For the most part, only a minority of users actually know and use keyboard shortcuts. Of those I bet a significant number desire at least some level of customization, but at the end of the day, it’s not a feature that moves units. It’s understandable, then, that it hasn’t been prioritized.

I initially suspected another reason: that improving the process would actually be quite difficult. Here’s why.

While it’s possible to get a complete list of the menu options of any running application with Applescript, it would be best if the preference pane didn’t need to run the application just to get the menus. So instead, providing a searchable list of default menu options for an application (dynamic things like the bookmarks and history in a web browser should be ignored) would require a registered list thereof for every available application. But do these even exist? If so, where?

Turns out they do. But “where” is exactly the problem.

The MainMenu NIB file.In many applications (both Apple’s and those by third parties), the default menus are found in the MainMenu.nib interface file of an application. See for yourself: ‘Show Package Contents’ on the Safari application, navigate down through ContentsResourcesEnglish.lprojMainMenu.nib. If you’ve got Developer Tools installed, you should be able to open that file. You’ll see in the MainMenu.nib window something called “MainMenu,” an object of the NSMenu class, which manages an application’s menus.

MainMenu NIB opened in Interface Builder.

Theoretically, a list of menu options should be obtainable from this .nib file. Unfortunately, it’s not always in the same place. For Calculator, it’s in Calculator.nib instead of MainMenu.nib. With DVD Player, it’s in MenuBar.nib. For Mail, I couldn’t even find it. So the preference pane wouldn’t know where to look without loading the application to tell it. Right?

Wrong! The location of the MainMenu-containing interface file is specified in the NSMainNibFile property of a given application, listed in the Info.plist directly inside the Contents folder of every application. Knowing this, it’s easy, for instance, to find the appropriate .nib for Mail, MailViewer:

The property list for Mail.app displays the location of its MainMenu-containing NIB.

Peachy Key’n

I’ve leave the implementation for another day, but all of the pieces are already there. The Keyboard & Mouse preference pane can already tell when an application disallows keyboard shortcuts:

An error explaining that custom keyboard shortcuts may not be added for Adobe Photoshop.

And it knows that because — and here’s the kicker — it checks the Info.plist file! Check it out:

Photoshop’s Property List file has a property that disallows customized keyboard shortcuts.

If a property exists to disallow keyboard shortcut customization, we can only assume that the list of available applications listed in the Keyboard & Mouse prefence pane is drawn from a cached list of applications whose menu commands can be edited. It wouldn’t be too far a stretch to get Keyboard & Mouse to then cache a list of the available commands from the MainMenu object in the appropriate .nib for each safe application.

The interface for finding the right menu command should work just like the new Help menu in Leopard. The screen would dim and a facsimile of the selected application’s default menus would appear. Start typing a command, and the close matches would be pointed out visually with the bobber. Once you’d selected a command (by searching or by manually navigating through the menus with the mouse), the command would fly from the menubar into the preference pane, where you could set a keyboard shortcut for it which would then be checked against existing shortcuts.

A proposed interface for choosing keyboard shortcuts.

Click for a larger view.

A warning dialog indicating that changes to existing keyboard shortcuts wouldn’t take place until the application was restarted would then appear, offering, like Software Update, to quit said application immediately or postpone quitting.

It can be done. It should be done. The ball’s in your court, Apple.

See Also

John Gruber’s article Losers, Weepers speaks to the problems of the OS X custom keyboard shortcut feature, and was written way back in 2003 when the feature first appeared. (There are a lot of similarities there, but it’s worse that the problems haven’t been addressed in four years than me not remembering John’s original post.) He mentions a key problems not mentioned or addressed here but just as vital — the lack of conflict management.

2 Comments

Next Page