Archive for the ‘Ajax’ Category

When Sockets Attack: DNS & DHCP

Wednesday, February 20th, 2008

Somehow I made it up to 2007 without ever writing code that opened a raw network connection or pulled apart a TCP/IP packet. Naturally, I had some hand-wavy notions of more-or-less what was going on under the hood—in college I took a 400 level CS course based on an old edition of Tanenbaum’s excellent Introduction to Computer Networks. But our homework was all theoretical, and I didn’t delve very deeply into the practicality of what powers our modern Internet.

But this year I was tasked to port some Windows networking code to Linux and OS/X. Looking at what was there, I guessed it was no big deal and said I’d do it. After all…there is a layer of abstraction known as “Berkeley sockets” which is practically identical to the UNIX API for reading and writing files. How hard could it be to recompile that on a new platform?

Though sometimes it might not be that hard, this case turned out to include the functionality of a DHCP server. The Windows version was able to work at the socket level by broadcasting UDP packets to 255.255.255.255, but the OS/X and Linux versions fundamentally couldn’t do it this way. Their semantics are different for how the socket calls are translated into packets.

I want to talk about some of the high-level gotchas to watch out for if you’ve just never run up against these particular dark alleys. Because I’m talking about “weirdness” only, I’m not going to explain basic mundane socket programming—because there are many guides explaining that. (One of the best I found was Beej’s Guide to Network Programming—so check that out if you’re interested.)

(more…)

Workaround for Firefox 2 Scroll Bar Bug on Mac

Tuesday, November 6th, 2007

Firefox 2 on the Mac has an unfortunate bug (#187435) which makes the scroll bars on lower regions “bleed through” and overwrite the areas above them. On traditional web pages that aren’t doing much tricky stuff, it will be only a minor visual nuisance. But it seriously impacts sites that are pushing the envelope of what HTML layout can do—like Mocha or the Extjs Web Desktop Demonstration:

extjs_firefox_scrollbar_bug

Phil Crosby has suggested that on the server side, it’s possible to adapt one’s code using the overflow:auto attribute. He also suggests it can be tricky to implement:

Working with overflow:auto on elements can be a pain, since your height and width need to be precise, and different browsers need different amounts of margins to prevent triggering the scrollbars. The scrollbar problem was a good chunk of the UI dev work on jjot.com.

So sometimes this method won’t be right for you, and a client-side fix for Firefox 2.0 would help. I have a workaround that patches the Firefox browser using a theme. All you have to do is download this file and drag it into the themes list you get when you go to the Tools->Add Ons menu:

download_arrow_icon aqua_scrollfix_together_icon download aqua_scrollfix_together-1.0-fx.jar

When installation is complete, go back to the menu and and click “Use Theme”. Note: If you have your Appearance palette set with scroll buttons to be “Top and Bottom” style instead of “Together”, then you’ll want to download this instead:

download_arrow_icon aqua_scrollfix_topbottom_icon download aqua_scrollfix_topbottom-1.0-fx.jar

A smattering of other themes you can find on the web will also incidentally work around the problem, but these two are intended for those Mac users who don’t actually want to change the appearance of the browser. They’re exactly the code for default Firefox in every aspect but scrollbars. The only caveats are:

  • The workaround is using a theme, and Firefox doesn’t let themes draw inactive scroll bars differently from active ones.
  • It’s not a perfect pixel match for the Aqua scrollbars—bear in mind, we’re simulating them with quirky CSS. But it’s close enough that most people won’t notice. If there’s enough interest to warrant trying harder to match more exactly, I’ll cross that bridge at that time.

How does it work?

Firefox has the default behavior of delegating the drawing of scroll bars to the operating system. The bug in question arises from a miscommunication about rendering priority. So if you provide enough information in the skin that it can draw scroll bars on its own and not call the OS, the problem just goes away.

Implementing skinned scroll bars requires you to provide bitmaps that serve as the pieces of the scroll bar control. To give you an idea what these pieces look like, let’s examine some of the ones from the MacFox II Aqua theme by Kelly Cunningham, which uses graphics made by Alex W. If you bothered to rename the .jar file to a .zip and unzip it, here’s some of what you’d find in the global / scrollbar / directory:

extjs_firefox_scrollbar_bug

One must take special care because on Mac OS/X, the description of how these parts integrate is in the theme file global / nativescrollbars.css. For all other platforms it is in global / xulscrollbars.css. If you aren’t going to have different behavior on different platforms, then you can set the contents of both those files into a 1-line shortcut that references a central global / scrollbar.css file:

1
@import url("chrome://global/skin/scrollbars.css");

MacFox II doesn’t do this, because it delegates to the OS if you’re on a Mac. This means it still has the bug. So I changed it to always draw the scroll bars, which quickly exposed another problem: the position of the buttons was being assumed to be “Together” on the same side of the thumb, while the graphics were drawn for being on the “Top and Bottom”. (This is something you can set in the Appearance palette of the System Preferences.)

To unmangle the scroll buttons, I used a tip from an article about scrollbar tweaks to position them the way the MacFox theme had expected. Yet I now realized I would need to make two variations—one for each possible user preference. Since I couldn’t find an existing theme with graphics and logic for the modern OS/X curved buttons “Together”, that meant making my own.

I was unfamiliar with CSS, so the files were hard to edit at first. Especially since almost all the themes I looked at contained patterns like this one (from MacFox’s global / scrollbars.css):

87
88
89
90
91
92
93
scrollbarbutton[type="increment"] {
	position: absolute;
	margin: 0px 0px 0px -9px;
	min-width: 24px;
	min-height: 15px;
	background: url("chrome://global/skin/scrollbar/right_cut.png");
}
99
100
101
102
103
104
105
scrollbar[orient="vertical"] >; scrollbarbutton[type="increment"] {
	position: absolute;
	margin: -9px 0px 0px 0px;
	min-width: 15px;
	min-height: 24px;
	background: url("chrome://global/skin/scrollbar/down_cut.png") no-repeat bottom left;
}

What this is saying is roughly:

  • Rule #1: All scrollbarbuttons you might find in the universe that increment the property to which they are attached—regardless of context—should be painted with the icon right_cut.png using the following attributes.
  • Rule #2: Oh…wait…!! There’s one context where that’s not the case. Override it if it’s a scrollbarbutton that increments and happens to be enclosed in the context of a vertical scrollbar, and use down_cut.png with these other attributes.

This is—in my view—an abuse of the inheritance mechanism. If you don’t remember to override all the characteristics you added to scrollbarbutton that gave it universal “horizontalness”, those attributes will get inherited by the vertical case, causing unexpected defaults to appear as you modify lines of code. It’s much better to have two narrow rules that apply explicitly to horizontal and vertical scrollbar contexts. (This is especially true because there are other places in Firefox that scrollbarbutton might appear and need to be handled differently.)

After fixing general problems of that type, I was able to more clearly determine what each line did. Eventually I discovered the position: absolute characteristic was not affecting position, but was indicating that those parts should be drawn in a higher Z-order than the relative pieces. The usages of negative margin values was to make sure they overlapped a little bit, to allow for what I call the “nestling” of the thumb into the buttons.

I had to be a little tricky with the graphics to implement the curved gutter at the edge of the scroll bar region. This involved putting a bit of empty space at the end of the thumb so that it would hit the edge prematurely, leaving the gutter showing. I mixed in some bitmaps from screen captures in a way that didn’t look too horrible—but my goal was only to do approximately as good a job as MacFox had done with the buttons “Top and Bottom”. If a better pixel artist wants to take this on and improve it, that would be great.

So there is the story. Beyond just addressing the problem I started out with, I think the source is reworked enough to be a nice place to start for anyone who is going to try theming scroll bars on their own. To assist with that, you can download the source to the scrollbar CSS files here:

  • aqua_scrollfix_together-1.0-fx.jar / global / scrollbars.css : view CSS
  • aqua_scrollfix_topbottom-1.0-fx.jar / global / scrollbars.css : view CSS

Feel free to ask questions if you have them!

Valid XHTML 1.0 Transitional

Day One of Mixing the “Ext-js” and “Yui” frameworks

Tuesday, October 30th, 2007

Note: most visitors to this page seem to be searching to find out why Firebug with the break all errors option detects an exception on obj.type. If that’s why you’re here, see the end of the article for edits that fix this problem.

I have seen the occasional attempt to build full windowing environments inside of a browser, and been only semi-impressed. After all, we do have mature remote desktop solutions like VNC. Why deal with the nightmare of browser inconsistencies when you can just set up a virtual machine of your choice, program to whatever hardened widget API you like, and let users control its screen through a terminal??

(That makes sense to me, and it will only make more sense as virtualization expands. For more on my thoughts, see the article “Virtualization and the Integrated Circuit”)

Putting this bias aside, I was somewhat inspired today by the Extjs Web Desktop Demonstration. Reading about the history of Extjs, I saw that it was conceived as an extension to the Yahoo User Interface Library. In fact, it could run on top of it and use its event model somehow. To test this claim, I got the idea to integrate the Yui Drag and Drop Groups Demo into the Extjs Web Desktop:

extjs_yui_combination

Despite my general ignorance from being on day one of meeting both of these frameworks, it sort of worked first try. I simply took the global variables out of the drag and drop demo page (slots, players, Event, DDM) and made them members of the created window object. I then substituted the HTML of the drag and drop space:

<div id="workarea">..blahblah...</div>

for the HTML that was in the default for blank windows in the Web Desktop sample:

<p>something useful would be in here</p>

The drag and drop worked as expected. But I use Firebug with the “Break on all Errors” option. And after gluing these two things together, clicking in the Extjs grid window causes a temporary halt in YUI’s connection-debug.js on line 240. It’s a little snip of code in _hasSubmitListener enclosed within a try/catch block, like so:

237
238
239
240
241
242
243
244
try
   {
   var obj = YAHOO.util.Event.getTarget(e);
   if(obj.type.toLowerCase() == 'submit') {
      YAHOO.util.Connect._submitElementValue = encodeURIComponent(obj.name) + "=" + encodeURIComponent(obj.value);
   }
}
catch(e) {}

What’s happening is that obj is div.x-grid3-cell-inner, which is an entity used by Extjs inside its grid. Yui somehow gets ahold of the click (how?), and finds the .type is undefined. This leads to an exception when toLowerCase() is called. Looking at the snippet I was puzzled… is the exception handling intentionally glossing over cases where the type isn’t defined? If that is the case, it would be much better to use a direct comparison with “undefined”:

if (obj.type != undefined)
   if (obj.type.toLowerCase() == 'submit') ...

If this situation isn’t supposed to happen, then the dereference of obj.type should be outside the try/catch block so that people who aren’t using Firebug with “Break on all Errors” will know they have a problem.

I posted about this to the YUI forum, and Thomas Sha (who works in the Yahoo platforms department) agreed that my change would be a good way to deal with it, at least until YUI 2.4.0 is released. So I made the following changes to yui / build / connection / connection-debug.js and yui / build / connection / connection.js :

237
238
239
240
241
242
243
244
/*try
   {*/
   var obj = YAHOO.util.Event.getTarget(e);
   if((obj.type != undefined) && (obj.type.toLowerCase() == 'submit')) {
      YAHOO.util.Connect._submitElementValue = encodeURIComponent(obj.name) + "=" + encodeURIComponent(obj.value);
   }
   /*}
   catch(e){}*/

In yui / build / connection-min.js, you should just replace the string:

try{var S=YAHOO.util.Event.getTarget(q);if(S.type.toLowerCase()=="submit"){YAHOO.util.Connect._submitElementValue=encodeURIComponent(S.name)+"="+encodeURIComponent(S.value);}}catch(q){}

with:

/*try{*/var S=YAHOO.util.Event.getTarget(q);if((S.type!=undefined)&&(S.type.toLowerCase()=="submit")){YAHOO.util.Connect._submitElementValue=encodeURIComponent(S.name)+"="+encodeURIComponent(S.value);}/*}catch(q){}*/

That seemed to take care of it, and the system no longer generates spurious breaks in Firebug. I had a working demo. Though there were issues with the scroll bars bleeding through the windows in Firefox on Mac, but that’s due to a Firefox bug:

extjs_firefox_scrollbar_bug

I’m sympathetic to the nastiness of the quirk but I feel like this is what such frameworks must have workarounds for—as they exist precisely to help us not worry about all the bugs in commonly deployed browsers. I managed to work around it using theming—which might give Firefox OS/X users some peace of mind.)

Valid XHTML 1.0 Transitional


Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported
Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported