2008年3月31日星期一

解决Qt4.4 beta输入法侯选框的问题

昨天在QInputContext.cpp找了半天,尝试修改代码也没有解决侯选框出不来的问题。在说到解决方法之前,首先感谢souce insight,没有这么好的编辑器,我都不知道要怎么去看这些大型工程的源代码。

查看了一下IME编辑相关的资料,顺代的在qt4.4的源码中搜索与WM_IME开头的消息除理代码,不多,也就几条,最后在qapplication_win.cpp让我给发现了,嘿嘿,就是在处理WM_IME_NOTIFY消息的代码有问题,代码如下:

case WM_IME_NOTIFY:
            // special handling for ime, only for widgets in a popup
            if (wParam  == IMN_OPENCANDIDATE) {
                imeParentWnd = hwnd;
                if (QApplication::activePopupWidget()) {
                    // temporarily disable the mouse grab to allow mouse input in
                    // the ime candidate window. The actual handle is untouched
                    if (autoCaptureWnd)
                        ReleaseCapture();
                }
            } else if (wParam  == IMN_CLOSECANDIDATE) {
                imeParentWnd = 0;
                if (QApplication::activePopupWidget()) {
                    // undo the action above, when candidate window is closed
                    if (autoCaptureWnd)
                        SetCapture(autoCaptureWnd);
                }
            }

result = false;//added by zhongfanglin@gmail.com
            break;
        default:
            result = false;                        // event was not processed
            break;
        }
    }

    if (evt_type != QEvent::None) {                // simple event
        QEvent e(evt_type);
        result = qt_sendSpontaneousEvent(widget, &e);
    }

//add by zhongfanglin@anzsoft.com
    if(AnzSkin->winEventFilter(&msg,&res))
        RETURN(res);
    //end add

    if (result)
        RETURN(false);

do_default:
    RETURN(QWinInputContext::DefWindowProc(hwnd,message,wParam,lParam))
}

 

 

 

作用没太看明白,但是从代码可以看出,WM_IME_NOTIFY被拦截了,并没有交给默认的消息处理函数,所以在case WM_IME_NOTIFY:节添加了一句代码,result = false,重新编译QtGui模块,运行程序,期待已久的输入法侯选框终于出现了。

不过没明白的是,我用的五笔加加在修改这个代码之前是能出侯选框的,看来是五笔加加不是用的IME体系的侯选框处理机制。

顺便发个牢骚,现在好用的拼音输入法真多,又漂亮又好用,为吓咪就没人做好看漂亮又好用的五笔呢。。。。。。只怪用不来拼音输入法,只好老实的用偶的五笔了。

升级至Qt4.4又碰到输入法问题

昨天把QT库的版本升级到了4.4_beta以解决之前版本的切换窗口之后输入法叫不起来的问题。我自己用的是五笔加加输入法,因为测试过没有问题,所以决定不等Qt发布Release版本,先用beta版本对付一下。

升级的时候也碰到不少问题,特别是stylesheet的问题,很多style都要修改,郁闷。最后还是完成了升级。

不过晚上的时候老詹说又有输入法问题,输入法的选字窗口显示了。咦,我的五笔加加工作是正常的啊。我是那种典型的发音不准的南方人,所以从来不用拼音输入法的,一直都用五笔加加输入法,所以没有发现这个问题!装上其它的输入法试了一下,果然是!!!郁闷

 

在网上搜索了一下,发现在有个在Trolltech工作的中国工程师齐亮,给他发了封邮件询问一下这个问题,不知道会不会看到这个邮件。希望这个问题能够解决。

Qt4.4 QTabWidget fixed

在设置tabPosition为west,并且想设置tab只显示Icon不显示文字时Tab会比想要的效果长,为了解决这个问题,修改

QStyleSheetStyle::sizeFromContents函数,修改部分如下:(只要修改一句代码,注释一些代码即可)

 

#ifndef QT_NO_TABBAR
    case CT_TabBarTab: {
        QRenderRule subRule = renderRule(w, opt, PseudoElement_TabBarTab);
        sz = csz.expandedTo(subRule.minimumContentsSize());
        if (subRule.hasBox() || subRule.hasBorder()) {
            sz = subRule.boxSize(sz);
            int spaceForIcon = 0;
            bool vertical = false;
            if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
                if (!tab->icon.isNull())
                    spaceForIcon = 6 /* icon offset */ + 4 /* spacing */ + 2 /* magic */; // ###: hardcoded to match with common style
                vertical = verticalTabs(tab->shape);
            }
            return sz;//commited by zhongfanglin@gmail.com + QSize(vertical ? 0 : spaceForIcon, vertical ? spaceForIcon : 0);
        }
        break;
                       }
#endif // QT_NO_TABBAR

firefox开发:使用XPCOM访问Windows注册表(Accessing the Windows Registry Using XPCOM)

Introduction

When implementing Windows-specific functionality, it is often useful to access the Windows registry for information about the environment or other installed programs. To this end, there exist XPCOM interfaces to read and write registry data. This article will show you how to use the available interfaces in several Mozilla products.

The examples in this document are all written in JavaScript using XPCOM.

[edit] Support in Firefox 1.5 or newer

In Firefox 1.5, a new API was added, nsIWindowsRegKey, which provides extensive registry functionality. The interface follows the Windows API fairly closely, but with many of the low-level details taken care of for you. If you are writing an extension that only needs to support Firefox 1.5 or newer, then you only need to read this section.

[edit] A simple example

Here's a simple example showing how to read your Windows ProductId:

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
.createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
wrk.ACCESS_READ);
var id = wrk.readStringValue("ProductId");
wrk.close();


This example, while simple, shows several important things about using the interface. First, you must use createInstance() to get an object implementing this interface, not getService(). Second, you must call open() on the key before attempting to read a value.



Notice in the open() call that the root key to use is specified using the named constants available on the nsIWindowsRegKey interface, in this case ROOT_KEY_LOCAL_MACHINE, which corresponds to HKEY_LOCAL_MACHINE in the Windows registry. Also notice that the path to the key has backslashes escaped, a necessity in JavaScript and C++ string constants.



The desired access rights are specified using a named constant from the interface, in this example ACCESS_READ. This can be very important when dealing with non-Administrator accounts with restricted privileges.



The value is read using readStringValue(). You have to specify what type of data you expect to read, which we will expand on later. Finally, note that you should close the key when you are done to avoid wasting system resources.





[edit] Opening Registry Keys


Before doing anything with a registry key you must first open the key you are interested in. The example above demonstates this using the open() method. If you want to create a new key, you can use the create() method, which takes the same parameters as open(). Note that it is not an error to call create() on an existing key, and doing so has the same result as calling open().



Both of these methods take a root key as the first parameter. From JavaScript, you will want to use the named constants on the interface for this parameter. They are:




  • ROOT_KEY_CLASSES_ROOT — Corresponds to HKEY_CLASSES_ROOT


  • ROOT_KEY_CURRENT_USER — Corresponds to HKEY_CURRENT_USER


  • ROOT_KEY_LOCAL_MACHINE — Corresponds to HKEY_LOCAL_MACHINE



The second parameter for open() and create() is the path to the key. As noted in the example above, you will need to escape backslashes within the string.



The third parameter for open() and create() is the access mode. It is specified as a bitwise combination of flags defined on the interface. You can read the interface documentation for a full explanation, but we will show only the three most commonly used modes here:




  • ACCESS_READ — For reading values, enumerating keys, and receiving notifications


  • ACCESS_WRITE — For setting values and creating sub keys


  • ACCESS_ALL — Access for all operations



In addition to open() and create(), there are the openChild() and createChild() methods. You can call these methods on an already-opened registry key to open a child key. Both methods take a relative path and access mode as parameters and return a new object implementing nsIWindowsRegKey. Here's the simple example again, but using openChild():



var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
.createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft",
wrk.ACCESS_READ);
var subkey = wrk.openChild("Windows\\CurrentVersion", wrk.ACCESS_READ);
var id = subkey.readStringValue("ProductId");
subkey.close();
wrk.close();


Once you've opened a registry key, you can begin to make use of it.





[edit] Reading Registry Values


Probably the most common action associated with the Windows registry is reading values. The simple example above shows how to read an existing string value. However, Windows registry values can have several data types, so you need to ensure that you read the correct type. You can check the type of a value using the method getValueType(). This method returns an integer indicating the data type of the value. The data types supported by this interface are defined as named constants on the interface as follows:




  • TYPE_NONE — Probably not useful


  • TYPE_STRING — A Unicode string value


  • TYPE_BINARY — Binary data


  • TYPE_INT — A 32 bit integer


  • TYPE_INT64 — A 64 bit integer



Each of these types (except TYPE_NONE) has a corresponding method to read the value data:




  • readStringValue()


  • readBinaryValue()


  • readIntValue()


  • readInt64Value()



Since JavaScript is a dynamically-typed language, you may wish to use the following code to handle all types of data. In this function, wrk is expected to be an already opened nsIWindowsRegKey.



function readRegistryValue(wrk, value)
{
switch (wrk.getValueType(value)) {
case wrk.TYPE_STRING:
return wrk.readStringValue(value);
case wrk.TYPE_BINARY:
return wrk.readBinaryValue(value);
case wrk.TYPE_INT:
return wrk.readIntValue(value);
case wrk.TYPE_INT64:
return wrk.readInt64Value(value);
}
// unknown type
return null;
}



[edit] Writing Registry Values


Writing registry values is quite similar to reading. For each supported data type, there is a write*Value() method complementary to the read*Value() method. Don't forget that if you are writing a new value, you may need to create() the parent key first. This example demonstrates writing a new string value:



var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
.createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.create(wrk.ROOT_KEY_CURRENT_USER,
"SOFTWARE\\MDC\\Test",
wrk.ACCESS_WRITE);
wrk.writeStringValue("TestValue", "Hello World!");
wrk.close();



[edit] Checking the Existence of Keys and Values


Before you attempt to read a value or open a child key, you should check to see whether it exists first. The nsIWindowsRegKey interface provides methods for both of these—hasValue() and hasChild()—as demonstrated in this example:



var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
.createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft",
wrk.ACCESS_READ);
if (wrk.hasChild("Windows")) {
var subkey = wrk.openChild("Windows\\CurrentVersion", wrk.ACCESS_READ);
var id;
if (subkey.hasValue("ProductId"))
id = subkey.readStringValue("ProductId");
subkey.close();
}
wrk.close();



[edit] Enumerating Registry Keys and Values


In some situations, you may want to enumerate a number of keys or values whose names you do not know. The nsIWindowsRegKey interface provides the childCount, getChildName(), valueCount, and getValueName() properties and methods for enumerating keys and values respectively. You can use these methods to read a list of values or recursively access a branch of the registry. This example reads all the startup programs in one key of the registry.



var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
.createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",
wrk.ACCESS_READ);
for (var i=0; i<wrk.valueCount; i++) {
var name = wrk.getValueName(i);
var value = readRegistryValue(wrk, name);
// do something interesting here...
}
wrk.close();


For simplicity, this example assumes the existence of the readRegistryValue() function defined above.





[edit] Removing Registry Keys and Values


To remove child keys and values from the registry, you can use the removeChild() and removeValue() methods. removeChild() removes a child key and all of its values, but will fail if the key has any child keys of its own. In that case you must manually enumerate the children and remove them individually. This example shows how to recursively delete a registry key and all of its children. Use with caution!



function removeChildrenRecursive(wrk)
{
// we count backwards because we're removing them as we go
for (var i = wrk.childCount - 1; i >= 0; i--) {
var name = wrk.getChildName(i);
var subkey = wrk.openChild(name, wrk.ACCESS_ALL);
removeChildrenRecursive(subkey);
subkey.close();
wrk.removeChild(name);
}
}

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
.createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_CURRENT_USER,
"SOFTWARE\\MDC\\Test",
wrk.ACCESS_ALL);
removeChildrenRecursive(wrk);
wrk.close();



[edit] Monitoring Registry Keys


If you would like to know whether a registry key has changed since you last checked it, you can use the startWatching(), stopWatching(), and hasChanged() methods. You must call startWatching() for the key to be monitored. The method takes one parameter, a boolean indicating whether child keys should be watched. After that, you can call hasChanged() to determine whether or not you need to reread the value. Calling hasChanged() automatically resets the watch, so you can be sure that if it returns true there are changes. This example demonstrates a trivial registry value cache for one key:



var cache = {};

function readRegistryValueNoCache(wrk, value)
{
switch (wrk.getValueType(value)) {
case wrk.TYPE_STRING:
return wrk.readStringValue(value);
case wrk.TYPE_BINARY:
return wrk.readBinaryValue(value);
case wrk.TYPE_INT:
return wrk.readIntValue(value);
case wrk.TYPE_INT64:
return wrk.readInt64Value(value);
}
// unknown type
return null;
}

function readRegistryValue(wrk, value)
{
if (wrk.hasChanged()) {
// wipe out the cache
cache = {};
}

if (value in cache) {
return cache[value];
}

cache[value] = readRegistryValueNoCache(wrk, value);
return cache[value];
}

var wrk = Components.classes["@mozilla.org/windows-registry-key;1"]
.createInstance(Components.interfaces.nsIWindowsRegKey);
wrk.open(wrk.ROOT_KEY_LOCAL_MACHINE,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
wrk.ACCESS_READ);
wrk.startWatching(false); // only watch the values on this key, not child keys
var id = readRegistryValue(wrk, "ProductId");
/* later you can read this again,
and it should come from the cache unless
there have been changes to the registry.
Remember to call wrk.close() when you
are finished!
*/



[edit] Support in Firefox 1.0



Firefox 1.0 includes a much simpler interface to the Windows registry, without most of the functionality supported in newer versions. The functionality is exposed in the nsIWindowsShellService interface. It consists of only one method, getRegistryEntry(), and a set of named constants to specify the root key. You can use it as shown in the following example:



var wss = Components.classes["@mozilla.org/browser/shell-service;1"]
.getService(Components.interfaces.nsIWindowsShellService);
var id = wss.getRegistryEntry(wss.HKLM,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
"ProductId");


Note: There's no way to set a registry value using this interface.





[edit] Support in SeaMonkey and Other Non-toolkit Applications



In older versions of SeaMonkey and other non-toolkit-based applications, an interface existed called nsIWindowsRegistry, containing the same method and named constants as the methods described above for Firefox 1.0. It can be used as follows:



var wss = Components.classes["@mozilla.org/winhooks;1"]
.getService(Components.interfaces.nsIWindowsRegistry);
var id = wss.getRegistryEntry(wss.HKLM,
"SOFTWARE\\Microsoft\\Windows\\CurrentVersion",
"ProductId");



[edit] Backwards Compatibility



If you need to support Firefox 1.0 and other older browser versions, you should check to see which interfaces are available. The following skeleton code will allow you to determine which interface to use:



if ("@mozilla.org/windows-registry-key;1" in Components.classes) {
// Firefox 1.5 or newer
}
else if ("@mozilla.org/winhooks;1" in Components.classes) {
// SeaMonkey or other older non-toolkit application
}
else if ("@mozilla.org/browser/shell-service;1" in Components.classes) {
var wss = Components.classes["@mozilla.org/browser/shell-service;1"]
.getService(Components.interfaces.nsIWindowsShellService);
if ("getRegistryEntry" in wss) {
// Firefox 1.0
}
else {
// nothing supported
}
}
else {
// nothing supported
}

[转]在Windows中查看端口占用情况的简单方法

用这个命令,在DOS窗口执行:netstat -ano
看看占用0.0.0:80端口的PID是多少
然后在“任务管理器”中查到与该PID对应的程序。
如果任务管理器的进程页中看不到PID栏,则在任务管理器的菜单〖查看〗〖选择列〗中选择一下

XUL Tutorial:XUL Structure

XUL,是XML User Interface Language的缩写。

XUL Tutorial:XUL Structure

From MDC

« Previous Next »

Contents

[hide]

We'll begin by looking at how the XUL is handled in Mozilla.

[edit] How XUL is Handled

In Mozilla, XUL is handled much in the same way that HTML or other types of content are handled. When you type the URL of an HTML page into the browser's address field, the browser locates the web site and downloads the content. The Mozilla rendering engine takes the content in the form of HTML source and transforms it into a document tree. The tree is then converted into a set of objects that can be displayed on the screen. Style sheets (CSS), images, and other technologies are used to control the presentation. XUL functions in much the same way.

In fact, in Mozilla, all document types, whether they are HTML or XUL, or even SVG, are all handled by the same underlying code. This means that the same CSS properties may be used to style both HTML and XUL, and many of the features can be shared between both. However, there are some features that are specific to HTML such as forms, and others which are specific to XUL such as overlays. Since XUL and HTML are handled in the same way, you can load both from either your local file system, from a web page, or from an extension or standalone XULRunner application.

Content from remote sources eg http://localhost/~username/, regardless of whether they are HTML or XUL or another document type, are limited in the type of operations they can perform, for security reasons. For this reason, Mozilla provides a method of installing content locally and registering the installed files as part of its chrome system. This allows a special URL form to be used called a chrome:// URL. By accessing a file using a chrome URL, the files receive elevated privileges to access local files, access preferences and bookmarks and perform other privileged operations. Obviously, web pages do not get these privileges, unless they are signed with a digital certificate and the user has granted permission to perform these operations.

This chrome package registration is the way Firefox extensions are able to add features to the browser. The extensions are small packages of XUL files, JavaScript, style sheets and images packed together into a single file. This file can be created by using a ZIP utility. When the user downloads it, it will be installed onto the user's machine. It will hook into the browser using a XUL specific feature called an overlay which allows the XUL from the extension and the XUL in the browser to combine together. To the user, it may seem like the extension has modified the browser, but in reality, the code is all separate, and the extension may be uninstalled easily. Registered packages are not required to use overlays, of course. If they don't, you won't be able to access them via the main browser interface, but you can still access them via the chrome URL, if you know what it is.

Standalone XUL applications may include XUL code in a similar way, but, of course, the XUL for the application will be included as part of the installation, instead of having to be installed separately as an extension. However, this XUL code will be registered in the chrome system such that the application can display the UI.

It is worth noting that the Mozilla browser itself is actually just a set of packages containing XUL files, JavaScript and style sheets. These files are accessed via a chrome URL and have enhanced privileges and work just like any other package. Of course, the browser is much larger and more sophisticated than most extensions. Firefox and Thunderbird as well as number of other components are all written in XUL and are all accessible via chrome URLs. You can examine these packages by looking in the chrome directory where Firefox or another XUL application is installed.

The chrome URL always begins with 'chrome://'. Much like how the 'http://' URL always refers to remote web sites accessed using HTTP and the 'file://' URL always refers to local files, the 'chrome://' URL always refers to installed packages and extensions. We'll look more at the syntax of a chrome URL in the next section. It is important to note that when accessing content through a chrome URL, it gains the enhanced privileges described above that other kinds of URLs do not. For instance, an HTTP URL does not have any special privileges, and an error will occur if a web page tries, for example, to read a local file. However, a file loaded via a chrome URL will be able to read files without restriction.

This distinction is important. This means that there are certain things that content of web pages cannot do, such as read the user's bookmarks. This distinction is not based on the kind of content being displayed; only on the type of URL used. Both HTML and XUL placed on a web site have no extra permissions; however both HTML and XUL loaded through a chrome URL have enhanced permissions.

If you are going to use XUL on a web site, you can just put the XUL file on the web site as you would an HTML file, and then load its URL in a browser http://localhost/xul.php. Ensure that your web server is configured to send XUL files with the content type of application/vnd.mozilla.xul+xml (eg with PHP header('Content-type: application/vnd.mozilla.xul+xml');). This content type is how Mozilla knows the difference between HTML and XUL. Mozilla does not use the file extension, unless reading files from the file system, but you should use the .xul extension for all XUL files. You can load XUL files from your own machine by opening them in the browser, or by double-clicking the file in your file manager.

Remember that remote XUL will have significant restrictions on what it can do.

[edit] Document types: HTML XML XUL CSS

Mozilla uses a distinctly different kind of document object (DOM) for HTML and XUL, although they share most of their functionality. There are three main types of document in Mozilla: HTML, XML, and XUL. Naturally, the HTML document is used for HTML documents, the XUL document is used for XUL documents, and the XML document is used for other types of XML documents. Since XUL is also XML, the XUL document is a subtype of the more generic XML document. There are subtle differences in functionality. For example, while the form controls on an HTML page are accessible via the document.forms property, this property isn't available for XUL documents, since XUL doesn't have forms in the HTML sense. Likewise, XUL specific features such as overlays and templates are only available in XUL documents.

This distinction between documents is important. It is possible to use many XUL features in HTML or XML documents since they aren't document type specific; however other features require the right kind of document. For instance, you can use the XUL layout types in other documents since they don't rely on the XUL document type to function.

To summarize the points made above:

  • Mozilla renders both HTML and XUL using the same underlying engine and uses CSS to specify their presentation.
  • XUL may be loaded from a remote site, the local file system, or installed as a package and accessed using a chrome URL. This last option is what browser extensions do.
  • Chrome URLs may be used to access installed packages and open them with enhanced privileges.
  • HTML, XML, and XUL each have a different document type. Some features may be used in any document type whereas some features are specific to one kind of document.

The next few sections describe the basic structure of a chrome package which can be installed into Mozilla. However, if you just want to get started building a simple application, you may skip ahead to Creating a Window and save this section for later.

[edit] Package Organization

Mozilla is organized in such a way that you can have as many components as you want pre-installed. Each extension is also a component with a separate chrome URL. It also has one component for each installed theme and locale. Each of these components, or packages, is made up of a set of files that describe the user interface for it. For example, the messenger component has descriptions of the mail messages list window, the composition window and the address book dialogs.

The packages that are provided with Mozilla are located within the chrome directory, which are in the directory where you installed Mozilla. The chrome directory is where you find all the files that describe the user interface used by the Mozilla browser, mail client, and other applications. Typically, you put all the XUL files for an application in this directory, although extensions are installed in the extensions directory for a particular user. Just copying a XUL file into the chrome directory doesn't give the file any extra permissions, nor can it be accessed via a chrome URL. To gain the extra privileges, you will need to create a manifest file and put that in the chrome directory. This file is easy to create, as it is typically only a couple of lines long. It is used to map a chrome URL to a file or directory path on the disk where the XUL files are located. Details of how to create this file will be discussed in a later section.

The only way to create content that can be accessed through a chrome URL is by creating a package as described in the next few sections. This directory is called 'chrome' likely because it seemed like a convenient name to use for the directory where the chrome packages that are included with Mozilla are kept.

To further the confusion, there are two other places where the word "chrome" might appear. These are the -chrome command line argument and the chrome modifier to the window.open() function. Neither of these features grant extra privileges; instead they are used to open a new top-level window without the browser UI such as the menu and toolbar. You will commonly use this feature in more complex XUL applications since you wouldn't want the browser UI to exist around your dialog boxes.

The files for a package are usually combined into a single JAR file. A JAR file may created and examined using a ZIP utility. For instance, you can open the JAR files in Mozilla's chrome directory to see the basic structure of a package. Although it's normal to combine the files into a JAR file, packages may also be accessed in expanded form into a directory. Although you don't normally distribute a package this way, it is handy during development since you can edit the file directly and then reload the XUL file without having to repackage or reinstall the files.

By default, Mozilla applications parse XUL files and scripts, and store a pre-compiled version in memory for the remainder of the application session. This improves performance. However, because of this, the XUL will be not be reloaded even when the source files are changed. To disable this mechanism, it is necessary to change the preference nglayout.debug.disable_xul_cache. In Firefox, this preference may be added to the user preferences by typing "about:config" in the address field, and setting this value to true. Or, just manually edit your user.js preferences file and add the following line:

pref("nglayout.debug.disable_xul_cache", true);


There are usually three different parts to a chrome package, although they are all optional. Each part is stored in a different directory. These three sets are the content, the skin, and the locale, which are all described below. A particular package might provide one or more skins and locales, but a user can replace them with their own. In addition, the package might include several different applications, each accessible via different chrome URLs. The packaging system is flexible enough so that you can include whatever parts you need and allow other parts, such as the text for different languages, to be downloaded separately.



The three types of chrome packages are:




  • Content - Windows and scripts


    The declarations of the windows and the user interface elements contained within them. These are stored in XUL files, which have a .xul extension. A content package can have multiple XUL files, but the main window should have a filename that is the same as the package name. For example, the editor package will have a file within it called editor.xul. Scripts are placed in separate files alongside the XUL files.


  • Skin - Style sheets, images and other theme specific files


    Style sheets describe details of the appearance of a window. They are stored separately from XUL files to facilitate modifying the skin (theme) of an application. Any images used are stored here also.


  • Locale - Locale specific files


    All the text that is displayed within a window is stored separately. This way, a user can have a set for their own language.




[edit] Content Packages



The name of the JAR file might describe what it contains, but you can't be sure unless you view its contents. Let's use the browser package included with Firefox as an example. If you extract the files in browser.jar, you will find that it contains a directory structure much like the following:



content
browser
browser.xul
browser.js
-- other browser XUL and JS files goes here --
bookmarks
-- bookmarks files go here --
preferences
-- preferences files go here --
.
.
.


This is easily recognizable as a content package, as the top-level directory is called content. For skins, this directory will usually be called skin and for locales, it will usually be called locale. This naming scheme isn't necessary, but this is a common convention to make the parts of a package clearer. Some packages may include a content section, a skin, and a locale. In this case, you will find a subdirectory for each type. For example, Chatzilla is distributed in this way.



The content/browser directory contains a number of files with .xul and .js extensions. The XUL files are the ones with the .xul extension. The files with .js extensions are JavaScript files containing scripts that handle the functionality of a window. Many XUL files have a script file associated with them, and some may have more than one.



In the listing above, two files have been shown. There are of course others, but for simplicity they aren't shown. The file browser.xul is the XUL file that describes the main browser window. The main window for a content package should have the same name as the package with a .xul extension. In this case, the package name is "browser" so we expect to find browser.xul. Some of the other XUL files describe separate windows. For example, the file pageInfo.xul describes the page info dialog.



Many packages will include a contents.rdf file, which describes the package, its author, and the overlays it uses. However, this file is obsolete and has been replaced with a simpler mechanism. This newer method is the manifest file mentioned earlier, and you will find these as files with the .manifest extension in the chrome directory. For instance, browser.manifest describes the browser package.



Several subdirectories, such as bookmarks and preferences, describe additional sections of the browser component. They are placed in different directories only to keep the files more organized.





[edit] Skins or Themes



Although the underlying code for Mozilla calls them skins and the user interface calls them themes, they're both referring to the same thing. The classic.jar file describes the default theme provided with Firefox. The structure is similar to the content packages. For example, examining classic.jar:



skin
classic
browser
browser.css
-- other browser skin files go here --
global
-- global skin files go here --
.
.
.


Again, this directory structure isn't necessary and is used for convenience. You can actually put all the files in one directory at the top level and not use subdirectories. However, for larger applications, subdirectories are used to separate the different components. In the example above, a directory exists for theme related files for the browser and another for global theme related files. The global directory contains skin files that are general to all packages. These files will apply to all components and will be included with your own standalone applications. The global part defines the appearance of all of the common XUL widgets, whereas the other directories have files that are specific to those applications. Firefox includes both the global and browser theme files in one archive, but they can be included separately.



A skin is made up of CSS files and a number of images used to define the look of an interface. The file browser.css is used by browser.xul and contains styles that define the appearance of various parts of the browser interface. Again, note how the file browser.css has the same name as the package. By changing the CSS files, you can adjust the appearance of a window without changing its function. This is how you can create a new theme. The XUL part remains the same but the skin part changes independently.





[edit] Locales



The file en-US.jar describes the language information for each component, in this case for US English. Like the skins, each language file contains files that specify text used by the package for a specific language. The locale structure is similar to the others, so it won't be listed here.



The localized text is stored in two types of files: DTD files and properties files. The DTD files have a .dtd extension and contain entity declarations, one for each text string that is used in a window. For example, the file browser.dtd contains entity declarations for each menu command. In addition, keyboard shortcuts for each command are also defined, because they may be different for each language. DTD files are used by XUL files so, in general, you will have one per XUL file. The locale part also contains properties files, which are similar, but are used by script files. The file browser.properties contains a few such localized strings.



This structure allows you to translate Mozilla or a component into a different language by just adding a new locale for that language. You don't have to change the XUL code at all. In addition, another person could supply a separate package that applies a skin or locale to your content part, thus providing support for a new theme or language without having to change the original package.





[edit] Other Packages



There is a special package called toolkit (or global). We saw the global directory earlier for skins. The file toolkit.jar contains the corresponding content part for it. It contains some global dialogs and definitions. It also defines the default appearance and functionality of the various common XUL widgets such as textboxes and buttons. The files located in the global part of a skin package contain the default look for all of the XUL interface elements. The toolkit package is used by all XUL applications.





[edit] Adding a Package



Mozilla places the packages that are included with the installation in the chrome directory. However, they do not need to be placed there. When installing another package, you can place it anywhere on the disk, as long as a manifest file points to it. It is common to place packages into the chrome directory simply because it is convenient; however, they will work just as well from another directory or somewhere on your local network. You cannot store them on a remote site, unless the remote site is mounted through the local file system.



There are two chrome directories used for XUL applications: one is installed in the same place where the application is installed, while the other is part of user's profile. The former allows packages that are shared by all users while the latter allows packages to be created only for a specific user or users. Extensions, while installed in a separate extensions directory, are also usually user specific. Any manifest files located in either chrome directory will be examined to see which packages are installed.



In the next section, we'll look at how to refer to chrome packages using the chrome URL.

Setting up extension development environment

Setting up extension development environment

From MDC

This article gives suggestions on how to set up your Mozilla application for extension development.

Contents

[hide]

[edit] Development preferences

These preferences will make debugging easier at the expense of lower performance.

See Editing Configuration Files for information on setting preferences. Note that some of these preferences are not listed in about:config by default, so you'll need to create new (boolean) entries for them.

See below under "Development Profile" to setup a separate development profile before you make these changes.

  • javascript.options.showInConsole = true. Logs errors in chrome files to the Error Console.
  • nglayout.debug.disable_xul_cache = true. Disables the XUL cache so that changes to windows and dialogs do not require a restart. This assumes you're using directories rather than JARs. Changes to XUL overlays will still require reloading of the document overlaid.
  • browser.dom.window.dump.enabled = true. Enables the use of the dump() statement to print to the standard console. See window.dump for more info. You can also use nsIConsoleService from privileged script.
  • javascript.options.strict = true. Enables strict JavaScript warnings in the Error Console. Note that since many people have this setting turned off when developing, you will see lots of warnings for problems with their code in addition to warnings for your own extension. You can filter those with Console2.

[edit] Development extensions

These extensions may help you with your development.

[edit] Development profile

To avoid the performance hit of development-related prefs and extensions, and to avoid borking your personal data, you can use a separate profile for development work.

You can run two instances of Firefox using separate profiles if you start Firefox with the -no-remote parameter. For example, the following command will run your development profile whether "normal" Firefox is already running or not. (Assuming your development profile is called "dev"):

start "" "%ProgramFiles%\Mozilla Firefox\firefox.exe" -no-remote -P dev


To run Firefox with default profile just run "firefox" or "firefox -P default", as usual.





[edit] Custom code location



Rather than having to constantly reinstall the extension whenever you change something and to protect your source files from accidental deletion when uninstalling, you can place your source outside your profile in a location of your choosing.




  1. Find the extension ID from the install.rdf included with your extension


  2. Create a file in your_profile_directory/extensions/ with the above ID as the filename (eg. `your_profile_directory/extensions/{46D1B3C0-DB7A-4b1a-863A-6EE6F77ECB58}`) (Find your profile directory)


  3. The contents of this file should be the path to the folder that contains your install.rdf file. (eg. `/full/path/to/yourExtension`. Windows users should use the drive name (CAPS) and backslashes instead of slashes: eg. `C:\full\path\to\yourExtension`). In Firefox 3, if you already the extension installed via XPI, you might need to install one or all of the extensions.* files in the profile folder. Backup first, but these files will be regenerated.


  4. Place the file in the extensions folder of your profile and restart the application.




[edit] Using directories rather than JARs



Regardless of whether you choose to package your extension's chrome in a JAR or in directories, developing in directories is simpler. If you choose a JARed structure for releasing, you can still develop with a directory structure by editing your chrome.manifest. For example, rather than having



content	myExtension	jar:chrome/myExtension.jar!/content/


use



content	myExtension	chrome/content/