<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>nanoANT &#187; Programming</title>
	<atom:link href="http://www.nanoant.com/category/programming/feed" rel="self" type="application/rss+xml" />
	<link>http://www.nanoant.com</link>
	<description>Yet another self-employee site &#38; blog</description>
	<lastBuildDate>Mon, 24 Jan 2011 17:18:45 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
		<item>
		<title>Streaming thumbnails smoothly using HTTP in your iPhone app</title>
		<link>http://www.nanoant.com/programming/streaming-thumbnails-smoothly-using-http-in-your-iphone-app</link>
		<comments>http://www.nanoant.com/programming/streaming-thumbnails-smoothly-using-http-in-your-iphone-app#comments</comments>
		<pubDate>Wed, 06 Oct 2010 13:44:44 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[iPhone]]></category>

		<guid isPermaLink="false">http://www.nanoant.com/?p=629</guid>
		<description><![CDATA[Network enabled apps such as news aggregators, blogging clients often load lots of small files, such as thumbnails, trough HTTP connection. One of them is my app &#8211; Kozaczek, that loads thumbnails for every UITableView item when it is about to be displayed. Usually we expect that such application is: (1) responsive (does not block scrolling [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="size-full wp-image-637  aligncenter" title="HTTP" src="http://www.nanoant.com/wp/wp-content/uploads/2010/10/HTTP-smooth.png" alt="" width="649" height="343" /></p>
<p>Network enabled apps such as news aggregators, blogging clients often load lots of small files, such as thumbnails, trough HTTP connection. One of them is my app &#8211; <a href="/apple/browse-gossips-and-latest-paparazzi-shots-on-your-iphone">Kozaczek</a>, that loads thumbnails for every <tt>UITableView</tt> item when it is about to be displayed. Usually we expect that such application is: <strong>(1)</strong> responsive (does not block scrolling while loading), <strong>(2)</strong> it does load thumbnails almost realtime.</p>
<p>I suppose the first thing everybody tries is calling <tt>[<strong>UIImage</strong> imageWithData:[<strong>NSData</strong> dataWithContentsOfURL:<em>someURL</em>]]</tt>. There is nothing wrong with it, except it make your UI stutter and load images painfully slow. After trying that one may think of using background threads, <tt>NSOperationQueue</tt>, or something like that, but still any modern web browser loads those images much faster when they are embedded into regular web page than your application. Wonder why?</p>
<p><span id="more-629"></span></p>
<h2>Man behind the bar at HTTP server</h2>
<p>HTTP 1.1 introduces feature called persistent connections &#8211; later backported also to HTTP 1.0 in the form of an extra header <tt>Connection: keep-alive</tt> sent by the client. This is the clue of the solution here.</p>
<p>You may think of HTTP server working thread serving you as bartender taking your order and bring back drinks. First your connection is waiting in the queue to the bar, once bartender dispatches all orders of clients in the front of you, he asks for yours. Then (during the connection) you have the bartender (almost) exclusively serving you. Once you disconnect, the bartender focuses his attention on the next client, so if you decide to make another request short while afterwards you need to go back in the queue and wait again for your turn.</p>
<p>Back in HTTP 1.0 times, server was taking only one order, sending back response and disconnecting. But since HTTP 1.1 you may send many orders to the server one after the other (or even parallel). You can also stay connected while you are non sending requests, just in case you want something extra. All modern web browsers follow simple rule of trying to execute all the requests using existing persistent connection while not making more than 2-4 connections to single server.</p>
<p>Thats why putting your thumbnails download in background threads or <tt>NSOperationQueue</tt> does not do any better, but just pollutes remote HTTP server with many connections, that anyway will not be served altogether. Moreover the overall time you gonna spend waiting for response for all requests will be significantly longer than time use with single persistent connection sending requests one-by-one.</p>
<h2>CFNetwork HTTP connection pooling</h2>
<p>It is better then to keep your application single threaded, but instead use good event driven download mechanism based on persistent connections. The first candidate for that is <tt>NSURLConnection</tt> which unfortunately has some problems with keeping persistent connections to HTTP 1.0 servers via <tt>keep-alive</tt> header, even it uses internally <tt>CFNetwork</tt>. This is the reason I will focus on more low level solution directly based on <em>CFNetwork</em>&#8216;s <tt>CFReadStream</tt> object and <tt>CFReadStreamCreateForHTTPRequest</tt> function.</p>
<p><em>CFNetwork</em> documentation states that this framework tries to pool and reuse existing HTTP connections for newly created <tt>CFReadStream</tt> if there is still other <tt>CFReadStream</tt> connected to the same server. This implies two facts: <strong>(1)</strong> <em>CFNetwork</em> does queue all read requests to the same server where possible trough single connection <strong>(2)</strong> if only you keep the <tt>CFReadStream</tt> reference to the server (i.e. using global variable), so every time you open new <tt>CFReadStream</tt>, it will reuse connection kept inside previously used <tt>CFReadStream</tt>.</p>
<p>Below I attach ready to use implementation of <tt>Fetch</tt> class (under MIT-like license) that does all of that for you. All you need to do is to <tt>[<strong>Fetch</strong> fetchURL:<em>someURL</em> delegate:<strong>self</strong> tag:<em>someTagForYourComfort</em>]</tt>. The connection itself does retain <tt>Fetch</tt> instance and releases it once the request if over, so you do not need to retain it yourself. The delegate (also retained in case it is deallocated before request is over) should implement 3 methods:</p>
<pre>- (<strong>void</strong>)fetch:(<strong>Fetch</strong> *)<em>fetch</em> didFailWithError:(NSError *)<em>error</em>;
- (<strong>void</strong>)fetchDidFinishLoading:(<strong>Fetch</strong> *)<em>connection</em>;
- (<strong>void</strong>)fetch:(<strong>Fetch</strong> *)<em>fetch</em> didReceiveStatusCode:(<strong>NSInteger</strong>)<em>statusCode</em> contentLength:(<strong>NSInteger</strong>)<em>contentLength</em>;</pre>
<p><strong>HINT #1</strong>: Once you receive <tt>didReceiveStatusCode</tt>, you should assign <tt>fetch.data</tt> property (retained) some <tt>NSMutableData</tt> instance otherwise it will not store downloaded data anywhere.</p>
<p><strong>HINT #2</strong>: If you wish to cancel <tt>Fetch</tt> request you may use <tt>-[Fetch cancel]</tt>.</p>
<ul class="projects">
<li class="doc"><a href="/download/classes/Fetch.h">Fetch.h</a> downloader class interface</li>
<li class="doc"><a href="/download/classes/Fetch.m">Fetch.m</a> and implementation</li>
</ul>
<p>Since <em>iPhone/iPod Touch</em> is pretty quick to do image decoding in main thread once you get the data, creating image with <tt>[UIImage imageWithData:fetch.data]</tt> in <tt>fetchDidFinishLoading</tt> and binding the image to <tt>UITableView</tt> cell works for me fine.</p>
<p>Implementation part that deserves the attention is initialization part:</p>
<pre class="textmate-source"><span class="source source_objc">- (<span class="storage storage_type storage_type_id storage_type_id_objc">id</span>)initWithURL:(<span class="support support_class support_class_cocoa">NSURL</span> *)_url
         delegate:(<span class="meta meta_id-with-protocol meta_id-with-protocol_objc"><span class="storage storage_type storage_type_objc">id</span><span class="meta meta_protocol-list meta_protocol-list_objc"><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_begin punctuation_section_scope_begin_objc">&lt;</span>FetchDelegate<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_end punctuation_section_scope_end_objc">&gt;</span></span></span>)_delegate
              tag:(<span class="support support_type support_type_cocoa support_type_cocoa_leopard">NSInteger</span>)_tag
<span class="meta meta_block meta_block_c">{
    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> Copy properties
</span>    self<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.delegate</span> = _delegate;
    tag = _tag;

    CFHTTPMessageRef request =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">CFHTTPMessageCreateRequest</span>(</span>
                                                          <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFAllocatorDefault</span>,
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">                                                          </span><span class="support support_function support_function_any-method support_function_any-method_c">CFSTR</span>(</span><span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>GET<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>),
                                                          (CFURLRef)_url,
                                                          <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFHTTPVersion1_1</span>);
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">CFHTTPMessageSetHeaderFieldValue</span>(</span>request,<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">CFSTR</span>(</span><span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>Keep-Alive<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>),<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">CFSTR</span>(</span><span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>30<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>));

    stream =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">CFReadStreamCreateForHTTPRequest</span>(</span><span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFAllocatorDefault</span>, request);
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">CFRelease</span>(</span>request);
    CFStreamClientContext context = <span class="meta meta_block meta_block_c">{
        <span class="constant constant_numeric constant_numeric_c">0</span>, (<span class="storage storage_type storage_type_c">void</span> *)self,
        CFClientRetain,
        CFClientRelease,
        CFClientDescribeCopy
    }</span>;
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">CFReadStreamSetClient</span>(</span>stream,
                          <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFStreamEventHasBytesAvailable</span> |
                          <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFStreamEventErrorOccurred</span> |
                          <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFStreamEventEndEncountered</span>,
                          FetchReadCallBack,
                          &amp;context);
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">CFReadStreamScheduleWithRunLoop</span>(</span>stream,
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">                                    </span><span class="support support_function support_function_any-method support_function_any-method_c">CFRunLoopGetCurrent</span>(</span>),
                                    <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFRunLoopCommonModes</span>);

    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> In meantime our persistent stream may be closed, check that.
</span>    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> If we won't do it, our new stream will raise an error on startup
</span>    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> FIXME: This is a bug in CFNetwork!
</span>    <span class="keyword keyword_control keyword_control_c">if</span>(persistentStream != <span class="constant constant_language constant_language_c">NULL</span>) <span class="meta meta_block meta_block_c">{
        CFStreamStatus status =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">CFReadStreamGetStatus</span>(</span>persistentStream);
        <span class="keyword keyword_control keyword_control_c">if</span>(status == <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFStreamStatusNotOpen</span> || status == <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFStreamStatusClosed</span> || status == <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFStreamStatusError</span>) <span class="meta meta_block meta_block_c">{
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">            </span><span class="support support_function support_function_any-method support_function_any-method_c">CFReadStreamClose</span>(</span>persistentStream);
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">            </span><span class="support support_function support_function_any-method support_function_any-method_c">CFRelease</span>(</span>persistentStream);
            persistentStream = <span class="constant constant_language constant_language_c">NULL</span>;
        }</span>
    }</span>

<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">CFReadStreamSetProperty</span>(</span>stream, <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFStreamPropertyHTTPAttemptPersistentConnection</span>, <span class="constant constant_other constant_other_variable constant_other_variable_mac-classic constant_other_variable_mac-classic_c">kCFBooleanTrue</span>);
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">CFReadStreamOpen</span>(</span>stream);

    <span class="keyword keyword_control keyword_control_c">if</span>(persistentStream != <span class="constant constant_language constant_language_c">NULL</span>) <span class="meta meta_block meta_block_c">{
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">        </span><span class="support support_function support_function_any-method support_function_any-method_c">CFReadStreamClose</span>(</span>persistentStream);
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">        </span><span class="support support_function support_function_any-method support_function_any-method_c">CFRelease</span>(</span>persistentStream);
        persistentStream = <span class="constant constant_language constant_language_c">NULL</span>;
    }</span>

    streamCount++;

    <span class="keyword keyword_control keyword_control_c">return</span> self;
}</span>
</span></pre>
<p>Few notes about initialization part of <tt>Fetch</tt> instance:</p>
<ol>
<li>It forces using 30 seconds <tt>keep-alive</tt> trough <tt>CFHTTPMessageSetHeaderFieldValue</tt></li>
<li>It retains itself using <tt>CFReadStreamSetClient</tt></li>
<li>It uses main thread (current) runloop with <tt>CFReadStreamScheduleWithRunLoop</tt></li>
<li>It maintains <tt>persistentStream</tt> global reference to last used stream, and replaces it by its own connection (so <tt>persistentStream</tt> always points to the last one)</li>
<li>Finally it forces persistent connections, even they may be default (or not?) using <tt>CFReadStreamSetProperty(stream, kCFStreamPropertyHTTPAttemptPersistentConnection, kCFBooleanTrue);</tt></li>
</ol>
<p>So this is all folks. Waiting for your comments. I hope you will find this post useful.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nanoant.com/programming/streaming-thumbnails-smoothly-using-http-in-your-iphone-app/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Is closed-source project like CMSity doomed to the death nowadays?</title>
		<link>http://www.nanoant.com/projects/is-closed-source-project-like-cmsity-doomed-to-the-death-nowadays</link>
		<comments>http://www.nanoant.com/projects/is-closed-source-project-like-cmsity-doomed-to-the-death-nowadays#comments</comments>
		<pubDate>Tue, 28 Apr 2009 14:31:46 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[cmsity]]></category>
		<category><![CDATA[future]]></category>
		<category><![CDATA[open-source]]></category>

		<guid isPermaLink="false">http://www.nanoant.com/?p=317</guid>
		<description><![CDATA[Seems it is very hard to spread the news about CMSity around the world, and acquire some user base of this project. Till now I did few commercial deployments of CMSity, however the cmsity.com page hits look really miserable. I wrote mails to many CMS magazines asking to drop a note about my project. However [...]]]></description>
			<content:encoded><![CDATA[<p class="alignright"><a href="http://www.cmsity.com/"><img class="size-full wp-image-181" title="CMSity Logo" src="http://www.nanoant.com/wp/wp-content/uploads/2009/03/cmsity_ss.png" alt="" width="278" height="89" /></a></p>
<p>Seems it is very hard to spread the news about <a href="http://www.cmsity.com/">CMSity</a> around the world, and acquire some user base of this project. Till now I did few commercial deployments of <em>CMSity</em>, however the <a href="http://www.cmsity.com/users">cmsity.com</a> page hits look really miserable.</p>
<p>I wrote mails to many <em>CMS</em> magazines asking to drop a note about my project. However only two of them replied and posted something on their sites about <em>CMSity</em>. So I still miss some more reviews that can put a breathe into the project. But it seems my mails are ignored by majority of big <em>CMS</em> related sites making very hard to promote new project like <em>CMSity</em> nowadays.</p>
<p>Since I believe this software presents great value and <a href="http://www.cmsity.com/blog/cmsity-vs-wordpress">outperforms other popular solutions</a> I consider releasing it as <strong>open-source</strong>, however probably not <strong>GPL</strong> but some license that will force the code to stay by the author (me), deny all the forks, making all community changes happen to be included in the source code base.</p>
<p>Open-source is a great idea, but I have seen too many projects that were just bloated, forked and spoiled by masses of developers that were just about put something of themselves in the project regardless of quality of the included changes, missing overall sense and directions of the project itself. That is why I decided to keep the code closed initially, while giving the licenses for free, but it seems non-open source project are just kicked out of the focus today, and releasing the source code is a &#8220;must&#8221; to gain the momentum.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nanoant.com/projects/is-closed-source-project-like-cmsity-doomed-to-the-death-nowadays/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Haml + Gettext = automagic translation</title>
		<link>http://www.nanoant.com/programming/haml-gettext-automagic-translation</link>
		<comments>http://www.nanoant.com/programming/haml-gettext-automagic-translation#comments</comments>
		<pubDate>Mon, 13 Apr 2009 21:39:41 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[haml templates ruby performance i18n l10n multilanguage]]></category>

		<guid isPermaLink="false">http://www.nanoant.com/?p=290</guid>
		<description><![CDATA[I was rather sceptic to Haml once I have first time read about it. But after recently playing a while with it I can frankly express that it is simply outstanding template engine for Ruby. What I miss about Haml is some seamless integration with some i18n framework (gem). So I decided to create Haml [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright" src="http://www.nanoant.com/wp/wp-content/uploads/2009/04/haml.gif" alt="Haml logo" />I was rather sceptic to <a href="http://haml.hamptoncatlin.com/">Haml</a> once I have first time read about it. But after recently playing a while with it I can frankly express that it is simply outstanding template engine for <a href="http://www.ruby-lang.org/">Ruby</a>. What I miss about <em>Haml</em> is some seamless integration with some i18n framework (gem).</p>
<p>So I decided to create <em>Haml</em> &#8220;mod&#8221; that uses <a href="http://www.yotabanana.com/hiki/ruby-gettext.html">GetText</a> (<a href="http://github.com/grosser/fast_gettext/tree/master">FastGettext</a> alternatively) to automagically translate static texts from <em>Haml</em> templates during precompilation stage. So something that you don&#8217;t see and you don&#8217;t need to worry about.<span id="more-290"></span></p>
<p>Normally you would use <tt>_(text)</tt> calls to translate string in your templates as below:</p>
<pre class="textmate-source"><span class="text text_haml"><span class="meta meta_tag meta_tag_haml"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_haml">%</span><span class="entity entity_name entity_name_tag entity_name_tag_haml">h1</span></span><span class="meta meta_line meta_line_ruby meta_line_ruby_haml">=<span class="source source_ruby source_ruby_embedded source_ruby_embedded_haml"> _<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>Items<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span></span></span>
<span class="meta meta_line meta_line_ruby meta_line_ruby_haml">-<span class="source source_ruby source_ruby_embedded source_ruby_embedded_haml"> items<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>each </span><span class="source source_ruby source_ruby_embedded source_ruby_embedded_html"><span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block">do</span> |item|</span></span>
  <span class="entity entity_name entity_name_tag entity_name_tag_class entity_name_tag_class_haml">.item</span>
    <span class="meta meta_tag meta_tag_haml"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_haml">%</span><span class="entity entity_name entity_name_tag entity_name_tag_haml">h1</span></span><span class="meta meta_line meta_line_ruby meta_line_ruby_haml">=<span class="source source_ruby source_ruby_embedded source_ruby_embedded_haml"> item<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>title</span></span>
    <span class="meta meta_tag meta_tag_haml"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_haml">%</span><span class="entity entity_name entity_name_tag entity_name_tag_haml">a</span></span><span class="meta meta_section meta_section_attributes meta_section_attributes_haml">{<span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"> </span>href<span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span><span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>/edit<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span> }</span><span class="meta meta_line meta_line_ruby meta_line_ruby_haml">=<span class="source source_ruby source_ruby_embedded source_ruby_embedded_haml"> _<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>Edit<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span></span></span>
    <span class="meta meta_tag meta_tag_haml"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_haml">%</span><span class="entity entity_name entity_name_tag entity_name_tag_haml">a</span></span><span class="meta meta_section meta_section_attributes meta_section_attributes_haml">{<span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"> </span>href<span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span><span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>/delete<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span> }</span><span class="meta meta_line meta_line_ruby meta_line_ruby_haml">=<span class="source source_ruby source_ruby_embedded source_ruby_embedded_haml"> _<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>Delete<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span></span></span></span></pre>
<p>You can see this is pretty ugly and unreadable. If you gonna have multi-language site you want to translate all of the static texts there anyway, without doing anything extra. So you would prefer to type:</p>
<pre class="textmate-source"><span class="text text_haml"><span class="meta meta_tag meta_tag_haml"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_haml">%</span><span class="entity entity_name entity_name_tag entity_name_tag_haml">h1</span></span><span class="meta meta_line meta_line_ruby meta_line_ruby_haml">=<span class="source source_ruby source_ruby_embedded source_ruby_embedded_haml"> <span class="variable variable_other variable_other_constant variable_other_constant_ruby">Items</span></span></span>
<span class="meta meta_line meta_line_ruby meta_line_ruby_haml">-<span class="source source_ruby source_ruby_embedded source_ruby_embedded_haml"> items<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>each </span><span class="source source_ruby source_ruby_embedded source_ruby_embedded_html"><span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block">do</span> |item|</span></span>
  <span class="entity entity_name entity_name_tag entity_name_tag_class entity_name_tag_class_haml">.item</span>
    <span class="meta meta_tag meta_tag_haml"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_haml">%</span><span class="entity entity_name entity_name_tag entity_name_tag_haml">h1</span></span><span class="meta meta_line meta_line_ruby meta_line_ruby_haml">=<span class="source source_ruby source_ruby_embedded source_ruby_embedded_haml"> item<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>title</span></span>
    <span class="meta meta_tag meta_tag_haml"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_haml">%</span><span class="entity entity_name entity_name_tag entity_name_tag_haml">a</span></span><span class="meta meta_section meta_section_attributes meta_section_attributes_haml">{<span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"> </span>href<span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span><span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>/edit<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span> }</span> Edit
    <span class="meta meta_tag meta_tag_haml"><span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_haml">%</span><span class="entity entity_name entity_name_tag entity_name_tag_haml">a</span></span><span class="meta meta_section meta_section_attributes meta_section_attributes_haml">{<span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"> </span>href<span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span><span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>/delete<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span> }</span> Delete</span></pre>
<p>And have <em>&#8220;Items&#8221;</em>, <em>&#8220;Edit&#8221;</em>, <em>&#8220;Delete&#8221;</em> just translated, right? This is what my mod does. It translates all of those at precompilation stage which also is much better for your application performance, since <em>GetText</em> routines are called only once at precompilation stage. Here it goes.</p>
<h3>haml_gettext.rb</h3>
<pre class="textmate-source"><span class="source source_ruby"><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> Haml gettext module providing gettext translation for all Haml plain text calls
</span><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span>
</span><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> http://pastie.org/445295
</span>
<span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">Haml::Engine</span></span>
<span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> Inject _ gettext into plain text and tag plain text calls
</span>  <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">push_plain</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">text</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
    <span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby">super</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>_<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>text<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">))</span>
  <span class="keyword keyword_control keyword_control_ruby">end</span>
  <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">parse_tag</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">line</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
    tag_name<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> attributes<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> attributes_hash<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> object_ref<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> nuke_outer_whitespace<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span>
      nuke_inner_whitespace<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> action<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> value <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby">super</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>line<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
    value <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> _<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>value<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_control keyword_control_ruby">unless</span> action <span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby">||</span> value<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>empty?
    <span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span>tag_name<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> attributes<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> attributes_hash<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> object_ref<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> nuke_outer_whitespace<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span>
        nuke_inner_whitespace<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> action<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> value<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span>
  <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="keyword keyword_control keyword_control_ruby">end</span></span></pre>
<p>All you need is to choose <em>GetText</em> or <em>FastGettext</em> and load my mod later on.</p>
<pre class="textmate-source"><span class="source source_ruby"><span class="meta meta_require meta_require_ruby"><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">require</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>haml<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span></span>
<span class="meta meta_require meta_require_ruby"><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">require</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>fast_gettext<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span></span>
<span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">include</span> <span class="support support_class support_class_ruby">FastGettext</span><span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby">::</span><span class="variable variable_other variable_other_constant variable_other_constant_ruby">Translation</span>
<span class="meta meta_require meta_require_ruby"><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">require</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>haml_gettext<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span></span></span></pre>
<p>You probably want to know the way to your gettext pot/po files out of the tempaltes. I have prepared here Rake tasks for you as well (based on work I found somewhere over Ruby blogs) to parse Haml templates extended to include static texts in the translation.</p>
<h3>Rakefile</h3>
<pre class="textmate-source"><span class="source source_ruby">desc <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>Update pot/po files.<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
task <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>updatepo</span> <span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby">do
</span>  <span class="meta meta_require meta_require_ruby"><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">require</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>gettext/tools<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span></span>
  <span class="meta meta_require meta_require_ruby"><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">require</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>haml_parser<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span></span>
  <span class="support support_class support_class_ruby">GetText</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>update_pofiles<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>rbigg<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="support support_class support_class_ruby">Dir</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>glob<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>{lib,views}/**/*.{rb,haml}<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby">&lt;&lt;</span> <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>rbigg.rb<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>rbigg 1.0.0<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>po_root</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=&gt;</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>locale<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class="keyword keyword_control keyword_control_ruby">end</span></span></pre>
<h3>haml_parser.rb</h3>
<pre class="textmate-source"><span class="source source_ruby"><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> Haml gettext parser module
</span><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span>
</span><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> http://pastie.org/445297
</span><span class="meta meta_require meta_require_ruby"><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">require</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>gettext/tools/rgettext<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span></span>
<span class="meta meta_require meta_require_ruby"><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">require</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>gettext/parser/ruby<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span></span>
<span class="meta meta_require meta_require_ruby"><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">require</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>haml<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span></span>

<span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">Haml::Engine</span></span>
<span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> Overriden function that parses Haml tags
</span><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> Injects gettext call for plain text action.
</span>  <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">parse_tag</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">line</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
    tag_name<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> attributes<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> attributes_hash<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> object_ref<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> nuke_outer_whitespace<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span>
      nuke_inner_whitespace<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> action<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> value <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby">super</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>line<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
    <span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@</span>precompiled</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby">&lt;&lt;</span> <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>_(<span class="constant constant_character constant_character_escape constant_character_escape_ruby">\"</span><span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>value<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="constant constant_character constant_character_escape constant_character_escape_ruby">\"</span>)<span class="constant constant_character constant_character_escape constant_character_escape_ruby">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span> <span class="keyword keyword_control keyword_control_ruby">unless</span> action <span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby">||</span> value<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>empty?
    <span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span>tag_name<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> attributes<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> attributes_hash<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> object_ref<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> nuke_outer_whitespace<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span>
        nuke_inner_whitespace<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> action<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> value<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span>
  <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> Overriden function that producted Haml plain text
</span><span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby">  <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> Injects gettext call for plain text action.
</span>  <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">push_plain</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">text</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
    <span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@</span>precompiled</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby">&lt;&lt;</span> <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>_(<span class="constant constant_character constant_character_escape constant_character_escape_ruby">\"</span><span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>text<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="constant constant_character constant_character_escape constant_character_escape_ruby">\"</span>)<span class="constant constant_character constant_character_escape constant_character_escape_ruby">\n</span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
  <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="keyword keyword_control keyword_control_ruby">end</span>

<span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> Haml gettext parser
</span><span class="meta meta_module meta_module_ruby"><span class="keyword keyword_control keyword_control_module keyword_control_module_ruby">module</span> <span class="entity entity_name entity_name_type entity_name_type_module entity_name_type_module_ruby">HamlParser</span></span>
  <span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">module_function</span>

  <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">target?</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">file</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
    <span class="support support_class support_class_ruby">File</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>extname<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>file<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby">==</span> <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>.haml<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
  <span class="keyword keyword_control keyword_control_ruby">end</span>

  <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">parse</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">file<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> ary <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[]</span></span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
    haml <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="support support_class support_class_ruby">Haml</span><span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby">::</span><span class="support support_class support_class_ruby">Engine</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">new</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="support support_class support_class_ruby">IO</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>readlines<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>file<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>join<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
    code <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> haml<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>precompiled<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>split<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_regexp string_regexp_classic string_regexp_classic_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby">/</span>$<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_ruby">/</span></span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
    <span class="support support_class support_class_ruby">GetText</span><span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby">::</span><span class="support support_class support_class_ruby">RubyParser</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>parse_lines<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>file<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> code<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> ary<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
  <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="keyword keyword_control keyword_control_ruby">end</span>

<span class="support support_class support_class_ruby">GetText</span><span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby">::</span><span class="support support_class support_class_ruby">RGetText</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>add_parser<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="variable variable_other variable_other_constant variable_other_constant_ruby">HamlParser</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span></span></pre>
<p>So this is it. Have fun with nice and clean templates that are translated on the fly</p>
<h2>See &amp; get more&#8230;</h2>
<p>You can find more recent and complete code at my <a href="http://github.com/nanoant/sinatra-hat">Sinatra Hat</a> GitHub hosted Ruby gem project.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nanoant.com/programming/haml-gettext-automagic-translation/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Opening specified path in Terminal&#8217;s new tab</title>
		<link>http://www.nanoant.com/programming/opening-specified-path-in-terminals-new-tab</link>
		<comments>http://www.nanoant.com/programming/opening-specified-path-in-terminals-new-tab#comments</comments>
		<pubDate>Tue, 24 Mar 2009 11:13:36 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[mac]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[terminal]]></category>
		<category><![CDATA[textmate]]></category>

		<guid isPermaLink="false">http://www.nanoant.com/?p=284</guid>
		<description><![CDATA[Updates It uses now click menu instead of keystroke &#8220;System Events&#8221; command, because in some cases when you had this script assigned to shortcut that used Ctrl or Shift modifiers, those modifiers were sent together with Cmd to &#8220;Terminal&#8221; producing invalid behavior. It waits 0.5 second when window is busy just in case Terminal.app was not running and it [...]]]></description>
			<content:encoded><![CDATA[<h2>Updates</h2>
<ol>
<li>It uses now <tt>click menu</tt> instead of <tt>keystroke</tt> <em>&#8220;System Events&#8221;</em> command, because in some cases when you had this script assigned to shortcut that used <em>Ctrl</em> or <em>Shift</em> modifiers, those modifiers were sent together with <em>Cmd</em> to <em>&#8220;Terminal&#8221;</em> producing invalid behavior.</li>
<li>It waits 0.5 second when window is busy just in case <em>Terminal.app</em> was not running and it is just loading the shell which makes it <tt>busy</tt> for short while too. Fixes incorrect behavior of opening extra tab when <em>Terminal.app</em> was not running.</li>
</ol>
<p>If you ever wondered how to open specified path in new tab of <em>Terminal.app</em> or reuse current one if it is not busy (running a command), here&#8217;s a script you may use:</p>
<pre class="textmate-source"><span class="source source_applescript"><span class="meta meta_tell-block meta_tell-block_application meta_tell-block_application_generic meta_tell-block_application_generic_applescript"><span class="keyword keyword_control keyword_control_applescript">tell</span> <span class="support support_class support_class_built-in support_class_built-in_applescript">application</span> <span class="string string_quoted string_quoted_double string_quoted_double_application-name string_quoted_double_application-name_applescript"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_applescript">"</span>Terminal<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_applescript">"</span></span>

    <span class="support support_function support_function_standard-suite support_function_standard-suite_applescript">activate</span>

    <span class="keyword keyword_control keyword_control_applescript">set</span> <span class="variable variable_other variable_other_applescript">windowCount</span> <span class="keyword keyword_control keyword_control_applescript">to</span> <span class="punctuation punctuation_section punctuation_section_group punctuation_section_group_applescript">(</span><span class="support support_function support_function_standard-suite support_function_standard-suite_applescript">count</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">of</span> the <span class="support support_class support_class_standard-suite support_class_standard-suite_applescript">windows</span><span class="punctuation punctuation_section punctuation_section_group punctuation_section_group_applescript">)</span>

    <span class="comment comment_line comment_line_double-dash comment_line_double-dash_applescript"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_applescript">--</span> Terminal may be just launched loading the shell, wait a bit
</span>    <span class="keyword keyword_control keyword_control_applescript">if</span> windowCount <span class="keyword keyword_operator keyword_operator_applescript">is greater than</span> <span class="constant constant_numeric constant_numeric_applescript">0</span> <span class="keyword keyword_operator keyword_operator_applescript">and</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">first</span> <span class="support support_class support_class_standard-suite support_class_standard-suite_applescript">window</span> <span class="keyword keyword_operator keyword_operator_applescript">is</span> busy <span class="keyword keyword_control keyword_control_applescript">then</span>
        <span class="support support_function support_function_standardadditions support_function_standardadditions_user-interaction support_function_standardadditions_user-interaction_applescript">delay</span> <span class="constant constant_numeric constant_numeric_applescript">0.5</span>
    <span class="keyword keyword_control keyword_control_applescript">end</span>

    <span class="comment comment_line comment_line_double-dash comment_line_double-dash_applescript"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_applescript">--</span> Still busy / no windows? open new tab
</span>    <span class="keyword keyword_control keyword_control_applescript">if</span> windowCount <span class="keyword keyword_operator keyword_operator_applescript">is greater than</span> <span class="constant constant_numeric constant_numeric_applescript">0</span> <span class="keyword keyword_operator keyword_operator_applescript">and</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">first</span> <span class="support support_class support_class_standard-suite support_class_standard-suite_applescript">window</span> <span class="keyword keyword_operator keyword_operator_applescript">is</span> busy <span class="keyword keyword_operator keyword_operator_applescript">or</span> windowCount <span class="keyword keyword_operator keyword_operator_applescript">is</span> <span class="constant constant_numeric constant_numeric_applescript">0</span> <span class="keyword keyword_control keyword_control_applescript">then</span>
<span class="meta meta_tell-block meta_tell-block_application meta_tell-block_application_generic meta_tell-block_application_generic_applescript">        <span class="keyword keyword_control keyword_control_applescript">tell</span> <span class="support support_class support_class_built-in support_class_built-in_applescript">application</span> <span class="string string_quoted string_quoted_double string_quoted_double_application-name string_quoted_double_application-name_applescript"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_applescript">"</span>System Events<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_applescript">"</span></span> <span class="keyword keyword_control keyword_control_applescript">to</span> <span class="keyword keyword_control keyword_control_applescript">tell</span> process <span class="string string_quoted string_quoted_double string_quoted_double_applescript"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_applescript">"</span>Terminal<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_applescript">"</span></span>
            click <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">first</span> menu <span class="support support_class support_class_standard-suite support_class_standard-suite_applescript">item</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">of</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">first</span> menu <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">of</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">second</span> menu <span class="support support_class support_class_standard-suite support_class_standard-suite_applescript">item</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">of</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">first</span> menu <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">of</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">third</span> menu bar <span class="support support_class support_class_standard-suite support_class_standard-suite_applescript">item</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">of</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">first</span> menu bar
        <span class="keyword keyword_control keyword_control_applescript">end tell</span></span>
    <span class="keyword keyword_control keyword_control_applescript">end if</span>

    do <span class="support support_class support_class_built-in support_class_built-in_applescript">script</span> <span class="string string_quoted string_quoted_double string_quoted_double_applescript"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_applescript">"</span>cd #{e_as(e_sh(dir))}<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_applescript">"</span></span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">in</span> <span class="keyword keyword_control keyword_control_reference keyword_control_reference_applescript">first</span> <span class="support support_class support_class_standard-suite support_class_standard-suite_applescript">window</span>

<span class="keyword keyword_control keyword_control_applescript">end tell</span></span></span></pre>
<p>Where <tt>#{e_as(e_sh(dir))}</tt> is your desired folder. This is modified chunk of <em>TextMate</em>&#8216;s command script found at <a href="http://markelikalderon.com/blog/2008/05/18/open-terminal-in-new-tab/">Mark Eli Kalderon&#8217;s Blog</a>. Thanks Mark!</p>
<p><em>Note:</em> Mark&#8217;s <em>TextMate</em> command script does not open anything when <em>Terminal.app</em> has no windows or it is not running.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nanoant.com/programming/opening-specified-path-in-terminals-new-tab/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>MinGW on Mac, hell yeah!</title>
		<link>http://www.nanoant.com/programming/mingw-on-mac-hell-yeah</link>
		<comments>http://www.nanoant.com/programming/mingw-on-mac-hell-yeah#comments</comments>
		<pubDate>Thu, 19 Mar 2009 14:18:18 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.nanoant.com/?p=223</guid>
		<description><![CDATA[Want to build some small/or not, neat Windows/or Linux application on your Mac? Just use MinGW/Linux GCC cross compiler package from Pierre Molinaro. Those were recently updated to GCC 4.2 and do cross-compile really fast, especially when using make -j2. It is hard to be Switcher and totally forget/abandon Windows projects, since most of my clients&#8230; well [...]]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-full wp-image-227" title="GCC" src="http://www.nanoant.com/wp/wp-content/uploads/2009/03/gccegg-65.gif" alt="GCC Logo" width="109" height="130" />Want to build some small/or not, neat <em>Windows</em>/or <em>Linux</em> application on your <em>Mac</em>? Just use <em>MinGW</em>/<em>Linux GCC</em> cross compiler package from <a href="http://crossgcc.rts-software.org/">Pierre Molinaro</a>. Those were recently updated to <em>GCC 4.2</em> and do cross-compile really fast, especially when using <tt>make -j2.</tt></p>
<p>It is hard to be Switcher and totally forget/abandon <em>Windows</em> projects, since most of my clients&#8230; well almost all of them are on *indows. So since I switched, I am constant user of <a href="http://www.vmware.com/products/fusion/">VMWare Fusion</a> + XP (Win7, Win98) as a guest OS having <em>Visual Studio</em> installed inside. But sometimes if you want to create small cute application for *indows I prefer do it 100% on <em>Mac</em> with <em>TextMate</em>, then just test it on <em>Windows</em>. This is what <em>MinGW</em> cross compiler is perfect for. Not to mention I did <em>Miranda&#8217;s</em> <em>MinGW</em> <a href="https://miranda.svn.sourceforge.net/svnroot/miranda/trunk/miranda/Makefile">Makefile</a> that successfully builds miranda on Linux/Mac using cross-compiler, so it can be queued for nightly builds on SF.net servers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nanoant.com/programming/mingw-on-mac-hell-yeah/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>No more free lunch, maybe a pie for free?</title>
		<link>http://www.nanoant.com/publications/no-more-free-lunch-maybe-a-pie-for-free</link>
		<comments>http://www.nanoant.com/publications/no-more-free-lunch-maybe-a-pie-for-free#comments</comments>
		<pubDate>Wed, 11 Mar 2009 23:40:11 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Publications]]></category>
		<category><![CDATA[core]]></category>
		<category><![CDATA[cpu]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[parallel]]></category>

		<guid isPermaLink="false">http://www.nanoant.com/?p=205</guid>
		<description><![CDATA[How to survive computing paradigm shift We cannot count on free &#8220;performance lunch&#8221; anymore, but how about at least a pie for free? Do we need to throw all our old source-code into the trash bin and start over again?  Certainly, not. We may think of our old software as a zombie of the new multi-core [...]]]></description>
			<content:encoded><![CDATA[<h4>How to survive computing paradigm shift</h4>
<p>We cannot count on free &#8220;performance lunch&#8221; anymore, but how about at least a pie for free?<span> Do we need to throw all our old source-code into the trash bin and start over again?<span> </span></span></p>
<p><img class="alignright size-full wp-image-214" title="Double Core flow" src="http://www.nanoant.com/wp/wp-content/uploads/2009/03/doublecore-flow.png" alt="" width="273" height="142" />Certainly, not. We may think of our old software as a zombie of the new multi-core era. Still<span> there is a way to make the zombie walk, even walk faster. Of course we will need to rewrite<span> our code sometime, but we may postpone this nasty need for a while.<span> </span></span></span></p>
<p>The computing paradigm shift is now a fact we need to learn how to live with. It is unques<span>tionable that processor manufacturers hit the barrier of 3 GHz. There pretty many news about<span> spinning the CPU up to 5 GHz or so, but do not try to do so at home unless you got liquid<span> nitrogen cylinder around. Over 3 GHz heat emission grows unreasonably making the CPU<span> economically worthwhile.<span> </span></span></span></span></span></p>
<p>So the only sensible way is now horizontal performance improvement, doubling the number<span> of processing units. This means we can expect soon 128 core CPUs. Oh, wait they are here<span> already; nVidia GeForce 9 series are perfect example of 128 core streaming processor.<span> </span></span></span></p>
<p>Now how to keep up with things that happen so fast. First we need focus more on performance<span> of our code. Something that was not important before, now cannot be ignored.</span><br />
<span id="more-205"></span><br />
<em>Want more, read my article draft below:</em></p>
<ul class="projects">
<li class="pdf"><a href="/uj/A Pie for free.pdf">A Pie for free.pdf</a> 256KB, 2008-06-16</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.nanoant.com/publications/no-more-free-lunch-maybe-a-pie-for-free/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CMSity &#8211; small, generic content management system</title>
		<link>http://www.nanoant.com/projects/cmsity-small-generic-content-management-system</link>
		<comments>http://www.nanoant.com/projects/cmsity-small-generic-content-management-system#comments</comments>
		<pubDate>Thu, 05 Mar 2009 12:57:00 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[small]]></category>
		<category><![CDATA[template]]></category>

		<guid isPermaLink="false">http://www.nanoant.com/?p=179</guid>
		<description><![CDATA[After spending few years using WordPress, MODx, PHPnuke I found out those systems getting more and more complicated, well yes sophisticated too, but first of all complicated. Anyway, feeling that this is not right direction I have decided to rewrite something by my own; simple, but powerful enough to provide functionality that you expect from [...]]]></description>
			<content:encoded><![CDATA[<p class="alignright"><a href="http://www.cmsity.com/"><img class="size-full wp-image-181" title="CMSity Logo" src="http://www.nanoant.com/wp/wp-content/uploads/2009/03/cmsity_ss.png" alt="" width="278" height="89" /></a></p>
<p>After spending few years using <em>WordPress</em>, <em>MODx</em>, <em>PHPnuke</em> I found out those systems getting more and more complicated, well yes sophisticated too, but first of all complicated. Anyway, feeling that this is not right direction I have decided to rewrite something by my own; simple, but powerful enough to provide functionality that you expect from most of the modern sites &#8211; blog, forums, RSS feeds.</p>
<p><span id="more-179"></span></p>
<p>Such functionality was requested by few of my clients, asking me: &#8220;<em>Adam, we need something like WordPress, but we would like to have forums too, also site should be multi-lingual and finally we would like to limit the access to some parts of the site.&#8221;</em> Just to mention those clients were running websites at PHP virtual hosting. I said, <em>&#8220;Roger that&#8221;</em> and started looking for some (any) CMS that could satisfy their needs.</p>
<p>I use to browse for new CMSes time to time. I did it again last October. Nothing new. Okay, maybe I could somehow tailor <em>MODx</em>, or <em>WordPress</em>. Nah. Then I found <em>BBpress</em>, well I was excited. A forum system made by <em>WordPress</em> creators, that integrates with WP. Great! Maybe this will fit.</p>
<p>Unfortunately I was hitting so many problems syncing WP and <em>BBpress</em> user database and logins, cookies (Why the hell it is so complicated?), so I gave it up.</p>
<p>I decided to write my own system, having in mind that forum, blog, they just differ at presentation level! There is always some parent page and subpages, post and replies, forum and topics. All having some hierarchy relations, and different presentation model. So why we have to install <em>BBpress</em> over WP if it is just a matter of presentation. Forum should look more like a table&#8230; while blog more like list of post excerpts. Why we cannot just turn WP sub-blog into the forum?</p>
<h3>The difference is the presentation</h3>
<p>So thing that makes forum or blog special is the way it is presented to the user. But from structure point of view both are the same. So this is the idea of the <em>CMSity</em>. For <em>CMSity</em> all pages (document tree nodes) are the same, they just carry the <strong>type</strong> which is used to determine what template to use to render them &#8211; what is their presentation.</p>
<p style="text-align: center;"><img class="alignnone size-full wp-image-180" title="CMSity template resolution" src="http://www.nanoant.com/wp/wp-content/uploads/2009/03/template_s.png" alt="" width="403" height="303" /></p>
<p>Why PHP? Even I know more optimized/fast languages such as Ruby (1.9 is really fast), Java, C++.. started learning Erlang, still PHP is kind of standard that is present on most of the web servers and you can expect your clients will have PHP on their web servers. So I have chosen PHP; not really my favorite language, but the one I know pretty well and have spent quite a while with.</p>
<p>So this is genesis of <em><a href="http://www.cmsity.com/">CMSity</a></em>&#8230; hope it will find many users and will be useful for you all.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nanoant.com/projects/cmsity-small-generic-content-management-system/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Assigned to GNU</title>
		<link>http://www.nanoant.com/projects/assigned-to-gnu</link>
		<comments>http://www.nanoant.com/projects/assigned-to-gnu#comments</comments>
		<pubDate>Sat, 08 Mar 2008 15:17:37 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[gnu]]></category>
		<category><![CDATA[idn]]></category>
		<category><![CDATA[sasl]]></category>

		<guid isPermaLink="false">http://www.nanoant.com/?p=249</guid>
		<description><![CDATA[Today I got assigned to two GNU projects: GNU IDN Library &#38; GNU SASL Library. As jabberd2 relays on both of them and I am the one responsible for making it running on Windows, I had to make few patches, that were gratefully accepted by Simon Josefsson &#8211; maintainer of those GNU libraries. Recently I&#8217;ve [...]]]></description>
			<content:encoded><![CDATA[<p>Today I got assigned to two GNU projects: <a href="http://www.gnu.org/software/libidn/">GNU IDN Library</a> &amp; <a href="http://www.gnu.org/software/gsasl/">GNU SASL Library</a>. As jabberd2 relays on both of them and I am the one responsible for making it running on Windows, I had to make few patches, that were gratefully accepted by Simon Josefsson &#8211; maintainer of those GNU libraries.</p>
<p>Recently I&#8217;ve received two papers from GNU (originated from U.S.) and few great stickers with gnus <img src='http://www.nanoant.com/wp/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  I had to sign it back after carefully studying them. And now I am officially assigned and my changes went to the official repository.</p>
<p style="text-align: center;"><a href="http://www.nanoant.com/wp/wp-content/uploads/2009/03/gnu-libidn.gif"><img class="size-full wp-image-250  aligncenter" title="gnu-libidn" src="http://www.nanoant.com/wp/wp-content/uploads/2009/03/gnu-libidn.gif" alt="" width="499" height="140" /></a></p>
<p>Can I call myself genuine OpenSource developer now !?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nanoant.com/projects/assigned-to-gnu/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Themed menu&#8217;s icons, a complete Vista and XP solution (updated)</title>
		<link>http://www.nanoant.com/programming/themed-menus-icons-a-complete-vista-xp-solution</link>
		<comments>http://www.nanoant.com/programming/themed-menus-icons-a-complete-vista-xp-solution#comments</comments>
		<pubDate>Tue, 12 Jun 2007 15:43:01 +0000</pubDate>
		<dc:creator>Adam</dc:creator>
				<category><![CDATA[C/C++]]></category>
		<category><![CDATA[Programming]]></category>

		<guid isPermaLink="false">http://www.nanoant.com/programming/themed-menus-icons-a-complete-vista-xp-solution</guid>
		<description><![CDATA[Update: Steve King has patched my Vista GDI+ based menus with pure GDI method at TortoiseSVN revision 14191 as described lately by Microsoft. Pure GDI method no longer requires GDI+, which is not present in Premium versions of Vista, maintaining full compatibility with older versions of Windows. I&#8217;m an author of few patches for both Tortoise [...]]]></description>
			<content:encoded><![CDATA[<h4>Update: <em>Steve King</em> has patched my <em>Vista</em> GDI+ based menus with pure GDI method at TortoiseSVN revision 14191 as described lately by <a href="http://msdn.microsoft.com/en-us/library/bb757020.aspx?s=6">Microsoft</a>. Pure GDI method no longer requires GDI+, which is not present in Premium versions of Vista, maintaining full compatibility with older versions of <em>Windows</em>.</h4>
<p>I&#8217;m an author of few patches for both <a href="http://tortoisesvn.tigris.org/">Tortoise SVN</a> and <a href="http://www.tortoisecvs.org/">Tortoise CVS</a> that makes them display the explorer&#8217;s context menu icons nicely on <em>XP</em> and <em>Windows 2000</em>. Both programs are implementing <tt>IContextMenu</tt> and using <tt>QueryContextMenu</tt> function to create items of popup menu of explorer. Briefly the called extension must fill menu items with <tt>InsertMenuItem</tt> using suplied <tt>HMENU hmenu</tt> parameter.</p>
<p>During development of those few patches I&#8217;ve learnt some few new things about way we make icons displayed next to menu items I want to share with you&#8230; <span id="more-18"></span></p>
<h2>How to get icons in context menus</h2>
<p>Methods described here are related to shell context menu extension, however they can be used in any <em>Windows</em> application.</p>
<h3>hbmp(Un)checked method</h3>
<p><img title="Old Tortoise CVS menu icons" src="/screenshots/tortoise/TortoiseCVS-hbmpUnchecked.png" alt="Old Tortoise CVS menu icons" hspace="10" width="211" height="85" align="right" />Initially both <em>Tortoises</em> were filling <tt>hbmpUnchecked</tt> &amp; <tt>hbmpChecked</tt> fields of <tt>MENUITEMINFO</tt> that is passed to <tt>InsertMenuItem</tt> with <tt>HBITMAP</tt> created from icon to get icons on menu item. This solution works on all <em>Windows</em> since 95. However the strong limitation is that <tt>HBITMAP</tt> must be <tt>SM_CXMENUCHECK</tt> x <tt>SM_CYMENUCHECK</tt> (usually 12 x 12). So if you are using 16 x 16 icon, the icon gets squished and looks awfully. The function used to convert icon to bitmap is:</p>
<pre class="textmate-source"><span class="source source_c++">HBITMAP<span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"> </span><span class="entity entity_name entity_name_function entity_name_function_c">CShellExt::IconToBitmap</span><span class="meta meta_parens meta_parens_c">(std::string <span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sIcon</span>)</span>
<span class="meta meta_block meta_block_c">{
    RECT rect;

    rect<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.right</span> = ::<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">GetSystemMetrics</span>(</span>SM_CXMENUCHECK);
    rect<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.bottom</span> = ::<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">GetSystemMetrics</span>(</span>SM_CYMENUCHECK);

    rect<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.left</span> = rect<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.top</span>  = <span class="constant constant_numeric constant_numeric_c">0</span>;

    HICON hIcon = (HICON)<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">LoadImageA</span>(</span>g_hInstance, <span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sIcon</span>.<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">c_str</span>(</span>), IMAGE_ICON, rect<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.right</span>, rect<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.bottom</span>, LR_DEFAULTCOLOR);
    <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>!hIcon)
        <span class="keyword keyword_control keyword_control_c">return</span> <span class="constant constant_language constant_language_c">NULL</span>;

    HWND desktop = ::<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">GetDesktopWindow</span>(</span>);
    <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>desktop == <span class="constant constant_language constant_language_c">NULL</span>)
    <span class="meta meta_block meta_block_c">{
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">        </span><span class="support support_function support_function_any-method support_function_any-method_c">DestroyIcon</span>(</span>hIcon);
        <span class="keyword keyword_control keyword_control_c">return</span> <span class="constant constant_language constant_language_c">NULL</span>;
    }</span>

    HDC screen_dev = ::<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">GetDC</span>(</span>desktop);
    <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>screen_dev == <span class="constant constant_language constant_language_c">NULL</span>)
    <span class="meta meta_block meta_block_c">{
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">        </span><span class="support support_function support_function_any-method support_function_any-method_c">DestroyIcon</span>(</span>hIcon);
        <span class="keyword keyword_control keyword_control_c">return</span> <span class="constant constant_language constant_language_c">NULL</span>;
    }</span>

    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> Create a compatible DC
</span>    HDC dst_hdc = ::<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">CreateCompatibleDC</span>(</span>screen_dev);
    <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>dst_hdc == <span class="constant constant_language constant_language_c">NULL</span>)
    <span class="meta meta_block meta_block_c">{
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">        </span><span class="support support_function support_function_any-method support_function_any-method_c">DestroyIcon</span>(</span>hIcon);
<span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c">        </span><span class="entity entity_name entity_name_function entity_name_function_c">::ReleaseDC</span><span class="meta meta_parens meta_parens_c">(desktop, screen_dev)</span>;</span>
        <span class="keyword keyword_control keyword_control_c">return</span> <span class="constant constant_language constant_language_c">NULL</span>;
    }</span>

    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> Create a new bitmap of icon size
</span>    HBITMAP bmp = ::<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">CreateCompatibleBitmap</span>(</span>screen_dev, rect<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.right</span>, rect<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.bottom</span>);
    <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>bmp == <span class="constant constant_language constant_language_c">NULL</span>)
    <span class="meta meta_block meta_block_c">{
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">        </span><span class="support support_function support_function_any-method support_function_any-method_c">DestroyIcon</span>(</span>hIcon);
<span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c">        </span><span class="entity entity_name entity_name_function entity_name_function_c">::DeleteDC</span><span class="meta meta_parens meta_parens_c">(dst_hdc)</span>;</span>
<span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c">        </span><span class="entity entity_name entity_name_function entity_name_function_c">::ReleaseDC</span><span class="meta meta_parens meta_parens_c">(desktop, screen_dev)</span>;</span>
        <span class="keyword keyword_control keyword_control_c">return</span> <span class="constant constant_language constant_language_c">NULL</span>;
    }</span>

    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> Select it into the compatible DC
</span>    HBITMAP old_dst_bmp = (HBITMAP)::<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">SelectObject</span>(</span>dst_hdc, bmp);
    <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>old_dst_bmp == <span class="constant constant_language constant_language_c">NULL</span>)
    <span class="meta meta_block meta_block_c">{
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">        </span><span class="support support_function support_function_any-method support_function_any-method_c">DestroyIcon</span>(</span>hIcon);
        <span class="keyword keyword_control keyword_control_c">return</span> <span class="constant constant_language constant_language_c">NULL</span>;
    }</span>

    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> Fill the background of the compatible DC with the given colour
</span><span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c">    </span><span class="entity entity_name entity_name_function entity_name_function_c">::SetBkColor</span><span class="meta meta_parens meta_parens_c">(dst_hdc, RGB(<span class="constant constant_numeric constant_numeric_c">255</span>, <span class="constant constant_numeric constant_numeric_c">255</span>, <span class="constant constant_numeric constant_numeric_c">255</span>)</span>);</span>
<span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c">    </span><span class="entity entity_name entity_name_function entity_name_function_c">::ExtTextOut</span><span class="meta meta_parens meta_parens_c">(dst_hdc, <span class="constant constant_numeric constant_numeric_c">0</span>, <span class="constant constant_numeric constant_numeric_c">0</span>, ETO_OPAQUE, &amp;rect, <span class="constant constant_language constant_language_c">NULL</span>, <span class="constant constant_numeric constant_numeric_c">0</span>, <span class="constant constant_language constant_language_c">NULL</span>)</span>;</span>

    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> Draw the icon into the compatible DC
</span><span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c">    </span><span class="entity entity_name entity_name_function entity_name_function_c">::DrawIconEx</span><span class="meta meta_parens meta_parens_c">(dst_hdc, <span class="constant constant_numeric constant_numeric_c">0</span>, <span class="constant constant_numeric constant_numeric_c">0</span>, hIcon, rect.right, rect.bottom, <span class="constant constant_numeric constant_numeric_c">0</span>, <span class="constant constant_language constant_language_c">NULL</span>, DI_NORMAL)</span>;</span>

    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> Restore settings
</span><span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c">    </span><span class="entity entity_name entity_name_function entity_name_function_c">::SelectObject</span><span class="meta meta_parens meta_parens_c">(dst_hdc, old_dst_bmp)</span>;</span>
<span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c">    </span><span class="entity entity_name entity_name_function entity_name_function_c">::DeleteDC</span><span class="meta meta_parens meta_parens_c">(dst_hdc)</span>;</span>
<span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c">    </span><span class="entity entity_name entity_name_function entity_name_function_c">::ReleaseDC</span><span class="meta meta_parens meta_parens_c">(desktop, screen_dev)</span>;</span>
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">DestroyIcon</span>(</span>hIcon);
    <span class="keyword keyword_control keyword_control_c">return</span> bmp;
}</span></span>
</span></pre>
<h3>Ownerdraw method</h3>
<p><a href="http://tortoisesvn.tigris.org/">Tortoise SVN</a> was using also owner draw method. I won&#8217;t describe here details of this method. This relays on <tt>MENUITEMINFO</tt> <tt>fType</tt> flag set to <tt>MFT_OWNERDRAW</tt>. Shell extension in <tt>HandleMenuMsg2</tt> callback should handle <tt>WM_MEASUREITEM</tt> and <tt>WM_DRAWITEM</tt>.  This method is generally OK, however it has several flaws:</p>
<ol>
<li>We need to measure &amp; draw menu in all stated ourselves, which makes us write plenty of code.</li>
<li>Ownerdraw menus are not respecting visual styles of <em>Windows XP</em> or <em>Vista</em>. We would need to use uxtheme functions to somehow handle rendering of menu parts on those systems.</li>
<li>We need to keep exta context information for each menu item with text, icon handle, etc.</li>
<li>Keyboard shortcuts doesn&#8217;t work automatically, we must handle <tt>WM_MENUCHAR</tt> to make them work.</li>
</ol>
<h3>HBMMENU_CALLBACK method</h3>
<p>Since <em>Windows 98</em> <tt>MENUITEMINFO</tt> has extra field <tt>hbmpItem</tt>.  This field can be used for setting the <tt>HBITMAP</tt> with bitmap that is displayed next to the menu item. <tt>hbmpItem</tt> can be set also to <tt>HBMMENU_CALLBACK</tt> which will make menu item work like owner-draw, but <tt>WM_MEASUREITEM</tt> &amp; <tt>WM_DRAWITEM</tt> just need to handle icon drawing, rest will be done by <em>Windows</em>.  This method is easiest to implement and so it is used inside many application, I just name on I use or develop: <em>wxWidgets SDK,</em> <em>Miranda IM</em>. We just need to initialize menu item like that:</p>
<pre class="textmate-source"><span class="source source_c++">MENUITEMINFO menuiteminfo;
<span class="meta meta_function meta_function_c"><span class="entity entity_name entity_name_function entity_name_function_c">ZeroMemory</span><span class="meta meta_parens meta_parens_c">(&amp;menuiteminfo, <span class="keyword keyword_operator keyword_operator_sizeof keyword_operator_sizeof_c">sizeof</span>(menuiteminfo)</span>);</span>
menuiteminfo.cbSize = <span class="keyword keyword_operator keyword_operator_sizeof keyword_operator_sizeof_c">sizeof</span>(menuiteminfo);
menuiteminfo.<span class="variable variable_other variable_other_readwrite variable_other_readwrite_member variable_other_readwrite_member_c++">fMask</span> = MIIM_FTYPE | MIIM_ID | MIIM_SUBMENU | MIIM_DATA | MIIM_BITMAP | MIIM_STRING;
menuiteminfo.<span class="variable variable_other variable_other_readwrite variable_other_readwrite_member variable_other_readwrite_member_c++">fType</span> = MFT_STRING;
menuiteminfo.dwTypeData = lpszMenuTitle;
menuiteminfo.cch = _tcslen(lpszMenuTitle);
menuiteminfo.hbmpItem = HBMMENU_CALLBACK;
menuiteminfo.wID = id;
</span></pre>
<p>Rest is done in <tt>WM_MEASUREITEM</tt> where we need to just make sure we have space for 16 x 16 image using:</p>
<pre class="textmate-source"><span class="source source_c++">    <span class="keyword keyword_control keyword_control_c">case</span> WM_MEASUREITEM:
        <span class="meta meta_block meta_block_c">{
            MEASUREITEMSTRUCT* lpmis = (MEASUREITEMSTRUCT*)lParam;
            <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>lpmis==<span class="constant constant_language constant_language_c">NULL</span>)
                <span class="keyword keyword_control keyword_control_c">break</span>;
            lpmis-&gt;itemWidth += <span class="constant constant_numeric constant_numeric_c">2</span>;
            <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>lpmis-&gt;itemHeight &lt; <span class="constant constant_numeric constant_numeric_c">16</span>)
                lpmis-&gt;itemHeight = <span class="constant constant_numeric constant_numeric_c">16</span>;
            *pResult = <span class="constant constant_language constant_language_c">TRUE</span>;
        }</span>
        <span class="keyword keyword_control keyword_control_c">break</span>;
</span></pre>
<p>Then to draw an icon we need to handle WM_DRAWITEM, but just drawing the icon, nothing else:</p>
<pre class="textmate-source"><span class="source source_c++">    <span class="keyword keyword_control keyword_control_c">case</span> WM_DRAWITEM:
        <span class="meta meta_block meta_block_c">{
            LPCTSTR resource;
            DRAWITEMSTRUCT* lpdis = (DRAWITEMSTRUCT*)lParam;
            <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>(lpdis==<span class="constant constant_language constant_language_c">NULL</span>)||(lpdis-&gt;CtlType != ODT_MENU))
                <span class="keyword keyword_control keyword_control_c">return</span> S_OK; <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> not for a menu
</span>            resource =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">GetMenuIconResourceID</span>(</span>lpdis-&gt;itemID);
            <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>resource == <span class="constant constant_language constant_language_c">NULL</span>)
                <span class="keyword keyword_control keyword_control_c">return</span> S_OK;
            HICON hIcon = (HICON)<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">LoadImage</span>(</span>g_hResInst, resource, IMAGE_ICON, <span class="constant constant_numeric constant_numeric_c">16</span>, <span class="constant constant_numeric constant_numeric_c">16</span>, LR_DEFAULTCOLOR);
            <span class="keyword keyword_control keyword_control_c">if</span><span class="meta meta_initialization meta_initialization_c"> <span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_c">(</span></span>hIcon == <span class="constant constant_language constant_language_c">NULL</span>)
                <span class="keyword keyword_control keyword_control_c">return</span> S_OK;
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">            </span><span class="support support_function support_function_any-method support_function_any-method_c">DrawIconEx</span>(</span>lpdis-&gt;hDC,
                lpdis-&gt;rcItem<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.left</span> - <span class="constant constant_numeric constant_numeric_c">16</span>,
                lpdis-&gt;rcItem<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.top</span> + (lpdis-&gt;rcItem<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.bottom</span> - lpdis-&gt;rcItem<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.top</span> - <span class="constant constant_numeric constant_numeric_c">16</span>) / <span class="constant constant_numeric constant_numeric_c">2</span>,
                hIcon, <span class="constant constant_numeric constant_numeric_c">16</span>, <span class="constant constant_numeric constant_numeric_c">16</span>,
                <span class="constant constant_numeric constant_numeric_c">0</span>, <span class="constant constant_language constant_language_c">NULL</span>, DI_NORMAL);
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">            </span><span class="support support_function support_function_any-method support_function_any-method_c">DestroyIcon</span>(</span>hIcon);
            *pResult = <span class="constant constant_language constant_language_c">TRUE</span>;
        }</span>
        <span class="keyword keyword_control keyword_control_c">break</span>;</span></pre>
<p>Simple ? Yes it is. However there are some issues with this method as well:</p>
<ol>
<li>When this method is used on <em>Windows 2000</em> shell extension window background popup menu, then <tt>shell.dll</tt> is removing text from the menu, so we see just icons.This is obviously a bug of <em>Windows 2000</em> <tt>shell.dll</tt>, because MSDN documentation states this shall work regardless of the sittuation, but we need to somehow get over it. Surprisingly it does work fine when we right-click on explorer item (file or folder). The easiest solution is using <tt>hbmp(Un)checked</tt> method when <tt>uFlags == 0</tt> of <tt>QueryContextMenu</tt>, which indicated we clicked the background, so we fall back to most primitive method, but at least we got text and &#8220;some&#8221; icons in the menu.<strong>Note:</strong> This bug only appears in <em>Windows 2000</em> explorer&#8217;s background menu of shell extension, so in every other situation as standalone program menus <tt>HBMMENU_CALLBACK</tt> method can be used without any problem. So you may not care about it unless you are shell extension developer.</li>
<li><em>Vista</em> is removing menu theme when some menu item has <tt>hbmpItem</tt> set to <tt>HBMMENU_CALLBACK</tt>, so we will have nice icons and nice menu, but if we want to have nice icons with 100% themed menu on <em>Vista</em> we need to use last method&#8230;</li>
</ol>
<h3>Vista PARGB32 hbmpItem bitmap method (Updated)</h3>
<p><em>Vista</em> strongly relays on 32-bit pre-multiplied alpha RGB bitmaps for rendering its interface. In Vista hbmpItem can be set to PARGB32 HBITMAP and this bitmap will be nicely displayed by Vista together with theming as you can see on the screenshot at right.  I got know of this possibility reading nice article <a href="http://shellrevealed.com/blogs/shellblog/archive/2007/02/06/Vista-Style-Menus_2C00_-Part-1-_2D00_-Adding-icons-to-standard-menus.aspx">Vista Style Menus, Part 1 &#8211; Adding icons to standard menus</a> at <em>ShellRevealed</em> blog.</p>
<p>The most important question is how to we get our icon (regardless it is 32-bit with alpha, or 256-color with mask) converted to PARGB32 HBITMAP. <span style="text-decoration: line-through;">Windows API doesn&#8217;t give such possibility straight of the box.</span> Article from <em>ShellRevealed</em> proposes WIC (<em>Windows Imaging Component</em>) which is cool &amp; quite simple for conversion or <em>Vista</em>&#8216;s GDI method, but those require <em>Vista SDK</em>, which may be annoying for those using <em>Visual Studio</em>&#8216;s out of the box.</p>
<p><span style="text-decoration: line-through;">As an alternative to that I&#8217;ve used </span><em><span style="text-decoration: line-through;">Gdiplus</span></em><span style="text-decoration: line-through;"> which is present on most of the systems since </span><em><span style="text-decoration: line-through;">Windows 2000</span></em><span style="text-decoration: line-through;">, and most shipped with </span><em><span style="text-decoration: line-through;">Visual Studio</span></em><span style="text-decoration: line-through;">s </span><em><span style="text-decoration: line-through;">Platforms SDK</span></em><span style="text-decoration: line-through;">s.  This method is also much simpler than WIC or GDI method from described article</span>.</p>
<p>Alternative solution to WIC is to use pure <em>Vista GDI</em> (<em>UxTheme</em>) calls as described at <a href="http://msdn.microsoft.com/en-us/library/bb757020.aspx?s=6">http://msdn.microsoft.com/en-us/library/bb757020.aspx?s=6</a> (<tt><strong>GDI_CVistaMenuApp.cpp</strong></tt> sample). It was implemented in <em>TortoiseSVN</em> revision 14191 by <em>Steve King</em>. It uses <tt><em>BeginBufferedPaint</em></tt>, <tt><em>EndBufferedPaint</em></tt> and <tt><em>GetBufferedPaintBits</em></tt> dynamically loaded from <em>Vista</em>&#8216;s <tt>UXTHEME.DLL</tt> and <tt>Create32BitHBITMAP </tt>and <tt>ConvertBufferToPARGB32</tt> from <tt><strong>GDI_CVistaMenuApp.cpp</strong></tt> sample.</p>
<p>The PARGB32 function is as follows:</p>
<pre class="textmate-source"><span class="source source_c++">HBITMAP<span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"> </span><span class="entity entity_name entity_name_function entity_name_function_c">CShellExt::IconToBitmapPARGB32</span><span class="meta meta_parens meta_parens_c">(std::string <span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sIcon</span>)</span>
<span class="meta meta_block meta_block_c">{
    HRESULT hr = E_OUTOFMEMORY;
    HBITMAP hBmp = <span class="constant constant_language constant_language_c">NULL</span>;

    HICON hIcon = (HICON)<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">LoadImageA</span>(</span>g_hResInst, <span class="variable variable_other variable_other_readwrite variable_other_readwrite_static variable_other_readwrite_static_mac-classic variable_other_readwrite_static_mac-classic_c">sIcon</span>.<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">c_str</span>(</span>), IMAGE_ICON, <span class="constant constant_numeric constant_numeric_c">16</span>, <span class="constant constant_numeric constant_numeric_c">16</span>, LR_DEFAULTCOLOR);
    <span class="keyword keyword_control keyword_control_c">if</span>(!hIcon)
        <span class="keyword keyword_control keyword_control_c">return</span> <span class="constant constant_language constant_language_c">NULL</span>;

    SIZE sizIcon;
    sizIcon<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.cx</span> =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">GetSystemMetrics</span>(</span>SM_CXSMICON);
    sizIcon<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.cy</span> =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">GetSystemMetrics</span>(</span>SM_CYSMICON);

    RECT rcIcon;
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">SetRect</span>(</span>&amp;rcIcon, <span class="constant constant_numeric constant_numeric_c">0</span>, <span class="constant constant_numeric constant_numeric_c">0</span>, sizIcon<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.cx</span>, sizIcon<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.cy</span>);

    HDC hdcDest =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">CreateCompatibleDC</span>(</span><span class="constant constant_language constant_language_c">NULL</span>);
    <span class="keyword keyword_control keyword_control_c">if</span>(hdcDest) <span class="meta meta_block meta_block_c">{
        hr =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c"><strong>Create32BitHBITMAP</strong></span>(</span>hdcDest, &amp;sizIcon, <span class="constant constant_language constant_language_c">NULL</span>, &amp;hbmp);
        <span class="keyword keyword_control keyword_control_c">if</span>(<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">SUCCEEDED</span>(</span>hr)) <span class="meta meta_block meta_block_c">{
            hr = E_FAIL;

            HBITMAP hbmpOld = (HBITMAP)<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">SelectObject</span>(</span>hdcDest, hbmp);
            <span class="keyword keyword_control keyword_control_c">if</span>(hbmpOld) <span class="meta meta_block meta_block_c">{
                BLENDFUNCTION bfAlpha = <span class="meta meta_block meta_block_c">{ AC_SRC_OVER, <span class="constant constant_numeric constant_numeric_c">0</span>, <span class="constant constant_numeric constant_numeric_c">255</span>, AC_SRC_ALPHA }</span>;
                BP_PAINTPARAMS paintParams = <span class="meta meta_block meta_block_c">{<span class="constant constant_numeric constant_numeric_c">0</span>}</span>;
                paintParams<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.cbSize</span> =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c">sizeof</span>(</span>paintParams);
                paintParams<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.dwFlags</span> = BPPF_ERASE;
                paintParams<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.pBlendFunction</span> = &amp;bfAlpha;

                HDC hdcBuffer;
                HPAINTBUFFER hPaintBuffer =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c"><strong>pfnBeginBufferedPaint</strong></span>(</span>hdcDest, &amp;rcIcon, BPBF_DIB, &amp;paintParams, &amp;hdcBuffer);
                <span class="keyword keyword_control keyword_control_c">if</span>(hPaintBuffer) <span class="meta meta_block meta_block_c">{
                    <span class="keyword keyword_control keyword_control_c">if</span>(<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">DrawIconEx</span>(</span>hdcBuffer, <span class="constant constant_numeric constant_numeric_c">0</span>, <span class="constant constant_numeric constant_numeric_c">0</span>, hIcon, sizIcon<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.cx</span>, sizIcon<span class="variable variable_other variable_other_dot-access variable_other_dot-access_c">.cy</span>, <span class="constant constant_numeric constant_numeric_c">0</span>, <span class="constant constant_language constant_language_c">NULL</span>, DI_NORMAL)) <span class="meta meta_block meta_block_c">{
                        <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> If icon did not have an alpha channel, we need to convert buffer to PARGB.
</span>                        hr =<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c"> </span><span class="support support_function support_function_any-method support_function_any-method_c"><strong>ConvertBufferToPARGB32</strong></span>(</span>hPaintBuffer, hdcDest, hIcon, sizIcon);
                    }</span>

                    <span class="comment comment_line comment_line_double-slash comment_line_double-slash_c++"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">//</span> This will write the buffer contents to the destination bitmap.
</span><span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">                    </span><span class="support support_function support_function_any-method support_function_any-method_c"><strong>pfnEndBufferedPaint</strong></span>(</span>hPaintBuffer, <span class="constant constant_language constant_language_c">TRUE</span>);
                }</span>
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">                </span><span class="support support_function support_function_any-method support_function_any-method_c">SelectObject</span>(</span>hdcDest, hbmpOld);
            }</span>
        }</span>
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">        </span><span class="support support_function support_function_any-method support_function_any-method_c">DeleteDC</span>(</span>hdcDest);
    }</span>

<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">DestroyIcon</span>(</span>hIcon);
    <span class="keyword keyword_control keyword_control_c">if</span>(<span class="meta meta_function-call meta_function-call_c"><span class="support support_function support_function_any-method support_function_any-method_c">SUCCEEDED</span>(</span>hr)) <span class="meta meta_block meta_block_c">{
        <span class="keyword keyword_control keyword_control_c">return</span> hBmp;
    }</span>
<span class="meta meta_function-call meta_function-call_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function-call punctuation_whitespace_function-call_leading punctuation_whitespace_function-call_leading_c">    </span><span class="support support_function support_function_any-method support_function_any-method_c">DeleteObject</span>(</span>hBmp);
    <span class="keyword keyword_control keyword_control_c">return</span> <span class="constant constant_language constant_language_c">NULL</span>;
}</span></span>
</span></pre>
<p>So in this case instead <tt>menuiteminfo.hbmpItem = HBMMENU_CALLBACK</tt> we do <tt>menuiteminfo.hbmpItem = IconToBitmapPARGB32(lpszIconResourceID)</tt>. <span style="text-decoration: line-through;">We shouldn&#8217;t forget of initializing Gdiplus library with </span><tt><span style="text-decoration: line-through;">GdiplusStartup(&amp;m_gdipToken, &amp;gdiplusStartupInput, NULL)</span></tt><span style="text-decoration: line-through;"> in program/DLL initialization code and shutting it down after all with </span><tt><span style="text-decoration: line-through;">GdiplusShutdown(m_gdipToken)</span></tt><span style="text-decoration: line-through;">.</span></p>
<p>If we want to be compatible with older Windows versions, we shall load (map) the <em>Vista</em>&#8216;s <tt>UXTHEME.DLL</tt> functions dynamically only on Vista:</p>
<pre class="textmate-source"><span class="source source_c++"><span class="storage storage_type storage_type_c">typedef</span> DWORD ARGB;
<span class="storage storage_type storage_type_c">typedef</span><span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"> </span><span class="entity entity_name entity_name_function entity_name_function_c">HRESULT</span> <span class="meta meta_parens meta_parens_c">(WINAPI *FN_GetBufferedPaintBits)</span> <span class="meta meta_parens meta_parens_c">(HPAINTBUFFER hBufferedPaint, RGBQUAD **ppbBuffer, <span class="storage storage_type storage_type_c">int</span> *pcxRow)</span>;</span>
<span class="storage storage_type storage_type_c">typedef</span><span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"> </span><span class="entity entity_name entity_name_function entity_name_function_c">HPAINTBUFFER</span> <span class="meta meta_parens meta_parens_c">(WINAPI *FN_BeginBufferedPaint)</span> <span class="meta meta_parens meta_parens_c">(HDC hdcTarget, <span class="storage storage_modifier storage_modifier_c">const</span> RECT *prcTarget, BP_BUFFERFORMAT dwFormat, BP_PAINTPARAMS *pPaintParams, HDC *phdc)</span>;</span>
<span class="storage storage_type storage_type_c">typedef</span><span class="meta meta_function meta_function_c"><span class="punctuation punctuation_whitespace punctuation_whitespace_function punctuation_whitespace_function_leading punctuation_whitespace_function_leading_c"> </span><span class="entity entity_name entity_name_function entity_name_function_c">HRESULT</span> <span class="meta meta_parens meta_parens_c">(WINAPI *FN_EndBufferedPaint)</span> <span class="meta meta_parens meta_parens_c">(HPAINTBUFFER hBufferedPaint, BOOL <span class="variable variable_other variable_other_readwrite variable_other_readwrite_member variable_other_readwrite_member_c++">fUpdateTarget</span>)</span>;</span>
<span class="comment comment_block comment_block_c"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">/*</span> (...) <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_c">*/</span></span>
HMODULE hUxTheme = ::GetModuleHandle (_T(<span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>UXTHEME.DLL<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>));
pfnGetBufferedPaintBits = (FN_GetBufferedPaintBits)::GetProcAddress(hUxTheme, <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>GetBufferedPaintBits<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>);
pfnBeginBufferedPaint = (FN_BeginBufferedPaint)::GetProcAddress(hUxTheme, <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>BeginBufferedPaint<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>);
pfnEndBufferedPaint = (FN_EndBufferedPaint)::GetProcAddress(hUxTheme, <span class="string string_quoted string_quoted_double string_quoted_double_c"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_c">"</span>EndBufferedPaint<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_c">"</span></span>);</span></pre>
<p><span style="text-decoration: line-through;">Since we are going to use </span><em><span style="text-decoration: line-through;">Gdiplus</span></em><span style="text-decoration: line-through;"> only on </span><em><span style="text-decoration: line-through;">Vista</span></em><span style="text-decoration: line-through;">, we may use </span><tt><span style="text-decoration: line-through;">Gdiplus.dll</span></tt><span style="text-decoration: line-through;"> as delayed load DLL, so it won&#8217;t be loaded on older systems using previous methods, saving us some memory.</span> Simple enough ?</p>
<p>Testing <em>Windows</em> version number with <tt>GetVersionEx</tt> and combining this method for <em>Vista</em> with <tt>HBMENU_CALLBACK</tt> method for <em>Windows XP</em> and older systems (with <tt>hbmp(Un)checked</tt> fallback on explorer extension on <em>Windows 2000</em> if needed) is my opinion best method of having nice menus in all modern <em>Windows</em> systems. This is also current display method of <a href="http://www.tortoisecvs.org/">Tortoise CVS</a> &amp; <a href="http://tortoisesvn.tigris.org/">Tortoise SVN</a> latest development versions. If you need full code to browse you may want look into <a href="http://tortoisesvn.tigris.org/">Tortoise SVN</a> SVN trunk files: <tt>srcTortoiseShellContextMenu.cpp</tt>, <tt>srcTortoiseShellShellExt.cpp</tt> and <tt>srcTortoiseShellShellExt.h</tt>.</p>
<h2>Conclustion</h2>
<p>All those hacks and recipes would be worthless if only there was simple consistent API for making menu item icons. Unfortunately menu icons, something that was always present in <em>Windows</em> and <em>Microsoft</em> applications, never got any decent API, moreover the methods to get those icons working change for every major <em>Windows</em> release, making us developers wasting our time &#8220;porting&#8221; our applications to new &#8220;shinny&#8221; <em>Windows</em> rather than doing something productive.</p>
<p>One thing that is simply unacceptable for me (even more since I now work regularly on OSX) is that <em>Windows</em> system apps and <em>Microsoft</em> regular applications are using so many UI hacks and mods that are never exposed to the developers trough API. Those are either closed libraries like one for <em>Office&#8217;s</em> or <em>Visual Studio</em> GUI, or <em>Vista</em> hacks with <tt>PARGB</tt> that require tricky in memory conversions rather than just pointing <tt>hbmpItem</tt> to <tt>HICON</tt> and making <em>Vista</em> to do the conversion on its own.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nanoant.com/programming/themed-menus-icons-a-complete-vista-xp-solution/feed</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
	</channel>
</rss>

