1
2 /******************************************************************************
3 * MODULE : new_window.cpp
4 * DESCRIPTION: Global window management
5 * COPYRIGHT : (C) 1999-2012 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11
12 #include "tm_data.hpp"
13 #include "convert.hpp"
14 #include "file.hpp"
15 #include "web_files.hpp"
16 #include "tm_link.hpp"
17 #include "message.hpp"
18 #include "dictionary.hpp"
19 #include "new_document.hpp"
20
21 /******************************************************************************
22 * Manage global list of windows
23 ******************************************************************************/
24
25 static int last_window= 1;
26 static array<url> all_windows;
27 extern int nr_windows;
28
29 static path
reset(path p,int i)30 reset (path p, int i) {
31 if (is_nil (p)) return p;
32 else if (p->item == i) return p->next;
33 else return path (p->item, reset (p->next, i));
34 }
35
36 url
create_window_id()37 create_window_id () {
38 url r= "tmfs://window/" * as_string (last_window);
39 all_windows << r;
40 last_window++;
41 return r;
42 }
43
44 void
destroy_window_id(url win)45 destroy_window_id (url win) {
46 for (int i=0; i<N(all_windows); i++)
47 if (all_windows[i] == win) {
48 all_windows= append (range (all_windows, 0, i),
49 range (all_windows, i+1, N(all_windows)));
50 return;
51 }
52 }
53
54 url
abstract_window(tm_window win)55 abstract_window (tm_window win) {
56 if (win == NULL) return url_none ();
57 return win->id;
58 }
59
60 /******************************************************************************
61 * Low level creation and destruction of windows
62 ******************************************************************************/
63
64 static hashmap<url,tm_window> tm_window_table (NULL);
65
66 class kill_window_command_rep: public command_rep {
67 url* id;
68 public:
kill_window_command_rep(url * id2)69 inline kill_window_command_rep (url* id2): id (id2) {}
~kill_window_command_rep()70 inline ~kill_window_command_rep () { tm_delete (id); }
apply()71 inline void apply () {
72 object cmd= list_object (symbol_object ("safely-kill-window"),
73 object (*id));
74 exec_delayed (scheme_cmd (cmd)); }
print(tm_ostream & out)75 tm_ostream& print (tm_ostream& out) { return out << "kill window"; }
76 };
77
78 url
new_window(bool map_flag=true,tree geom="")79 new_window (bool map_flag= true, tree geom= "") {
80 int mask= 0;
81 if (get_preference ("header") == "on") mask += 1;
82 if (get_preference ("main icon bar") == "on") mask += 2;
83 if (get_preference ("mode dependent icons") == "on") mask += 4;
84 if (get_preference ("focus dependent icons") == "on") mask += 8;
85 if (get_preference ("user provided icons") == "on") mask += 16;
86 if (get_preference ("status bar") == "on") mask += 32;
87 if (get_preference ("side tools") == "on") mask += 64;
88 if (get_preference ("bottom tools") == "on") mask += 128;
89 url* id= tm_new<url> (url_none ());
90 command quit= tm_new<kill_window_command_rep> (id);
91 tm_window win= tm_new<tm_window_rep> (texmacs_widget (mask, quit), geom);
92 tm_window_table (win->id)= win;
93 if (map_flag) win->map ();
94 *id= abstract_window (win);
95 return abstract_window (win);
96 }
97
98 static bool
delete_view_from_window(url win)99 delete_view_from_window (url win) {
100 array<url> vs= get_all_views ();
101 for (int i=0; i<N(vs); i++)
102 if (view_to_window (vs[i]) == win) {
103 detach_view (vs[i]);
104 // delete_view (vs[i]);
105 // Don't delete view alltogether, because at least one view is needed
106 // for making the 'buffer_modified' predicate function appropriately
107 return true;
108 }
109 return false;
110 }
111
112 void
delete_window(url win_u)113 delete_window (url win_u) {
114 tm_window win= concrete_window (win_u);
115 if (win == NULL) return;
116 while (delete_view_from_window (win_u)) {}
117 win->unmap ();
118 tm_window_table->reset (win->id);
119 destroy_window_widget (win->win);
120 tm_delete (win);
121 }
122
123 tm_window
concrete_window(url win)124 concrete_window (url win) {
125 return tm_window_table [win];
126 }
127
128 /******************************************************************************
129 * Manage global list of windows
130 ******************************************************************************/
131
132 array<url>
windows_list()133 windows_list () {
134 return all_windows;
135 }
136
137 int
get_nr_windows()138 get_nr_windows () {
139 return nr_windows;
140 }
141
142 bool
has_current_window()143 has_current_window () {
144 tm_view vw= concrete_view (get_current_view_safe ());
145 return vw != NULL && vw->win != NULL;
146 }
147
148 tm_window
concrete_window()149 concrete_window () {
150 tm_view vw= concrete_view (get_current_view ());
151 ASSERT (vw->win != NULL, "no window attached to view");
152 return vw->win;
153 }
154
155 url
get_current_window()156 get_current_window () {
157 tm_window win= concrete_window ();
158 return abstract_window (win);
159 }
160
161 array<url>
buffer_to_windows(url name)162 buffer_to_windows (url name) {
163 array<url> r, vs= buffer_to_views (name);
164 for (int i=0; i<N(vs); i++) {
165 url win= view_to_window (vs[i]);
166 if (!is_none (win)) r << win;
167 }
168 return r;
169 }
170
171 url
window_to_buffer(url win)172 window_to_buffer (url win) {
173 return view_to_buffer (window_to_view (win));
174 }
175
176 url
window_to_view(url win)177 window_to_view (url win) {
178 array<url> vs= get_all_views ();
179 for (int i=0; i<N(vs); i++)
180 if (view_to_window (vs[i]) == win)
181 return vs[i];
182 return url_none ();
183 }
184
185 void
window_set_buffer(url win,url name)186 window_set_buffer (url win, url name) {
187 url old= window_to_view (win);
188 if (is_none (old) || view_to_buffer (old) == name) return;
189 window_set_view (win, get_passive_view (name), false);
190 }
191
192 void
window_focus(url win)193 window_focus (url win) {
194 if (win == get_current_window ()) return;
195 url old= window_to_view (win);
196 if (is_none (old)) return;
197 set_current_view (old);
198 }
199
200 /******************************************************************************
201 * Other subroutines
202 ******************************************************************************/
203
204 void
create_buffer(url name,tree doc)205 create_buffer (url name, tree doc) {
206 if (!is_nil (concrete_buffer (name))) return;
207 set_buffer_tree (name, doc);
208 }
209
210 void
new_buffer_in_this_window(url name,tree doc)211 new_buffer_in_this_window (url name, tree doc) {
212 if (is_nil (concrete_buffer (name)))
213 create_buffer (name, doc);
214 switch_to_buffer (name);
215 }
216
217 url
new_buffer_in_new_window(url name,tree doc,tree geom)218 new_buffer_in_new_window (url name, tree doc, tree geom) {
219 if (is_nil (concrete_buffer (name)))
220 create_buffer (name, doc);
221 url win= new_window (true, geom);
222 window_set_view (win, get_passive_view (name), true);
223 return win;
224 }
225
226 /******************************************************************************
227 * Exported routines
228 ******************************************************************************/
229
230 url
create_buffer()231 create_buffer () {
232 url name= make_new_buffer ();
233 switch_to_buffer (name);
234 return name;
235 }
236
237 url
open_window(tree geom)238 open_window (tree geom) {
239 url name= make_new_buffer ();
240 return new_buffer_in_new_window (name, tree (DOCUMENT), geom);
241 }
242
243 void
clone_window()244 clone_window () {
245 url win= new_window ();
246 window_set_view (win, get_passive_view (get_current_buffer ()), true);
247 }
248
249 void
kill_buffer(url name)250 kill_buffer (url name) {
251 array<url> vs= buffer_to_views (name);
252 for (int i=0; i<N(vs); i++)
253 if (!is_none (vs[i])) {
254 url prev= get_recent_view (name, false, true, false, true);
255 if (is_none (prev)) {
256 prev= get_recent_view (name, false, true, false, false);
257 if (is_none (prev)) break;
258 prev= get_new_view (view_to_buffer (prev));
259 }
260 window_set_view (view_to_window (vs[i]), prev, false);
261 }
262 remove_buffer (name);
263 }
264
265 void
kill_window(url wname)266 kill_window (url wname) {
267 array<url> vs= get_all_views ();
268 for (int i=0; i<N(vs); i++) {
269 url win= view_to_window (vs[i]);
270 if (!is_none (win) && win != wname) {
271 set_current_view (vs[i]);
272 // FIXME: make sure that win obtains the focus of the GUI too
273 delete_window (wname);
274 return;
275 }
276 }
277 if (number_of_servers () == 0) get_server () -> quit ();
278 else delete_window (wname);
279 }
280
281 void
kill_current_window_and_buffer()282 kill_current_window_and_buffer () {
283 if (N(bufs) <= 1) get_server () -> quit();
284 url name= get_current_buffer ();
285 array<url> vs= buffer_to_views (get_current_buffer ());
286 url win= get_current_window ();
287 bool kill= true;
288 for (int i=0; i<N(vs); i++)
289 if (view_to_window (vs[i]) != win)
290 kill= false;
291 kill_window (win);
292 if (kill) remove_buffer (name);
293 }
294