<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>millennium | ten</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/" />
    <link rel="self" type="application/atom+xml" href="http://www.bengoodger.com/atom.xml" />
   <id>tag:www.bengoodger.com,2009://2</id>
    <link rel="service.post" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2" title="millennium | ten" />
    <updated>2009-01-05T11:36:06Z</updated>
    <subtitle>A Weblog by Ben Goodger</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 3.2</generator>
 
<entry>
    <title>Basics / Minor Tweaks / Under the Hood - ???</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2009/01/basics_minor_tweaks_under_the.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=126" title="Basics / Minor Tweaks / Under the Hood - ???" />
    <id>tag:www.bengoodger.com,2009://2.126</id>
    
    <published>2009-01-05T11:24:11Z</published>
    <updated>2009-01-05T11:36:06Z</updated>
    
    <summary>Google Chrome&apos;s Options dialog box has perplexed some more traveled in the art of UI design with its unusual tab titles. Here&apos;s a brief explanation of why we ended up going with this arrangement: A core value for us was...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>Google Chrome's Options dialog box has perplexed some more traveled in the art of UI design with its unusual tab titles. Here's a brief explanation of why we ended up going with this arrangement:</p>

<p>A core value for us was to keep the number of options low. Obviously some options are necessary - your home page, your network settings, etc. Some things represent genuine user preferences and others represent configuration that might be specific to a given installation. What we didn't want to do was add a lot of choices that represented unresolved design decisions for the UI. This felt a little too much like "giving up" our responsibilities on the UI design team and making users to do our job.</p>

<p>At the end of the day, we ended up with a relatively small number of options. A simple sort of options into related categories proved problematic - the relationship between many of the choices was ambiguous. Some belonged in multiple categories. We quickly realized we'd end up with a lot of tabs that only had a few items in them.</p>

<p>So we went back and tried to think about what people would really want to get out of this UI. Mostly, people would be interested in changing their home page and other basic settings like that. Sometimes, people might like to change the default download folder or turn off password saving or something like that. Even less often, there might be a need to tweak proxy settings and make other lower level changes. So we did a sort by "most likely to be changed", and that's how we ended up with the grouping we have.</p>

<p>There are probably further improvements that could be made to our options dialog box, if we're lucky, we'll be able to remove a few more checkboxes. After working for several years on various sorts of options in numerous versions of Netscape and Firefox options dialog boxes though and watching the organizations that made sense at the time they were implemented become awkward when new features arrived, I'm not personally convinced any particular theme-based grouping scales well to the wide array of possible future modifications.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Speed Limits</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2009/01/speed_limits.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=125" title="Speed Limits" />
    <id>tag:www.bengoodger.com,2009://2.125</id>
    
    <published>2009-01-02T22:52:10Z</published>
    <updated>2009-01-02T23:00:03Z</updated>
    
    <summary>From the New Zealand Herald: &quot;More than a third of motorists drive over the 50km/h speed limit.&quot; (emphasis mine). Hold on a minute. From the Wikipedia article on speed limits: &quot;Traffic engineers may rely on the 85th percentile rule to...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p><a href="http://www.nzherald.co.nz/nz/news/article.cfm?c_id=1&objectid=10550299&ref=rss">From the New Zealand Herald</a>: <em>"More than <strong>a third</strong> of motorists drive over the 50km/h speed limit."</em> (emphasis mine).</p>

<p>Hold on a minute.</p>

<p>From the <a href="http://en.wikipedia.org/wiki/Speed_limit#Factors_in_setting_speed_limits">Wikipedia article on speed limits</a>: <em>"Traffic engineers may rely on the 85th percentile rule to establish speed limits. The speed limit should be set to the speed that separates the bottom 85% of vehicle speeds from the top 15%. ... The theory is that traffic laws that reflect the behavior of the majority of motorists may have better compliance than laws that arbitrarily criminalize the majority of motorists..."</em></p>

<p>Well that makes sense, doesn't it. But sense doesn't always apply when you're a nanny-state bent on protecting people from themselves. No, wait, hold on a minute... back to the Herald: <em>"Police collect about $50 million a year from speeding fines, figures released to the Weekend Herald under the Official Information Act show."</em></p>

<p>Ah, that's the reason. Maybe if NZ had a well-funded traffic police as in olden times, they could focus on dangerous driving rather than pure speed (it's possible to drive dangerously within the speed limit), and then the police could go back to spending most of their time stopping people from being stabbed, beaten and shot in South Auckland...</p>]]>
        
    </content>
</entry>
<entry>
    <title>Auld Lang Syne</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2009/01/auld_lang_syne.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=124" title="Auld Lang Syne" />
    <id>tag:www.bengoodger.com,2009://2.124</id>
    
    <published>2009-01-02T07:25:04Z</published>
    <updated>2009-01-02T07:28:02Z</updated>
    
    <summary>Happy 2009. New year&apos;s brings some philosophical reflection on the decisions one makes, deliberate and accidental, that shape where one ends up. 10 years ago, I started tinkering with browsers, as a hobby. 6 years ago, I moved to California...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>Happy 2009. New year's brings some philosophical reflection on the decisions one makes, deliberate and accidental, that shape where one ends up.</p>

<p>10 years ago, I started tinkering with browsers, as a hobby.<br />
6 years ago, I moved to California to continue doing this professionally.<br />
4 years ago, I began working at Google, to expand my horizons and meet some great new people.<br />
2 years ago, I moved into my house and take on my most significant non-work project to date.</p>]]>
        
    </content>
</entry>
<entry>
    <title>AKL</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/12/akl.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=123" title="AKL" />
    <id>tag:www.bengoodger.com,2008://2.123</id>
    
    <published>2008-12-18T05:22:03Z</published>
    <updated>2008-12-18T05:22:29Z</updated>
    
    <summary>In New Zealand until 1/9/09....</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>In New Zealand until 1/9/09.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Learn to count.</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/12/learn_to_count.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=122" title="Learn to count." />
    <id>tag:www.bengoodger.com,2008://2.122</id>
    
    <published>2008-12-09T02:54:03Z</published>
    <updated>2008-12-09T02:55:39Z</updated>
    
    <summary>When talking about software, why do people say &quot;You can do X with a single click&quot; when it actually takes two or three clicks? Hint: if it isn&apos;t on the app&apos;s main window, it&apos;s going to take more than one...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>When talking about software, why do people say "You can do X with a single click" when it actually takes two or three clicks?</p>

<p>Hint: if it isn't on the app's main window, it's going to take more than one click to access it. Stop lying and instead learn to count.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Meanwhile, on the other side of the world...</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/11/meanwhile_on_the_other_side_of.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=121" title="Meanwhile, on the other side of the world..." />
    <id>tag:www.bengoodger.com,2008://2.121</id>
    
    <published>2008-11-08T11:08:55Z</published>
    <updated>2008-11-08T11:09:54Z</updated>
    
    <summary></summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<center><img src="http://www.bengoodger.com/natlogo.png"></center>]]>
        
    </content>
</entry>
<entry>
    <title>A Better Day Has Come</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/11/a_better_day_has_come.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=120" title="A Better Day Has Come" />
    <id>tag:www.bengoodger.com,2008://2.120</id>
    
    <published>2008-11-06T20:18:16Z</published>
    <updated>2008-11-06T20:18:34Z</updated>
    
    <summary></summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<center><img src="http://www.bengoodger.com/obamalogoonwhiteicon.jpg"></center>]]>
        
    </content>
</entry>
<entry>
    <title>Communicating with Engineers</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/10/communicating_with_engineers.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=119" title="Communicating with Engineers" />
    <id>tag:www.bengoodger.com,2008://2.119</id>
    
    <published>2008-10-21T10:21:19Z</published>
    <updated>2008-10-21T10:29:19Z</updated>
    
    <summary>I love to write, so it pains me to say this, but when writing to an engineering audience (e.g. posting to a development discussion list), succinct always beats florid. If I have to read two 1200px high screenfuls of your...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>I love to write, so it pains me to say this, but when writing to an engineering audience (e.g. posting to a development discussion list), succinct always beats florid.</p>

<p>If I have to read two 1200px high screenfuls of your prose to understand ideas that could be better expressed in a couple of sentences, I'm likely to not even begin - I have other things to do.</p>

<p>Consider the "Paperwork Reduction Act" notice atop many government forms listing the "estimated burden" of time required to complete the form. What's the estimated burden to fully digest and respond to your email?</p>]]>
        
    </content>
</entry>
<entry>
    <title>Apple Trade-in program</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/10/apple_tradein_program.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=118" title="Apple Trade-in program" />
    <id>tag:www.bengoodger.com,2008://2.118</id>
    
    <published>2008-10-15T05:10:54Z</published>
    <updated>2008-10-15T05:13:17Z</updated>
    
    <summary>What with the never ending succession of coolness, obsolete but usable hardware becomes an annoying problem. What Apple really needs is a trade-in or lease program for its computers similar to that done by car dealers. It&apos;d take the edge...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>What with the never ending succession of coolness, obsolete but usable hardware becomes an annoying problem.</p>

<p>What Apple really needs is a trade-in or lease program for its computers similar to that done by car dealers. It'd take the edge off the $3k per machine cost every couple of years ;-)</p>]]>
        
    </content>
</entry>
<entry>
    <title>Aarhus</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/09/rhus.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=117" title="Aarhus" />
    <id>tag:www.bengoodger.com,2008://2.117</id>
    
    <published>2008-09-27T13:14:13Z</published>
    <updated>2008-09-27T13:15:32Z</updated>
    
    <summary>I am in Denmark this week....</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>I am in Denmark this week.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Writing a Custom Window Frame</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/09/writing_a_custom_window_frame.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=116" title="Writing a Custom Window Frame" />
    <id>tag:www.bengoodger.com,2008://2.116</id>
    
    <published>2008-09-17T06:18:28Z</published>
    <updated>2008-10-21T10:34:22Z</updated>
    
    <summary>In Chromium, we use custom frame windows on Windows XP, and on Windows Vista without DWM compositing enabled. We do something slightly different when DWM compositing is turned on, which I&apos;ll cover in a separate post. Right now, I&apos;m going...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>In Chromium, we use <a href="http://dev.chromium.org/user-experience/visual-design">custom frame windows</a> on Windows XP, and on Windows Vista without DWM compositing enabled. We do something slightly different when DWM compositing is turned on, which I'll cover in a separate post. Right now, I'm going to focus on how we built and are building the custom window frame for Windows XP. There are two components to this work, rendering the contents of the window and making Windows happy.</p>

<p><strong>Rendering</strong></p>

<p>To render the UI, including the browser window chrome, we use a lightweight UI framework that we call <a href="http://dev.chromium.org/developers/design-documents/chromeviews">ChromeViews</a>. ChromeViews is a set of C++ classes that provides a layout, rendering and event processing system similar to <a href="http://developer.apple.com/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/Reference/NSView.html">NSView</a>, and the rendering classes used by popular layout engines like WebKit and Gecko. At the core is the concept of a <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/view.h?view=markup">View</a>, which simply represents a rectangle. This rectangle can paint itself, lay out child views, and receive various kinds of events based on user input. By subclassing this View object we are able to develop the various bits of UI that Chrome uses. Each window is composed of a hierarchy of these View objects. The bridge between the native OS window and the View hierarchy is an object called a <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/view_container.h?view=markup">ViewContainer</a>, which hosts the <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/root_view.h?view=markup">RootView</a> that owns the hierarchy. The ViewContainer is an abstract interface that is typically implemented by <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/hwnd_view_container.h?view=markup">HWNDViewContainer</a>, which wraps a windows HWND. The window procedure for this HWND receives various messages, translates some into ChromeViews events and fires them into the hierarchy, paints the Views into a bitmap device context using a graphics API called <a href="http://src.chromium.org/viewvc/chrome/trunk/src/skia/">Skia</a>, and does various other things to make Windows happy.</p>

<p>Let's take a look at the browser window,  since it's an interesting and complex example of a custom frame window. At the top level there's a View called the RootView that contains the rest of the browser UI. Nested in layers beneath this are other Views like the TabStrip, the ToolbarView, Buttons, and so on and so forth.</p>

<p>But rendering the contents of the window is only part of the story. Since we wanted a custom look for our UI, we wanted to draw our own title bars and sizing borders too. In fact, for our browser window, we wanted to do something even stranger - we wanted to have the tabs living up in the title bar of the window - where they'd form the distinctive "skyline" of the browser. On Windows, the window title bar (called the "caption"), the sizing borders and other window controls are referred to as the "non-client area". The stuff inside them is called the "client area". We were throwing a spanner into works by having a non-rectangular client area that intrudes into the non-client area.</p>

<p>The first step was to keep things simple. We don't treat the non-client area as a separate set of stuff to paint. Rather, the non-client area is just another View in the same hierarchy that hosts the contents of the window. This had some implications though on how we implemented a ViewContainer that could host this view hierarchy to match the look we wanted.</p>

<p><strong>Keeping Windows Happy</strong></p>

<p>In the first implementation, which is what was shipped with the Google Chrome beta by the way, we create a Windows HWND with very basic window styles - because the ChromeViews hierarchy contained within is providing all the non-client area, we wanted to suppress things like WS_CAPTION etc. To make the portions of the window title bar area not occupied by tabs act like a title bar though, messages like WM_NCHITTEST were handled to determine if the mouse was in fact in a blank area, and if so HTCAPTION was returned. On the trunk now we are now somewhat more sophisticated about this - we establish hit-test masks for the tabs that closely follow their shape such that clicking in the blue area where two tabs meet is treated like a click to the title bar!</p>

<p>Because we weren't a frame window, some things like window resizing had to be implemented by hand. This had some undesirable side-effects: when Windows resizes a window it runs a modal loop that synchronously paints the window(s) being revealed... but with our system based entirely on the user dragging the mouse this didn't happen, and so we left artifacts behind as Windows caught up later and repainted the revealed window. We also found we didn't work well with Windows' built in window management features (e.g. window tiling) and various window manager extensions like SplitView didn't work because we either didn't have the appropriate window styles or just did things a little differently. The ViewContainer implementation for the browser window in the Chrome beta is called XPFrame.</p>

<p>This is where a new set of ChromeViews ViewContainers stepped in. Dialog boxes in Chrome on Windows XP are actually hosted in a different kind of window called a <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/custom_frame_window.h?view=markup">CustomFrameWindow</a>. This derives (via a class called Window) from HWNDViewContainer, a general purpose ViewContainer that wraps a HWND. Here's what CustomFrameWindow does differently:</p>

<ul>
<li>Bears the WS_CAPTION, WS_THICKFRAME, and WS_OVERLAPPED window styles, as well as the WS_EX_WINDOWEDGE and WS_EX_APPWINDOW extended styles. By having these styles, CustomFrameWindow gets a lot of the functionality that XPFrame had to do by hand for free (such as specifying the contents and enabled-state of system menu items). This did mean however some gymnastics when painting.
<li>Handles WM_NCCALCSIZE, passing the bounds of a "ClientView" as the bounds of the client area. This rectangle is smaller than the window rectangle, just like for a standard top level window. In XPFrame, the client area bounds were equal to the window bounds.
<li>Handles WM_NCHITTEST, doing more comprehensive checks to determine if the mouse is over the sizing borders etc. Doing this allows the CustomFrameWindow to be moved and sized by Windows, with all the painting benefits that come with this.
<li>Handles WM_NCPAINT, to make sure the client area is painted synchronously with the non-client area, to prevent effects where the window frame appears to "snap in" around its contents.
<li>Handles WM_NCLBUTTONDOWN, to make sure clicks to the non-client areas specifying the window controls are translated into events that are sent to the relevant ChromeView.
<li>Handles WM_SETCURSOR, to make sure the sizing cursors are set for various hit-test codes.
<li>Handles the undocumented <a href="http://www.bengoodger.com/2008/09/the_joy_of_custom_window_frame.html">WM_NCUAHDRAWCAPTION and WM_NCUAHDRAWFRAME</a> messages to suppress excessive flickering in the title bar area.
<li><strong>Update:</strong>Handle a growing list of messages, starting with WM_SETTEXT and WM_ENTERMENULOOP, removing the window's WS_VISIBLE style, calling the default window procedure and then adding the WS_VISIBLE style back. Why? Well, sometimes the window gets into a state (not reproducible via a repeatable set of steps, but always eventually) where it begins to paint the standard non-client title bar and controls over the one you rendered. Windows doesn't do this in its default WM_NCPAINT handler, rather it does it directly in its default handlers for these messages. You need to handle these messages and fake invisibility to convince Windows not to do it. If anyone knows other messages that this rule applies to please let me know!
<strong>Update 2</strong> this is not quite right. I'm going to summarize in a separate document.
</ul>

<p>CustomFrameWindow also taps in to a lot of the benefits offered by the <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/window.h?view=markup">Window</a>/<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/window_delegate.h?view=markup">WindowDelegate</a>/<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/non_client_view.h?view=markup">NonClientView</a>/<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/client_view.h?view=markup">ClientView</a> framework we use for our dialog boxes. As an example, the shape of our window is actually slightly different from the standard Windows shape. Windows supports rounded corners on its windows with 1-bit transparency by using window regions. This is used on Windows XP Luna to provide rounded corners at the top left and right of each window. We use a custom radius, and the ChromeViews framework allows us to easily specify a custom window shape by creating a Skia path.</p>

<p><strong>Conclusion</strong></p>

<p>In developing frameworks for building UI in Chromium, we've found that trying wherever possible to do what Windows expects means less code, better display integrity and performance, and that the more subtle features some users expect "just work". </p>

<p>A lot of what I've described are things that relate closely to Chromium source code, and design decisions that we've made to meet the objectives we've set for ourselves, and as such they may not be directly applicable to other work. But I do think many of the issues addressed in the implementation of the CustomFrameWindow ViewContainer are potentially useful to others developing custom user interfaces on Windows, especially considering the documentation for some of the things we had to do here is non-existent aside from postings similar to this!</p>

<p>If you've done work like this before, I'd be interested in hearing your thoughts on our approach. Maybe you have some good stories to share!</p>]]>
        
    </content>
</entry>
<entry>
    <title>The Joy of Custom Window Frames</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/09/the_joy_of_custom_window_frame.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=115" title="The Joy of Custom Window Frames" />
    <id>tag:www.bengoodger.com,2008://2.115</id>
    
    <published>2008-09-12T01:04:30Z</published>
    <updated>2008-09-23T03:50:19Z</updated>
    
    <summary>A colleague and I were looking at an interesting bug today. For a little while I&apos;ve been working on some new frames for the Chromium browser window. These frames are based on the CustomFrameWindow/Window ChromeViews classes that we use to...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>A colleague and I were looking at an interesting bug today. For a little while I've been working on some new frames for the Chromium browser window. These frames are based on the <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/custom_frame_window.cc?view=markup">CustomFrameWindow</a>/<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/window.cc?view=markup">Window</a> ChromeViews classes that we use to contain much of the UI. Anyway the frames handle various windows non-client messages to implement Chromium's custom looking UI while still using the standard window styles expected of a resizable top level frame window, so that other system level window management functionality works properly (and window management add-ins like <a href="http://www.splitview.com/">SplitView</a> work better too).</p>

<p>One issue preventing the frames from being turned on on the trunk is an annoying flicker in the title bar when switching tabs (or loading a page, or doing just about anything that causes painting to happen near the top of the window). It wasn't happening in an easily reproducible fashion, however it nearly always happened after using the browser for a while. You'd switch tabs and it looked like Windows was trying to paint the standard windows title bar. Then our custom code would kick in and paint our window contents, which would result in an ugly flash.</p>

<p>After trying some elementary logging and poking around in our <code>WM_NCPAINT</code> handling, we looked at the message log sent to each window as the tab was switched, and compared that against the message log sent to a window using the old frames.</p>

<p>The new frames received this string of messages:<br />
<code><br />
S WM_COMMAND wNotifyCode:0400 wID:36648 hwndCtl:073C0244 [wParam:04008F28 lParam:073C0244]<br />
R WM_COMMAND lResult:00000000<br />
S WM_ERASEBKGND hdc:9D0164EB [wParam:9D0164EB lParam:00000000]<br />
R WM_ERASEBKGND fErased:True [lResult:00000001]<br />
S WM_SETTEXT lpsz:0012E8B8 ("Netvibes (200) - Chromium") [wParam:00000000 lParam:0012E8B8]<br />
S message:0x00AE [Unknown] wParam:00000008 lParam:00000000<br />
S WM_GETTEXT cchTextMax:510 lpszText:0012D730 [wParam:000001FE lParam:0012D730]<br />
R WM_GETTEXT cchCopied:25 lpszText:0012D730 ("N") [lResult:00000019]<br />
R message:0x00AE [Unknown] lResult:00000000<br />
</code></p>

<p>The first <code>WM_COMMAND</code> is the Ctrl+PageUp sent to the window when I switched to the previous tab. Then comes the background erase message <code>WM_ERASEBKGND</code>. At this point code in <code>BrowserView2</code> updates the native window title using <code>WM_SETTEXT</code>. This is done so that the Windows Taskbar title is in sync with the newly selected tab. Then things get interesting.</p>

<p>We receive an "[Unknown]" message <code>0x00AE</code>, which wraps a <code>WM_GETTEXT</code> message. This message is <em>not</em> sent to the window using the old frames. I theorize that the <code>WM_GETTEXT</code> is being called from some Windows routine that's painting the native titlebar. Since this is all asynchronous that explains the flashing.</p>

<p>A quick Google search reveals that in fact yes, this mystery message <code>0x00AE</code> is the cause of the problem. Under the hood it maps to <strong><code>WM_NCUAHDRAWCAPTION</code></strong>, which is not <code>#defined</code> in winuser.h. It has a sibling <code>0x00AF</code> (which apparently maps to <strong><code>WM_NCUAHDRAWFRAME</code></strong>). The <a href="http://www.google.com/search?rlz=1C1GGLD_enUS285&sourceid=chrome&ie=UTF-8&q=WM_NCUAHDRAWCAPTION">forums I found</a> discussing this message all suggest that if you are drawing a custom frame (as we are with Chromium), then you must handle these messages to prevent <code>DefWindowProc</code> from doing it (and trying to paint the caption).</p>

<p>I have applied this change now to <code>HWNDViewContainer</code> and <code>CustomFrameWindow</code>, and things are going smoothly! I'm hoping that the code in ChromeViews will be a good reference for others wanting to build custom window frames on Windows, since the pathway here is far from clear. I may do another post later on describing all the things that need to be done, but in the mean time you can just look at the code in <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/custom_frame_window.cc?view=markup">custom_frame_window.cc</a>/<a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/views/custom_frame_window.h?view=markup">h</a> and go from there. At the very least, we are another step closer to turning on <code>--magic_browzR</code> by default!</p>]]>
        
    </content>
</entry>
<entry>
    <title>Google Chrome &amp; Chromium</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/09/get_google_chrome.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=114" title="Google Chrome &amp; Chromium" />
    <id>tag:www.bengoodger.com,2008://2.114</id>
    
    <published>2008-09-03T00:16:28Z</published>
    <updated>2008-09-23T03:50:59Z</updated>
    
    <summary>Google Chrome has launched, download it now. The source is available under a permissive BSD style license. Find out more at the Chromium website and blog. I love browsers, and so I&apos;m really excited that this project and the amazing...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p><a href="http://googleblog.blogspot.com/2008/09/fresh-take-on-browser.html">Google</a> <a href="http://www.google.com/chrome/intl/en/features.html">Chrome</a> <a href="http://www.mattcutts.com/blog/download-google-chrome-browser-beta/">has</a> <a href="http://news.google.com/?ncl=1241595050&hl=en&topic=h">launched</a>, <a href="http://www.google.com/chrome">download it now</a>. The source is available under a permissive BSD style license. Find out more at the <a href="http://www.chromium.org/">Chromium website</a> and <a href="http://blog.chromium.org/">blog</a>.</p>

<p><a href="http://www.bengoodger.com/plate.jpg">I love browsers</a>, and so I'm really excited that this project and the amazing team that I've been lucky enough to be a part of has finally shipped.</p>]]>
        
    </content>
</entry>
<entry>
    <title>Goodbye Fake Steve, Hello Linux Hater</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/07/goodbye_fake_steve_hello_linux.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=113" title="Goodbye Fake Steve, Hello Linux Hater" />
    <id>tag:www.bengoodger.com,2008://2.113</id>
    
    <published>2008-07-10T22:09:04Z</published>
    <updated>2008-09-23T03:51:29Z</updated>
    
    <summary>Fake Steve may be closing shop, but at least we now have Linux Hater......</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>Fake Steve may be <a href="http://fakesteve.blogspot.com/2008/07/i-am-so-friggin-high-its-not-funny.html">closing shop</a>, but at least we now have <a href="http://linuxhaters.blogspot.com/">Linux Hater</a>...</p>]]>
        
    </content>
</entry>
<entry>
    <title>Updaters</title>
    <link rel="alternate" type="text/html" href="http://www.bengoodger.com/2008/03/updaters.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://www.bengoodger.com/mt/mt-atom.cgi/weblog/blog_id=2/entry_id=109" title="Updaters" />
    <id>tag:www.bengoodger.com,2008://2.109</id>
    
    <published>2008-03-21T22:23:44Z</published>
    <updated>2008-09-23T03:52:41Z</updated>
    
    <summary>Back when we were building the Application Update Service for Firefox 1.5, I decided it would be a good idea to show users an informational dialog box letting them know that an update was available, and that they would be...</summary>
    <author>
        <name>Ben</name>
        <uri>http://www.bengoodger.com/</uri>
    </author>
    
    <content type="html" xml:lang="en" xml:base="http://www.bengoodger.com/">
        <![CDATA[<p>Back when we were building the Application Update Service for Firefox 1.5, I decided it would be a good idea to show users an informational dialog box letting them know that an update was available, and that they would be updated the next time they restarted. This turns out to have been one of those miserable user interface decisions that as a developer you really wish you hadn't made.</p>

<center><img src="http://www.bengoodger.com/images/screens/firefox-update.png"></center>
<center><em>A familiar sight for Firefox users</em></center>

<p>This dialog box is so annoying, and it's compounded by the fact that when the user clicks "Later" - basically "Sod off you stupid dialog box" the situation is made worse by <strong>another</strong> dialog box telling the user that they will be updated anyway the next time they restart. At this point the natural reaction is <strong>"I DON'T CARE GO AWAY"</strong>.</p>

<p>Software Update is something that users expect to be pretty transparent, and the fact that it isn't in a lot of software is a cause of annoyance (and <a href="http://img441.imageshack.us/img441/671/lolfirefoxrj1.jpg">occasional hilarity</a>).</p>

<p>One of the worst offenders I think is Adobe. Today I'm going to bitch about their updater. It pops up every time Crap-o-bat is started, offering some cryptically worded and I'm convinced irrelevant update to one of the myriad pieces of shared code junk Adobe software installs onto my computer. In general, the Crap-o-bat user experience is among the worst of desktop software, but I'll stay focused on the updater. I swat this annoying dialog box away over and over, until eventually other circumstances cause me to have to restart the computer.</p>

<p>At startup, Windows does its usual charming thing of showing the desktop approximately 3-4 minutes before anything's actually interactive, and so I sit here dumbly waiting for all the startup items and tray icons to load. After a short while, the Adobe updater appears. I figure what the heck, I've rebooted, let's let it do its thing.</p>

<center><img src="http://www.bengoodger.com/images/screens/adobe-updater.png"></center>
<center><em>The Adobe Updater</em></center>

<p>One of the first rules of progress meters is to make sure that progress is shown immediately and that it's constantly updated, even if the steps are very small. This provides the user with a sense of satisfaction that something is happening and that they are slowly getting towards their goal state. The Adobe Updater appears and sits for about 2-3 minutes with an empty progress bar. Is it hung? No, the window is still interactive. I wonder if this is not some retarded Windows MSI database checking phase. Eventually the updater begins chugging through each update. The best (and by best I mean worst) part is that Adobe seems to have invented a new kind of progress meter, which shows indeterminate progress within a particular step of a multi-step install progress within a single master progress meter. The updater achieves this by having the progress meter step up, and then once it reaches some arbitrary limit fall back to where it was at the start of the step, and repeats this process over and over until that step is complete. This is very disconcerting to the user since it looks like something is failing causing progress to be reset. Since little in the UI changes, I began to think the updater had jammed and was about to close it until after another 3 minutes or so it continued on to the next step and I figured out what it was doing.</p>

<p>In all, the process took about 20 minutes to complete, which is staggeringly long considering the software being updated. In the process, the updater dropped an unwanted Crap-o-bat icon on my desktop. Why they felt the need to do this I'll never know - especially since Crap-o-bat is one of those pieces of software that actually needs no icons anywhere on your computer, since the way you typically launch it is either through its browser plugin or by double clicking on a PDF file in Explorer. Why their updater felt like their software deserved a spot on my precious desktop is beyond me, except perhaps to think that their marketing department holds users in utter contempt and that simply branding people's computing experiences with unnecessary junk bearing their company name is worthwhile.<br />
</p>]]>
        
    </content>
</entry>

</feed> 

