XUL((XML User-interface Language)
<xul로 만드는 Firefox extention>
작성자: 유시형
작성일: 2007.11.12
I. XUL이란?
XUL 은 Mozilla browser를 쉽고 빠르게 만들기 위한 목적으로
만들어진 XML기반의 마크업 언어로서 실제로 Firefox와 Thunderbird의 UI를 만드는데 사용되었습니다. 통상 zool(줄)이라고
발음하며 XUL이라는 이름에서 알 수 있 듯 XML로
할 수 있는 모든 것을 제공하고 인터넷과 연결되거나 또는 연결되지 않은 채로 동작하는 풍부한 기능을 제공하는 크로스 플랫폼 응용프로그램을 만들
수 있게 해줍니다.
XUL로 만들 수 있는 어플리케이션의 유형을 몇가지 살펴보면 다음과 같습니다.
- Firefox
extention
- Standalone
XULRunner application
- XUL package
- Remote XUL
application
XUL은 XML의 문법을 그대로 사용하고 있기 때문에 DHTML에 친숙한 웹 개발자들은 XUL을 금방 배워서 바로 응용프로그램을
만들어 볼 수 있습니다. 또 namespace 를 사용하여 HTML엘리먼트를 XUL문서에 삽입 할 수도 있습니다.(예,
<html:textarea value="hello"></html:textarea>)
II. Firefox extention 만들기
Firefox의 extention은 두 개 이상의 각각 독립적인 XUL어플리케이션을 묶어 하나의 어플리케이션처럼 사용 할 수 있게 해주는
XUL의 <overlay>엘리먼트를 사용하여 만들 수 있습니다.
예 제의 extention은 Firefox의 메뉴바에 "다음" 이라는 메뉴항목을 추가 하고 해당 메뉴에 Firefox의 새 탭 혹은 현재 탭에서 다음 서비스 페이지로 이동시키는 몇 개의 메뉴아이템을
추가하는 기능을 같습니다. 이 extention 개발에 필요한
도구는 단지 간단한 텍스트 에디터와 Firefox뿐입니다.
개발순서는 다음과 같습니다.
1.
디렉토리 생성 및 설정파일 작성
2.
extention 의 개발 정보를 담고 있는 about.xul 파일 작성
3.
firefox의 메뉴바에 추가할 메뉴와 항목들에 대한 내용을 담고 있는 xul 파일 작성
4.
사용자 행동을 처리할 함수를 갖고
있는 javascript 파일 작성
5.
chrome 시스템에 extention 등록
1.개발환경 구성하기
* 한글 표현을 위해서는 소스 파일을 UTF-8로 인코딩 해야 합니다.
l
디렉토리 구조
daummenu(*)/
+ chrome/
+ content
+ main.xul(*)
+ script.js(*)
+ locale/
+ skin/
+ defaults/
+ preferences
+ prefs.js
+components/
+ install.rdf
+ chrome.manifest
l
install.rdf
XUL어플리케이션의 기본 정보를 설정하는 파일입니다. 제작자
정보, 프로그램 버전, 실행가능한 어플리케이션의 범위등을
설정 할 수 있으며, 특히 <em:id>엘리먼트의
값은 어플리케이션의 고유 번호와 같은 역할을 하며 어플리케이션을 chrome시스템에 등록 할 때 등록
파일의 이름으로 사용되어집니다.
<?xml version="1.0" encoding="utf-8"?>
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:aboutURL>chrome://daummenu/content/about.xul</em:aboutURL>
<em:id>daummenu@asrada.net</em:id>
<em:version>1.0</em:version>
<em:type>2</em:type>
<!-- Target Application this extension can install into,
with minimum and maximum supported versions. -->
<em:targetApplication>
<Description>
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
<em:minVersion>1.5+</em:minVersion>
<em:maxVersion>2.0.0.*</em:maxVersion>
</Description>
</em:targetApplication>
<!-- Front End MetaData -->
<em:name>Daum Menu</em:name>
<em:description>extention
example</em:description>
<em:creator>Asrada</em:creator>
<em:homepageURL>http://asrada2001.tistory.com/</em:homepageURL>
</Description>
</RDF>
l
chrome.manifest
어플리케이션의 환경 설정 역할을 담당하는 파일입니다. 다른
어플리케이션과의 overlay 를 설정하거나 skin,locale 파일들의
위치 정보를 설정 할 수 있습니다.
content daumment chrome/content/
overlay chrome://browser/content/browser.xul chrome://daummenu/content/main.xul
공백으로 구분 되는 각 컬럼의 의미는 아래와 같습니다.
1.chrome 패키지 안에 material 형
2.chrome 패키지 이름(overlay의 경우
overlay될 어플리케이션의 경로)
3.chrome 패키지 파일의 위치(overlay의 경우
overlay할 어플리케이션의 경로)
(복잡한 chrome.manifest 파일의 예)
content necko jar:comm.jar!/content/necko/
xpcnativewrappers=yes
locale necko en-US jar:en-US.jar!/locale/en-US/necko/
content xbl-marquee jar:comm.jar!/content/xbl-marquee/
content pipnss
jar:pipnss.jar!/content/pipnss/
locale pipnss en-US jar:en-US.jar!/locale/en-US/pipnss/
# Firefox-only
overlay chrome://browser/content/pageInfo.xul
chrome://pippki/content/PageInfoOverlay.xul
application={ec8030f7-c20a-464f-9b0e-13a3a9e97384}
overlay chrome://communicator/content/pref/preftree.xul chrome://pippki/content/PrefOverlay.xul
overlay chrome://navigator/content/pageInfo.xul
chrome://pippki/content/PageInfoOverlay.xul application=seamonkey@applications.mozilla.org
content pippki
jar:pippki.jar!/content/pippki/ xpcnativewrappers=yes
locale pippki en-US jar:en-US.jar!/locale/en-US/pippki/
content global-platform
jar:toolkit.jar!/content/global-platform/ platform
skin global classic/1.0
jar:classic.jar!/skin/classic/global/
override chrome://global/content/netError.xhtml
jar:embedder.jar!/global/content/netError.토싀
content inspector
jar:inspector.jar!/content/inspector/ xpcnativewrappers=no
* What is Chrome?
Chrome is the user interface parts of the application window that are outside
of a window's content area.
Toolbars, menu bars, progress bars, and window title bars are all examples of
elements that are typically part of the chrome.
·
chrome - the
browser UI around the web page
·
chrome URLs - the
chrome protocol which is the only way to get
privileges(ex.chrome://browser/content/browser.xul)
·
chrome directory -
the directory where the apps put their UI files
·
chrome command
line argument - start and open a file in a top level window
·
chrome argument to
window.open - opens a new window top level
·
chrome.rdf - the
chrome registry, in install directory and in profile
2.about.xul
<?xml version="1.0"
encoding="utf-8"?>
<?xml-stylesheet href="chrome://global/skin/"
type="text/css"?>
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"title="About
favdaum" orient="vertical" buttons="accept"
width="320" height="240">
<groupbox
align="center" flex="1">
<vbox
align="center">
<description
id="title" value="Daum Menu" />
<description
id="version" value="version: 0.1.0" />
<description
id="created" value="created by" />
<description
id="author" value="Asrada" />
</vbox>
</groupbox>
<description id="made" value="Made
with EditPlus" />
</dialog>
3.main.xul
<?xml version="1.0"
encoding="utf-8"?>
<overlay id="daummenu"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script src="script.js" />
<menubar id="main-menubar">
<menu
id="daumMenu" label="다음" insertbefore="helpMenu" accesskey="D">
<menupopup
id="daumMenuPop">
<menu
id="entertainment" label="엔터테인먼트" accesskey="E">
<menupopup
id="ent_pop">
<menuitem
id="cartoon" label="만화·소설" oncommand="openURL('http://comic.daum.net/?nil_profile=g&nil_site=comic',event)"
/>
<menuitem
id="music" label="뮤직"
oncommand="openURL('http://52street.daum.net/?nil_profile=g&nil_site=music',event)"
/>
<menuitem
id="movie" label="영화" oncommand="openURL('http://movie.daum.net/?nil_profile=g&nil_site=movie',event)"
/>
</menupopup>
</menu>
<menuseparator/>
<menuitem
id="daumHome" label="Home"
oncommand="gBrowser.addTab('http://www.daum.net')" />
<menuitem
id="daumYV" label="YouthVoice" oncommand="gBrowser.addTab('http://youthvoice.daum.net')"
/>
<menuitem
id="daumMS" label="MediaSchool"
oncommand="gBrowser.addTab('http://mediaschool.daum.net')" />
</menupopup>
</menu>
</menubar>
</overlay>
4.script.js
function openOnCurrentTab(url){
gBrowser.selectedBrowser.setAttribute("src",url);
}
function openURL(url){
if(arguments.length
== 2 && arguments[1] instanceof Event && arguments[1].shiftKey
== true){
var newTab =
gBrowser.addTab(url);
gBrowser.selectedTab
= newTab;
}else{
openOnCurrentTab(url);
}
}
5.Chrome 시스템에 등록
만들어진 extention은 chrome 시스템에 등록을 해야 사용이 가능합니다. firefox의 경우 profile 디렉토리에 등록 파일을 만드는
것으로 간단히 extention을 추가 할 수 있습니다.
* 윈도우 사용자의 경우 실행(윈도우키 + R)메뉴에서
%APPDATA% 를 입력하면 사용자 어플리케이션 데이터 폴더가 열립니다.그 안에서 Mozilla>Firefox>Profiles>bz94kxr2.default(사용자마다 다름)>extensions 폴더가 Firefox 의 chrome시스템 디렉토리입니다
등록 파일의 이름은 install.rdf 파일에서 만든 extention의 ID와 동일하게 설정하고 내용은 extention의 루트 디렉토리 - 엄밀히 말하면 chrome 디렉토리의 부모 디렉토리 - 입니다.
예) 등록파일: daummenu@asrada.net
내 용: E:\workspace\xul\daumment
등 록 과정을 마친 후 Firefox를 실행시켜보면 메뉴바의 help 메뉴 왼쪽에 "다음" 이라는 메뉴가 추가되었음을 확인할 수 있습니다. 그리고 Firefox의 도구
> 부가기능을 보면 우리가 만든 daummenu 라는 확장기능이 표시가 되고 daummenu에서 오른쪽 버튼을 눌러 "daummenu 정보"를 클릭하면 about.xul의 내용이 다이얼로그로 나타납니다.
III.with XPCOM
XPCOM 은 Microsoft COM과 비슷한 Cross Platform Component Object Model로서
Java,Javascript,Python,perl,Ruby 등 다양한 언어로 컴포넌트를 사용하거나 인터페이스를 구현 할 수 있으며
파일과 메모리 관리,쓰레드 제어 등 XUL과 Javascript로는 불가능한 부분을 구현 할 수 있도록 해줍니다.
XPCOM 컴포넌트는 C++ 뿐만 아니라
Javascript로도 구현 할 수 있기 때문에 C++을 다룰줄 몰라도 원하는 컴포넌트를
손 쉽게 만들어 사용할 수 있습니다.
* 작업표시줄 위로 메세지 다이얼로그를 보여주는 예제
var alertsService =
Components.classes["@mozilla.org/alerts-service;1"].getService(Components.interfaces.nsIAlertsService);
alertsService.showAlertNotification("chrome://mozapps/skin/downloads/downloadIcon.png",
"업데이트가 있습니다", "확인", false, "", null);
* 파일 복사를 구현한 예제
function copyFile(sourcefile,destdir)
{
// get a component for the file to copy
var aFile =
Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
if (!aFile) return false;
// get a component for the directory to copy to
var aDir =
Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
if (!aDir) return false;
// next, assign URLs to the file components
aFile.initWithPath(sourcefile);
aDir.initWithPath(destdir);
// finally, copy the file, without renaming it
aFile.copyTo(aDir,null);
}
copyFile("/mozilla/testfile.txt","/etc");
참고문헌