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