티스토리 뷰

XML User-interface Language
– XUL Application 개발 (1)







작성자 : 이은규
작성일 : 2006.10.09
홈페이지 : http://unkyulee.net


1. XUL 소개
2. 개발환경 설정
3. 통합 웹 검색기 작성


1. XUL 소개

XUL은 XML User-interface Language의 약어이고 줄(zool) 이라고 읽습니다. XML로 UI를 기술할 수 있는 언어로 Firefox, Thunderbird, Songbird등 브라우저, 메일 클라이언트, 음악 재생기 등 여러 분야의 어플리케이션에서 응용되고 있습니다.


그림 1 Songbird


XML로 UI를 작성하는 것의 가장 커다란 장점은 쉽다는 것입니다. XUL은 UI 렌더링을 HTML 렌더링 하는 것과 동일한 방식으로 하고, 화면 표시도 동일합니다. 이는 HTML의 쉽고 강력한 표현 기능을 그대로 가지고 올 수 있다는 XUL의 커다란 장점이지요.

UI의 이벤트 핸들링이나 기타 로직에 관련된 작업은 자바스크립트로 합니다. 자바스크립트라니! 정말 HTML과 유사한 것처럼 느껴집니다. XUL에서 사용하는 자바스크립트는 HTML에서 사용하는 자바스크립트와 동일한 문법을 사용하는 언어입니다만, 차이점은 XUL에서는 자바스크립트에서 시스템에 관련된 처리를 할 수 있다는 것입니다. 예를 들면 파일처리 같은 류의 작업을 XUL에서는 할 수 있습니다. 일반 C++ 코드가 할 수 있는 일도 XUL의 자바스크립트에서는 가능하지요. XPCOM 객체를 사용할 수 있기 때문입니다.

튜토리얼에서는 여러 검색 사이트의 검색결과를 한번에 볼 수 있는 통합 웹 검색기를 만들어 보려고 합니다. XUL을 이용하면 불과 20~30 줄 만으로 훌륭한 어플리케이션을 만들 수 있습니다.



2. 개발환경 설정

XUL 어플리케이션을 개발하기 위해서는 XML로 기술된 UI 명세 파일과 자바스크립트 파일이 필요합니다. XML과 자바스크립트 파일은 바이너리 파일이 아닙니다. 뭔가 이상합니다. 실행을 하려면 바이너리 파일이 필요한데 산출물은 고작 XML 파일과 js 파일이 끝입니다.

그럼 어떻게 XUL 어플리케이션을 실행할 수 있을까요? 제가 아는 방법은 2가지 입니다.

1. Firefox를 이용하는 방법
2. XULRunner를 이용하는 방법

Firefox 브라우저는 XUL 파일을 렌더링 할 수 있습니다. Firefox 자체가 XUL로 만들어 졌기 때문에 어쩌면 당연하다고도 할 수 있습니다. 하지만 이 방식은 Firefox가 있어야만 프로그램을 돌릴 수 있고, 또한 제한적인 기능밖에 제공하지 않는다는 단점이 있습니다.

XULRunner를 이용해서 돌리는 방식은 완전히 독립된 어플리케이션을 실행하는 방식과 동일하게 실행할 수 있습니다. 뭐 각자의 목적에 따라 다르겠지만 저는 왠지 XULRunner로 돌리는 방식이 더 재밌어 보이고, 더 쓸만해 보입니다.

Step 1. 바탕화면이나 어디 작업할 만한 곳에 폴더를 하나 생성합니다.

Step 2. 그리고 XULRunner를 다운로드 받아서 복사해놓습니다.

XULRunner :
http://developer.mozilla.org/en/docs/XULRunner

Download XULRunner (Windows) :
http://ftp.mozilla.org/pub/mozilla.org/xulrunner/releases/1.8.0.4/win32/en-US/xulrunner-1.8.0.4.en-US.win32.zip


Step 3. 폴더 구조를 아래와 동일하게 구성합니다.

Chrome 폴더는 XUL 파일과 JS 파일이 저장될 곳입니다.

Defaults 폴더는 설정 파일이 저장되는 곳 입니다.

Xulrunner 폴더는 Step 2.에서 다운로드 받은 xulrunner가 위치하는 곳 입니다.







위 폴더 구조는 xulrunner가 인식하는 기본 구조이기 때문에 반드시 맞추어 주어야 합니다.
여기서는 편의상 루트를 XUL 디렉토리로 잡아서 Chrome 디렉토리는 XUL/Chrome 으로 설명하겠습니다.

Step 4. Application.ini 파일 생성

XUL/application.ini 파일을 생성합니다. 이 파일은 어플리케이션에 대한 명세가 들어가는 파일입니다. XUL 버전 정보와 어플리케이션 타이틀 정보를 지정하는 파일입니다.

[App]
;
; This field specifies your organization's name.  This field is recommended,
; but optional.
Vendor=unkyulee
;
; This field specifies your application's name.  This field is required.
Name=serach
;
; This field specifies your application's version.  This field is optional.
Version=0.2.2
;
; This field specifies your application's build ID (timestamp).  This field is
; required.
BuildID=2006041718
;
; This field specifies a compact copyright notice for your application.  This
; field is optional.
Copyright=Copyright (c) 2004 unkyulee.net
;
; This ID is just an example.  Every XUL app ought to have it's own unique ID.
; You can use the microsoft "guidgen" or "uuidgen" tools, or go on
; irc.mozilla.org and /msg botbot uuid.  This field is optional.
ID={3bdb0d0c-b8d1-4b2c-82ab-b5d13526a7e3}

[Gecko]
;
; This field is required.  It specifies the minimum Gecko version that this
; application requires.
MinVersion=1.8
;
; This field is optional.  It specifies the maximum Gecko version that this
; application requires.  It should be specified if your application uses
; unfrozen interfaces.
MaxVersion=1.8.0.*


Step 5. pref.js 파일 작성

XUL/defaults/preferences/pref.js 파일을 생성합니다. 이 파일은 어플리케이션 전역에서 사용되는 설정을 저장하는 곳입니다.

pref("toolkit.defaultChromeURI", "chrome://search/content/search.xul");

// 디버그 정보 표시 설정
pref("browser.dom.window.dump.enabled", true);
pref("javascript.options.showInConsole", true);
pref("javascript.options.strict", true);
pref("nglayout.debug.disable_xul_cache", true);
pref("nglayout.debug.disable_xul_fastload", true);

pref("toolkit.defaultChromeURI", "chrome://search/content/search.xul");
이 설정은 어플리케이션이 처음 실행될 때 로드할 xul 파일을 설정하는 부분입니다.
나머지 설정은 디버그 용도로 사용되는 설정입니다. 자바스크립트 오류나 덤프 메시지를 볼 수 있는 콘솔창이 표시 되도록 설정하는 부분입니다.


Step 6. chrome.manifest 파일 작성

XUL/chrome/chrom.manifest 파일을 작성합니다. 이 파일은 chrome URI를 실제 로컬 경로와 매핑 해주는 설정 파일입니다.

content search jar:search.jar!/
content navigator jar:search.jar!/

위의 파일 설정대로 라면 chrome://search/content/search.xul 은 XUL/chrome/search.jar 파일 내의 content/search.xul 경로를 가리키게 됩니다.

jar:search.jar! 로 된 부분은 ZIP 형식으로 압축된 파일입니다.



Step 7. xul 파일 작성

XUL/chrome/content/search.xul 파일을 작성합니다. XML 형식으로 UI를 기술하는 파일입니다.

<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<window
  id         = "SearchWindow"
  windowtype    = "Search"
  title      = "Web Search"
  width      = "600"
  height     = "600"
  screenX     = "100"
  screenY     = "100"  
  xmlns      = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

</window>



Step 8. XUL Application 실행

1) XUL/xulrunner/xulrunner-stub.exe 파일을 XUL/xulrunner-stub.exe로 복사합니다. 아무 이름으로 복사해도 상관없습니다.

2) XUL/chrome/content 폴더를 ZIP으로 압축한 뒤에 XUL/chrome/search.jar 파일로 이름을 바꿔줍니다.



ZIP으로 압축된 내용은 위 그림과 같이 폴더 구조 없이 바로 content 폴더의 파일이 보이도록 구성하면 됩니다.

XUL/xulrunner-stub.exe를 실행하면 다음과 같은 화면이 보입니다.



이제 XUL Application 개발 환경 설정은 마무리가 되었습니다. 이제 XUL 파일을 작성하면 바로 실행 해볼 수 있는 환경이 갖추어 졌습니다. XULPlanet 사이트를 레퍼런스 삼아서 XUL 파일만 작성하면 자신만의 XUL Application을 만들 수 있습니다.


3. 통합 웹 검색기 작성

XUL Application의 예로 통합 웹 검색기를 만들어 보려고 합니다. 키워드를 하나를 입력하면 여러 검색 사이트에 동시에 접속해서 검색 결과를 보여주는 식의 프로그램입니다.




먼저 위 어플리케이션의 XUL 파일을 볼까요? 개발환경 설정하면서 작성한 search.xul 파일에 이어서 작성한 내용입니다.



<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>

<window
id         = "SearchWindow"
windowtype    = "Search"
title      = "Web Search"
width      = "600"
height     = "600"
screenX     = "100"
screenY     = "100"
onload    = "OnLoad();"
xmlns      = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">

<script src="search.js" />

<hbox>
   <textbox control="SearchButton" id="SearchText" onkeypress="OnKeyPress(event);" />
   <button id="SearchButton" label="Search" oncommand="Search();" />
</hbox>    


<tabbox flex="1">
   <tabs>
       <tab label="Google"/>
       <tab label="Naver"/>
       <tab label="Yahoo"/>
       <tab label="Empas"/>
   </tabs>
   
   <tabpanels flex="1">
   <tabpanel>
   <vbox height="100%" flex="1">                            
       <browser flex="1" id="Google" src="" type="content-primary" />
   </vbox>
   </tabpanel>
   
   <tabpanel>
   <vbox height="100%" flex="1">                            
       <browser flex="1" id="Naver" src="" type="content-primary" />
   </vbox>
   </tabpanel>
   
   <tabpanel>
   <vbox height="100%" flex="1">                            
       <browser flex="1" id="Yahoo" src="" type="content-primary" />
   </vbox>
   </tabpanel>
   
   <tabpanel>
   <vbox height="100%" flex="1">                            
       <browser flex="1" id="Empas" src="" type="content-primary" />
   </vbox>
   </tabpanel>
   </tabpanels>
</tabbox>



</window>


<script src="search.js" />
이 부분은 JavaScript를 XUL에 포함시키기 위한 것 입니다. Search.js 파일에는 UI에서 발생하는 이벤트를 핸들링하는 함수들이 정의되어 있습니다.


<hbox>
   <textbox control="SearchButton" id="SearchText" onkeypress="OnKeyPress(event);" />
   <button id="SearchButton" label="Search" oncommand="Search();" />
</hbox>    

이 부분은 옆 그림과 같은 것을 표현하기 위한 XML 입니다. 가로로 UI가 배치 될 수 있도록 <hbox> 태그로 묶었고, 텍스트박스와 버튼으로 이루어 진 것을 알 수 있습니다.

<tabbox flex="1">
   <tabs>
       <tab label="Google"/>
   </tabs>
   
   <tabpanels flex="1">
   <tabpanel>
   <vbox height="100%" flex="1">                        
       <browser flex="1" id="Google" src="" type="content-primary" />
   </vbox>
   </tabpanel>
   
   </tabpanels>
</tabbox>

위 코드는 탭을 표현하기 위한 XML 입니다. 탭 들을 정의 하는 <tabs> 태그가 있고, 탭의 내용을 정의하는 <tabpanels> 가 있습니다.



tabpannel에는 검색 결과를 표시하기 위한 브라우저가 만들어 집니다.



JS 파일의 내용을 보도록 하겠습니다. JS 파일의 역할은 검색 버튼이 눌렸을 때 tabpanel 안에 있는 브라우저들에게 검색 요청을 합니다.

function Search()
{
   dump( "Search\n" ) ;
   var strKeyword = document.getElementById( "SearchText" ).value ;
   dump( strKeyword + "\n" ) ;
   
   SearchGoogle( strKeyword ) ;}

function SearchGoogle( strKeyword )
{
   dump( "SearchGoogle\n" ) ;
   var browser = document.getElementById( "Google" ) ;    
   browser.loadURI( "http://www.google.co.kr/search?q=" + strKeyword , null , null ) ;
}

텍스트 박스에서 검색 키워드 값을 얻어온 후에 SearchGoogle 함수를 호출해서 검색을 요청합니다. SearchGoogle에서는 loadURI 함수를 통해서 해당 URL로 페이지를 표시하도록 합니다. "http://www.google.co.kr/search?q=은규리" URL로 브라우징을 시키면 구글에서 은규리로 검색한 결과 화면이 브라우저에 표시가 되는 것이지요. 다른 검색 엔진들도 위와 동일한 방식으로 표시가 됩니다.