<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.3.3" -->
<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/"
	>

<channel>
	<title>Vacuous Virtuoso &#187; Tutorial</title>
	<link>http://lipidity.com</link>
	<description>Despotic Development</description>
	<pubDate>Wed, 02 Apr 2008 14:18:15 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
	<language>en</language>
			<item>
		<title>Modifier flags during app launch</title>
		<link>http://lipidity.com/apple/modifier-flags-launch/</link>
		<comments>http://lipidity.com/apple/modifier-flags-launch/#comments</comments>
		<pubDate>Tue, 27 Nov 2007 10:45:57 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Source Code]]></category>

		<category><![CDATA[Tutorial]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://lipidity.com/apple/modifier-flags-launch/</guid>
		<description><![CDATA[Unfortunately, [[NSApp currentEvent] modiferFlags] can&#8217;t be used to determine if any modifier keys were held down during launch. To accomplish this, it seems one must delve into the world of Carbon.



The GetCurrentEventKeyModifiers() call works on Mac OS X v10.2 and later through which one can check for shiftKey, cmdKey, optionKey and controlKey.

I use the something [...]]]></description>
			<content:encoded><![CDATA[<p>Unfortunately, <code>[[NSApp currentEvent] modiferFlags]</code> can&#8217;t be used to determine if any modifier keys were held down during launch. To accomplish this, it seems one must delve into the world of Carbon.</p>

<!--more-->

<p>The <code>GetCurrentEventKeyModifiers()</code> call works on Mac OS X v10.2 and later through which one can check for <code>shiftKey</code>, <code>cmdKey</code>, <code>optionKey</code> and <code>controlKey</code>.</p>

<p>I use the something like the following to check if the shift key is pressed during launch for <a href="http://lipidity.com/software/zippit/">my compression app</a>.</p>

<pre><code>#import &lt;Cocoa/Cocoa.h&gt;
#import &lt;Carbon/Carbon.h&gt;

int main(int argc, char *argv[]) {
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    if((GetCurrentEventKeyModifiers() &amp; shiftKey)!=0) {
        // Change something useful
        NSLog(@"Shift key pressed during launch");
    }
    [[NSApplication sharedApplication] run];
    [pool release];
    return 0;
}
</code></pre>

<p>In the highly unlikely event that you&#8217;ve just got a call to <code>NSApplicationMain</code> in your <code>main</code> function (joking), you can just test <code>(GetCurrentEventKeyModifiers() &amp; shiftKey)!=0</code> in the <code>-applicationWillFinishLaunching:</code> method in your NSApplication delegate.</p>

<p>Any new APIs in Leopard to achieve this or any easier way?</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/modifier-flags-launch/feed/</wfw:commentRss>
		</item>
		<item>
		<title>CTGradient code bloat</title>
		<link>http://lipidity.com/apple/ctgradient-code-bloat/</link>
		<comments>http://lipidity.com/apple/ctgradient-code-bloat/#comments</comments>
		<pubDate>Tue, 20 Nov 2007 21:05:12 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[CoreGraphics]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Review]]></category>

		<category><![CDATA[Source Code]]></category>

		<category><![CDATA[Tutorial]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://lipidity.com/apple/cgradient-code-bloat/</guid>
		<description><![CDATA[While getting rid of extraneous junk in an application package is easy using Trimmit, the only way to prevent &#34;code bloat&#34; (and accompanying excess RAM and CPU usage) is through good programming practices. Where most developers fall short is in poor optimization of borrowed code. Let&#8217;s take CTGradient as an example as it&#8217;s well known [...]]]></description>
			<content:encoded><![CDATA[<p>While getting rid of extraneous junk in an application package is easy using <a href="http://lipidity.com/software/trimmit/">Trimmit</a>, the only way to prevent &quot;code bloat&quot; (and accompanying excess RAM and CPU usage) is through good programming practices. Where most developers fall short is in poor optimization of borrowed code. Let&#8217;s take CTGradient as an example as it&#8217;s well known and used (or more accurately, abused) in dozens of applications.</p>

<!--more-->

<p>CTGradient contains an incredible diversity of built-in gradients, gradient styles, and methods for creating fancy rainbows, radial gradients, linear gradients, aqua gradients, and a number of other interesting class and instance methods. It allows you to dynamically alter gradients by adding or removing colors, changing the level of transparency, filling NSRects or NSBezierPaths, rotating the gradient, etc. For demonstration purposes, all these features are excellent. For production, this is a nightmare.</p>

<p><strong><a href="http://pub.lipidity.com/CTGradient/CTGradient.m">CTGradient.m</a> weighs in at over 1300 lines of code.</strong></p>

<p>Ignoring Mr. Weider&#8217;s unique style of formatting, take a look through the code. If you&#8217;re putting this class in an application, you can immediately remove over a thousand lines. Just like that. But if you take some time to understand what&#8217;s going on, you can optimize this thing till it runs like a Ferrari.</p>

<p>You&#8217;ll notice <a href="http://lipidity.com/software/trimmit/">Trimmit</a> uses a gradient background for it&#8217;s window. Let&#8217;s cut down CTGradient until it matches the level of optimization of Trimmit&#8217;s gradient code.</p>

<h2>Clear the junk</h2>

<p>Firstly, let&#8217;s remove the methods we know for sure we won&#8217;t need. Remove the following methods completely from both the interface and the implementation (scroll down for more):</p>

<pre style='height:340px;overflow:scroll'><code>// We don't need the preset gradients

+ (id)dividerGradient;
+ (id)statusBarGradient;
+ (id)aquaSelectedGradient;
+ (id)aquaNormalGradient;
+ (id)aquaPressedGradient;
+ (id)unifiedSelectedGradient;
+ (id)unifiedNormalGradient;
+ (id)unifiedPressedGradient;
+ (id)unifiedDarkGradient;
+ (id)sourceListSelectedGradient;
+ (id)sourceListUnselectedGradient;
+ (id)rainbowGradient;
+ (id)hydrogenSpectrumGradient;

// We won't make any drastic modifications to the gradient once created

- (CTGradient *)gradientWithAlphaComponent:(float)alpha;
- (CTGradient *)addColorStop:(NSColor *)color atPosition:(float)position;
- (CTGradient *)removeColorStopAtIndex:(unsigned)index;
- (CTGradient *)removeColorStopAtPosition:(float)position;
- (CTGradientBlendingMode)blendingMode;
- (NSColor *)colorStopAtIndex:(unsigned)index;
- (NSColor *)colorAtPosition:(float)position;

// Now we don't need to conform to the NSCopying and NSCoding protocols

- (id)copyWithZone:(NSZone *)zone;
- (void)encodeWithCoder:(NSCoder *)coder;
- (id)initWithCoder:(NSCoder *)coder;

// We only need to fill a simple NSRect

- (void)drawSwatchInRect:(NSRect)rect;
- (void)radialFillRect:(NSRect)rect;
- (void)fillBezierPath:(NSBezierPath *)path angle:(float)angle;
- (void)radialFillBezierPath:(NSBezierPath *)path;

// Remove the entire (Private) category;
// but leave -addElement:

- (void)_commonInit;
// move setBlendingMode code into init
- (void)setBlendingMode:(CTGradientBlendingMode)mode;
- (CTGradientElement *)elementAtIndex:(unsigned)index;
- (CTGradientElement)removeElementAtIndex:(unsigned)index;
- (CTGradientElement)removeElementAtPosition:(float)position;
</code></pre>

<p>The following C functions are now unused:</p>

<pre><code>static void chromaticEvaluation(void *info, const float *in, float *out);
static void inverseChromaticEvaluation(void *info, const float *in, float *out);
static void transformRGB_HSV(float *components);
static void transformHSV_RGB(float *components);
static void resolveHSV(float *color1, float *color2);
</code></pre>

<p>And also remove the following from the header:</p>

<pre><code>typedef enum  _CTBlendingMode
    {
    CTLinearBlendingMode,
    CTChromaticBlendingMode,
    CTInverseChromaticBlendingMode
    } CTGradientBlendingMode;
</code></pre>

<p>Remove the <code>&lt;protocols&gt;</code> and unnecessary instance variables so the interface looks like this:</p>

<pre><code>@interface CTGradient : NSObject {
    CTGradientElement* elementList;
    CGFunctionRef gradientFunction;
}
+ (id)gradientWithBeginningColor:(NSColor *)begin endingColor:(NSColor *)end;
- (void)fillRect:(NSRect)rect angle:(float)angle;
- (void)addElement:(CTGradientElement *)newElement;
@end
</code></pre>

<p>Before we go further, we&#8217;ll need to take a detour and fix the remaining code so that it compiles. That&#8217;s easy enough - just remove any references to code we&#8217;ve removed.</p>

<p>If you&#8217;ve been following along, your CTGradient should now look like <a href="http://pub.lipidity.com/CTGradient/CTGradient2.m">this</a> (also made it readable!).</p>

<p>In a few short minutes, we&#8217;re down from more than <strong>1300</strong> to a little over <strong>200 lines</strong>.</p>

<p><big>It gets better.</big></p>

<h2>Optimize it</h2>

<p>First stop, <code>fillRect:angle:</code>. Since the gradient for Trimmit&#8217;s window only runs vertically (angle 90), we can straight away take out the <var>angle</var> argument, and also cut the entire if / else structure with the angle down to the two lines that are under the <code>if(angle == 90)</code>. Ah, much better.</p>

<p>Now things start getting a teeny bit more complex - and fun.</p>

<hr />

<p>The CTGradient code is written so that one can have many different color stops. The CTGradientElement struct has a nextElement which points to the next CTGradientElement and the position of the current element is stored under the float <var>position</var>. However, we need just two - the starting and ending shades.</p>

<p>Let&#8217;s take a look at cutting the multiple elements down to just two.</p>

<p>The <code>addElement:</code> method has a lot of looping to insert the element at the correct place. However, since we know that we only ever need two, we can cut it down to this:</p>

<pre><code>- (void)addElement:(CTGradientElement *)newElement {
    if(elementList) {
        // elementList exists, add second element
        elementList-&gt;nextElement = malloc(sizeof(CTGradientElement));
        *(elementList-&gt;nextElement) = *newElement;
        elementList-&gt;nextElement-&gt;nextElement = 0;
    } else {
        // no elements - add first element
        elementList = malloc(sizeof(CTGradientElement));
        *elementList = *newElement;
        elementList-&gt;nextElement = 0;
    }
}
</code></pre>

<p>Similarly with <code>dealloc</code>,</p>

<pre><code>- (void)dealloc {
    CGFunctionRelease(gradientFunction);
    free(elementList-&gt;nextElement);
    free(elementList);
    [super dealloc];
}
</code></pre>

<p>While we&#8217;re at it, let&#8217;s clean up <code>init</code> as well:</p>

<pre><code>- (id)init {
    if(self = [super init]) {
        CGFunctionCallbacks evaluationCallbackInfo = {0 , &amp;linearEvaluation, 0};
        static const float input_value_range[2] = { 0, 1 };
        static const float output_value_ranges[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
        gradientFunction = CGFunctionCreate(&amp;elementList, 1, input_value_range, 4, output_value_ranges, &amp;evaluationCallbackInfo);
    }
    return self;
}
</code></pre>

<p>Now we head to the <code>linearEvaluation</code> function. <var>info</var> passed in refers to <var>elementList</var> (see the CGFunctionCreate call). Again, since we know that we&#8217;ll only ever have two elements we can reduce it to:</p>

<pre><code>void linearEvaluation (void *info, const float *in, float *out) {
    float position = *in;

    CTGradientElement *color1 = *(CTGradientElement **)info;
    CTGradientElement *color2 = color1-&gt;nextElement;

    out[0] = (color2-&gt;red - color1-&gt;red)*position + color1-&gt;red; 
    out[1] = (color2-&gt;green - color1-&gt;green)*position + color1-&gt;green;
    out[2] = (color2-&gt;blue - color1-&gt;blue)*position + color1-&gt;blue;
    out[3] = (color2-&gt;alpha - color1-&gt;alpha)*position + color1-&gt;alpha;
}
</code></pre>

<p>And now we can finally remove the lines from <code>+gradientWithBeginningColor:endingColor:</code> where the positions are set, and also remove the <var>position</var> float from the CTGradientElement struct.</p>

<hr />

<p>We&#8217;re now down to a little over <strong>100 lines</strong>. Your CTGradientElement.m should now be looking something like <a href="http://pub.lipidity.com/CTGradient/CTGradient3.m">this</a>. Going well, but let&#8217;s take things up a notch.</p>

<hr />

<p>For Trimmit&#8217;s background, we&#8217;re not interested in the red, green, blue and alpha components - we just need a grayscale shading. This is the most fun part.</p>

<p>Instead of <code>float red, green, blue, alpha;</code> in the CTGradientElement struct, we can have just <code>float shade;</code>.</p>

<p>Now, during <code>init</code> we have:</p>

<pre><code>CGFunctionCallbacks evaluationCallbackInfo = {0 , &amp;linearEvaluation, 0};
static const float input_value_range[2] = { 0, 1 };
static const float output_value_ranges[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
gradientFunction = CGFunctionCreate(&amp;elementList, 1, input_value_range, 4, output_value_ranges, &amp;evaluationCallbackInfo);
</code></pre>

<p>The third argument, <var>input_value_range</var> is the domain. This gets passed into linearEvalution through <var>*in</var>.This is the independent variable. When we&#8217;re drawing the gradient, linearEvaluation is called with <var>*in</var> (the domain) starting at the first value of <var>input_value_range</var> and ending up at the second. So, something like 0.000, 0.001, 0.002 &#8230; 0.998, 0.999, 1.000. The function&#8217;s job is to set the the color components for each given value of the domain.</p>

<p>The first optimization we can make here is to return only one channel instead of four. This changes it to:</p>

<pre><code>- (id)init {
    if (self = [super init]) {
        CGFunctionCallbacks evaluationCallbackInfo = {0, &amp;linearEvaluation, 0};
        static const float range[2] = {0, 1};
        static const float domain[2] = {0, 1};
        gradientFunction = CGFunctionCreate(&amp;elementList, 1, domain, 1, range, &amp;evaluationCallbackInfo);
    }
    return self;
}
</code></pre>

<p>This change impacts back on the linearEvaluation function - now it only needs to return one channel:</p>

<pre><code>void linearEvaluation (void *info, const float *in, float *out) {
    CTGradientElement *color1 = *(CTGradientElement **)info;
    out[0] = (color1-&gt;nextElement-&gt;shade - color1-&gt;shade)*(*in) + color1-&gt;shade;
}
</code></pre>

<p>And don&#8217;t forget <code>+gradientWithBeginningColor:endingColor:</code>. We improve performance here, as we only need the shade - not a color. We can rename it to something appropriate.</p>

<pre><code>+ (id)gradientWithBeginningShade:(float)begin endingShade:(float)end {
    id newInstance = [[[self class] alloc] init];
    CTGradientElement color1, color2;

    color1.shade = begin; color2.shade = end;

    [newInstance addElement:&amp;color1];
    [newInstance addElement:&amp;color2];
    return [newInstance autorelease];
}
</code></pre>

<p>Now we&#8217;re only returning one grayscale channel. But hold on, we&#8217;re still in the RGB colorspace! That&#8217;s easily fixed. In <code>fillRect:</code>, replace:</p>

<pre><code>#if MAC_OS_X_VERSION_MAX_ALLOWED &gt;= MAC_OS_X_VERSION_10_4
    CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
#else
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
#endif
</code></pre>

<p>with:</p>

<pre><code>CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
</code></pre>

<p class="note">CGColorSpaceCreateDeviceGray is device-dependent on Mac OS X 10.3 and below, but starting from Tiger, it&#8217;s now device-independent which is good in terms of appearance.</p>

<p>While we&#8217;re in <code>fillRect:</code>, we can also make a few more improvements:</p>

<pre><code>- (void)fillRect:(NSRect)rect {
    CGContextRef currentContext = [[NSGraphicsContext currentContext] graphicsPort];
    CGContextSaveGState(currentContext);
    CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceGray();
    CGContextClipToRect(currentContext, *(CGRect *)&amp;rect);
    CGShadingRef myCGShading = CGShadingCreateAxial(colorspace, CGPointMake(0, 0), CGPointMake(0, NSMaxY(rect)), gradientFunction, 0, 0);
    CGContextDrawShading(currentContext, myCGShading);

    CGShadingRelease(myCGShading);
    CGColorSpaceRelease(colorspace);
    CGContextRestoreGState(currentContext);
}
</code></pre>

<p>I moved the startPoint and endPoint CGPoints straight into the CGShadingCreateAxial call. Also, we only ever fill the whole view with the gradient, so just put in <code>0</code> instead of using NSMinX and NSMinY. We could replace the <code>CGPointMake(0, 0)</code> with <code>(CGPoint){0,0}</code>, but I&#8217;m not sure if that&#8217;d be noticeably faster.</p>

<hr />

<p>Our code is at a lean <strong>80 lines</strong>. Now for the biggest change yet.</p>

<hr />

<p>Heading back to dear old linearEvaluation. Look at this line:</p>

<pre><code>out[0] = (color1-&gt;nextElement-&gt;shade - color1-&gt;shade)*(*in) + color1-&gt;shade;
</code></pre>

<p>What&#8217;s happening here? Think about it like this:</p>

<p>Essentially, we&#8217;re just &quot;graphing&quot; a straight line:</p>

<pre><code>y = mx + c
</code></pre>

<p>where <var>x</var> is the position, <var>*in</var>, and <var>y</var> is the shade we return (<var>out[0]</var>), and <var>c</var> is the initial shade.</p>

<p>Since our <var>x</var> value only goes from 0 to 1 (see domain in CGFunctionCreate), at <code>x = 0</code>, we will have <code>y = c</code>. At <code>x = 1</code>, we&#8217;ll have <code>y = m + c</code>.</p>

<p><img src='http://lipidity.com/wordpress/wp-content/uploads/2007/11/gradient-graph.png' alt='Graph of Gradient Function' class='feature' /></p>

<p><strong>So</strong> we only need the start shade as our <var>*info</var> value, since we can have <var>m</var> as the difference between the final and initial shades. Let&#8217;s effect this in our code.</p>

<p>We can get rid of the CTGradientElement struct. Remove from the header:</p>

<pre><code>typedef struct _CTGradientElement {
    float shade;
    struct _CTGradientElement *nextElement;
} CTGradientElement;
</code></pre>

<p>Instead of the struct, we&#8217;ll use a single <var>shade</var> instance variable. We don&#8217;t need the <code>+gradientWithBeginningShade:endingShade:</code> anymore, nor do we need <code>-addElement:</code>. So our interface now looks like this:</p>

<pre><code>@interface CTGradient : NSObject {
    float shade;
    CGFunctionRef gradientFunction;
}
- (void)fillRect:(NSRect)rect;
@end
</code></pre>

<p>From the implementation, we can remove the <code>free</code> calls in <code>dealloc</code> as well as the whole of <code>+gradientWithBeginningShade:endingShade:</code> and <code>addElement:</code>. We can set the <code>shade</code> in the init method (and replace <code>&amp;elementList</code> with <code>&amp;shade</code>), and change the linearEvaluation function to:</p>

<pre><code>void linearEvaluation (void *info, const float *in, float *out) {
    out[0] = *(float*)info + (*in)*0.1;
}
</code></pre>

<p>The <code>0.1</code> is what determines how much brighter the top of the gradient is (it&#8217;s the <var>m</var> value of our straight line) compared to the bottom.</p>

<p><strong>But</strong> since the <code>(*in)*0.1</code> will go from <code>0</code> to <code>0.1</code> (as <var>*in</var> goes from 0 to 1), we can actually change the <code>domain</code> we declare for CGFunctionCreate to {0, 0.1} and have our function as:</p>

<pre><code>void linearEvaluation (void *info, const float *in, float *out) {
    out[0] = *(float*)info + *in;
}
</code></pre>

<p>You can now add accessors for <code>shade</code> if you need to change the shade of the gradient or you could even have an <code>initWithShade:</code> method. In fact, here&#8217;s an Xcode project with the gradient.</p>

<p class="download"><a href="http://pub.lipidity.com/CTGradient/GradientSample.tar.bz2">Lean Gradient Xcode Project</a></p>

<p>We now have our gradient code down <big>from <strong>1300 lines</strong> to just over <strong>30 lines</strong></big>.</p>

<hr />

<p>We&#8217;ve almost reached a similar level of optimization to Trimmit&#8217;s gradient. There will be further optimizations you can make, but it depends on what you&#8217;re using the gradient for. For example, if the gradient you&#8217;re drawing is always the same, you can optimize further by removing the <code>shade</code> instance variable and all references to it, and hardcode the value into the linearEvaluation function.</p>

<p>Getting to the end of this article, you&#8217;re probably thinking that it would be a bit of a waste to use CTGradient if by the time you optimize it for your application, it doesn&#8217;t resemble the original at all. And you&#8217;re quite right. The documentation already shows you <a href="http://developer.apple.com/documentation/GraphicsImaging/Conceptual/drawingwithquartz2d/dq_shadings/chapter_9_section_6.html">how to draw gradients</a>, yet the number of applications using CTGradient - the whole 1300 lines of it - is astonishing.</p>

<p>Please: When you use other people&#8217;s code, don&#8217;t put it in without a thought. Go through it, understand it, and optimize it for your specific need. For the better performance and reduced RAM usage, computers will thank you.</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/ctgradient-code-bloat/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Hide in your shell</title>
		<link>http://lipidity.com/apple/hide-in-your-shell/</link>
		<comments>http://lipidity.com/apple/hide-in-your-shell/#comments</comments>
		<pubDate>Wed, 03 Oct 2007 14:00:15 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[shell]]></category>

		<category><![CDATA[terminal]]></category>

		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://lipidity.com/apple/hide-in-your-shell/</guid>
		<description><![CDATA[Your Mac has a UNIX core - learn to use it.]]></description>
			<content:encoded><![CDATA[<p>The &#8220;command line&#8221; on your Mac can be accessed using the Terminal in /Applications/Utilities.</p>

<p>If you&#8217;re not familiar with shell scripting, there&#8217;s a good tutorial <a href="http://www.linuxcommand.org/learning_the_shell.php">here</a>. You can also find, run or manage shell commands using the free <a href="http://rixstep.com/4/0/clix/">CLIX</a> utility from Rixstep.</p>

<hr />

<p>These commands are ones I use frequently - in many instances they are given a pretty Cocoa front-end and a hefty price-tag when you already have all this functionality inside your computer.</p>

<p>For more information about any of these commands, type in <code>man command-name</code>, where <code>command-name</code> is the name of the command you want information about (type <kbd>q</kbd> to quit the man page once you&#8217;re done).</p>

<h3>Downloading</h3>

<p>The <code>curl</code> command is invaluable when it comes to downloading. To download a file from a specific URL (be it ftp or http), use the command:</p>

<pre><code>curl -o <kbd>local-file.ext</kbd> <kbd>http://www.url.com/file.ext</kbd></code></pre>

<p>If you were downloading something, but your internet connection died, or you had to stop it for some other reason (even if you were downloading with some other program such as your browser), you can use curl to resume the download:</p>

<pre><code>curl -C - -o <kbd>local-file.ext</kbd> <kbd>http://remote.tld/file.ext</kbd></code></pre>

<p>Very nifty!</p>

<h3>Compression</h3>

<p>A few different compression formats. Bzip2 generally provides the most compressions, but for text, gzip is often better. To compress multiple files (ie. folders), you&#8217;ll need to use either the <code>tar</code> or <code>zip</code> command.</p>

<pre><code>bzip2 <kbd>file</kbd></code></pre>

<pre><code>gzip <kbd>file</kbd></code></pre>

<pre><code>zip <kbd>output</kbd> <kbd>files</kbd></code></pre>

<pre><code>tar -cjf <kbd>output.tbz</kbd> <kbd>files</kbd></code></pre>

<pre><code>tar -czf <kbd>file.tgz</kbd> <kbd>file</kbd></code></pre>

<h3>Cleaning</h3>

<p>If you <a href="http://lipidity.com/downloads/trim-app/">download</a> the trim-app shell script, you can do a lot of cleaning up of your system very easily. Move it to /usr/bin/, then you can do the following:</p>

<p>Remove .DS_Store files from the current directory:</p>

<pre><code>trim-app -d</code></pre>

<p>Trim universal binaries to a single architecture (use i386 instead of ppc for Intel):</p>

<pre><code>trim-app -a ppc</code></pre>

<p>Compress tiff images:</p>

<pre><code>trim-app -t</code></pre>

<p>Clean resource forks:</p>

<pre><code>trim-app -r</code></pre>

<p>Or all of the above:</p>

<pre><code>trim-app --all ppc</code></pre>

<p>Since trim-app is a shell script, you can open it in a text editor to see how it works. You can download an uncompressed version of trim-app <a href="http://pub.lipidity.com/trim-app-unc.gz">here</a> to dissect it.</p>

<h3>Misc</h3>

<p>If you need to search the <em>contents</em> of files for a particular string, use the following:</p>

<pre><code>grep -r &#34;<kbd>search-query</kbd>&#34; *</code></pre>

<p>Find out the size of the current directory in kilobytes:</p>

<pre><code>du -csk</code></pre>

<p>Delete all languages other than English in applications in the current folder.</p>

<pre><code>find . -name \*.lproj -and \! \( -name En\* -or -name en\* \) -exec rm -rf {} \;</code></pre>

<p>Create a symbolic link:</p>

<pre><code>ln -s <kbd>source</kbd> <kbd>dest</kbd></code></pre>

<p>Create an .icns file from a tiff image:</p>

<pre><code>tiff2icns <kbd>image.tiff</kbd></code></pre>

<hr />

<p>These are just a few of the useful shell commands available - explore a bit and you&#8217;ll find plenty of fantastic tools that will make your life much, much easier.</p>

<p>Now it&#8217;s your turn - know any super time-saving commands?</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/hide-in-your-shell/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mac developer? Clean up your app</title>
		<link>http://lipidity.com/apple/cleaning-apps-mac-os-x/</link>
		<comments>http://lipidity.com/apple/cleaning-apps-mac-os-x/#comments</comments>
		<pubDate>Sat, 15 Sep 2007 14:00:24 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[Download]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[shell]]></category>

		<category><![CDATA[terminal]]></category>

		<category><![CDATA[Tutorial]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/tutorial/cleaning-apps-mac-os-x</guid>
		<description><![CDATA[
  The reason for this article should be obvious: too many OS X third party developers do an absolutely terrible job of building and packaging their applications. rixstep


Too many apps are shipped with debug symbols, uncompressed images, redundant files or generally useless rubbish that not only wastes users&#8217; disk space, it ultimately ends up [...]]]></description>
			<content:encoded><![CDATA[<blockquote>
  <p>The reason for this article should be obvious: too many OS X third party developers do an absolutely terrible job of building and packaging their applications. <cite><a href="http://rixstep.com/2/2/20070526,00.shtml">rixstep</a></cite></p>
</blockquote>

<p>Too many apps are shipped with debug symbols, uncompressed images, redundant files or generally useless rubbish that not only wastes users&#8217; disk space, it ultimately ends up increasing the developer&#8217;s own bandwidth costs.</p>

<!--more-->

<p>It&#8217;s not just the script kiddies at fault. <a href="http://www.cocoatech.com">Path Finder</a> weighs in at over 60 MB on disk, but after a few simple operations, is halved in size to just over 30 MB. <a href="http://appzapper.com">AppZapper</a> can be trimmed from three megabytes to just one. <a href="http://www.xslimmer.com">Xslimmer</a> (ironically) is over 80% junk, going from 5 MB on disk to a meagre 1 MB after being cleaned. In this case, the <em>disk image</em> is <em>three times as big</em> as the cleaned, <em>uncompressed</em> app. Starting to see the trend? Almost every app can be cleaned up to save a good deal of space.</p>

<h2>Deploying your app</h2>

<p>Rixstep provide instructions on <a href="http://rixstep.com/2/20070306,00.shtml">deploying OS X apps</a> covering most of the major areas.</p>

<p>Essentially, you need to:</p>

<dl>
<dt>Remove Junk</dt>
<dd>Get rid of all .DS_Store files. In Cocoa apps, remove PkgInfo.
You should only have objects.nib or keyedobjects.nib in your nibs: remove classes.nib, info.nib, and data.dependency; these are not relevant for the user. Also remove all header files from your app and from embedded frameworks.</dd>

<dt>Clean up localization</dt>
<dd>Keep all non-language-specific resources in the Resources folder rather than duplicating them in each .lproj folder.
Look through the framework you&#8217;re embedding, and remove any unnecessary files files. That includes language projects which your main app doesn&#8217;t support.</dd>

<dt>Compress images</dt>
<dd>Make sure all your images are compressed, especially if they&#8217;re in TIFF format. (But you shouldn&#8217;t use images for simple graphics like curves or gradients anyway; there are Cocoa drawing routines for that and NSBezierPath is your friend)</dd>

<dt>Trim binaries</dt>
<dd>Do not release an app that has been built using the Xcode &#8220;Debug&#8221; configuration. Remove the debug symbols from your build product, and if possible, release architecture-specific versions of your app, as well as a universal binary.</dd>
</dl>

<p>Get all the details in <a href="http://rixstep.com/2/2/20070526,00.shtml">Building and Packaging Native OS X Applications</a>.</p>

<h2>Automation</h2>

<blockquote>
  <p>A relevant question is: are there any tools that automate this process? And the answer has to be &#8216;not up to now there aren&#8217;t&#8217;. Until something comes along to save users from these issues it&#8217;s still all up to that developer you trust. <cite><a href="http://rixstep.com/2/20070306,00.shtml">Rixstep</a></cite></p>
</blockquote>

<p>There is finally a tool that automates at least some of the cleaning process. Say hello:</p>

<p class="centre"><big><a href='http://lipidity.com/downloads/trim-app/' title='download trim-app shell script'>Go get trim-app</a></big></p>

<p>Trim-app is a shell script. It:</p>

<ul>
<li>Cleans out all the horrible .DS_Store files</li>
<li>Removes unnecessary info.nib, classes.nib, and data.dependency files from inside nibs</li>
<li>Strips &#8220;fat&#8221; universal binaries to contain code for a chosen architecture only</li>
<li>Eliminates debug symbols that may be left in your application</li>
</ul>

<p>You can perform all procedures at once, one at a time, multiple at a time, etc. using different parameters or flags (run <code>trim-app -h</code> for help).</p>

<p>The script searches the current working directory including every subdirectory so no files are missed. Even embedded frameworks are scanned through and cleaned out. So make sure you&#8217;re in the right directory before running (use the <code>pwd</code> command if unsure)</p>

<p>All changes performed are <strong>permanent</strong> and non-recoverable. (If you&#8217;re writing the app, that shouldn&#8217;t be a problem. Just build it again if something goes wrong)</p>

<p class="note">While it&#8217;s written for cleaning out applications, this script is also great for general tasks - cleaning out .DS_Store files in a certain folder, for example.</p>

<h3>Installation</h3>

<ul>
<li>Unzip the <a href="http://lipidity.com/downloads/trim-app/">download</a>.</li>
<li>Open Terminal and navigate to the folder where the unzipped trim-app is.</li>
<li>Run <code>chmod 0700 trim-app</code>. This makes sure only you can execute it.</li>
</ul>

<p>If you want easy access to the command, move the file to /usr/bin/ by running <code>sudo mv trim-app /usr/bin/</code>. You&#8217;ll be asked for the admin password, then file will be moved.</p>

<p>You can now test if it&#8217;s working by running <code>trim-app -h</code>. Instructions for trim-app will appear. Once you&#8217;re done reading them, press <code>q</code> to exit, and start using it!</p>

<h3>Usage</h3>

<p>Running the shell script without any parameters will attempt to run all four procedures. You&#8217;ll be prompted for an architecture to keep in universal binaries. Leave this blank (just hit return) to leave universal binaries universal, or type in an architecture to keep (usually <code>ppc</code> or <code>i386</code>) if you want them stripped down.</p>

<p>Here&#8217;s an example of how you would use it in the Terminal:</p>

<pre><code>% <kbd>cd myApp.app/</kbd>
% <kbd>trim-app</kbd>
<samp>Architecture to keep? (ppc/i386)</samp> <kbd>ppc</kbd>
<samp>   Removing .DS_Store files&#8230;</samp>
<samp>   Trimming nibs&#8230;</samp>
<samp>   Trimming universal binaries&#8230;</samp>
<samp>   Stripping debug symbols&#8230;</samp>
<samp>   Cleaning up&#8230;</samp>
<samp>Done.</samp>
%</code></pre>

<p>If you don&#8217;t want to be prompted each time for the architecture, use either <code>--all</code> (as in, <code>trim-app --all</code>) (which will run everything <em>except</em> the liposuction of universal binaries), or add the architecture to keep immediately after, like <code>trim-app --all ppc</code>.</p>

<p>Add a <code>-p</code> flag to the end if you want to see a list of affected files. For example,</p>

<pre><code>% trim-app --all i386 -p
</code></pre>

<p>You can also run individual procedures. The following cleans out .DS_Stores from the entire Macintosh HD:</p>

<pre><code>% cd /
% sudo trim-app -d
</code></pre>

<p class="note">Run <code>trim-app -h</code> to find out more about the available parameters.</p>

<hr />

<p>Don&#8217;t forget the standard shell practices still apply. Ctrl-C any time during operation to immediately halt execution, save output to a file with <code>trim-app -p &gt; trim-log.txt</code>, and so on.</p>

<p>Lastly, remember that while this shell script does a lot of the work (and there is an application called <a href="http://www.synium.de/cleanapp/index.html">CleanApp</a> which can help remove unnecessary lproj files), it&#8217;s still up to you to take care of removing headers, compressing images, etc.</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/cleaning-apps-mac-os-x/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Javascript does Cocoa too</title>
		<link>http://lipidity.com/apple/javascript-cocoa-webkit/</link>
		<comments>http://lipidity.com/apple/javascript-cocoa-webkit/#comments</comments>
		<pubDate>Sat, 28 Jul 2007 08:07:49 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[javascript]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Tutorial]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/dev/cocoa/javascript-cocoa-webkit</guid>
		<description><![CDATA[Running Objective-C code from Javascript

Java, Python and Ruby can access Cocoa APIs and Objective-C classes. What about the super-extensible yet severely under-appreciated Javascript? With the WebKit framework, you can access Objective-C from any script present in a HTML document.



A `WebScriptObject` is an Objective-C wrapper passed to your application from the scripting environment. You can&#8217;t create [...]]]></description>
			<content:encoded><![CDATA[<p><big>Running Objective-C code from Javascript</big></p>

<p>Java, Python and Ruby can access Cocoa APIs and Objective-C classes. What about the super-extensible yet severely under-appreciated Javascript? With the WebKit framework, you can access Objective-C from any script present in a HTML document.</p>

<!--more-->

<blockquote><p>A `WebScriptObject` is an Objective-C wrapper passed to your application from the scripting environment. You can&#8217;t create an instance directly, but you need to get a `WebScriptObject` by sending `webScriptObject` to a WebView.</p><cite>Paraphrase of <a href="http://developer.apple.com/documentation/Cocoa/Reference/WebKit/Classes/WebScriptObject_Class/Reference/Reference.html#//apple_ref/doc/c_ref/WebScriptObject" title="WebScriptObject Class Reference" target="_blank">WebScriptObject Overview</a></cite></blockquote>

<p>This class, <code>WebScriptObject</code>, lets you &#8220;talk&#8221; and &#8220;listen&#8221; to Javascript (or any other code allowable inside <acronym title="Hyper Text Markup Language">HTML</acronym> <code>&lt;script&gt;</code> tags). That is, you can run Javascript code or functions in the WebView, but you can also let the Javascript run Objective-C methods.</p>

<p>This is the same way Dashboard widgets interact with Cocoa plugins. You know how you access <code>window.widget</code> in your Javascript? That&#8217;s an Objective-C class you&#8217;re referencing. The WebKit framework provides all the necessary classes and functionality for this interaction, making this seemingly difficult task ridiculously easy.</p>

<h4>Exposing an Objective-C class to the scripting environment</h4>

<p>Exposing a class to the scripting environment is very easy. You can use key-value coding methods (for example, <code>setValue:forKey:</code> and <code>valueForKey:</code>) to get and set the properties of a <code>WebScriptObject</code>. These will be accessible as children of the window object in Javascript. Use the <code>removeWebScriptKey:</code> method to remove a scripting object property.</p>

<p>As an example, let&#8217;s say we have a class <code>NSFoo</code>. We&#8217;ve linked to the WebKit framework and <code>webView</code> is a <code>WebView</code>.</p>

<p>We use the delegate method <code>webView:windowScriptObjectAvailable:</code> to ensure that the <code>WebScriptObject</code> is available before we start using it. Then we expose an instance of <code>NSFoo</code> to the scripting environment:</p>

<pre><code>- (void)webView:(WebView *)sender windowScriptObjectAvailable: (WebScriptObject *)windowScriptObject {
    NSFoo *myFoo = [[NSFoo alloc] init];

    scriptObject = windowScriptObject;
    [scriptObject setValue:myFoo forKey:@"foo"];
}
</code></pre>

<p>Now you can access <code>foo</code> through javascript;</p>

<pre><code>&lt;script language='text/javascript'&gt;
var myFoo = foo;
&lt;/script&gt;
</code></pre>

<h4>Allow Javascript access</h4>

<p>For obvious security reasons, no methods or KVC keys are exposed to the Javascript environment by default. This means at this stage while <code>window.foo</code> exists, you can&#8217;t do much with it. To allow Javascript to send messages or get / set properties, the following two class methods need to be utilized:</p>

<pre><code>+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector;
+ (BOOL)isKeyExcludedFromWebScript:(const char *)name;
</code></pre>

<p>So for example, if we want to allow Javascript to send a <code>bar:</code> message to a class, all we have to do is add the following class method to the implementation:</p>

<pre><code>+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector {
    if ( selector == @selector(bar:) ) {
        return NO;
    }
    return YES;
}
</code></pre>

<p>Now running <code>foo.bar_(0)</code> in Javascript will be equivalent to running <code>[myFoo bar:0]</code> in Objective-C. Why the underscore? Selectors accessed from Javascript are renamed using the following rules:</p>

<ul>
<li>Any colon (&quot;:&quot;) in the Objective-C selector is replaced by an underscore (&quot;_&quot;).</li>
<li>Any underscore in the Objective-C selector is prefixed with a dollar sign (&quot;$&quot;).</li>
<li>Any dollar sign in the Objective-C selector is prefixed with another dollar sign.</li>
</ul>

<p>So a method called <code>doAction:(id)action withThing:(id)thing</code> will be turned into <code>doAction_withThing_(action,thing)</code>, while <code>do$This:</code> will become <code>do$$This_</code>. This is often pretty ugly and inconvenient. Fortunately, the Javascript name for the selectors can be changed.</p>

<h4>Change Javascript selector names</h4>

<p>Using <code>+ (NSString *)webScriptNameForSelector:(SEL)sel</code>, we can change the name of the selector in Javascript:</p>

<pre><code>+ (NSString *)webScriptNameForSelector:(SEL)sel
{
    if (sel == @selector(bar:))
        return @"bar";
    return nil;
}
</code></pre>

<p>Now we can run <code>foo.bar(0)</code> in Javascript to equal <code>[myFoo bar:0]</code>. Here are a few more examples:</p>

<pre><code>+ (NSString *)webScriptNameForSelector:(SEL)sel
{
    if (sel == @selector(performTransition))
        return @"performTransition";    // widget.performTransition()
    else if (sel == @selector(prepareForTransition:))
        return @"prepareForTransition"; // widget.prepareForTransition(arg)
    else if (sel == @selector(setPreference:forKey:))
        return @"setPreferenceForKey";  // widget.setPreferenceForKey(pref,key)
    else if (sel == @selector(preferenceForKey:))
        return @"preferenceForKey";     // widget.preferenceForKey(key)
    return nil;
}
</code></pre>

<p>If you want to expose all the instance methods of the class to the scripting environment, just return <code>NO</code> without doing any checks:</p>

<pre><code>+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector { return NO; }
</code></pre>

<p>Remember: selectors are converted into Javascript functions, so even if the method doesn&#8217;t need any arguments, you still need to add the parenthesis at the end for the Javascript; eg. <code>[object doMethod]</code> becomes <code>object.doMethod()</code>.</p>

<h4>Key-Value-Coding from Javascript</h4>

<p>Exposing KVC keys is a similar procedure. Here we&#8217;re giving access to the &#8220;name&#8221; property:</p>

<pre><code>+ (BOOL)isKeyExcludedFromWebScript:(const char *)property {
    if (strcmp(property, "name") == 0) {
        return NO;
    }
    return YES;
}
</code></pre>

<p>Now in Javascript, we can read and write <code>foo.name</code>. Reading <code>foo.name</code> will be equivalent to <code>[myFoo name]</code> and writing to it (<code>foo.name = "A big foo"</code>) will be the same as running <code>[myFoo setName:@"A big foo"]</code>.</p>

<p>As before, just <code>return NO</code> without any checks to allow all KVC keys to be accessed from the scripting environment.</p>

<h3>Summary</h3>

<ul>
<li>Load WebKit.framework which contains the classes <code>WebView</code> and <code>WebScriptObject</code>.</li>
<li>Send <code>setValue:forKey:</code> to a <code>WebScriptObject</code>; makes an object available to the scripting environment.</li>
<li>Implement <code>+isSelectorExcludedFromWebScript:</code> and <code>+isKeyExcludedFromWebScript:</code> and return NO to allow the scripting environment to run a method or access a key.</li>
<li>Use <code>webScriptNameForSelector:</code> / <code>webScriptNameForKey:</code> to specify the names of your methods / keys as seen by Javascript.</li>
</ul>

<h3>Further reading</h3>

<ul>
<li><a href="http://developer.apple.com/documentation/Cocoa/Reference/WebKit/ObjC_classic/index.html">WebKit Documentation</a></li>
<li><a href="http://developer.apple.com/documentation/Cocoa/Reference/WebKit/Protocols/WebScripting_Protocol/index.html#//apple_ref/doc/uid/TP40003837">WebScripting Documentation</a></li>
<li><a href="http://developer.apple.com/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/ObjCFromJavaScript.html">Obj-C From JavaScript</a></li>
<li><a href="http://will.thimbleby.net/script/">TurtleScript</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/javascript-cocoa-webkit/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Make the most of the iPhone SDK</title>
		<link>http://lipidity.com/apple/iphone-webkit-css-3/</link>
		<comments>http://lipidity.com/apple/iphone-webkit-css-3/#comments</comments>
		<pubDate>Tue, 26 Jun 2007 02:00:11 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Design]]></category>

		<category><![CDATA[Web]]></category>

		<category><![CDATA[CSS]]></category>

		<category><![CDATA[iPhone]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/apple/make-the-most-of-the-iphone-sdk</guid>
		<description><![CDATA[<img src="http://dev.lipidity.com/wp-content/uploads/2007/06/safari.jpg" alt="Safari" title="Safari icon" class="fright" />
The iPhone, like Safari and many other browsers, runs on WebKit, which is one of the most blazing fast, powerful, standards-compliant rendering engine ever. Although there is no official Cocoa API for iPhone app development, it's not like we have nothing to work with. Writing web apps for the iPhone will be a pretty good experience for two reasons:

<ol>
<li>We don't have to worry about IE support when writing our web app</li>
<li>WebKit is amazing.</li>
</ol>

Highlighted below are ten CSS rules that make WebKit extra-great. <strong>Many of the previews require a WebKit-based browser like Safari, OmniWeb or Shiira.</strong><br />
<br />]]></description>
			<content:encoded><![CDATA[<h2>WebKit and <abbr title="Cascading Stylesheets">CSS</abbr></h2>

<h3>1. Native Controls</h3>

<p>A feature unique to the later versions of WebKit is the ability to style form controls. For a long time, the form inputs were kept as the operating system&#8217;s native controls, but now they are specifically styled that way. This means, we can easily over-ride that styling, or make elements appear like native controls.</p>

<p>Take a look at these text inputs:</p>

<div class="example">
<input type="text" value="I am a text input" />
<input type="text" style="-webkit-appearance:searchfield;" value="Me too, but I am round" />
<input type="search" value="I am a proper search input" />
</div>

<p>If you&#8217;re running a WebKit-based browser like Safari, you&#8217;ll see the first text input as a normal OS X-style
control, but the second one is a rounded control (like the search input minus the cancel widget).</p>

<p>Now look at these anchors:</p>

<div class="example">
<a href="#top">Go to top</a>
<a href="#top" style="-webkit-appearance:push-button;text-decoration:none;color:black">Go to top</a>
</div>

<p>Both are <code>&lt;a&gt;</code> tags, but the second one appears as a push-button in Safari.</p>

<p>That&#8217;s not all. Here are two button inputs:</p>

<div class="example">
<input type="button" value="I do nothing" />
<input type="button" value="I do nothing" style="-webkit-appearance:square-button" />
</div>

<p>Notice how the second button is a square button?</p>

<p>Have I caught your interest? Here&#8217;s how you do it.</p>

<h4>Mimic native widgets / controls</h4>

<p>Elements are styled to look like native controls for WebKit-based browsers using the <code>-webkit-appearance</code> <abbr title="Cascading Stylesheets">CSS</abbr> property. Some of the values this can take are (in two columns if you&#8217;re on WebKit):</p>

<div style="-webkit-column-count:2;-webkit-column-rule:1px solid rgba(0,0,0,0.1);">
<ul style="padding-left:2em">
<li>checkbox</li>
<li>radio</li>
<li>push-button</li>
<li>square-button</li>
<li>button</li>
<li>button-bevel</li>
<li>listbox</li>
<li>listitem</li>
<li>menulist</li>
<li>menulist-button</li>
<li>menulist-text</li>
<li>menulist-textfield</li>
<li>slider-horizontal</li>
<li>slider-vertical</li>
<li>sliderthumb-horizontal</li>
<li>sliderthumb-vertical</li>
<li>searchfield</li>
<li>searchfield-decoration</li>
<li>searchfield-results-decoration</li>
<li>searchfield-results-button</li>
<li>searchfield-cancel-button</li>
<li>textfield</li>
<li>textarea</li>
</ul>
</div>

<p>Setting <code>-webkit-appearance</code> simply makes the element appear as if it were the control. This could be of enormous use within WebViews inside Cocoa applications or with web apps for the iPhone.</p>

<p>If don&#8217;t have access to a WebKit-based browser, here&#8217;s a screenshot of what some of the &#8220;controls&#8221; look like:</p>

<p class="centre"><img class="feature" src="http://dev.lipidity.com/wp-content/uploads/2007/06/webkit-controls.png" alt="Webkit Controls" title="WebKit OS X Native Controls or Widgets" /></p>

<p>The important thing to note is that although the controls can be made to look like other controls using <code>-webkit-appearance</code>, their function is not affected. That is, textboxes will still accept text when they&#8217;re made to appear like <code>push-button</code> and so on.</p>

<h3>2. Element Drag</h3>

<p><ins class="block"><a href="http://fettig.net/weblog/2007/06/29/a-few-iphone-safari-notes/">Apparently</a> dragging doesn&#8217;t work with the iPhone, as it&#8217;s used for scrolling. That&#8217;s to be expected, I guess.</ins></p>

<p>Generally there is a lot of javascript involved in making an element draggable. Now you can achieve the same thing with only one line of <abbr title="Cascading Stylesheets">CSS</abbr>. Javascript will still be required to have drop targets, etc. but this allows the user to drag the entire element rather than just text or an image.</p>

<p>Try dragging this element (from the side):</p>

<div class="example" style="-webkit-appearance:push-button;-webkit-user-drag:element;-webkit-user-select:ignore">Drag me if you dare</div>

<p>Notice how the whole element is dragged? It&#8217;s just a regular <code>div</code> (made to act as a push-button) with the <abbr title="Cascading Stylesheets">CSS</abbr> rule <code>-webkit-user-drag:element</code> applied to it. Easy!</p>

<h3>3. Edit the webpage</h3>

<p><ins class='block'>Doesn&#8217;t work on the iPhone. You can click in the element, but the keyboard doesn&#8217;t show up. This is likely to work when there are copy-paste functions in the phone.</ins></p>

<p class="feature" style="-webkit-user-modify:read-write-plaintext-only">
This is a paragraph that you can edit if you&#8217;re running a WebKit-based browser like Safari or the iPhone. Just click here and edit the text like a normal textbox.
</p>

<p>To allow users to edit elements of the page (or all of it) in real time, there exists a property <code>-webkit-user-modify</code>. Obviously this defaults to read-only, but you can set it to the following:</p>

<ul>
<li>read-only</li>
<li>read-write</li>
<li>read-write-plaintext-only</li>
</ul>

<p><code>read-write</code> allows the user to copy and paste in <strong>rich</strong> <em>text</em> with formatting, while <code>read-write-plaintext-only</code> pastes in only the text. This could be useful with debugging or as part of a <abbr title="What You See Is What You Get">WYSIWYG</abbr> editor, etc. Just be careful with the security side of things.</p>

<h3>4. Selection (Highlighting)</h3>

<p style="-webkit-user-select:ignore" class="feature">I am a paragraph that you can&#8217;t select (if you&#8217;re running Safari). Try and highlight me and realize that your attempts are futile. Bwah, ha ha&#8230;</p>

<p>To disallow selection (highlighting) of text for a particular element, set the <abbr title="Cascading Stylesheets">CSS</abbr> rule <code>-webkit-user-select:ignore</code>. This may be useful for many web apps, but use it sparingly to avoid irritating the user.</p>

<p class="feature selection_hilite">I am a paragraph that you can select. If your browser supports the `::selection` selector, highlighting this will result in a black background and white text for the highlighted region.</p>

<h3>5. Rounded corners</h3>

<p><big class='example' style='-webkit-border-radius:6px; border:1px solid #000;'>
Rounded corners: Look, no hacks!
</big></p>

<p><code>-webkit-border-radius</code> specifies the radius of the corners. You can specify certain corners only by using one of</p>

<ul>
<li>-webkit-border-top-left-radius</li>
<li>-webkit-border-top-right-radius</li>
<li>-webkit-border-bottom-left-radius</li>
<li>-webkit-border-bottom-right-radius</li>
</ul>

<p>For example, the following has the top-right and bottom-left corners set to a radius of 7px:</p>

<p><big class='example' style='-webkit-border-top-right-radius:7px;-webkit-border-bottom-left-radius:7px;border:1px solid #000;'>
A bit of fancy corner-work
</big></p>

<p>Elliptical corners are possible by specifying two values, eg. <code>-webkit-border-radius: 3px 7px;</code>.</p>

<h3>6. Shadows</h3>

<h4>text-shadow</h4>

<p><big class='example' style='color:#FFF;text-shadow:2px 2px 2px #000;'>
This text has a shadow when viewed with a compliant browser.
</big></p>

<p>For the text-shadow <abbr title="Cascading Stylesheets">CSS</abbr> property, the parameters are</p>

<ol>
<li>horizontal offset (negative is to the left)</li>
<li>vertical offset (negative is up)</li>
<li>blur radius (higher is more blurred)</li>
<li>shadow color</li>
</ol>

<p>For example, using <code>text-shadow: 1px 1px 7px #000;</code> we get:</p>

<p><big class='example' style='color:#fff;text-shadow:1px 1px 7px #000;'>
this excellent text with a blurred, but visible shadow.
</big></p>

<h4>box-shadow</h4>

<p><big class='example' style='-webkit-box-shadow:1px 1px 7px #000;'>
This entire element has a shadow using -webkit-box-shadow:
</big></p>

<p>To add a shadow to the actual element rather than just the text, use <code>-webkit-box-shadow</code>. Parameters are the same as for the <code>text-shadow</code> property.</p>

<ol>
<li>the horizontal offset</li>
<li>the vertical offset</li>
<li>the blur radius</li>
<li>shadow color</li>
</ol>

<p>The shadow automatically compensates for any rounded corners you may have added.</p>

<p><big class='example' style='-webkit-box-shadow:1px 1px 7px #000;-webkit-border-radius:5px;'>
This element has a shadow, but also a border-radius.
</big></p>

<h4>text-stroke</h4>

<p><big class='example' style='-webkit-text-fill-color:yellow;-webkit-text-stroke:1px black;'>
I guess I&#8217;m really just a string of text. Oh, I&#8217;m stroked.
</big></p>

<p>Use <code>-webkit-text-stroke</code> to set a border or stroke around the text. Specify thickness and color.</p>

<p>To change the fill color, use -webkit-text-fill-color; otherwise value for the color property is used.</p>

<h3>7. Backgrounds</h3>

<p>WebKit allows multiple background images using <abbr title="Cascading Stylesheets">CSS</abbr>. If you&#8217;re running Safari or other WebKit-based browser, see <a href="http://www.decaffeinated.org/archives/projects/multibg/background-image.html">this great example</a> of multiple background images with <abbr title="Cascading Stylesheets">CSS</abbr>.</p>

<p>The syntax for multiple backgrounds:</p>

<pre><code>  background-image:    url("first-img"), url("second-img"),
                       url("other-img"), url("another-img");
  background-repeat:   no-repeat, no-repeat,
                       repeat-y, repeat-x;
  background-position: top left, top right,
                       left, top;
</code></pre>

<p>The first image is associated with the first background-repeat, and the first background-position value and so on. The order in which the images appear also determines the stacking order - earlier images are stacked higher.</p>

<p>Shorthand background notation also works, the example above is equivalent to:</p>

<pre><code>background: url("first-img") top left no-repeat,
            url("second-img") top right no-repeat,
            url("other-img") left repeat-y,
            url("another-img") top repeat-x;
</code></pre>

<p>This could be really handy with making the background of a web-app, such as for the iPhone, without the need for multiple nested elements.</p>

<h3>8. Border Image</h3>

<p>To set fancy borders, you often need to use images. However, you can do away with all the javascript and <abbr title="Cascading Stylesheets">CSS</abbr> hacks and use <code>-webkit-border-image</code>.</p>

<p>Syntax:</p>

<pre><code>-webkit-border-image: url("image-url") size fit fit;
</code></pre>

<p>&#8220;image-url&#8221; needs to be an image divided into nine parts for each corner and edge and the content. The size is the height / width of the squares that the image is divided into. Fit can be <code>round</code> or <code>stretch</code>, which are ways of fitting the image into the border. To show the border, you need to actually have a <code>border</code> rule, but that can be integrated into the border-image by using something like:</p>

<pre><code>-webkit-border-image: url("image-url") 27 / 27px round round;
</code></pre>

<p>The <code>/ 27px</code> bit specifies the width of the border and makes it show if it isn&#8217;t already.</p>

<h3>9. Resizing</h3>

<p><big class='example' style="border:1px solid;resize:both;overflow:auto;max-width:100%">
This element is actually resizable.<br />If you&#8217;re using a compatible browser, drag the handle at the bottom right to resize this box.<br />Max-width is restricted to 100%.
</big></p>

<p>Making an element resizable is really easy: just set the <code>resize</code> property to <code>vertical</code>, <code>horizontal</code> or <code>both</code>.</p>

<p><big class='example' style="border:1px solid;resize:horizontal;overflow:auto;max-width:100%">
This box can only be resized horizontally (along the x-axis)
</big></p>

<p>To make scrollbars appear when the content doesn&#8217;t fit completely inside the box, it&#8217;s a good idea to set <code>overflow:auto;</code>.</p>

<p>Restrict the size that an element can be resized to by setting <code>min-width</code>, <code>min-height</code>, <code>max-width</code> and / or <code>max-height</code>.</p>

<h3>10. Colors and Opacity</h3>

<p><big class='example' style="background-color: hsla(100,90%,50%,0.6);">I am a-hued, a-saturated, and a-alpha-ed.</big></p>

<p>Colors can be set using <code>rgb(red, green, blue)</code>, <code>rgba(red, green, blue, alpha)</code>, <code>hsl(hue, saturation, lightness)</code> or <code>hsla(hue, saturation, lightness, alpha)</code>.</p>

<p>The example above has the rule <code>background-color: hsla(100,90%,50%,0.6);</code>.</p>

<hr />

<div class='example' style="background-color: black; opacity: 0.5; color: white"><big>
Easily set opacity. This element has a black background, but an alpha value of 0.5.<br />
<span style='color: yellow'>Opacity is inherited by any child elements.</span>
</big></div>

<p>Set <code>opacity</code> as a number between 0 (completely transparent) and 1 (completely opaque). If you don&#8217;t want the opacity to be inherited by child elements, set the background color using rgba or hsla and specify the alpha value there.</p>

<h2>Further reading:</h2>

<ul>
<li><a href="http://qooxdoo.org/documentation/general/webkit_css_styles">http://qooxdoo.org/documentation/general/webkit_css_styles</a></li>
<li><a href="http://www.css3.info">http://www.css3.info</a></li>
<li><a href="http://andybudd.com/presentations/css3">http://andybudd.com/presentations/css3</a></li>
</ul>

<p><style type="text/css">
    .example {
        display: block;
        padding: 3px;
        text-align: center;
    }
    .selection_hilite::selection {
        background: rgba(2, 2, 2, 0.8);
        color: white;
    }
</style></p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/iphone-webkit-css-3/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Writing internal commands for Quicksilver</title>
		<link>http://lipidity.com/apple/quicksilver-internal-commands/</link>
		<comments>http://lipidity.com/apple/quicksilver-internal-commands/#comments</comments>
		<pubDate>Mon, 25 Jun 2007 13:41:56 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[Quicksilver]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[plugin]]></category>

		<category><![CDATA[Tutorial]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/feature/tutorial/quicksilver-internal-commands</guid>
		<description><![CDATA[Internal commands in Quicksilver are essentially actions that don't require a subject (direct object) defined by the user. Most tasks, such as "Force Catalog Rescan", and some commands like "QS Preferences" are internal commands. The Clipboard plugin also adds a large number of internal commands so as you can see, they're quite useful in some circumstances.]]></description>
			<content:encoded><![CDATA[<p class='centre'><img src="http://dev.lipidity.com/wp-content/uploads/2007/06/quicksilver-internal-commands1.jpg" alt="[Quicksilver internal commands screenshot]" title="Internal commands in the Quicksilver catalog" class="feature" width="542" height="137" /><br /><small>Internal commands are found in the Quicksilver section of the Catalog.</small></p>

<p>There&#8217;s absolutely no documentation on how to write an internal command for Quicksilver <em>anywhere</em> and figuring out the internal workings of the application can be frustrating at best. This tutorial aims to fill that void and, like some of my other Quicksilver-related articles, provide you with the knowledge and resources to make a working internal command.</p>

<h2>Prerequisites</h2>

<p>An internal command is written much like a standard Quicksilver action, so the only thing required is the <a href="todo:lnk">Xcode project template</a> for creating Quicksilver plugins. (However, if you really need <em>another</em> project template for writing internal commands, just ask)</p>

<p>It would also be a good idea to familiarize yourself with <a href="http://dev.lipidity.com/feature/tutorial/anatomy-of-a-plugin-part-2" title="Quicksilver plugins in Xcode and Cocoa">writing a Quicksilver action</a> before going on.</p>

<h2>Info.plist keys</h2>

<p>Somewhere in the plist, you need to set QSLoadImmediately to true for Quicksilver to load your internal command properly. That&#8217;s simply:</p>

<pre><code>&lt;key&gt;QSLoadImmediately&lt;/key&gt;
&lt;true/&gt;
</code></pre>

<p>To register our internal command with Quicksilver, we need to add <code>QSInternalMessages</code> to the <code>QSRegistration</code> key. So, find the <code>QSRegistrationTemplate</code> key, rename it to <code>QSRegistration</code>, and configure the command in the following manner:</p>

<pre><code>&lt;key&gt;QSRegistration&lt;/key&gt;
&lt;dict&gt;
    &lt;key&gt;QSInternalMessages&lt;/key&gt;
    &lt;dict&gt;
        &lt;key&gt;testInternalCommand&lt;/key&gt;
        &lt;dict&gt;
            &lt;key&gt;target&lt;/key&gt;
            &lt;string&gt;testCommand&lt;/string&gt;
            &lt;key&gt;action&lt;/key&gt;
            &lt;string&gt;doTestCommand:&lt;/string&gt;
            &lt;key&gt;name&lt;/key&gt;
            &lt;string&gt;Just a Test&lt;/string&gt;
            &lt;key&gt;icon&lt;/key&gt;
            &lt;string&gt;&lt;/string&gt;
        &lt;/dict&gt;
        ...
</code></pre>

<p>What do the keys mean?</p>

<dl>
<dt>target</dt>
<dd>
<p>The class that will be running the internal command. This needs to be a singleton. More on that later.</p>
</dd>

<dt>action</dt>
<dd>
<p>An instance method that the target class responds to; this is the command.</p>
</dd>

<dt>name</dt>
<dd>
<p>A brief and meaningful name for your internal command.</p>
</dd>

<dt>icon</dt>
<dd>
<p>An icon for your command. You can use an identifier like <code>com.blacktree.Quicksilver</code> or <code>com.apple.AddressBook</code> and Quicksilver will load up the appropriate icon for you.</p>
</dd>
</dl>

<h2>The class</h2>

<p>As I mentioned earlier, the class that runs the command should be a singleton - that means only one copy of the class is instantiated and used (<a href="http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CocoaObjects/chapter_3_section_10.html">Apple&#8217;s documentation on singletons</a>). The internal command will be called like: <code>[[targetClass sharedInstance] doActionMethod:nil]</code> where <code>targetClass</code> is the class you specified under <code>target</code> and <code>doActionMethod:</code> is the method for the key <code>action</code> in the Info.plist.</p>

<p>From the example Info.plist excerpt given above, the class that would be written would look something like this:</p>

<pre><code>// testCommand.h

#import &lt;QSCore/QSActionProvider.h&gt;

@interface testCommand : QSActionProvider
{
}
+ (id)sharedInstance;
-(IBAction)doTestCommand:(id)sender;
@end
</code></pre>

<hr />

<pre><code>// testCommand.m

#import "testCommand.h"

@implementation testCommand

// Following few methods to make this class a singleton

static testCommand *sharedTestCommandManager = nil;

+ (id)sharedInstance {
    if (sharedTestCommandManager == nil) {
        [[self alloc] init]; // assignment not done here
    }
    return sharedTestCommandManager;
}
+ (id)allocWithZone:(NSZone *)zone{
    //    @synchronized(self) {
    if (sharedTestCommandManager == nil) {
        sharedTestCommandManager = [super allocWithZone:zone];
        return sharedTestCommandManager;  // assignment and return on first allocation
    }
    //      }
    return nil; //on subsequent allocation attempts return nil
}
- (id)copyWithZone:(NSZone *)zone{
    return self;
}
- (id)retain{
    return self;
}
- (unsigned)retainCount{
    return UINT_MAX;  //denotes an object that cannot be released
}
- (void)release{
    //do nothing
}
- (id)autorelease{
    return self;
}

// Method to perform the internal command

-(IBAction)doTestCommand:(id)sender
{
    NSLog(@"Running test internal command...");
    // do something useful
}

@end
</code></pre>

<p>And that&#8217;s it. Possibly the shortest ever Quicksilver development tutorial you&#8217;re going to see in a while.</p>

<p><a name="cube-smoking" id="cube-smoking"></a></p>

<p>I thought I&#8217;d drive home the usefulness of internal commands by showing off a little something I&#8217;ve been playing with for a while.</p>

<p class='centre'><img class='feature' src="http://dev.lipidity.com/wp-content/uploads/2007/06/quicksilver-cube-disco-smoking.png" alt="[Quicksilver Cube Smoking]" title="Quicksilver cube interface smoking" longdesc="http://dev.lipidity.com/feature/tutorial/now-this-is-hot-cocoa" width="290" height="375" /><br /><small>A simple internal command allows any interface to smoke</small></p>

<p>Yeah, it&#8217;s the cube interface. Smoking.</p>

<p>In fact, with this internal command, I can make <em>anything</em> smoke.</p>

<p class='centre'><a rel="lightbox" href="http://dev.lipidity.com/wp-content/uploads/2007/06/primer-smoking.jpg" title="Quicksilver Primer interface smoking"><img src="http://dev.lipidity.com/wp-content/uploads/2007/06/primer-smoking-thumb.jpg" alt="[Primer interface smoking]" title="Quicksilver Primer interface smoking" width="426" height="343" class='feature' /></a></p>

<h2>Summary</h2>

<ul>
<li>Add QSLoadImmediately key, set to true</li>
<li>Add QSInternalMessages to the QSRegistration key</li>
<li>Write singleton class that runs the command</li>
</ul>

<p>As always, I&#8217;ll be thrilled to see what you come up with.</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/quicksilver-internal-commands/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Secret Quicksilver animation effects</title>
		<link>http://lipidity.com/apple/quicksilver-animation-effects/</link>
		<comments>http://lipidity.com/apple/quicksilver-animation-effects/#comments</comments>
		<pubDate>Wed, 20 Jun 2007 02:00:14 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[Quicksilver]]></category>

		<category><![CDATA[Animation]]></category>

		<category><![CDATA[CoreGraphics]]></category>

		<category><![CDATA[GUI]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[plugin]]></category>

		<category><![CDATA[Tutorial]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/feature/tutorial/quicksilver-animation-effects</guid>
		<description><![CDATA[You may have had a shot at creating a Quicksilver interface. (If you haven't, see <a href="http://dev.lipidity.com/feature/tutorial/quicksilver-interface-tutorial">the tutorial</a>). While it's good fun to play with changing the colors and positions of the controls, there is a whole lot of really clever code in Quicksilver that lets you go beyond that and play with some weird and wacky effects on <em>any</em> window.]]></description>
			<content:encoded><![CDATA[<p class="centre"><a rel="lightbox" href="http://dev.lipidity.com/wp-content/uploads/2007/06/quicksilver-cube-animation.png" title="Mac Cube Transition Effect"><img alt="[Quicksilver Cube Effect]" title="Image of Core Graphics cube transition effect" src="http://dev.lipidity.com/wp-content/uploads/2007/06/quicksilver-cube-effect.png" class="feature" width="292" height="233" /></a><br /><small>Quicksilver is capable of some very futuristic transition effects</small></p>

<h2>Standard Animation Effects</h2>

<p>Quicksilver adds a category to the NSWindow class to allow for some pretty cool effects.
The following should be pretty self-explanatory:</p>

<pre><code>-(void)pulse:(id)sender;
-(void)flare:(id)sender;
-(void)shrink:(id)sender;
-(void)fold:(id)sender;
</code></pre>

<p>What these methods essentially mean, is that you can pulse, flare, shrink or fold <em>any window</em> you have a reference to in a plugin - whether it&#8217;s an interface or dialog or something completely different. Eg, just call <code>[window shrink:nil]</code> and watch that NSWindow shrink down to nothing, or <code>[window flare:nil]</code> to make it burst away!</p>

<h2>Private Core Graphics Animations</h2>

<p>Quicksilver also adds methods to use private <a href="http://dev.lipidity.com/feature/tutorial/xcode-transitions-core-graphics-image-2" title="Core Graphics Transitions Tutorial">Core Graphics transitions</a> for instances of NSWindow or its subclasses. The main method is defined something like:</p>

<pre><code>- (void) displayWithTransition:(CGSTransitionType)type option:(CGSTransitionOption)option duration:(float)duration;
</code></pre>

<p>The transitions you have access to are fade, zoom, reveal, slide, warp-fade, swap, warp-switch and the famous cube animation. You can use them on any window, for example:</p>

<pre><code>[window displayWithTransition:CGSCube option:CGSLeft duration:1.3];
</code></pre>

<p>To learn more about Core Graphics transitions, see the <a href="http://dev.lipidity.com/feature/tutorial/ebook-xcode-animations-core-graphics" title="Core Graphics Animations and Transitions Tutorial">Core Graphics ebook</a>, or play around with the <a href="http://dev.lipidity.com/apple/core-transitions-framework" title="Core Graphics and Core Image transition animations">Core Transitions Framework</a>.</p>

<p class="yellow_note">Quicksilver&#8217;s CGSPrivate.h file is missing CGSFlip, but you can run the Dashboard-style flip effect by using the integer 9.</p>

<h2>Quicksilver&#8217;s own animations</h2>

<p>Alcor has used various techniques to write several very interesting animation effects into Quicksilver. You&#8217;ll be familiar with some of these (just watch the Primer interface activate and deactivate) but for whatever reason, many of these bizarre animations never made into an interface. They&#8217;re really very clever. I&#8217;ve played around with some of these:</p>

<ul>
<li>QSGrowEffect</li>
<li>QSShrinkEffect</li>
<li>QSSlightGrowEffect</li>
<li>QSSlightShrinkEffect</li>
<li>QSBingeEffect</li>
<li>QSPurgeEffect</li>
<li>QSExplodeEffect</li>
<li>QSExtraExtraEffect</li>
<li>QSShakeItLikeAPolaroidPictureEffect</li>
<li>QSBoobTubeEffect</li>
<li>QSVExpandEffect</li>
<li>QSVillainousKryptonianEffect</li>
<li>QSMMBlowEffect</li>
<li>QSLudicrousSpeedEffect</li>
</ul>

<p>Very interesting to look at, but how does one use these effects?</p>

<p>As we are dealing with Quicksilver, the solution is (as expected) very elegant. There are very simple methods to set a show, hide or execute effect for a window. These methods don&#8217;t even require an explanation; they&#8217;re so simple:</p>

<pre><code>// Effect for showing the QSWindow
[window setShowEffect:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;QSSlightGrowEffect&quot;,@&quot;transformFn&quot;,@&quot;show&quot;,@&quot;type&quot;,[NSNumber numberWithFloat:2.0],@&quot;duration&quot;,nil]];

// Effect for hiding the QSWindow
[window setHideEffect:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;QSSlightShrinkEffect&quot;,@&quot;transformFn&quot;,@&quot;hide&quot;,@&quot;type&quot;,[NSNumber numberWithFloat:2.0],@&quot;duration&quot;,nil]];

// The "execute" effect is slightly different:
[window setWindowProperty:[NSDictionary dictionaryWithObjectsAndKeys:@&quot;QSExplodeEffect&quot;,@&quot;transformFn&quot;,@&quot;hide&quot;,@&quot;type&quot;,[NSNumber numberWithFloat:1.5],@&quot;duration&quot;,nil] forKey:kQSWindowExecEffect];</code></pre>

<p>Easy!</p>

<h2>Sample plugin</h2>

<p><a href="http://dev.lipidity.com/wp-content/uploads/2007/06/effects.zip" title="Download Quicksilver Effects Plugin"><img class="fright" src="http://qs.lipidity.com/fumo/QSPlugin.png" title="Quicksilver Plugin Icon" alt="[Plugin Icon]" height="128" width="128" /></a> 
I don&#8217;t dare mention all this private goodness and not even provide a demonstration. I&#8217;ve created an &#8220;Effects&#8221; plugin that will allow you to change the activate, deactivate and execute effects for <em>any</em> Quicksilver interface temporarily to play around with the effects. Just for good measure, I&#8217;ve also thrown in an action that lets you explore Core Graphics transitions as well.</p>

<p>This is not really a bona fide Quicksilver plugin; while it does let you have some fun with the effects, it&#8217;s not very user-friendly and doesn&#8217;t save your configuration. 
If these animations prove to be popular, then I&#8217;ll write a proper plugin to let you configure the effects more easily (probably through a preference pane) and remembers your settings.</p>

<p class="download"><a href="http://dev.lipidity.com/wp-content/uploads/2007/06/effects.zip" title="Download Quicksilver Effects Plugin">Download Quicksilver Effects Plugin</a></p>

<h4>Usage</h4>

<p>Type in the name of the effect you want, then use &#8220;Set Hide Effect&#8221;, &#8220;Set Show Effect&#8221; or the &#8220;Set Exec Effect&#8221; action. The list of effects is given <a href="#toc-quicksilvers-own-animations">above</a>; just type one in and run the relevant action.</p>

<p>To run a Core Graphics transition, type in the name of the transition, and use the &#8220;Run CoreGraphics Transition&#8221; action. You can optionally specify a direction in the indirect selector. (You can enter text in the direct and indirect selectors by pressing the period &#8220;.&#8221; key)</p>

<h4>For example</h4>

<ul>
<li><big>&#8220;QSBingeEffect&#8221; -&gt; Set Show Effect</big></li>
<li><big>&#8220;QSPurgeEffect&#8221; -&gt; Set Hide Effect</big></li>
<li><big>&#8220;QSExplodeEffect&#8221; -&gt; Set Exec Effect</big></li>
<li><big>&#8220;flip&#8221; -&gt; Run CoreGraphics Transition</big></li>
<li><big>&#8220;slide&#8221; -&gt; Run CoreGraphics Transition -&gt; &#8220;up&#8221;</big></li>
<li><big>&#8220;swap&#8221; -&gt; Run CoreGraphics Transition -&gt; &#8220;inout&#8221;</big></li>
</ul>

<p class="centre">
<a rel="lightbox[demo]" href='http://dev.lipidity.com/wp-content/uploads/2007/06/set-show-effect.png' title='Set Show Effect'><img src='http://dev.lipidity.com/wp-content/uploads/2007/06/set-show-effect.thumbnail.png' alt='Set Show Effect' width='108' height='128' /></a>
<a rel="lightbox[demo]" href='http://dev.lipidity.com/wp-content/uploads/2007/06/set-hide-effect.png' title='Set Hide Effect'><img src='http://dev.lipidity.com/wp-content/uploads/2007/06/set-hide-effect.thumbnail.png' alt='Set Hide Effect' width='108' height='128' /></a>
<a rel="lightbox[demo]" href='http://dev.lipidity.com/wp-content/uploads/2007/06/set-exec-effect.png' title='Set Exec Effect'><img src='http://dev.lipidity.com/wp-content/uploads/2007/06/set-exec-effect.thumbnail.png' alt='Set Exec Effect' width='106' height='128' /></a>
<a rel="lightbox[demo]" href='http://dev.lipidity.com/wp-content/uploads/2007/06/core-graphics-cube.png' title='Core Graphics Cube Effect'><img src='http://dev.lipidity.com/wp-content/uploads/2007/06/core-graphics-cube.thumbnail.png' alt='Core Graphics Cube Effect' width='105' height='128' /></a>
<a rel="lightbox[demo]" href='http://dev.lipidity.com/wp-content/uploads/2007/06/core-graphics-swap-effect.png' title='Core Graphics Swap Effect'><img src='http://dev.lipidity.com/wp-content/uploads/2007/06/core-graphics-swap-effect.thumbnail.png' alt='Core Graphics Swap Effect' width='92' height='128' /></a><br />
<small>Pictures show how to use the effects plugin. Actual animations are not shown.</small>
</p>

<hr />

<p>Quicksilver has many such hidden surprises and nifty time-saving methods; it&#8217;s so well thought out and full of these amazing gems!</p>

<p>What do you think about these animations? Be sure to let me know if you&#8217;d like a proper, more user-friendly plugin to use these effects.</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/quicksilver-animation-effects/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Write your own Quicksilver interface</title>
		<link>http://lipidity.com/apple/quicksilver-interface-tutorial/</link>
		<comments>http://lipidity.com/apple/quicksilver-interface-tutorial/#comments</comments>
		<pubDate>Tue, 05 Jun 2007 02:00:17 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[Quicksilver]]></category>

		<category><![CDATA[GUI]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[plugin]]></category>

		<category><![CDATA[Tutorial]]></category>

		<category><![CDATA[Xcode]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/feature/tutorial/quicksilver-interface-tutorial</guid>
		<description><![CDATA[Writing your own interface for Quicksilver is surprisingly easy, especially if you have experience in Cocoa and Xcode. Having covered the basics about the <a href="http://dev.lipidity.com/feature/tutorial/anatomy-of-a-plugin-infoplist-part-1" title="Basics of writing a Quicksilver plugin">QSPlugin key</a> in the Info.plist, as well the as the fundamentals of writing <a href="http://dev.lipidity.com/feature/tutorial/anatomy-of-a-plugin-part-2" title="Quicksilver plugin development">Quicksilver actions using Xcode</a>, we are ready to start in a completely new direction. The Quicksilver interface.]]></description>
			<content:encoded><![CDATA[<h2>Setup Xcode</h2>

<p><a name="download" id="download"></a>
<a href='http://dev.lipidity.com/wp-content/uploads/2007/06/quicksilver-interface-plug-in.zip' title='Xcode Project Template (Quicksilver interface)'><img src='http://dev.lipidity.com/wp-content/uploads/2007/04/xcode-project.png' alt='[Download Quicksilver Interface Project Template]' title='Xcode Project Template' longdesc='Xcode Project Template for creating a Quicksilver interface.' height='128' width='128' class='fright' /></a>
Writing an interface is very similar to writing an action, but the classes and Info.plist keys are somewhat different. <big>Download the <a href="http://dev.lipidity.com/wp-content/uploads/2007/06/quicksilver-interface-plug-in.zip" title="Quicksilver Interface Project Template for Xcode">QS Interface Project Template</a></big>. If you haven&apos;t previously downloaded a Quicksilver plugin template for Xcode, you&apos;ll have to do some <a href="http://lipidity.com/apple/quicksilver-plugins-in-objective-c">basic setup</a>.</p>

<p>Once you&apos;ve installed the project template, you can build a new interface project &quot;out-of-the-box&quot; to make sure it works.</p>

<p class='yellow_note'>Unfortunately, development isn&#8217;t a linear process, so you&#8217;ll probably have to keep referring back to different sections of this article as you develop your interface.</p>

<!--

### Got Class? ###

The class that is subclassed in the interface plugin is itself a subclass of `NSWindowController` called `QSInterfaceController`. By default, the project uses `QSResizingInterfaceController`, which is able to handle expanding and collapsing of the interface as well. Most of the work that needs to be done with regard to notifications, updating actions, executing or canceling commands, etc. is taken care of by the superclass. However you need to write any animations, effects, bindings, custom controls or extra features.

-->

<h2>Info.plist keys specifications</h2>

<p><img src="http://dev.lipidity.com/wp-content/uploads/2007/02/5_info_plist.png" alt="Info.plist icon" title="Info.plist icon" class='fright no-space' />We tell Quicksilver that we&apos;re providing it an interface in the <em>QSRegistration</em> section of the Info.plist file, under <em>QSCommandInterfaceControllers</em>. By default, this should have been already added in when you created the project.</p>

<pre><code>&lt;key&gt;QSRegistration&lt;/key&gt;
&lt;dict&gt;
    &lt;key&gt;QSCommandInterfaceControllers&lt;/key&gt;
    &lt;dict&gt;
        &lt;key&gt;testInterface&lt;/key&gt;
        &lt;string&gt;testInterface&lt;/string&gt;
    &lt;/dict&gt;
    . . .
    . . .
&lt;/dict&gt;
</code></pre>

<p>There is also a key called <em>QSPreferencePanesTemplate</em> inside <em>QSRegistration</em>. If you wish to have a preference pane for your plugin, rename the key to <em>QSPreferencePanes</em> and <a href="#toc-preference-panes">create the pref pane</a>; otherwise you can leave it or delete it. As per the previous setting, these values should be filled in already by the project.</p>

<pre><code>&lt;key&gt;QSRegistration&lt;/key&gt;
&lt;dict&gt;
    . . .
    . . .
    &lt;key&gt;QSPreferencePanesTemplate&lt;/key&gt;
    &lt;dict&gt;
        &lt;key&gt;testInterfacePrefPane&lt;/key&gt;
        &lt;dict&gt;
            &lt;key&gt;class&lt;/key&gt;
            &lt;string&gt;QSPreferencePane&lt;/string&gt;
            &lt;key&gt;description&lt;/key&gt;
            &lt;string&gt;testInterface interface preferences&lt;/string&gt;
            &lt;key&gt;icon&lt;/key&gt;
            &lt;string&gt;&lt;/string&gt;
            &lt;key&gt;name&lt;/key&gt;
            &lt;string&gt;testInterface&lt;/string&gt;
            &lt;key&gt;nibBundle&lt;/key&gt;
            &lt;string&gt;com.blacktree.Quicksilver.testInterface&lt;/string&gt;
            &lt;key&gt;nibName&lt;/key&gt;
            &lt;string&gt;testInterfacePrefPane&lt;/string&gt;
            &lt;key&gt;type&lt;/key&gt;
            &lt;string&gt;hidden&lt;/string&gt;
        &lt;/dict&gt;
    &lt;/dict&gt;
&lt;/dict&gt;
</code></pre>

<p class='yellow_note'>If you&apos;re not having a preference pane, you should remove the PrefPane.nib file from your project when you&apos;re ready to release your plugin; it&apos;ll save bandwidth as well as reduce clutter.</p>

<p>You may not have an idea of the bindings you&#8217;ll be using yet (or maybe you do), but when you do use them, it&apos;s good practice to specify some default values for Quicksilver to use when the value hasn&apos;t been set by the user. These values go in the <em>QSDefaults</em> key.</p>

<pre><code>&lt;key&gt;QSDefaultsTemplate&lt;/key&gt;
&lt;dict&gt;
    &lt;key&gt;interface.bindingname&lt;/key&gt;
    &lt;string&gt;value&lt;/string&gt;
    &lt;key&gt;interface.bindingname2&lt;/key&gt;
    &lt;real&gt;2.54328&lt;/real&gt;
    &lt;key&gt;interface.bindingname2&lt;/key&gt;
    &lt;integer&gt;4&lt;/integer&gt;
&lt;/dict&gt;
</code></pre>

<p class='yellow_note'>If you&apos;re using the &quot;QSDefaults&quot; key, make sure you&#8217;re renamed it from &quot;QSDefaultsTemplate&quot; to &quot;QSDefaults&quot;.</p>

<p>Don&#8217;t forget there&#8217;s also a <a href="http://lipidity.com/apple/anatomy-of-a-plugin-infoplist-part-1"><em>QSPlugin</em> section</a> in the Info.plist file that you should fill in.</p>

<h2>Coding</h2>

<p>That&apos;s the Info.plist file out of the way for now. It&apos;s time to start coding!</p>

<p>There are a few basic Quicksilver terms I hope you&apos;re familiar with:</p>

<p class='centre'>
<img class='feature' src="http://dev.lipidity.com/wp-content/uploads/2007/06/qs-selectors1.png" alt="[Quicksilver Interface Selectors]" title="Quicksilver interface selectors" /><br />
<small>Fig 1. The selectors are the used to pick the direct object, action, and indirect object respectively. Indirect object is often optional or not required.</small>
</p>

<p>Arrangement and positioning of the views using Interface Builder is left as an exercise for the reader. You don&apos;t want a lesson on how to drag and drop, do you?</p>

<h3>Controlling the Controller</h3>

<p>As mentioned before, the superclass (<code>QSResizingInterfaceController</code>) handles most of the work for you, therefore the majority of code you add will not be in new methods. Most of the code you write is (probably) going to be in existing methods that you will subclass.</p>

<h4>Major methods</h4>

<p>Here are the main methods you may decide to add extend:</p>

<dl>
<dt>- windowDidLoad</dt>
<dd>
<p>Anything that requires interaction with the interface window when it is first loaded. As the name implies, this method is called when the interface window is first loaded. All your setup <em>with the window</em> goes in this method. For example, setting the colors, adding bindings, and choosing animation effects for hiding / showing the interface etc. Please make sure you call <code>[super windowDidLoad];</code> somewhere to let Quicksilver to do its setup as well.</p>

<p>This is not the place to add initialization code for the class itself. There&apos;s an <code>-init</code> method for that.</p>
</dd>

<dt>- maxIconSize</dt>
<dd>
<p>The maximum size allowed for icons in the interface selectors. Adjust this depending on how big or small your interface is. It&apos;s set at 128 x 128 by default, which should be fine in most circumstances.</p>
</dd>

<dt>- showMainWindow:</dt>
<dd>
<p>Any fancy animations or transitions you want for when the interface is being shown can go in here. You could also do something like: <code>if ( [[self window]isVisible] ) [[self window] pulse:self];</code>. (The pulse method is explained later). If you&apos;re having your own transition effect and don&apos;t want Quicksilver&apos;s default fade-in animation, run <code>[window setFastShow:YES]</code>.</p>

<p>If you can, call the super implementation of the method where you would call <code>-makeKeyAndOrderFront:</code>, otherwise the option to suppress hotkeys while the command window is shown wont be honored.</p>
</dd>

<dt>- hideMainWindow:</dt>
<dd>
<p>Calling the super&apos;s implementation will hide the window with Quicksilver&apos;s effect. If you&apos;re using your own animation, you can run <code>[window setHideEffect:nil]</code> so Quicksilver doesn&apos;t run its own effect as well.</p>
</dd>

<dt>- activateInTextMode:</dt>
<dd>
<p>The use of the &quot;Activate in Text Mode&quot; trigger may be a rare occasion, but it&apos;s a cool place to throw in a surprising animation. <a href="http://dev.lipidity.com/downloads/fumo" title="Fumo Quicksilver Interface">Fumo</a> has used <a href="http://dev.lipidity.com/index.php?tag=core-graphics" title="Core Graphics Animation and Transition Effects">Core Graphics</a> warp and cube effects for this in the past.</p>
</dd>
</dl>

<h4>Expansion</h4>

<p>If you&apos;re having your interface expand and collapse, you&apos;ll need to subclass the following methods:</p>

<dl>
<dt>- showIndirectSelector:</dt>
<dd>
<p>Position the indirect selector in an appropriate location on the window. It may be useful to position it relative to another object, for example: <code>[iSelector setFrame:NSOffsetRect([aSelector frame],0,-250)];</code>
Don&apos;t forget to call super!</p>
</dd>

<dt>- expandWindow:</dt>
<dd>
<p>Expand your interface. You&apos;ll probably be using <code>[[self window] setFrame: display: animate:]</code> to resize the window smoothly.</p>
</dd>

<dt>- contractWindow:</dt>
<dd>
<p>As per <code>-expandWindow:</code>, but make the window smaller.</p>
</dd>

<dt>-hideIndirectSelector:</dt>
<dd>
<p>In most cases you wont need to subclass this. It just hides the indirect selector.</p>
</dd>
</dl>

<h2>Preference Panes</h2>

<h3>The easy stuff</h3>

<p>Creating your preference pane is easy since a lot of the work is done for you by the project template. There&apos;s a .nib file included in the interface project called &quot;testInterfacePrefPane&quot; (where &quot;testInterface&quot; is the name of your Xcode project). With this .nib file:</p>

<ol>
<li>Open it.</li>
<li>Add controls and bindings.</li>
<li>Save and quit.</li>
</ol>

<p>That&#8217;s <em>creating</em> it, though. There&apos;s still a little more work to be done.</p>

<h3>Info.plist keys</h3>

<p>Remember the <em>QSPreferencePanes</em> key I mentioned earlier? That needs to be present under the QSRegistration key in the Info.plist file. You don&#8217;t need to configure it, but you can change some keys like <em>description</em> with a short summary of the preference pane, or set an <em>icon</em>.</p>

<p>(Reminder: Make sure to drop the &quot;Template&quot; from &quot;QSPreferencePanesTemplate&quot;)</p>

<h3>The &quot;Customize&quot; button</h3>

<p>To set a customize button to show the preference pane for your interface, simply uncomment the <code>-customize:</code> method that&apos;s added in by default. It&#8217;s that easy.</p>

<pre><code>- (IBAction)customize:(id)sender{
    [[NSClassFromString(@"QSPreferencesController") sharedInstance] showPaneWithIdentifier:@"testInterfacePrefPane"];
}</code></pre>

<h3>A note on bindings</h3>

<p>When the user changes something in the preference pane, the binding will be updated. And that&#8217;s it. You&#8217;ll need to bind your classes / controls not only in the preference pane, but also in your code so that any changes to bindings reflect in your interface. For example, if you add a binding for &quot;testInterface.fadeStyle&quot;, you may want to do something like:</p>

<pre><code>[self bind:@"fadeStyle"
     toObject:[NSUserDefaultsController sharedUserDefaultsController]
  withKeyPath:@"values.testInterface.fadeStyle"
      options:nil];</code></pre>

<p class='note'>If you&#8217;re binding an NSColor, make sure to use NSUnarchiveFromDataTransformerName</p>

<h2>Building</h2>

<p>Once you&#8217;ve got your code ready, build the project.</p>

<p>(Don&#8217;t puke if you get warnings that you can&#8217;t get rid of; there will be a few warnings regarding some methods like <code>-setWindowProperty:</code>, and another great error if you add a preference pane and the customize button. We&#8217;ll have to live with them for now.)</p>

<p>Double-click on the built product to have Quicksilver install it. If there are no serious faults with the code, you&#8217;ll see your Incredible Interface&trade; and be able to enjoy, use, and distribute it!</p>

<h2>Summary</h2>

<ul>
<li>Download the <a href="#download" title="Quicksilver Interface Project Template for Xcode">Xcode Project Template</a>, making sure everything else is <a href="http://lipidity.com/apple/quicksilver-plugins-in-objective-c" title="Setup Xcode for Quicksilver plugin development">setup correctly</a></li>
<li>Add code to the subclass of <code>QSResizingInterfaceController</code></li>
<li>Arrange the views in Interface Builder</li>
<li>Add preference pane and bindings</li>
<li>Build project</li>
<li>Test and distribute</li>
</ul>

<p>If you need any additional information or resources, help is always available at the <a href="http://blacktree.cocoaforge.net/forums/">Quicksilver forums</a> or you can contact me.</p>

<p>Be sure to show me how you go with your interface!</p>

<h4>Also in this series</h4>

<h6><a href="http://lipidity.com/apple/quicksilver-plugins-in-objective-c" title="Step by step guide to writing plugins for Quicksilver in Cocoa using Xcode.">Quicksilver plugins in Objective-C</a></h6>

<blockquote><p>A guide to obtaining the required resources for Quicksilver plugin development in Xcode. Also runs through setting up Xcode to make creating plugins easier.</p></blockquote>

<h6><a href="http://lipidity.com/apple/anatomy-of-a-plugin-infoplist-part-1">Info.plist - QSPlugIn</a></h6>

<blockquote><p>The various sections of Quicksilver plugins, including the basics on how to properly configure your plugin, setup the correct options and settings, and how and where to write your plugin.</p></blockquote>

<h6><a href="http://lipidity.com/apple/anatomy-of-a-plugin-part-2" title="How to write a Quicksilver action using Xcode and Cocoa.">Quicksilver Actions</a></h6>

<blockquote><p>A quick look at QSActions in the Info.plist, followed by our first look at the code needed to get a plugin up and running.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/quicksilver-interface-tutorial/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Zap unwanted apps the Quicksilver way</title>
		<link>http://lipidity.com/apple/zap-apps-quicksilver/</link>
		<comments>http://lipidity.com/apple/zap-apps-quicksilver/#comments</comments>
		<pubDate>Wed, 09 May 2007 12:23:23 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Quicksilver]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/feature/tutorial/zap-apps-quicksilver</guid>
		<description><![CDATA[<a href="http://appzapper.com" title="AppZapper">AppZapper</a>, the <q>uninstaller Apple forget</q>, is a great way to remove applications along with any <del>garbage</del> files they may have left on your system in the form of preferences, caches, and application support. Using Quicksilver, removing an application with AppZapper is as easy as a simple hotkey or trigger.]]></description>
			<content:encoded><![CDATA[<p class='centre'><img src='http://dev.lipidity.com/wp-content/uploads/2007/05/app-zapz.png' alt='AppZapper' class='feature' height="333" width="476" /><br />
<small class='centre'>AppZapper allows the removal of software along with any associated files.
</small>
</p>

<p>I considered writing a Quicksilver plugin to add a &#8220;Zap!&#8221; action, but the solution is so much easier!</p>

<p>You&#8217;ll need to make sure proxy objects are enabled (Enable advanced features, and enable Proxy Objects in the Quicksilver catalog). Then, add a trigger for:
<big>Current Application -&gt; Open With Quicksilver</big>.
You can now simply run the trigger when you have the application that needs to be zapped open and out pops AppZapper, ready to banish the application to the land of the Trash Can.</p>

<p>As with every other Quicksilver trick, you can extend this. You can use <q>Finder Selection</q> or <q>Quicksilver Selection</q> instead of <q>Current Application</q> to zap apps from the Finder or from Quicksilver&#8217;s direct object pane respectively. Another possibility is to use a mouse trigger, and run <q>Open With &#8230; AppZapper</q> on the dragged-in file. Whatever suits you.</p>

<p>Got any more handy Quicksilver tricks that you&#8217;d like to share? Post them up in the comments.</p>

<p>[ There is a freeware clone of AppZapper available called <a href="http://reggie.ashworth.googlepages.com/appdelete">AppDelete</a>. ]</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/zap-apps-quicksilver/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
