whitespace
[conkeror.git] / modules / window.js
blob8d333b627a1b49f5921c7d3dbe5e682243dfa1ef
1 /**
2  * (C) Copyright 2007 John J. Foerch
3  * (C) Copyright 2007-2008 Jeremy Maitin-Shepard
4  *
5  * Use, modification, and distribution are subject to the terms specified in the
6  * COPYING file.
7 **/
9 in_module(null);
11 require("mode.js");
13 var define_window_local_hook = simple_local_hook_definer();
14 var define_window_local_coroutine_hook = simple_local_coroutine_hook_definer();
17 define_hook("make_window_hook");
19 var window_watcher = Cc["@mozilla.org/embedcomp/window-watcher;1"]
20     .getService(Ci.nsIWindowWatcher);
22 function generate_new_window_tag (tag) {
23     var existing = [];
24     var exact_match = false;
25     var en = window_watcher.getWindowEnumerator();
26     if (tag == '')
27         tag = null;
28     var re;
29     if (tag)
30         re = new RegExp ("^" + tag + "<(\\d+)>$");
31     else
32         re = new RegExp ("^(\\d+)$");
33     while (en.hasMoreElements()) {
34         var w = en.getNext().QueryInterface(Ci.nsIDOMWindow);
35         if ('tag' in w)  {
36             if (tag && w.tag == tag) {
37                 exact_match = true;
38                 continue;
39             }
40             var re_result = re.exec(w.tag);
41             if (re_result)
42                 existing.push(re_result[1]);
43         }
44     }
45     if (tag && ! exact_match)
46         return tag;
48     existing.sort(function (a, b) { return a - b; });
50     var n = 1;
51     for (var i = 0; i < existing.length; i++) {
52         if (existing[i] < n) continue;
53         if (existing[i] == n) { n++; continue; }
54         break;
55     }
56     if (tag)
57         return tag + "<" + n + ">";
58     else
59         return n;
62 function make_chrome_window (chrome_uri, args) {
63     return window_watcher.openWindow(null, chrome_uri, "_blank",
64                                      "chrome,dialog=no,all,resizable", args);
67 var conkeror_chrome_uri = "chrome://conkeror-gui/content/conkeror.xul";
69 function make_window (initial_buffer_creator, tag) {
70     var args = { tag: tag,
71                  initial_buffer_creator: initial_buffer_creator };
72     var result = make_chrome_window(conkeror_chrome_uri, null);
73     result.args = args;
74     make_window_hook.run(result);
75     var close = result.close;
76     result.close = function () {
77         function attempt_close () {
78             var res = yield window_before_close_hook.run(result);
79             if (res) {
80                 window_close_hook.run(result);
81                 close.call(result);
82             }
83         }
84         co_call(attempt_close());
85     };
86     return result;
89 function get_window_by_tag (tag) {
90     var en = window_watcher.getWindowEnumerator();
91     while (en.hasMoreElements()) {
92         var w = en.getNext().QueryInterface(Ci.nsIDOMWindow);
93         if ('tag' in w && w.tag == tag)
94             return w;
95     }
96     return null;
99 /* FIXME: decide if this should include not-fully-initialized windows  */
100 function for_each_window (func) {
101     var en = window_watcher.getWindowEnumerator();
102     while (en.hasMoreElements()) {
103         var w = en.getNext().QueryInterface(Ci.nsIDOMWindow);
104         if ('conkeror' in w)
105             func(w);
106     }
109 function get_recent_conkeror_window () {
110     var wm = Cc['@mozilla.org/appshell/window-mediator;1']
111        .getService(Ci.nsIWindowMediator);
112     var window = wm.getMostRecentWindow("navigator:browser");
113     if (window && ("conkeror" in window))
114         return window;
115     var en = window_watcher.getWindowEnumerator();
116     while (en.hasMoreElements()) {
117         window = en.getNext().QueryInterface(Ci.nsIDOMWindow);
118         if ('conkeror' in window)
119             return window;
120     }
121     return null;
124 define_window_local_hook("window_initialize_early_hook");
125 define_window_local_hook("window_initialize_hook");
126 define_window_local_hook("window_initialize_late_hook");
128 var window_extra_argument_list = [];
130 define_variable("window_extra_argument_max_delay", 100);
132 function window_setup_args (window) {
133     if (window.args != null)
134         return;
136     var cur_time = Date.now();
137     var i;
138     var result = null;
139     for (i = 0; i < window_extra_argument_list.length; ++i) {
140         var a = window_extra_argument_list[i];
141         if (a.time > cur_time - window_extra_argument_max_delay) {
142             delete a.time;
143             result = a;
144             i++;
145             break;
146         }
147     }
148     window_extra_argument_list = window_extra_argument_list.slice(i);
150     if (result == null)
151         window.args = {};
152     else
153         window.args = result;
156 function window_set_extra_arguments (args) {
157     args.time = Date.now();
158     window_extra_argument_list.push(args);
161 function window_get_this_browser () {
162     return this.buffers.current.browser;
165 function window_initialize (window) {
166     window.conkeror = conkeror;
168     // Used by get_window_from_frame to get an unwrapped window reference
169     window.escape_wrapper = function (x) { x(window); };
171     window_setup_args(window);
173     // Set tag
174     var tag = null;
175     if ('tag' in window.args)
176         tag = window.args.tag;
177     window.tag = generate_new_window_tag(tag);
179     // Add a getBrowser() function to help certain extensions designed
180     // for Firefox work with conkeror
181     window.getBrowser = window_get_this_browser;
183     window_initialize_early_hook.run(window);
184     delete window.window_initialize_early_hook; // used only once
186     window_initialize_hook.run(window);
187     delete window.window_initialize_hook; // used only once
189     window.setTimeout(function () {
190             window_initialize_late_hook.run(window);
191             delete window.window_initialize_late_hook; // used only once
192             delete window.args; // get rid of args
193         }, 0);
195     window.addEventListener("close",
196                             function (event) {
197                                 event.preventDefault();
198                                 event.stopPropagation();
199                                 this.close();
200                             },
201                             true /* capture */);
204 define_window_local_coroutine_hook("window_before_close_hook",
205                                    RUN_HOOK_UNTIL_FAILURE);
206 define_window_local_hook("window_close_hook", RUN_HOOK);
209 function define_global_window_mode (name, hook_name) {
210     function install (window) {
211         if (name in window)
212             throw new Error(name + " already initialized for window");
213         window[name] = new conkeror[name](window);
214     }
215     function uninstall (window) {
216         if (!window[name])
217             throw new Error(name + " not initialized for window");
218         window[name].uninstall();
219         delete window[name];
220     }
221     define_global_mode(name + "_mode",
222                        function () { // enable
223                            add_hook(hook_name, install);
224                            for_each_window(install);
225                        },
226                        function () { // disable
227                            remove_hook(hook_name, install);
228                            for_each_window(uninstall);
229                        });
231 ignore_function_for_get_caller_source_code_reference("define_global_window_mode");
235 /// Window title formatting
238  * Default tile formatter.  The page url is ignored.  If there is a
239  * page_title, returns: "Page title - Conkeror".  Otherwise, it
240  * returns just: "Conkeror".
241  */
242 function default_title_formatter (window) {
243     var page_title = window.buffers.current.title;
245     if (page_title && page_title.length > 0)
246         return page_title + " - Conkeror";
247     else
248         return "Conkeror";
251 var title_format_fn = null;
253 function set_window_title (window) {
254     window.document.title = title_format_fn(window);
257 function init_window_title () {
258     title_format_fn = default_title_formatter;
260     add_hook("window_initialize_late_hook", set_window_title);
261     add_hook("current_content_buffer_location_change_hook",
262              function (buffer) {
263                  set_window_title(buffer.window);
264              });
265     add_hook("select_buffer_hook",
266              function (buffer) {
267                  set_window_title(buffer.window);
268              }, true);
269     add_hook("current_buffer_title_change_hook",
270              function (buffer) {
271                  set_window_title(buffer.window);
272              });
275 init_window_title();
278 function call_builtin_command (window, command, clear_mark) {
279     var m = window.minibuffer;
280     if (m.active && m._input_mode_enabled) {
281         m._restore_normal_state();
282         var e = m.input_element;
283         var c = e.controllers.getControllerForCommand(command);
284         try {
285             if (c && c.isCommandEnabled(command))
286                 c.doCommand(command);
287         } catch (e) {
288             // ignore errors
289         }
290         if (clear_mark)
291             m.current_state.mark_active = false;
292     } else {
293         function attempt_command (element) {
294             var c;
295             if (element.controllers
296                 && (c = element.controllers.getControllerForCommand(command)) != null
297                 && c.isCommandEnabled(command))
298             {
299                 try {
300                     c.doCommand(command);
301                 } catch (e) {
302                     // ignore errors
303                 }
304                 if (clear_mark)
305                     window.buffers.current.mark_active = false;
306                 return true;
307             }
308             return false;
309         }
310         var element = window.buffers.current.focused_element;
311         if (element && attempt_command(element, command))
312             return;
313         var win = window.buffers.current.focused_frame;
314         while (true) {
315             if (attempt_command(win, command))
316                 return;
317             if (!win.parent || win == win.parent)
318                 break;
319             win = win.parent;
320         }
321     }
324 provide("window");