Seed 也支援對資料庫的存取,目前只支援 SQLite。
用法也超級簡單…
基本上只有 constructor 跟用來執行 SQL 的 exec()。以下代碼來自源碼裡 (modules/sqlite/example.js):
[javascript]
#!/usr/local/bin/seed
Seed.import_namespace(“sqlite”);
d = new sqlite.Database(Seed.argv[2]);
d.exec(“create table t1 (t1key INTEGER PRIMARY KEY,data TEXT,num double,timeEnter DATE);”);
d.exec(“insert into t1 (data,num) values (‘This is sample data’,3);”);
d.exec(“insert into t1 (data,num) values (‘More sample data’,6);”);
d.exec(“insert into t1 (data,num) values (‘And a little more’,9);”);
d.exec(“select * from t1”, function(results){Seed.print(JSON.stringify(results))});
[/javascript]
取出資料的作法則是將 callback 傳入,以處理一筆 record。上面是用 JSON 輸出整筆 record 內容,其實你也可以將欄位名稱代入 indexer 來取得該欄內容:
[javascript]
d.exec(“select * from t1”, function(results){Seed.print(results[“data”])});
[/javascript]
Run Android on VirtualBox/VMWare
有人問了,所以這裡大致整理一下,也算是留下一個記憶(之後沒有要繼續…Orz…)。
事實上,網路上可以找到許多人的文章,根據歸納之後,我發現大多都是從 android-porting 裡的這篇:Howto build Android full source for X86 Architecture like EeePC(ASUS)轉貼來的,所以只要耐心爬完這篇,大致上都沒問題。
- 第一步當然是要把 source 拉下來,這個步驟,官方描述得很清楚:Get source (Android Open Source Project),這裡不多作描述。如果你用的是 Ubuntu 8.10,會踩到雷的只有 libreadline5-dev,因為並沒有該頁面描述的 lib32readline5-dev。這裡我假設你跟官方教學步驟一樣,建了 mydroid 目錄。
- sync 整份 source code 以後,還需要 eee 701 的部份,所以要在 .repo 下新增一個檔案,並命名為 local_manifest.xml:
<manifest> <project name="platform/vendor/asus/eee_701" path="vendor/asus/eee_701"/> </manifest>
,然後再 sync 一次。
- 這次的 sync 會很快,結束以後,要先 build kernel。切到 mydroid/kernel 目錄下,複製 mydroid/vendor/asus/eee_701/kernel.config 為 mydroid/kernel/.config,接著執行 make menuconfig,進入 kernel configuration 選單以後,把這幾個 driver 選為 built-in:
- Device drivers / Network device support / Ethernet (10 or 100Mbit) / EISA, VLB, PCI and on board controllers / AMD PCnet32 PCI support
- Device drivers / Graphics support / Support for frame buffer devices / VESA VGA graphics support
- Device drivers / Graphics support / Console display driver support / Framebuffer Console support
- Device drivers / Graphics support / Console display driver support / Select Compiled-in fonts (VGA 8×8 font, VGA 8×16 font)
,再把這些取消:
- Device drivers / Real Time Clock / Android alarm driver
- Device drivers / Misc devices / Android pmem allocator
,然後重新建置 kernel:make bzImage。
- 編譯好之後,把 arch/x86/boot/bzImage 複製為 mydroid/vendor/asus/eee_701/kernel。
- 我稍稍更動了一些設定,這樣我後面就省打一些東西:
- vendor/asus/eee_701/BoardConfig.mk:在 BOARD_KERNEL_CMDLINE 加上 vga=788
- vendor/asus/eee_701/init.eee_701.sh:把 netcfg eth0 dhcp 改為 dhcpcd eth0
- 接著就是建置 image 了,這裡是我用的 script,把以下內容存為 build.sh,並放在 mydroid 下:
#!/bin/bash cp kernel/arch/x86/boot/bzImage vendor/asus/eee_701/kernel mkdir -p out/target/product/eee_701/data/ cp kernel/arch/x86/boot/bzImage out/target/product/eee_701/kernel TARGET_ARCH=x86 TARGET_PRODUCT=eee_701 DISABLE_DEXPREOPT=true make -j2 installer_img
,執行前別忘了 chmod +x 。
- 建置完以後,你會在 out/target/product/eee_701 下找到 installer.img。
- 把 installer.img 轉為 VirtualBox/VMWare 可用的 disk image,這邊要利用 VirtualBox 的 vboxmanage 來轉:vboxmanage convertfromraw -format vdi installer.img installer.vdi,如果你用 VMWare,則是:vboxmanage convertfromraw -format vmdk installer.img installer.vmdk
- 建置新的 VM,設置為 Linux kernel 2.6,256M 的 RAM,以及一個超過 2G 的硬碟。然後把上個步驟轉好的 disk image 加為第二個儲存裝置。
- 接下來,我只以 VirtualBox 為例,因為我沒試過 VMWare,不過原理一樣。將這個 VM 開機,一開機馬上按 F12,選擇從第二個儲存裝置開機。一開機,你會看到 grub 的開機選單,趕緊按下任意鍵,因為這邊要修改一下,預設 Loader 的開機磁碟是 hd(0,0),你要按 e 進行修改,把 hd(0,0) 改為 hd(1,0),再按 b 繼續開機(如果你不熟 grub,麻煩熟悉,這邊我不多說)。開機以後,就會開始進行安裝的動作,Android 會安裝到第一個磁碟上去,這個步驟要等一陣子,如果有錯誤,再重複一次即可,根據我的經驗,有時候會因為切割磁碟失敗而停止安裝,但再從第二個磁碟開機安裝一次,通常即可解決。安裝完成不會有什麼訊息,但看一下畫面上訊息,你應該可以知道已經完成,輸入 reboot 重新開機。
- 最後就大功告成啦~接著你可以移除第二個磁碟,因為再也用不到啦~
Seed(3) – Glade
純手工寫 UI 實在是很苦,還好有 Glade,你可以用 Glade 設計出介面以後,再用 Seed 把事件指派一下就可以完成一個程式了。這裡假設你已經用 Glade 設計出畫面,把主要的視窗命名為 window1,並且存為 glade-1.glade。存好以後,要使用 gtk-builder-convert 把 .glade 轉為 .xml。
gtk-builder-convert glade-1.glade glade-1.xml
接著就可以寫 code 了:
#!/usr/bin/env seed
// First, you need to use gtk-builder-convert to convert glade to xml.
// gtk-builder-convert glade-1.glade glade-1.xml
// Import libraries that are used by the program
Seed.import_namespace("Gtk");
// Initialize GTK+
Gtk.init(null, null);
var ui = new Gtk.Builder();
ui.add_from_file("glade-1.xml");
var window = ui.get_object("window1");
window.signal.hide.connect(Gtk.main_quit);
// Start the main GTK+ loop and initiate the program
Gtk.main();
Seed(2)
GObject、Gio、Gtk、Glib、Clutter 等在範例裡看到的 library,在 Seed 原始碼裡是看不到的,Seed 是利用 GObject Introspection 來跟這些 library 互動。
Cairo、sqlite、readline 的話,因為並沒有使用 GObject 這個 library,所以 Seed 另外寫 Module 來跟這些 library 互動,你可以在 Seed 原始碼的 modules 目錄下看到~
Cairo 實際上是在 Canvas 這個 module 裡,Canvas 裡共有四個主要的類別:CairoCanvas、PDFCanvas、SVGCanvas、ImageCanvas,創建這些 Canvas 以後,基本上都是使用 Cairo 來在這些 Canvas 上繪圖。裡面沒有封裝 cairo_pattern_xxxx、cairo_text_xxxx、cairo_mask…等函數,所以不能用 Cairo 來繪圖或是繪字。
#!/usr/bin/env seed
Seed.import_namespace("Gtk");
Seed.import_namespace("Canvas");
Seed.import_namespace("Gdk");
//
// Initialize GTK+
//
Gtk.init(null, null);
// Create the main application window and set the title
var window = new Gtk.Window({title: "Canvas Demo"});
var vbox = new Gtk.VBox();
var drawingArea = new Gtk.DrawingArea();
var status = new Gtk.Statusbar();
var hbox = new Gtk.HBox();
var exposeEvent = function() { return true;};
//
// create Cairo Canvas
//
function createCairoCanvas()
{
var cairo = Gdk.cairo_create( drawingArea.window );
return new Canvas.CairoCanvas( cairo );
}
//
// Demos from http://cairographics.org/tutorial/
//
function strokeDemo()
{
drawingArea.window.clear();
var canvas = createCairoCanvas();
canvas.strokeStyle = "rgb( 0, 0, 255 )";
canvas.strokeRect( 10, 10, 50, 50 );
canvas.stroke();
return true;
}
function fillDemo()
{
drawingArea.window.clear();
var canvas = createCairoCanvas();
canvas.fillStyle = "rgb( 0, 0, 255 )";
canvas.fillRect( 10, 10, 50, 50 );
canvas.fill();
return true;
}
function fourColorDemo() {
drawingArea.window.clear();
var canvas = createCairoCanvas();
canvas.strokeStyle = "rgb( 0, 0, 0 )";
canvas.moveTo( 0, 0 );
canvas.lineTo( 100, 100 );
canvas.moveTo( 100, 0 );
canvas.lineTo( 0, 100 );
canvas.lineWidth = 10;
canvas.stroke();
canvas.fillStyle = "rgb( 255, 0, 0 )";
canvas.globalAlpha = 0.8;
canvas.fillRect( 0, 0, 50, 50 );
canvas.fillStyle = "rgb( 0, 255, 0 )";
canvas.globalAlpha = 0.6;
canvas.fillRect( 0, 50, 50, 50 );
canvas.fillStyle = "rgb( 0, 0, 255 )";
canvas.globalAlpha = 0.4;
canvas.fillRect( 50, 0, 50, 50 );
return true;
}
function pathDemo() {
drawingArea.window.clear();
var canvas = createCairoCanvas();
canvas.strokeStyle = "rgb( 255, 0, 0 )";
canvas.beginPath();
canvas.moveTo( 25, 25 );
canvas.lineTo( 50, 37.5 );
canvas.lineTo( 75, 25 );
canvas.arc( 50, 50, 25*Math.sqrt(2), -0.25*Math.PI, 0.25*Math.PI, false );
canvas.bezierCurveTo( 50, 37.5, 50, 62.5, 25, 75 );
canvas.closePath();
canvas.stroke();
return true;
}
function scaleAndTransformDemo() {
drawingArea.window.clear();
var canvas = createCairoCanvas();
canvas.strokeStyle = "rgb( 255, 0, 0 )";
canvas.lineWidth=10;
canvas.save();
canvas.scale( 0.5, 1 );
canvas.arc( 50, 50, 40, 0, 2*Math.PI, true );
canvas.stroke();
canvas.translate( 100, 0 );
canvas.arc( 50, 50, 40, 0, 2*Math.PI, true );
canvas.restore();
canvas.stroke();
return true;
}
//
// Demos from http://cairographics.org/samples/
//
function arcDemo() {
drawingArea.window.clear();
var canvas = createCairoCanvas();
var xc = 128;
var yc = 128;
var radius = 100;
var angle1 = 45 * (Math.PI/180);
var angle2 = 180 * (Math.PI/180);
canvas.lineWidth = 10;
canvas.arc( xc, yc, radius, angle1, angle2, true );
canvas.stroke();
canvas.fillStyle = "rgb( 255, 51, 51 )";
canvas.globalAlpha = 0.6;
canvas.lineWidth = 6;
canvas.arc( xc, yc, 10, 0, 2*Math.PI, true );
canvas.fill();
canvas.arc( xc, yc, radius, angle1, angle2, true );
canvas.lineTo( xc, yc );
canvas.arc( xc, yc, radius, angle2, angle2, true );
canvas.lineTo( xc, yc );
canvas.stroke();
return true;
}
function clipDemo() {
drawingArea.window.clear();
var canvas = createCairoCanvas();
canvas.arc( 128, 128, 76.8, 0, 2*Math.PI, true );
canvas.clip();
canvas.beginPath();
canvas.fillRect( 0, 0, 256, 256 );
canvas.strokeStyle = "rgb( 0, 255, 0)";
canvas.moveTo( 0, 0 );
canvas.lineTo( 256, 256 );
canvas.moveTo( 256, 0 );
canvas.lineTo( 0, 256 );
canvas.lineWidth = 10;
canvas.closePath();
canvas.stroke();
return true;
}
function curveRectangleDemo() {
drawingArea.window.clear();
var canvas = createCairoCanvas();
var x0 = 25.6;
var y0 = 25.6;
var rect_width = 204.8;
var rect_height = 204.8;
var radius = 102.4;
var x1, y1;
x1 = x0 + rect_width;
y1 = y0 + rect_height;
if( rect_width/2 < radius ) {
if( rect_height/2<radius ) {
canvas.moveTo( x0, (y0+y1)/2 );
canvas.bezierCurveTo( x0, y0, x0, y0, (x0+x1)/2, y0 );
canvas.bezierCurveTo( x1, y0, x1, y0, x1, (y0+y1)/2 );
canvas.bezierCurveTo( x1, y1, x1, y1, (x0+x1)/2, y1 );
canvas.bezierCurveTo( x0, y1, x0, y1, x0, (y0+y1)/2 );
}
else {
canvas.moveTo( x0, y0+raius );
canvas.bezierCurveTo( x0, y0, x0, y0, (x0+x1)/2, y0 );
canvas.bezierCurveTo( x1, y0, x1, y0, x1, y0+radius );
canvas.lineTo( x1, y1-radius );
canvas.bezierCurveTo( x1, y1, x1, y1, (x1+x0)/2, y1 );
canvas.bezierCurveTo( x0, y1, x0, y1, x0, y1-radius );
}
}
else {
if( rect_height/2<radius ) {
canvas.moveTo( x0, (y0+y1)/2 );
canvas.bezierCurveTo( x0, y0, x0, y0, x0+radius, y0 );
canvas.lineTo( x1-radius, y0 );
canvas.bezierCurveTo( x1, y0, x1, y0, x1, (y0+y1)/2 );
canvas.bezierCurveTo( x1, y1, x1, y1, x1-radius, y1 );
canvas.lineTo( x0+radius, y1 );
canvas.bezierCurveTo( x0, y1, x0, y1, x0, (y0+y1)/2 );
}
else {
canvas.moveTo( x0, y0+radius );
canvas.bezierCurveTo( x0, y0, x0, y0, x0+radius, y0 );
canvas.lineTo( x1-radius, y0 );
canvas.bezierCurveTo( x1, y0, x1, y0, x1, y0+radius );
canvas.lineTo( x1, y1-radius );
canvas.bezierCurveTo( x1, y1, x1, y1, x1-radius, y1 );
canvas.lineTo( x0+radius, y1 );
canvas.bezierCurveTo( x0, y1, x0, y1, x0, y1-radius );
}
}
canvas.closePath();
canvas.fillStyle = "rgb( 128, 128, 255 )";
canvas.fill(); // no fill_preserve(), so you won't see the border.
canvas.strokeStyle = "rgb( 255, 0, 0 )";
canvas.globalAlpha = 0.5;
canvas.lineWidth = 10;
canvas.stroke();
return true;
}
function curveToDemo() {
drawingArea.window.clear();
var canvas = createCairoCanvas();
var x=25.6, y=128;
var x1=102.4, y1=230.4, x2=153.6, y2=25.6, x3=230.4, y3=128.0;
canvas.moveTo( x, y );
canvas.bezierCurveTo( x1, y1, x2, y2, x3, y3 );
canvas.lineWidth = 10;
canvas.stroke();
canvas.strokeStyle = "rgb( 255, 51, 51 )";
canvas.globalAlpha = 0.6;
canvas.lineWidth = 6;
canvas.moveTo( x, y ); canvas.lineTo( x1, y1 );
canvas.moveTo( x2, y2 ); canvas.lineTo( x3, y3 );
canvas.stroke();
return true;
}
function rotateDemo() {
drawingArea.window.clear();
var canvas = createCairoCanvas();
canvas.translate( 128, 128 );
canvas.rotate( 45*Math.PI/180 );
canvas.scale( 0.9, 0.9 );
canvas.fillStyle = "rgb(200,0,0)";
canvas.fillRect( 10, 10, 55, 50 );
canvas.strokeStyle = "rgb( 0, 200, 0 )";
canvas.strokeRect( 50, 50, 155, 150 );
canvas.strokeStyle = "rgb( 0, 0, 255 )";
canvas.arc( 137.5, 137.5, 100, 0, Math.PI*2, true );
canvas.stroke();
return true;
}
//
// routines
//
function createButton( label, handler ) {
var button = new Gtk.Button( {label: label} );
button.signal.clicked.connect( handler );
return button;
}
function createButtonGroup()
{
var buttonGroup = new Gtk.VBox();
//var buttonGroup = new Gtk.VButtonBox();
buttonGroup.pack_start( createButton( "Stroke", function() {
exposeEvent = strokeDemo;
return exposeEvent();
}), true, true);
buttonGroup.pack_start( createButton( "Fill", function() {
exposeEvent = fillDemo;
return exposeEvent();
}), true, true);
buttonGroup.pack_start( createButton( "4 color", function() {
exposeEvent = fourColorDemo;
return exposeEvent();
}), true, true);
buttonGroup.pack_start( createButton( "Path", function() {
exposeEvent = pathDemo;
return exposeEvent();
}), true, true);
buttonGroup.pack_start( createButton( "Scale and Transform", function() {
exposeEvent = scaleAndTransformDemo;
return exposeEvent();
}), true, true);
buttonGroup.pack_start( createButton( "Arc", function() {
exposeEvent = arcDemo;
return exposeEvent();
}), true, true);
buttonGroup.pack_start( createButton( "Clip", function() {
exposeEvent = clipDemo;
return exposeEvent();
}), true, true);
buttonGroup.pack_start( createButton( "Curve Rectangle", function() {
exposeEvent = curveRectangleDemo;
return exposeEvent();
}), true, true);
buttonGroup.pack_start( createButton( "Curve To", function() {
exposeEvent = curveToDemo;
return exposeEvent();
}), true, true);
buttonGroup.pack_start( createButton( "Rotate", function() {
exposeEvent = rotateDemo;
return exposeEvent();
} ), true, true);
return buttonGroup;
}
//
// Events
//
function drawingArea_ExposeEvent() {
return exposeEvent();
}
//
// Main
//
// Make the program terminate when the window is closed
window.signal.hide.connect(Gtk.main_quit);
drawingArea.signal.expose_event.connect( drawingArea_ExposeEvent );
hbox.pack_start( createButtonGroup(), false, false);
hbox.pack_start( drawingArea, true, true );
vbox.pack_start( hbox, true, true );
vbox.pack_start( status, false, false, 0);
window.add(vbox);
window.show_all();
window.resize( 640, 480 );
// Start the main GTK+ loop and initiate the program
Gtk.main();
關於這個例子,大部分都是從 Cairo網站上的範例搬來的,也幾乎演示了所有的函數,但還是有少數函數與屬性沒有涵蓋到,如 transform、setTransform、clearRect、quadraticCurveTo…等~
有需要再自己去翻 seed-canvas.c 看吧~
xming 與中文輸入
- 開終端機以後,要先設置環境變數,告訴兩大 framework 你要使用的輸入法:
export GTK_IM_MODULE=gcin export QT_IM_MODULE=gcin
,這裡的 gcin,你可以替換為自己熟悉的輸入法,例如 scim、fcitx…。
- Hot key 會打架,所以你用 ctrl-space 的話,是 windows 的輸入法起來,不是 linux 的輸入法起來。因此要把 hot key 換掉,gcin 可以用 ctrl+alt+數字鍵 來切換,要切換為英文,則可以用 caps lock。這邊就看你自己輸入法的設定了。
Seed(1)
在Ubuntu裡安裝 Seed 很簡單,參考PPA for Orange Owners裡,把
deb http://ppa.launchpad.net/orange-owners/ppa/ubuntu intrepid main deb-src http://ppa.launchpad.net/orange-owners/ppa/ubuntu intrepid main
放到 /etc/sources.list 裡,然後用 sudo apt-get update 更新,sudo apt-get install seed 來安裝即可。
執行 script 也很簡單,有兩種方法:
- 直接以 seed 執行:seed your_script.js
- 把 js 檔的第一行改為 #!/usr/bin/env seed,再以 chmod +x 為 js 檔加上執行權限,就可以用 ./your_script.js 執行。
目前官方沒有文件說明 Seed 內部有哪些類別與方法,這很讓人困擾,這兩天看了 source code 跟 example code 之後,大致上有點了解。
Seed 主要的類別是 Seed,提供了如下方法:
- include:用來含括其他 js,讓你可以為程式作適當的切割,不至於讓檔案變得太大而難以維護。
Seed.include("other.js"); - print:印字串。
Seed.print("Hello world!"); - check_syntax:檢查語法,你可以傳 javascript 程式進去檢查,如果有錯,會丟出 exception。
try { Seed.check_syntax("Seed.print(;"); Seed.print("syntax ok!"); } catch( e ) { Seed.print( e.message ); } - spawn:執行外部程式,執行以後會回傳一個 object,這個 object 有兩個屬性:stdout 與 stderr。
var result = Seed.spawn("ls"); Seed.print( "=== spawn result(stdout) ===" ); Seed.print( result.stdout ); Seed.print( "=== spawn result(stderr) ===" ); Seed.print( result.stderr ); - fork:這跟 C 的 fork() 一樣,回傳值是 0,表示是子行程,-1 表示失敗,大於 0 的值,表示是父行程。
var pid = Seed.fork(); if( pid == 0 ) { // child process var result = Seed.spawn( "ls" ); Seed.print( result.stdout ); Seed.quit(); } else if( pid == -1 ) { Seed.print( "cannot create child process." ); } else { // parent process. Seed.print( "I am parent process." ); } - quit:離開。
- introspect:這個函數可以用來探知類別成員函數如何使用,安裝 Seed 以後,/usr/share/doc/seed/examples 下有個 introspect.js,就是一個很好的範例。不過我還不是很懂怎麼去用~
- import_namespace:含括其他 library 進來使用,不要跟 include 搞混了,include 是含括其他 js 檔。
把檔案內容放到環境變數
在 bash 下很簡單的一件事情,批次檔似乎沒有比較好的解~
在 bash 下:
VERSION=`cat version.txt`
在批次檔裡,我發現可以用 for 來解:
@For /f "" %%a in (version.txt) do (set VERSION=%%a)
但缺點是,當檔案有多行時,VERSION 會是最後一行的內容。
當 jQuery().ajax() 遇到 ASP
利用 jqGrid 新增中文欄位資料時,到伺服器端時,就變成亂碼了。
請 FireBug 大神幫忙,發現 request header content-type 的編碼是 utf-8,查過jqGrid的 source code,裡面也只是調用 jQuery 的 ajax 函數而已。
照理來說,應該可以用 $.ajaxSetup() 來修正,但試了好一陣子,發現沒辦法,即使我在 contentType 裡指定了 charset=big5,最後送出時,仍然會是 utf-8…
好吧,山不轉路轉,再拜請Google大神,發現有人利用 escape() 解,也就是先用 javascript escape() 編碼,server 端再解碼,這樣就解了。
大致的代碼是這樣:
//
$("#jqGrid2").jqGrid(
// ... 略 ...
).navGrid( "#pager2", {
// ... 略 ...
add:true,
addfunc: function() {
$("#jqGrid2").editGridRow( "new", {
url: "server.asp",
beforeSubmit: function( postdata, o ) {
var s = postdata[ "your_field_name" ];
var ret=[true, "", ""];
postdata[ "your_field_name" ] = escape( s );
return ret;
}
} );
return false;
}
} );
Xming 的字太小?
Xming 等同是 Windows 上的 X Server,使用的說明可以參考:Xming 簡易使用說明,圖文並茂,寫的非常好。
對我來說,唯一的問題是字太小,該怎麼解決?我找了好久~
最後終於意外發現,只要在 XLaunch 最後一個步驟的畫面的 “Additional parameters for Xming” 裡填上 -dpi 100,就可以解決字太小的問題。
vim auto completion
在Linux Today看到這篇文章:Vi and Vim Editor: 5 Awesome Examples For Automatic Word Completion Using Ctrl-X Magic,看完的當下,非常的高興。
原本以為要安裝特定 plugin 才能達到的 auto completion 功能,居然早已內建,而且只需要在編輯時按下 ctrl+x ,再搭配下列按鍵即可:
- ctrl+p:向前找可以自動完成的字
- ctrl+n:向後找
- ctrl+i:找所有單行開頭的,特別適合寫程式,因為通常函數都會是先以單行宣告,根據同事實驗,這還會去找 header 裡的…
- ctrl+f:檔名的自動完成
能說什麼呢?只能說Vim太威了!
