Archive for December, 2008

More Blaqua

moreblaqua

A couple years ago, some lad going by the pseudonym of @binderskagnaes, at DeviantArt, released a set of icons on a dark background lovingly named “Blaqua.”

Then, he ventured to a great forest and got devoured. Or something.
Whatever the reason, he never created more icons, which frankly is a pity.
I am still using his icon set in my Dock, unfortunately the set was created before Twitter got popular, uTorrent or Evernote were released on OS X, etc.
So, I took a few hours to re-create an original dark PSD and put together a pack of 24 new icons.

I will create more packs if my beloved readers suggest more applications.

In the meantime, go get it!

If you enjoyed this post, make sure you subscribe to my RSS feed!


GMail is the new Mutt! Shortcuts galore.

I know, it’s a bold assertion. But, please, bear with me: as a longtime Unix-head, I need a tool that allows me to zoom through my emails rather than click-glance-click-glance-click-yawn-right-click-delete, etc.

For years I’ve been happy with Mutt because nothing compares with using the arrow keys to navigate through my emails, ALT-O to open a folder, SHIFT-O-R to do a reverse-sort, M for a new message, etc.
That, and using Visor, give me the comfort of a HUD-based email management tool whose speed is quite unbeatable.

Unfortunately, with today’s evolution of mail, everything is more or less HTML-based, which really doesn’t work well with Mutt — even using V to open in a text-based browser isn’t that good. If I ask Mutt to open a full-fledged browser instead, there goes the speed advantage…

So, I have reluctantly moved to a pure Google Mail solution and my experience has been positive so far: I run GMail as a standalone program using Fluid — on another platform I would use Prism — and I can keep using keyboard shortcuts for all my tasks!

If you wish to give it a try, start with only this subset of GMail’s keyboard shortcuts: JKEX#[ENTER]U are all you need to replicate 99% of your Mutt experience…

K/J: cursor up/down
X: select message
E: archive messages
#: delete messages
ENTER: read message
U: back to messages list

If you enjoyed this post, make sure you subscribe to my RSS feed!


Adobe Alchemy: Passing a ByteArray from Flex to C++

fxlogoI started playing with Alchemy a couple days ago, with the intent of finally writing OpensIFRr3 — you know, the one working with sIFR3. Since the previous release was in Java, I was planning on creating this one in Flex.
I am not quite there yet, due to the nightmare that porting libxml would be. But I’ve learnt that reading Alchemy’s currently meager documentation could have saved me a few headaches. For instance, do not assume that you will find here some of the magic that other “gateways” offer. More specifically, do not assume that a ByteArray will automatically be passed from ActionScript to C++ as a char *.
Nope, it’s passed as a ByteArray structure, with all sorts of fun overhead that will drive you crazy if you assume a “StringType” object.

If this is gibberish to you, keep reading:
Yes, Alchemy is verbose.
No, you should not fear its complexity.

Here is how I read a compressed flash file in a ByteArray, in Flex, then pass it to C++ for parsing. Obviously it is the start of OpensIFRr3 (jump to the end of the listing if you are only curious about seeing an Alchemy call in action):

?View Code ACTIONSCRIPT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package
{
	import flash.display.Sprite;
	import flash.filesystem.File;
	import flash.filesystem.FileMode;
	import flash.filesystem.FileStream;
	import flash.utils.ByteArray;
	import flash.utils.CompressionAlgorithm;
	import cmodule.swfmill.CLibInit; // My C code
 
	public class EchoTest extends Sprite
	{
		private var length:uint;
		private var compressed:Boolean;
		private var version:uint
		private var sig:String;
		private var data:ByteArray;
 
		private function main_fread_uint(fs:FileStream):uint
		{
			return fs.readUnsignedByte();	
		}
 
		private function main_fread_char(fs:FileStream):String
		{
			return String.fromCharCode(fs.readUnsignedByte());	
		}
 
		private function main_fread_str(fs:FileStream, offset:uint, length:uint):String
		{
			var ba:ByteArray = new ByteArray();
			fs.readBytes(ba, offset, length);
			return ba.toString();
		}
 
		private function main_load(name:String):Boolean
		{
			try
			{
				var file:File = new File("/Users/Chris/Projects/sIFRr3/rockwell.swf");
				var fs:FileStream = new FileStream();
				if(!file.exists)
				{
					trace("File does not exist");
					return false;
				}
				fs.open(file, FileMode.READ);
				sig = main_fread_str(fs, 0, 3);
				version = main_fread_uint(fs);
				if(sig != "CWS" && sig != "FWS")
				{
					trace("ERROR: input is no SWF");
					return false;
				}
				length = main_fread_uint(fs);
				length += main_fread_uint(fs) << 8;
				length += main_fread_uint(fs) << 16;
				length += main_fread_uint(fs) << 24;
				length -= 8;
				compressed = sig.charAt(0) == 'C';
				if(length != file.size - 8)
				{
					if( length > file.size - 8 && !compressed)
					{
						trace("WARNING: size specified in SWF (" + length + ") != file.size (" + file.size + "), using filesize-8.");
						length = file.size - 8;
					}
				}
				data = new ByteArray();
				fs.readBytes(data);
				if(compressed)
				{
					data.uncompress(CompressionAlgorithm.ZLIB);					
				}
				fs.close();
			}
			catch(e:Error)
			{
				trace("Error: " + e.message);
				return false;
			}				
			return true;
		}
 
		public function SWFTest()
		{
			var loader:CLibInit = new CLibInit;
			var lib:Object = loader.init();
 
			if(main_load("/Users/Chris/Projects/sIFRr3/rockwell.swf"))
			{
				trace("ASLength = " + data.length);
				lib.swfmill_swf2xml(version, data.length, data); // Exported method
			}
		}
	}
}

The magic happens here: lib.swfmill_swf2xml(…)

Let’s have a look a this little guy in his natural habitat — in swmill.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
	//define the methods exposed to ActionScript
	//typed as an ActionScript Function instance
	AS3_Val swfmill_swf2xml_method = AS3_Function( NULL, swfmill_swf2xml);
 
	// construct an object that holds references to the functions
	AS3_Val result = AS3_Object( "swfmill_swf2xml: AS3ValType", swfmill_swf2xml_method );
 
	// Release
	AS3_Release( swfmill_swf2xml_method );
 
	// notify that we initialized -- THIS DOES NOT RETURN!
	AS3_LibInit( result );
 
	// should never get here!
	return 0;
}

So, main() will be invoked when the program instance comes up and Flex will be informed that there is a method of interest (swfmill_swf2xml).

Digression:
I know, this is a bit hard to read, but so far most of Alchemy is. After all, the whole bridge relies on the C++ code being compiled to bytecode that is linked indirectly against Flash libraries, the result being turned into ActionScript that will then be compiled to asm-asc. If you look at the work files, you will see ActionScript mixed directly with what looks like assembly code. To quote Adobe, the end-result is “basically one huge finite state machine.”
This means that your C++ code will run “somewhat” in parallel with ActionScript. Beware!

How does this swfmill_swf2xml method manage with our ByteArray? After all, C++ doesn’t know anything about that type of structure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
static AS3_Val swfmill_swf2xml( void *self, AS3_Val args )
{
	bool success = false;
	unsigned int e_version;
	unsigned int e_length;
	AS3_Val		 e_data = AS3_Undefined();
 
	AS3_ArrayValue( args, "IntType, IntType, AS3ValType", &e_version, &e_length, &e_data );
	fprintf(stderr, "Clength: %u", e_length);
	unsigned char * data = (unsigned char *)malloc(sizeof(unsigned char) * (e_length + 1));
	for(int runner=0; runner < e_length; runner++)
	{
		*(data + runner) = AS3_IntValue(AS3_Get(e_data, AS3_Int(runner))) & 0xFF;
	}
 
	...
 
	return AS3_Int(success ? 0 : -1);
}

Did you see it? Did you see the awesomely hackish way we have to retrieve our arguments using AS3_ArrayValue?
Use of AS3ValType means “You, C++, will store this object as a blob because you do not know better. However, if you use the correct AS3 calls, you will be able to ask ActionScript to manipulate this object on your behalf.”
Therefore, to convert that object, which, I happen to know, is a ByteArray, I will ask ActionScript to read its content and I will store it in an array of chars. Note that I am masking the returned value with 0xFF, because there is no function to read a byte, therefore I need to get rid of the irrelevant bits after reading an integer. And, yes, AS3_IntValue() is a function that maps AS3 integers to C integers. More info here.

If you read the page I just provided a link to, you may wonder why I am passing AS3_Int(runner) to AS3_Get(…)
After all, the second parameter is supposed to be a method name. And this is the case – in a way. By passing an integer, I am asking ActionScript to use the ‘[]‘ form to access our ByteArray.
Note that I had no joy trying to use readUnsignedByte() instead. That’s to be expected; after all, Alchemy is far from stable — or complete.

But it’s certainly promising.

If you enjoyed this post, make sure you subscribe to my RSS feed!


Flex: Render your tree nodes with a line through

So…how hard can it be, right? After all, Flex offers to change your text style — using setStyle — to bold, italics, underlined…oh, but no strikethrough.

But I really needed that for my tree nodes, so here is how I did it.

First, my tree, as defined in a MXML file — well, a simplified version:

?View Code ACTIONSCRIPT
1
2
3
4
<mx:Tree id="outlinerTree" 
    height="100%" width="100%"
    itemRenderer="com.voilaweb.tfd.OutlinerRenderer"
    creationComplete="main_initOutliner();"/>

As you can see, I explicitely reference my renderer. Let’s have a look at OutlinerRenderer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.voilaweb.tfd
{
	import mx.collections.*;
	import mx.controls.treeClasses.*;
 
	public class OutlinerRenderer extends TreeItemRenderer
	{
		override public function set data(value:Object):void
		{
			super.data = value;
		}
 
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
		{
			super.updateDisplayList(unscaledWidth, unscaledHeight);
			var startx:Number = data ? TreeListData(listData).indent : 0;
			if(disclosureIcon)
				startx += disclosureIcon.measuredWidth;
			if(icon)
				startx += icon.measuredWidth;
			graphics.clear();
			graphics.lineStyle(1, getStyle("color"));
			var y:Number = label.y + label.measuredHeight / 2;
			graphics.moveTo(startx, y);
			graphics.lineTo(startx + label.measuredWidth, y);
		}
	}
}

In a nuthsell, I let the parent paint the label, then add my own line to my graphic context. I use the label’s measurements to size my line.

For those of you new to ActionScript but familiar with Java: yes, it’s just like overriding the paint() method. In fact, ActionScript offers so many similarities with Java — renderers, editors, listeners, annotations… — that if you’ve ever written front-end code, you should give AS3 a try.

If you enjoyed this post, make sure you subscribe to my RSS feed!