ExportDialog compiles. Removed gtkmm.h's.
[ardour.git] / gtk2_ardour / ardour_ui.cc
1 /*
2     Copyright (C) 1999-2002 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18     $Id$
19 */
20
21 #include <algorithm>
22 #include <cmath>
23 #include <fcntl.h>
24 #include <signal.h>
25 #include <unistd.h>
26 #include <cerrno>
27 #include <fstream>
28
29 #include <iostream>
30
31 #include <pbd/error.h>
32 #include <pbd/compose.h>
33 #include <pbd/basename.h>
34 #include <pbd/pathscanner.h>
35 #include <pbd/failed_constructor.h>
36 #include <gtkmm2ext/gtk_ui.h>
37 #include <gtkmm2ext/pix.h>
38 #include <gtkmm2ext/utils.h>
39 #include <gtkmm2ext/click_box.h>
40 #include <gtkmm2ext/fastmeter.h>
41 #include <gtkmm2ext/stop_signal.h>
42 #include <gtkmm2ext/popup.h>
43
44 #include <midi++/port.h>
45 #include <midi++/mmc.h>
46
47 #include <ardour/ardour.h>
48 #include <ardour/port.h>
49 #include <ardour/audioengine.h>
50 #include <ardour/playlist.h>
51 #include <ardour/utils.h>
52 #include <ardour/diskstream.h>
53 #include <ardour/filesource.h>
54 #include <ardour/recent_sessions.h>
55 #include <ardour/session_diskstream.h>
56 #include <ardour/port.h>
57 #include <ardour/audio_track.h>
58
59 #include "ardour_ui.h"
60 #include "ardour_message.h"
61 #include "public_editor.h"
62 #include "audio_clock.h"
63 #include "keyboard.h"
64 #include "mixer_ui.h"
65 #include "prompter.h"
66 #include "opts.h"
67 #include "keyboard_target.h"
68 #include "add_route_dialog.h"
69 #include "new_session_dialog.h"
70 #include "about.h"
71 #include "utils.h"
72 #include "gui_thread.h"
73
74 #include "i18n.h"
75
76 using namespace ARDOUR;
77 using namespace Gtkmm2ext;
78 using namespace Gtk;
79 using namespace sigc;
80
81 ARDOUR_UI *ARDOUR_UI::theArdourUI = 0;
82
83 sigc::signal<void,bool> ARDOUR_UI::Blink;
84 sigc::signal<void>      ARDOUR_UI::RapidScreenUpdate;
85 sigc::signal<void>      ARDOUR_UI::SuperRapidScreenUpdate;
86 sigc::signal<void,jack_nframes_t> ARDOUR_UI::Clock;
87
88 /* XPM */
89 static const gchar *h_meter_strip_xpm[] = {
90 "186 5 187 2",
91 "       c None",
92 ".      c #2BFE00",
93 "+      c #2DFE00",
94 "@      c #2FFE01",
95 "#      c #32FE01",
96 "$      c #34FE02",
97 "%      c #36FE02",
98 "&      c #38FE03",
99 "*      c #3BFE03",
100 "=      c #3DFD04",
101 "-      c #3FFD04",
102 ";      c #41FD05",
103 ">      c #44FD05",
104 ",      c #46FD06",
105 "'      c #48FD06",
106 ")      c #4AFD07",
107 "!      c #4DFD07",
108 "~      c #4FFD08",
109 "{      c #51FC08",
110 "]      c #53FC09",
111 "^      c #56FC09",
112 "/      c #58FC09",
113 "(      c #5AFC0A",
114 "_      c #5CFC0A",
115 ":      c #5FFC0B",
116 "<      c #61FC0B",
117 "[      c #63FB0C",
118 "}      c #65FB0C",
119 "|      c #68FB0D",
120 "1      c #6AFB0D",
121 "2      c #6CFB0E",
122 "3      c #6EFB0E",
123 "4      c #71FB0F",
124 "5      c #73FB0F",
125 "6      c #75FB10",
126 "7      c #77FA10",
127 "8      c #7AFA11",
128 "9      c #7CFA11",
129 "0      c #7EFA12",
130 "a      c #80FA12",
131 "b      c #83FA12",
132 "c      c #85FA13",
133 "d      c #87FA13",
134 "e      c #89FA14",
135 "f      c #8CF914",
136 "g      c #8EF915",
137 "h      c #90F915",
138 "i      c #92F916",
139 "j      c #95F916",
140 "k      c #97F917",
141 "l      c #99F917",
142 "m      c #9BF918",
143 "n      c #9EF818",
144 "o      c #A0F819",
145 "p      c #A2F819",
146 "q      c #A4F81A",
147 "r      c #A7F81A",
148 "s      c #A9F81A",
149 "t      c #ABF81B",
150 "u      c #ADF81B",
151 "v      c #B0F81C",
152 "w      c #B2F71C",
153 "x      c #B4F71D",
154 "y      c #B6F71D",
155 "z      c #B9F71E",
156 "A      c #BBF71E",
157 "B      c #BDF71F",
158 "C      c #BFF71F",
159 "D      c #C2F720",
160 "E      c #C4F720",
161 "F      c #C6F621",
162 "G      c #C8F621",
163 "H      c #CBF622",
164 "I      c #CDF622",
165 "J      c #CFF623",
166 "K      c #D1F623",
167 "L      c #D4F624",
168 "M      c #D6F624",
169 "N      c #D8F524",
170 "O      c #DAF525",
171 "P      c #DDF525",
172 "Q      c #DFF526",
173 "R      c #E1F526",
174 "S      c #E3F527",
175 "T      c #E6F527",
176 "U      c #E8F528",
177 "V      c #EAF528",
178 "W      c #ECF429",
179 "X      c #EFF429",
180 "Y      c #F1F42A",
181 "Z      c #F3F42A",
182 "`      c #F5F42B",
183 " .     c #F8F42B",
184 "..     c #FAF42C",
185 "+.     c #FCF42C",
186 "@.     c #FFF42D",
187 "#.     c #FFF22C",
188 "$.     c #FFF12B",
189 "%.     c #FFF02A",
190 "&.     c #FFEF2A",
191 "*.     c #FFEE29",
192 "=.     c #FFED28",
193 "-.     c #FFEC28",
194 ";.     c #FFEB27",
195 ">.     c #FFE926",
196 ",.     c #FFE826",
197 "'.     c #FFE725",
198 ").     c #FFE624",
199 "!.     c #FFE524",
200 "~.     c #FFE423",
201 "{.     c #FFE322",
202 "].     c #FFE222",
203 "^.     c #FFE021",
204 "/.     c #FFDF20",
205 "(.     c #FFDE20",
206 "_.     c #FFDD1F",
207 ":.     c #FFDC1E",
208 "<.     c #FFDB1E",
209 "[.     c #FFDA1D",
210 "}.     c #FFD91C",
211 "|.     c #FFD71B",
212 "1.     c #FFD61B",
213 "2.     c #FFD51A",
214 "3.     c #FFD419",
215 "4.     c #FFD319",
216 "5.     c #FFD218",
217 "6.     c #FFD117",
218 "7.     c #FFD017",
219 "8.     c #FFCF16",
220 "9.     c #FFCD15",
221 "0.     c #FFCC15",
222 "a.     c #FFCB14",
223 "b.     c #FFCA13",
224 "c.     c #FFC913",
225 "d.     c #FFC812",
226 "e.     c #FFC711",
227 "f.     c #FFC611",
228 "g.     c #FFC410",
229 "h.     c #FFC30F",
230 "i.     c #FFC20F",
231 "j.     c #FFC10E",
232 "k.     c #FFC00D",
233 "l.     c #FFBF0C",
234 "m.     c #FFBE0C",
235 "n.     c #FFBD0B",
236 "o.     c #FFBB0A",
237 "p.     c #FFBA0A",
238 "q.     c #FFB909",
239 "r.     c #FFB808",
240 "s.     c #FFB708",
241 "t.     c #FFB607",
242 "u.     c #FFB506",
243 "v.     c #FFB406",
244 "w.     c #FFB205",
245 "x.     c #FFB104",
246 "y.     c #FFB004",
247 "z.     c #FFAF03",
248 "A.     c #FFAE02",
249 "B.     c #FFAD02",
250 "C.     c #FFAC01",
251 "D.     c #FFAB00",
252 "E.     c #FFA900",
253 "F.     c #F11F00",
254 "G.     c #F21E00",
255 "H.     c #F21C00",
256 "I.     c #F31B00",
257 "J.     c #F31A00",
258 "K.     c #F41800",
259 "L.     c #F41700",
260 "M.     c #F51600",
261 "N.     c #F61400",
262 "O.     c #F61300",
263 "P.     c #F71100",
264 "Q.     c #F71000",
265 "R.     c #F80F00",
266 "S.     c #F90D00",
267 "T.     c #F90C00",
268 "U.     c #FA0B00",
269 "V.     c #FA0900",
270 "W.     c #FB0800",
271 "X.     c #FC0600",
272 "Y.     c #FC0500",
273 "Z.     c #FD0400",
274 "`.     c #FD0200",
275 " +     c #FE0100",
276 ".+     c #FE0000",
277 "++     c #FF0000",
278 ". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z `  ...+.@.@.#.$.%.&.*.=.-.;.>.,.'.).!.~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.0.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.`. +.+",
279 ". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z `  ...+.@.@.#.$.%.&.*.=.-.;.>.,.'.).!.~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.0.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.`. +.+",
280 ". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z `  ...+.@.@.#.$.%.&.*.=.-.;.>.,.'.).!.~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.0.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.`. +++",
281 ". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z `  ...+.@.@.#.$.%.&.*.=.-.;.>.,.'.).!.~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.0.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.`. +++",
282 ". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 1 2 3 4 5 6 7 8 9 0 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z `  ...+.@.@.#.$.%.&.*.=.-.;.>.,.'.).!.~.{.].^./.(._.:.<.[.}.|.1.2.3.4.5.6.7.8.9.0.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.A.B.C.D.E.F.G.H.I.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.X.Y.Z.`. +++"};
283
284 /* XPM */
285 static const gchar * v_meter_strip_xpm[] = {
286 "5 250 230 2",
287 "       c None",
288 ".      c #FE0000",
289 "+      c #FF0000",
290 "@      c #FE0100",
291 "#      c #FD0200",
292 "$      c #FD0300",
293 "%      c #FD0400",
294 "&      c #FC0500",
295 "*      c #FC0600",
296 "=      c #FC0700",
297 "-      c #FB0800",
298 ";      c #FA0900",
299 ">      c #FA0A00",
300 ",      c #FA0B00",
301 "'      c #F90C00",
302 ")      c #F90D00",
303 "!      c #F80E00",
304 "~      c #F80F00",
305 "{      c #F71000",
306 "]      c #F71100",
307 "^      c #F61200",
308 "/      c #F61300",
309 "(      c #F61400",
310 "_      c #F51600",
311 ":      c #F41700",
312 "<      c #F41800",
313 "[      c #F31A00",
314 "}      c #F31B00",
315 "|      c #F21C00",
316 "1      c #F21E00",
317 "2      c #F11F00",
318 "3      c #F54A00",
319 "4      c #FFA900",
320 "5      c #FFAB00",
321 "6      c #FFAC01",
322 "7      c #FFAD02",
323 "8      c #FFAE02",
324 "9      c #FFAF03",
325 "0      c #FFB004",
326 "a      c #FFB104",
327 "b      c #FFB205",
328 "c      c #FFB406",
329 "d      c #FFB506",
330 "e      c #FFB607",
331 "f      c #FFB708",
332 "g      c #FFB808",
333 "h      c #FFB909",
334 "i      c #FFBA0A",
335 "j      c #FFBB0A",
336 "k      c #FFBC0A",
337 "l      c #FFBD0B",
338 "m      c #FFBE0C",
339 "n      c #FFBF0C",
340 "o      c #FFC00D",
341 "p      c #FFC10E",
342 "q      c #FFC20F",
343 "r      c #FFC30F",
344 "s      c #FFC410",
345 "t      c #FFC511",
346 "u      c #FFC611",
347 "v      c #FFC711",
348 "w      c #FFC812",
349 "x      c #FFC913",
350 "y      c #FFCA13",
351 "z      c #FFCB14",
352 "A      c #FFCC15",
353 "B      c #FFCD15",
354 "C      c #FFCF16",
355 "D      c #FFD017",
356 "E      c #FFD117",
357 "F      c #FFD218",
358 "G      c #FFD319",
359 "H      c #FFD419",
360 "I      c #FFD51A",
361 "J      c #FFD61B",
362 "K      c #FFD71B",
363 "L      c #FFD81C",
364 "M      c #FFD91C",
365 "N      c #FFDA1D",
366 "O      c #FFDB1E",
367 "P      c #FFDC1E",
368 "Q      c #FFDD1F",
369 "R      c #FFDE20",
370 "S      c #FFDF20",
371 "T      c #FFE021",
372 "U      c #FFE222",
373 "V      c #FFE322",
374 "W      c #FFE423",
375 "X      c #FFE524",
376 "Y      c #FFE624",
377 "Z      c #FFE725",
378 "`      c #FFE826",
379 " .     c #FFE926",
380 "..     c #FFEA26",
381 "+.     c #FFEB27",
382 "@.     c #FFEC28",
383 "#.     c #FFED28",
384 "$.     c #FFEE29",
385 "%.     c #FFEF2A",
386 "&.     c #FFF02A",
387 "*.     c #FFF12B",
388 "=.     c #FFF22C",
389 "-.     c #FFF32D",
390 ";.     c #FFF42D",
391 ">.     c #FDF42C",
392 ",.     c #FBF42C",
393 "'.     c #FAF42C",
394 ").     c #F8F42B",
395 "!.     c #F6F42B",
396 "~.     c #F4F42B",
397 "{.     c #F3F42A",
398 "].     c #F1F42A",
399 "^.     c #F0F429",
400 "/.     c #EEF429",
401 "(.     c #ECF429",
402 "_.     c #EAF528",
403 ":.     c #E9F528",
404 "<.     c #E7F528",
405 "[.     c #E5F527",
406 "}.     c #E3F527",
407 "|.     c #E2F526",
408 "1.     c #E0F526",
409 "2.     c #DFF526",
410 "3.     c #DDF525",
411 "4.     c #DBF525",
412 "5.     c #D9F525",
413 "6.     c #D8F524",
414 "7.     c #D6F624",
415 "8.     c #D5F624",
416 "9.     c #D3F624",
417 "0.     c #D1F623",
418 "a.     c #CFF623",
419 "b.     c #CEF622",
420 "c.     c #CCF622",
421 "d.     c #CBF622",
422 "e.     c #C9F621",
423 "f.     c #C7F621",
424 "g.     c #C5F621",
425 "h.     c #C4F720",
426 "i.     c #C2F720",
427 "j.     c #C0F71F",
428 "k.     c #BEF71F",
429 "l.     c #BDF71F",
430 "m.     c #BBF71E",
431 "n.     c #BAF71E",
432 "o.     c #B8F71E",
433 "p.     c #B6F71D",
434 "q.     c #B5F71D",
435 "r.     c #B3F71D",
436 "s.     c #B2F71C",
437 "t.     c #B0F81C",
438 "u.     c #AEF81B",
439 "v.     c #ACF81B",
440 "w.     c #ABF81B",
441 "x.     c #A9F81A",
442 "y.     c #A8F81A",
443 "z.     c #A6F81A",
444 "A.     c #A4F81A",
445 "B.     c #A2F819",
446 "C.     c #A1F819",
447 "D.     c #9FF819",
448 "E.     c #9EF818",
449 "F.     c #9BF918",
450 "G.     c #9AF917",
451 "H.     c #98F917",
452 "I.     c #97F917",
453 "J.     c #95F916",
454 "K.     c #93F916",
455 "L.     c #91F916",
456 "M.     c #90F915",
457 "N.     c #8EF915",
458 "O.     c #8DF914",
459 "P.     c #8BF914",
460 "Q.     c #89FA14",
461 "R.     c #87FA13",
462 "S.     c #86FA13",
463 "T.     c #84FA13",
464 "U.     c #83FA12",
465 "V.     c #81FA12",
466 "W.     c #7FFA12",
467 "X.     c #7DFA12",
468 "Y.     c #7CFA11",
469 "Z.     c #7AFA11",
470 "`.     c #78FA10",
471 " +     c #76FA10",
472 ".+     c #75FB10",
473 "++     c #73FB0F",
474 "@+     c #72FB0F",
475 "#+     c #70FB0F",
476 "$+     c #6EFB0E",
477 "%+     c #6DFB0E",
478 "&+     c #6BFB0E",
479 "*+     c #6AFB0D",
480 "=+     c #68FB0D",
481 "-+     c #66FB0C",
482 ";+     c #64FB0C",
483 ">+     c #63FB0C",
484 ",+     c #61FC0B",
485 "'+     c #60FC0B",
486 ")+     c #5EFC0B",
487 "!+     c #5CFC0A",
488 "~+     c #5AFC0A",
489 "{+     c #59FC09",
490 "]+     c #57FC09",
491 "^+     c #56FC09",
492 "/+     c #53FC09",
493 "(+     c #52FC08",
494 "_+     c #50FC08",
495 ":+     c #4FFD08",
496 "<+     c #4DFD07",
497 "[+     c #4BFD07",
498 "}+     c #49FD07",
499 "|+     c #48FD06",
500 "1+     c #46FD06",
501 "2+     c #45FD05",
502 "3+     c #43FD05",
503 "4+     c #41FD05",
504 "5+     c #3FFD04",
505 "6+     c #3EFD04",
506 "7+     c #3CFD04",
507 "8+     c #3BFE03",
508 "9+     c #39FE03",
509 "0+     c #37FE02",
510 "a+     c #35FE02",
511 "b+     c #34FE02",
512 "c+     c #32FE01",
513 "d+     c #30FE01",
514 "e+     c #2EFE01",
515 "f+     c #2DFE00",
516 "g+     c #2BFE00",
517 ". . + + + ",
518 ". . + + + ",
519 "@ @ @ @ @ ",
520 "# # # # # ",
521 "$ $ $ $ $ ",
522 "% % % % % ",
523 "& & & & & ",
524 "* * * * * ",
525 "= = = = = ",
526 "- - - - - ",
527 "; ; ; ; ; ",
528 "> > > > > ",
529 ", , , , , ",
530 "' ' ' ' ' ",
531 ") ) ) ) ) ",
532 "! ! ! ! ! ",
533 "~ ~ ~ ~ ~ ",
534 "{ { { { { ",
535 "] ] ] ] ] ",
536 "^ ^ ^ ^ ^ ",
537 "/ / / / / ",
538 "( ( ( ( ( ",
539 "_ _ _ _ _ ",
540 ": : : : : ",
541 ": : : : : ",
542 "< < < < < ",
543 "[ [ [ [ [ ",
544 "} } } } } ",
545 "} } } } } ",
546 "| | | | | ",
547 "1 1 1 1 1 ",
548 "2 2 2 2 2 ",
549 "3 3 3 3 3 ",
550 "4 4 4 4 4 ",
551 "5 5 5 5 5 ",
552 "6 6 6 6 6 ",
553 "6 6 6 6 6 ",
554 "7 7 7 7 7 ",
555 "8 8 8 8 8 ",
556 "9 9 9 9 9 ",
557 "9 9 9 9 9 ",
558 "0 0 0 0 0 ",
559 "a a a a a ",
560 "a a a a a ",
561 "b b b b b ",
562 "c c c c c ",
563 "d d d d d ",
564 "d d d d d ",
565 "e e e e e ",
566 "f f f f f ",
567 "g g g g g ",
568 "g g g g g ",
569 "h h h h h ",
570 "i i i i i ",
571 "j j j j j ",
572 "k k k k k ",
573 "l l l l l ",
574 "m m m m m ",
575 "n n n n n ",
576 "n n n n n ",
577 "o o o o o ",
578 "p p p p p ",
579 "q q q q q ",
580 "q q q q q ",
581 "r r r r r ",
582 "s s s s s ",
583 "t t t t t ",
584 "u u u u u ",
585 "v v v v v ",
586 "w w w w w ",
587 "x x x x x ",
588 "x x x x x ",
589 "y y y y y ",
590 "z z z z z ",
591 "A A A A A ",
592 "A A A A A ",
593 "B B B B B ",
594 "C C C C C ",
595 "D D D D D ",
596 "D D D D D ",
597 "E E E E E ",
598 "F F F F F ",
599 "G G G G G ",
600 "G G G G G ",
601 "H H H H H ",
602 "I I I I I ",
603 "I I I I I ",
604 "J J J J J ",
605 "K K K K K ",
606 "L L L L L ",
607 "M M M M M ",
608 "N N N N N ",
609 "O O O O O ",
610 "P P P P P ",
611 "P P P P P ",
612 "Q Q Q Q Q ",
613 "R R R R R ",
614 "S S S S S ",
615 "S S S S S ",
616 "T T T T T ",
617 "U U U U U ",
618 "V V V V V ",
619 "V V V V V ",
620 "W W W W W ",
621 "X X X X X ",
622 "Y Y Y Y Y ",
623 "Y Y Y Y Y ",
624 "Z Z Z Z Z ",
625 "` ` ` ` ` ",
626 " . . . . .",
627 "..........",
628 "+.+.+.+.+.",
629 "@.@.@.@.@.",
630 "#.#.#.#.#.",
631 "#.#.#.#.#.",
632 "$.$.$.$.$.",
633 "%.%.%.%.%.",
634 "&.&.&.&.&.",
635 "&.&.&.&.&.",
636 "*.*.*.*.*.",
637 "=.=.=.=.=.",
638 "-.-.-.-.-.",
639 ";.;.;.;.;.",
640 ";.;.;.;.;.",
641 ">.>.>.>.>.",
642 ",.,.,.,.,.",
643 "'.'.'.'.'.",
644 ").).).).).",
645 "!.!.!.!.!.",
646 "~.~.~.~.~.",
647 "{.{.{.{.{.",
648 "].].].].].",
649 "^.^.^.^.^.",
650 "/././././.",
651 "(.(.(.(.(.",
652 "_._._._._.",
653 ":.:.:.:.:.",
654 "<.<.<.<.<.",
655 "[.[.[.[.[.",
656 "}.}.}.}.}.",
657 "|.|.|.|.|.",
658 "1.1.1.1.1.",
659 "2.2.2.2.2.",
660 "3.3.3.3.3.",
661 "4.4.4.4.4.",
662 "5.5.5.5.5.",
663 "6.6.6.6.6.",
664 "7.7.7.7.7.",
665 "8.8.8.8.8.",
666 "9.9.9.9.9.",
667 "0.0.0.0.0.",
668 "a.a.a.a.a.",
669 "b.b.b.b.b.",
670 "c.c.c.c.c.",
671 "d.d.d.d.d.",
672 "e.e.e.e.e.",
673 "f.f.f.f.f.",
674 "g.g.g.g.g.",
675 "h.h.h.h.h.",
676 "i.i.i.i.i.",
677 "j.j.j.j.j.",
678 "k.k.k.k.k.",
679 "l.l.l.l.l.",
680 "m.m.m.m.m.",
681 "n.n.n.n.n.",
682 "o.o.o.o.o.",
683 "p.p.p.p.p.",
684 "q.q.q.q.q.",
685 "r.r.r.r.r.",
686 "s.s.s.s.s.",
687 "t.t.t.t.t.",
688 "u.u.u.u.u.",
689 "v.v.v.v.v.",
690 "w.w.w.w.w.",
691 "x.x.x.x.x.",
692 "y.y.y.y.y.",
693 "z.z.z.z.z.",
694 "A.A.A.A.A.",
695 "B.B.B.B.B.",
696 "C.C.C.C.C.",
697 "D.D.D.D.D.",
698 "E.E.E.E.E.",
699 "F.F.F.F.F.",
700 "G.G.G.G.G.",
701 "H.H.H.H.H.",
702 "I.I.I.I.I.",
703 "J.J.J.J.J.",
704 "K.K.K.K.K.",
705 "L.L.L.L.L.",
706 "M.M.M.M.M.",
707 "N.N.N.N.N.",
708 "O.O.O.O.O.",
709 "P.P.P.P.P.",
710 "Q.Q.Q.Q.Q.",
711 "R.R.R.R.R.",
712 "S.S.S.S.S.",
713 "T.T.T.T.T.",
714 "U.U.U.U.U.",
715 "V.V.V.V.V.",
716 "W.W.W.W.W.",
717 "X.X.X.X.X.",
718 "Y.Y.Y.Y.Y.",
719 "Z.Z.Z.Z.Z.",
720 "`.`.`.`.`.",
721 " + + + + +",
722 ".+.+.+.+.+",
723 "++++++++++",
724 "@+@+@+@+@+",
725 "#+#+#+#+#+",
726 "$+$+$+$+$+",
727 "%+%+%+%+%+",
728 "&+&+&+&+&+",
729 "*+*+*+*+*+",
730 "=+=+=+=+=+",
731 "-+-+-+-+-+",
732 ";+;+;+;+;+",
733 ">+>+>+>+>+",
734 ",+,+,+,+,+",
735 "'+'+'+'+'+",
736 ")+)+)+)+)+",
737 "!+!+!+!+!+",
738 "~+~+~+~+~+",
739 "{+{+{+{+{+",
740 "]+]+]+]+]+",
741 "^+^+^+^+^+",
742 "/+/+/+/+/+",
743 "(+(+(+(+(+",
744 "_+_+_+_+_+",
745 ":+:+:+:+:+",
746 "<+<+<+<+<+",
747 "[+[+[+[+[+",
748 "}+}+}+}+}+",
749 "|+|+|+|+|+",
750 "1+1+1+1+1+",
751 "2+2+2+2+2+",
752 "3+3+3+3+3+",
753 "4+4+4+4+4+",
754 "5+5+5+5+5+",
755 "6+6+6+6+6+",
756 "7+7+7+7+7+",
757 "8+8+8+8+8+",
758 "9+9+9+9+9+",
759 "0+0+0+0+0+",
760 "a+a+a+a+a+",
761 "b+b+b+b+b+",
762 "c+c+c+c+c+",
763 "d+d+d+d+d+",
764 "e+e+e+e+e+",
765 "f+f+f+f+f+",
766 "g+g+g+g+g+"};
767
768 static const char* channel_setup_names[] = {
769         "mono",
770         "stereo",
771         "3 channels",
772         "4 channels",
773         "5 channels",
774         "8 channels",
775         "manual setup",
776         0
777 };
778
779 vector<string> channel_combo_strings;
780
781 ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile)
782
783         : Gtkmm2ext::UI ("ardour", argcp, argvp, rcfile),
784
785           primary_clock (X_("TransportClockDisplay"), true, false, true),
786           secondary_clock (X_("SecondaryClockDisplay"), true, false, true),
787           preroll_clock (X_("PreRollClock"), true, true),
788           postroll_clock (X_("PostRollClock"), true, true),
789
790           /* adjuster table */
791
792           adjuster_table (3, 3),
793
794           /* preroll stuff */
795
796           preroll_button (_("pre\nroll")),
797           postroll_button (_("post\nroll")),
798
799           /* big clock */
800
801           big_clock ("BigClockDisplay", true),
802
803           /* transport */
804
805           shuttle_units_button (_("% ")),
806           shuttle_style_button (_("spring")),
807           
808           punch_in_button (_("punch\nin")),
809           punch_out_button (_("punch\nout")),
810           auto_return_button (_("auto\nreturn")),
811           auto_play_button (_("auto\nplay")),
812           auto_input_button (_("auto\ninput")),
813           click_button (_("click")),
814           follow_button (_("follow\nPH")),
815           auditioning_alert_button (_("AUDITIONING")),
816           solo_alert_button (_("SOLO")),
817           shown_flag (false)
818
819 {
820         using namespace Gtk::Menu_Helpers;
821
822         Gtkmm2ext::init();
823
824         /* actually, its already loaded, but ... */
825
826         cerr << "Loading UI configuration file " << rcfile << endl;
827
828         about = 0;
829
830         if (theArdourUI == 0) {
831                 theArdourUI = this;
832         }
833
834         editor = 0;
835         mixer = 0;
836         session = 0;
837         _session_is_new = false;
838         big_clock_window = 0;
839         session_selector_window = 0;
840         last_key_press_time = 0;
841         connection_editor = 0;
842         add_route_dialog = 0;
843         route_params = 0;
844         meter_bridge = 0;
845         option_editor = 0;
846         location_ui = 0;
847         new_session_window = 0;
848         open_session_selector = 0;
849         have_configure_timeout = false;
850         have_disk_overrun_displayed = false;
851         have_disk_underrun_displayed = false;
852         _will_create_new_session_automatically = false;
853         session_loaded = false;
854
855         last_configure_time.tv_sec = 0;
856         last_configure_time.tv_usec = 0;
857
858         ui_manager = UIManager::create ();
859
860         shuttle_grabbed = false;
861         shuttle_fract = 0.0;
862
863         set_shuttle_units (Percentage);
864         set_shuttle_behaviour (Sprung);
865
866         Glib::RefPtr<ActionGroup> shuttle_actions = ActionGroup::create ("ShuttleActions");
867         
868         shuttle_actions->add (Action::create (X_("SetShuttleUnitsPercentage"), _("Percentage")), bind (mem_fun(*this, &ARDOUR_UI::set_shuttle_units), Percentage));
869         shuttle_actions->add (Action::create (X_("SetShuttleUnitsSemitones"), _("Semitones")), bind (mem_fun(*this, &ARDOUR_UI::set_shuttle_units), Semitones));
870         shuttle_actions->add (Action::create (X_("SetShuttleActionSprung"), _("Sprung")), bind (mem_fun(*this, &ARDOUR_UI::set_shuttle_behaviour), Sprung));
871         shuttle_actions->add (Action::create (X_("SetShuttleActionWheel"), _("Wheel")), bind (mem_fun(*this, &ARDOUR_UI::set_shuttle_behaviour), Wheel));
872         
873         ui_manager->insert_action_group (shuttle_actions);
874
875         shuttle_style_menu = dynamic_cast<Menu*> (ui_manager->get_widget ("ShuttleStylePopup"));
876         shuttle_unit_menu = dynamic_cast<Menu*> (ui_manager->get_widget ("ShuttleUnitPopup"));
877         
878         gettimeofday (&last_peak_grab, 0);
879         gettimeofday (&last_shuttle_request, 0);
880
881         ARDOUR::DiskStream::CannotRecordNoInput.connect (mem_fun(*this, &ARDOUR_UI::cannot_record_no_input));
882         ARDOUR::DiskStream::DeleteSources.connect (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread));
883         ARDOUR::DiskStream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler));
884         ARDOUR::DiskStream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
885
886         /* handle pending state with a dialog */
887
888         ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog));
889
890         channel_combo_strings = internationalize (channel_setup_names);
891         
892         /* have to wait for AudioEngine and Configuration before proceeding */
893 }
894
895 void
896 ARDOUR_UI::cannot_record_no_input (DiskStream* ds)
897 {
898         ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::cannot_record_no_input), ds));
899         
900         string msg = string_compose (_("\
901 You cannot record-enable\n\
902 track %1\n\
903 because it has no input connections.\n\
904 You would be wasting space recording silence."),
905                               ds->name());
906
907         ArdourMessage message (editor, X_("cannotrecord"), msg);
908 }
909
910 void
911 ARDOUR_UI::set_engine (AudioEngine& e)
912 {
913         engine = &e;
914
915         engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped));
916         engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running));
917         engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted));
918         engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate));
919
920         _tooltips.enable();
921
922         keyboard = new Keyboard;
923         install_keybindings ();
924
925         FastMeter::set_vertical_xpm (v_meter_strip_xpm);
926         FastMeter::set_horizontal_xpm (h_meter_strip_xpm);
927
928         if (setup_windows ()) {
929                 throw failed_constructor ();
930         }
931
932         if (GTK_ARDOUR::show_key_actions) {
933                 KeyboardTarget::show_all_actions ();
934                 exit (0);
935         }
936
937         /* start with timecode, metering enabled
938         */
939         
940         blink_timeout_tag = -1;
941
942         /* this being a GUI and all, we want peakfiles */
943
944         FileSource::set_build_peakfiles (true);
945         FileSource::set_build_missing_peakfiles (true);
946
947         if (Source::start_peak_thread ()) {
948                 throw failed_constructor();
949         }
950
951         /* start the time-of-day-clock */
952         
953         update_wall_clock ();
954         Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000);
955
956         update_disk_space ();
957         update_cpu_load ();
958         update_sample_rate (engine->frame_rate());
959
960         starting.connect (mem_fun(*this, &ARDOUR_UI::startup));
961         stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown));
962 }
963
964 ARDOUR_UI::~ARDOUR_UI ()
965 {
966         save_ardour_state ();
967
968         if (keyboard) {
969                 delete keyboard;
970         }
971
972         if (editor) {
973                 delete editor;
974         }
975
976         if (mixer) {
977                 delete mixer;
978         }
979
980         if (add_route_dialog) {
981                 delete add_route_dialog;
982         }
983
984         Source::stop_peak_thread ();
985 }
986
987 gint
988 ARDOUR_UI::configure_timeout ()
989 {
990         struct timeval now;
991         struct timeval diff;
992
993         if (last_configure_time.tv_sec == 0 && last_configure_time.tv_usec == 0) {
994                 /* no configure events yet */
995                 return TRUE;
996         }
997
998         gettimeofday (&now, 0);
999         timersub (&now, &last_configure_time, &diff);
1000
1001         /* force a gap of 0.5 seconds since the last configure event
1002          */
1003
1004         if (diff.tv_sec == 0 && diff.tv_usec < 500000) {
1005                 return TRUE;
1006         } else {
1007                 have_configure_timeout = false;
1008                 save_ardour_state ();
1009                 return FALSE;
1010         }
1011 }
1012
1013 gboolean
1014 ARDOUR_UI::configure_handler (GdkEventConfigure* conf)
1015 {
1016         if (have_configure_timeout) {
1017                 gettimeofday (&last_configure_time, 0);
1018         } else {
1019                 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100);
1020                 have_configure_timeout = true;
1021         }
1022                 
1023         return FALSE;
1024 }
1025
1026 void
1027 ARDOUR_UI::save_ardour_state ()
1028 {
1029         if (!keyboard || !mixer || !editor) {
1030                 return;
1031         }
1032         
1033         /* XXX this is all a bit dubious. add_extra_xml() uses
1034            a different lifetime model from add_instant_xml().
1035         */
1036
1037         XMLNode* node = new XMLNode (keyboard->get_state());
1038         Config->add_extra_xml (*node);
1039         Config->save_state();
1040
1041         XMLNode& enode (static_cast<Stateful*>(editor)->get_state());
1042         XMLNode& mnode (mixer->get_state());
1043
1044         if (session) {
1045                 session->add_instant_xml(enode, session->path());
1046                 session->add_instant_xml(mnode, session->path());
1047         } else {
1048                 Config->add_instant_xml(enode, Config->get_user_ardour_path());
1049                 Config->add_instant_xml(mnode, Config->get_user_ardour_path());
1050         }
1051 }
1052
1053 void
1054 ARDOUR_UI::startup ()
1055 {
1056         /* Once the UI is up and running, start the audio engine. Doing
1057            this before the UI is up and running can cause problems
1058            when not running with SCHED_FIFO, because the amount of
1059            CPU and disk work needed to get the UI started can interfere
1060            with the scheduling of the audio thread.
1061         */
1062
1063         Glib::signal_idle().connect (mem_fun(*this, &ARDOUR_UI::start_engine));
1064 }
1065
1066 void
1067 ARDOUR_UI::finish()
1068 {
1069         if (session && session->dirty()) {
1070                 switch (ask_about_saving_session(_("quit"))) {
1071                 case -1:
1072                         return;
1073                         break;
1074                 case 1:
1075                         /* use the default name */
1076                         if (save_state_canfail ("")) {
1077                                 /* failed - don't quit */
1078                                 ArdourMessage (editor, X_("badsave dialog"),
1079                                                _("\
1080 Ardour was unable to save your session.\n\n\
1081 If you still wish to quit, please use the\n\n\
1082 \"Just quit\" option."));
1083                                 return;
1084                         }
1085                         break;
1086                 case 0:
1087                         break;
1088                 }
1089         }
1090
1091         quit();
1092 }
1093
1094 int
1095 ARDOUR_UI::ask_about_saving_session (string what)
1096 {
1097         ArdourDialog window ("saving dialog");
1098         Gtk::VBox   packer;
1099         Gtk::Label  prompt_label;
1100         Gtk::HBox   button_packer;
1101
1102         string msg;
1103
1104         msg = string_compose(_("Save and %1"), what);
1105         
1106         Gtk::Button save_button (msg);
1107         save_button.set_name ("EditorGTKButton");
1108
1109         msg = string_compose(_("Just %1"), what);
1110
1111         Gtk::Button nosave_button (msg);
1112         nosave_button.set_name ("EditorGTKButton");
1113
1114         msg = string_compose(_("Don't %1"), what);
1115
1116         Gtk::Button noquit_button (msg);
1117         noquit_button.set_name ("EditorGTKButton");
1118
1119         string prompt;
1120         string type;
1121
1122         if (session->snap_name() == session->name()) {
1123                 type = _("session");
1124         } else {
1125                 type = _("snapshot");
1126         }
1127         prompt = string_compose(_("The %1\n\"%2\"\nhas not been saved.\n\nAny changes made this time\nwill be lost unless you save it.\n\nWhat do you want to do?"), 
1128                          type, session->snap_name());
1129         
1130         prompt_label.set_text (prompt);
1131         prompt_label.set_alignment (0.5, 0.5);
1132         prompt_label.set_name (X_("PrompterLabel"));
1133
1134         save_button.signal_clicked().connect (bind(mem_fun(window,&ArdourDialog::stop), 1));
1135         nosave_button.signal_clicked().connect (bind(mem_fun(window,&ArdourDialog::stop), 0));
1136         noquit_button.signal_clicked().connect (bind(mem_fun(window,&ArdourDialog::stop), -1));
1137
1138         button_packer.set_spacing (10);
1139         button_packer.pack_start (save_button);
1140         button_packer.pack_start (nosave_button);
1141         button_packer.pack_start (noquit_button);
1142         
1143         packer.set_spacing (10);
1144         packer.set_border_width (10);
1145         packer.pack_start (prompt_label);
1146         packer.pack_start (button_packer);
1147
1148         window.set_name (_("Prompter"));
1149         window.set_title (_("ardour: save session?"));
1150         window.set_position (Gtk::WIN_POS_MOUSE);
1151         window.set_modal (true);
1152         window.add (packer);
1153         window.show_all ();
1154         window.set_keyboard_input (true);
1155
1156         save_the_session = 0;
1157
1158         editor->ensure_float (window);
1159
1160         window.run ();
1161
1162         return window.run_status();
1163 }
1164         
1165 gint
1166 ARDOUR_UI::every_second ()
1167 {
1168         update_cpu_load ();
1169         update_buffer_load ();
1170         update_disk_space ();
1171         // update_disk_rate ();
1172         return TRUE;
1173 }
1174
1175 gint
1176 ARDOUR_UI::every_point_one_seconds ()
1177 {
1178         struct timeval now;
1179         struct timeval diff;
1180         
1181         /* do not attempt to grab peak power more than once per cycle.
1182          */
1183
1184         gettimeofday (&now, 0);
1185         timersub (&now, &last_peak_grab, &diff);
1186
1187         if ((diff.tv_usec + (diff.tv_sec * 1000000)) >= engine->usecs_per_cycle()) {
1188                 IO::GrabPeakPower(); /* EMIT_SIGNAL */
1189                 last_peak_grab = now;
1190         } 
1191
1192         update_speed_display ();
1193         RapidScreenUpdate(); /* EMIT_SIGNAL */
1194         return TRUE;
1195 }
1196
1197 gint
1198 ARDOUR_UI::every_point_zero_one_seconds ()
1199 {
1200         SuperRapidScreenUpdate(); /* EMIT_SIGNAL */
1201         return TRUE;
1202 }
1203
1204 void
1205 ARDOUR_UI::update_sample_rate (jack_nframes_t ignored)
1206 {
1207         char buf[32];
1208
1209         ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored));
1210
1211         if (!engine->connected()) {
1212
1213                 snprintf (buf, sizeof (buf), _("disconnected"));
1214
1215         } else {
1216
1217                 jack_nframes_t rate = engine->frame_rate();
1218                 
1219                 if (fmod (rate, 1000.0) != 0.0) {
1220                         snprintf (buf, sizeof (buf), _("SR: %.1f kHz / %4.1f msecs"), 
1221                                   (float) rate/1000.0f,
1222                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1223                 } else {
1224                         snprintf (buf, sizeof (buf), _("SR: %u kHz / %4.1f msecs"), 
1225                                   rate/1000,
1226                                   (engine->frames_per_cycle() / (float) rate) * 1000.0f);
1227                 }
1228         }
1229
1230         sample_rate_label.set_text (buf);
1231 }
1232
1233 void
1234 ARDOUR_UI::update_cpu_load ()
1235 {
1236         char buf[32];
1237         snprintf (buf, sizeof (buf), _("DSP Load: %.1f%%"), engine->get_cpu_load());
1238         cpu_load_label.set_text (buf);
1239 }
1240
1241 void
1242 ARDOUR_UI::update_disk_rate ()
1243 {
1244         char buf[64];
1245
1246         if (session) {
1247                 snprintf (buf, sizeof (buf), _("Disk r:%5.1f w:%5.1f MB/s"), 
1248                           session->read_data_rate()/1048576.0f, session->write_data_rate()/1048576.0f);
1249                 disk_rate_label.set_text (buf);
1250         } else {
1251                 disk_rate_label.set_text ("");
1252         }
1253 }
1254
1255 void
1256 ARDOUR_UI::update_buffer_load ()
1257 {
1258         char buf[64];
1259
1260         if (session) {
1261                 snprintf (buf, sizeof (buf), _("Buffers p:%" PRIu32 "%% c:%" PRIu32 "%%"), 
1262                           session->playback_load(), session->capture_load());
1263                 buffer_load_label.set_text (buf);
1264         } else {
1265                 buffer_load_label.set_text ("");
1266         }
1267 }
1268
1269 void
1270 ARDOUR_UI::count_recenabled_diskstreams (DiskStream& ds)
1271 {
1272         if (ds.record_enabled()) {
1273                 rec_enabled_diskstreams++;
1274         }
1275 }
1276
1277 void
1278 ARDOUR_UI::update_disk_space()
1279 {
1280         if (session == 0) {
1281                 return;
1282         }
1283
1284         jack_nframes_t frames = session->available_capture_duration();
1285         char buf[64];
1286
1287         if (frames == max_frames) {
1288                 strcpy (buf, _("space: 24hrs+"));
1289         } else {
1290                 int hrs;
1291                 int mins;
1292                 int secs;
1293                 jack_nframes_t fr = session->frame_rate();
1294                 
1295                 if (session->actively_recording()){
1296                         
1297                         rec_enabled_diskstreams = 0;
1298                         session->foreach_diskstream (this, &ARDOUR_UI::count_recenabled_diskstreams);
1299                         
1300                         if (rec_enabled_diskstreams) {
1301                                 frames /= rec_enabled_diskstreams;
1302                         }
1303                         
1304                 } else {
1305                         
1306                         /* hmmm. shall we divide by the route count? or the diskstream count?
1307                            or what? for now, do nothing ...
1308                         */
1309                         
1310                 }
1311                 
1312                 hrs  = frames / (fr * 3600);
1313                 frames -= hrs * fr * 3600;
1314                 mins = frames / (fr * 60);
1315                 frames -= mins * fr * 60;
1316                 secs = frames / fr;
1317                 
1318                 snprintf (buf, sizeof(buf), _("space: %02dh:%02dm:%02ds"), hrs, mins, secs);
1319         }
1320
1321         disk_space_label.set_text (buf);
1322 }                 
1323
1324 gint
1325 ARDOUR_UI::update_wall_clock ()
1326 {
1327         time_t now;
1328         struct tm *tm_now;
1329         char buf[16];
1330
1331         time (&now);
1332         tm_now = localtime (&now);
1333
1334         sprintf (buf, "%02d:%02d", tm_now->tm_hour, tm_now->tm_min);
1335         wall_clock_label.set_text (buf);
1336
1337         return TRUE;
1338 }
1339
1340 void
1341 ARDOUR_UI::toggle_recording_plugins ()
1342 {
1343         /* XXX use toggle_some_session_state */
1344
1345         if (session == 0) {
1346                 return;
1347         }
1348
1349         session->set_recording_plugins (!session->get_recording_plugins());
1350 }
1351         
1352 void
1353 ARDOUR_UI::toggle_auto_play ()
1354
1355 {
1356         toggle_some_session_state (auto_play_button,
1357                                    &Session::get_auto_play,
1358                                    &Session::set_auto_play);
1359 }
1360
1361 void
1362 ARDOUR_UI::toggle_auto_return ()
1363
1364 {
1365         toggle_some_session_state (auto_return_button,
1366                                    &Session::get_auto_return,
1367                                    &Session::set_auto_return);
1368 }
1369
1370 void
1371 ARDOUR_UI::toggle_click ()
1372 {
1373         toggle_some_session_state (click_button,
1374                                    &Session::get_clicking,
1375                                    &Session::set_clicking);
1376 }
1377
1378 void
1379 ARDOUR_UI::follow_changed ()
1380 {
1381         bool x;
1382
1383         if (!editor) {
1384                 return;
1385         }
1386
1387         if (follow_button.get_active() != (x = editor->follow_playhead())) {
1388                 follow_button.set_active (x);
1389         }
1390 }
1391
1392 void
1393 ARDOUR_UI::toggle_follow ()
1394 {
1395         bool x;
1396
1397         if (!editor) {
1398                 return;
1399         }
1400
1401         if (editor->follow_playhead() != (x = follow_button.get_active())) {
1402                 editor->set_follow_playhead (x);
1403         }
1404 }
1405
1406 void
1407 ARDOUR_UI::toggle_session_auto_loop ()
1408 {
1409         if (session) {
1410                 if (session->get_auto_loop()) {
1411                         if (session->transport_rolling()) {
1412                                 transport_roll();
1413                         }
1414                         else {
1415                                 session->request_auto_loop (false);
1416                         }
1417                 }
1418                 else {
1419                         session->request_auto_loop (true);
1420                 }
1421         }
1422 }
1423
1424 void
1425 ARDOUR_UI::toggle_session_punch_in ()
1426 {
1427         if (session) {
1428                 session->set_punch_in (!session->get_punch_in());
1429         }
1430 }
1431
1432 void
1433 ARDOUR_UI::toggle_punch_out ()
1434 {
1435         toggle_some_session_state (punch_out_button,
1436                                    &Session::get_punch_out,
1437                                    &Session::set_punch_out);
1438 }
1439
1440 void
1441 ARDOUR_UI::toggle_punch_in ()
1442 {
1443         toggle_some_session_state (punch_in_button,
1444                                    &Session::get_punch_in,
1445                                    &Session::set_punch_in);
1446 }
1447
1448 void
1449 ARDOUR_UI::map_button_state ()
1450
1451 {
1452         map_some_session_state (auto_return_button,
1453                                 &Session::get_auto_return);
1454         map_some_session_state (auto_play_button,
1455                                 &Session::get_auto_play);
1456         map_some_session_state (auto_input_button,
1457                                 &Session::get_auto_input);
1458         map_some_session_state (punch_in_button,
1459                                 &Session::get_punch_in);
1460         map_some_session_state (punch_out_button,
1461                                 &Session::get_punch_out);
1462         map_some_session_state (click_button,
1463                                 &Session::get_clicking);
1464 }
1465
1466 void
1467 ARDOUR_UI::queue_map_control_change (Session::ControlType t)
1468 {
1469         ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::map_control_change), t));
1470 }
1471
1472 void
1473 ARDOUR_UI::map_control_change (Session::ControlType t)
1474 {
1475         switch (t) {
1476         case Session::AutoPlay:
1477                 map_some_session_state (auto_play_button, &Session::get_auto_play);
1478                 break;
1479
1480         case Session::AutoLoop:
1481                 break;
1482
1483         case Session::AutoReturn:
1484                 map_some_session_state (auto_return_button, &Session::get_auto_return);
1485                 break;
1486
1487         case Session::AutoInput:
1488                 map_some_session_state (auto_input_button, &Session::get_auto_input);
1489                 break;
1490
1491         case Session::PunchOut:
1492                 map_some_session_state (punch_in_button, &Session::get_punch_out);
1493                 break;
1494
1495         case Session::PunchIn:
1496                 map_some_session_state (punch_in_button, &Session::get_punch_in);
1497                 break;
1498
1499         case Session::Clicking:
1500                 map_some_session_state (click_button, &Session::get_clicking);
1501                 break;
1502
1503         case Session::SlaveType:
1504 //              map_some_session_state (mtc_slave_button, &Session::get_mtc_slave);
1505                 break;
1506
1507         case Session::SendMTC:
1508 //              map_some_session_state (send_mtc_button, &Session::get_send_mtc);
1509                 break;
1510
1511         case Session::SendMMC:
1512 //              map_some_session_state (send_mmc_button, &Session::get_send_mmc);
1513                 break;
1514
1515         case Session::MMCControl:       
1516 //              map_some_session_state (mmc_control_button, &Session::get_mmc_control);
1517                 break;
1518
1519         case Session::MidiFeedback:       
1520 //              map_some_session_state (mmc_control_button, &Session::get_mmc_control);
1521                 break;
1522         case Session::MidiControl:       
1523 //              map_some_session_state (mmc_control_button, &Session::get_mmc_control);
1524                 break;
1525                 
1526         case Session::Live:
1527                 break;
1528
1529         case Session::RecordingPlugins:
1530                 break;
1531
1532         case Session::CrossFadesActive:
1533                 break;
1534                 
1535         case Session::EditingMode:
1536                 break;
1537
1538         case Session::PlayRange:
1539                 break;
1540
1541         case Session::AlignChoice:
1542                 /* don't care, this is handled by the options editor */
1543                 break;
1544         case Session::SeamlessLoop:
1545                 /* don't care, this is handled by the options editor */
1546                 break;
1547                
1548         }
1549 }
1550
1551 void
1552 ARDOUR_UI::control_methods_adjusted ()
1553
1554 {
1555         int which_method;
1556
1557         which_method = (int) online_control_button->adjustment.get_value();
1558         switch (which_method) {
1559         case 0:
1560                 allow_mmc_and_local ();
1561                 break;
1562         case 1:
1563                 allow_mmc_only ();
1564                 break;
1565         case 2:
1566                 allow_local_only ();
1567                 break;
1568         default:
1569                 fatal << _("programming error: impossible control method") << endmsg;
1570         }
1571 }
1572         
1573
1574 void
1575 ARDOUR_UI::mmc_device_id_adjusted ()
1576
1577 {
1578 #if 0
1579         if (mmc) {
1580                 int dev_id = (int) mmc_id_button->adjustment.get_value();
1581                 mmc->set_device_id (dev_id);
1582         }
1583 #endif
1584 }
1585
1586 void
1587 ARDOUR_UI::map_some_session_state (ToggleButton& button,
1588                                    bool (Session::*get)() const)
1589         
1590 {
1591         bool x;
1592
1593         if (session == 0) {
1594                 return;
1595         }
1596         
1597         if (button.get_active() != (x = (session->*get)())) {
1598                 button.set_active (x);
1599         }
1600 }
1601
1602 void
1603 ARDOUR_UI::toggle_some_session_state (ToggleButton& button,
1604                                       bool (Session::*get)() const,
1605                                       void (Session::*set)(bool))
1606
1607 {
1608         bool button_state;
1609         bool session_state;
1610
1611         if (session == 0) {
1612                 return;
1613         }
1614
1615         button_state = button.get_active ();
1616         session_state = (session->*get)();
1617
1618         if (button_state != session_state) {
1619                 (session->*set) (button_state);
1620 #if 0
1621         
1622                 /* check that it worked, and reverse
1623                    the button state if it didn't
1624                 */
1625
1626                 if ((session->*get)() != button_state) {
1627                         button->set_active (!button_state);
1628                 }
1629 #endif
1630
1631         }
1632 }       
1633
1634 gint
1635 ARDOUR_UI::session_menu (GdkEventButton *ev)
1636 {
1637         session_popup_menu->popup (0, 0);
1638         return TRUE;
1639 }
1640
1641 void
1642 ARDOUR_UI::redisplay_recent_sessions ()
1643 {
1644         vector<string *> *sessions;
1645         vector<string *>::iterator i;
1646         RecentSessionsSorter cmp;
1647         
1648         recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
1649         recent_session_model->clear ();
1650
1651         RecentSessions rs;
1652         ARDOUR::read_recent_sessions (rs);
1653
1654         if (rs.empty()) {
1655                 recent_session_display.set_model (recent_session_model);
1656                 return;
1657         }
1658
1659         /* sort them alphabetically */
1660         sort (rs.begin(), rs.end(), cmp);
1661         sessions = new vector<string*>;
1662
1663         for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
1664                 sessions->push_back (new string ((*i).second));
1665         }
1666
1667         for (i = sessions->begin(); i != sessions->end(); ++i) {
1668
1669                 vector<string*>* states;
1670                 vector<const gchar*> item;
1671                 string fullpath = *(*i);
1672                 
1673                 /* remove any trailing / */
1674
1675                 if (fullpath[fullpath.length()-1] == '/') {
1676                         fullpath = fullpath.substr (0, fullpath.length()-1);
1677                 }
1678
1679                 /* now get available states for this session */
1680
1681                 if ((states = Session::possible_states (fullpath)) == 0) {
1682                         /* no state file? */
1683                         continue;
1684                 }
1685
1686                 TreeModel::Row row = *(recent_session_model->append());
1687
1688                 row[recent_session_columns.visible_name] = PBD::basename (fullpath);
1689                 row[recent_session_columns.fullpath] = fullpath;
1690
1691                 if (states->size() > 1) {
1692
1693                         /* add the children */
1694                         
1695                         for (vector<string*>::iterator i2 = states->begin(); i2 != states->end(); ++i2) {
1696                                 
1697                                 TreeModel::Row child_row = *(recent_session_model->append (row.children()));
1698
1699                                 child_row[recent_session_columns.visible_name] = **i2;
1700                                 child_row[recent_session_columns.fullpath] = fullpath;
1701
1702                                 delete *i2;
1703                         }
1704                 }
1705
1706                 delete states;
1707         }
1708
1709         recent_session_display.set_model (recent_session_model);
1710         delete sessions;
1711 }
1712
1713 void
1714 ARDOUR_UI::build_session_selector ()
1715 {
1716         session_selector_window = new ArdourDialog ("session selector");
1717         
1718         Gtk::VBox *vpacker = manage (new Gtk::VBox);
1719         Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow);
1720         Gtk::HBox *button_packer = manage (new Gtk::HBox);
1721         Gtk::Button *cancel_button = manage (new Gtk::Button (_("cancel")));
1722         Gtk::Button *rescan_button = manage (new Gtk::Button (_("rescan")));
1723
1724         button_packer->pack_start (*rescan_button);
1725         button_packer->pack_start (*cancel_button);
1726
1727         vpacker->pack_start (*scroller);
1728         vpacker->pack_start (*button_packer, false, false);
1729
1730         recent_session_model = TreeStore::create (recent_session_columns);
1731         recent_session_display.set_model (recent_session_model);
1732         recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
1733         recent_session_display.set_headers_visible (false);
1734
1735         scroller->add (recent_session_display);
1736         scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
1737
1738         session_selector_window->add (*vpacker);
1739         session_selector_window->set_name ("SessionSelectorWindow");
1740         session_selector_window->set_size_request (200, 400);
1741 }
1742
1743 void
1744 ARDOUR_UI::open_recent_session ()
1745 {
1746         /* popup selector window */
1747
1748         if (session_selector_window == 0) {
1749                 build_session_selector ();
1750         }
1751
1752         redisplay_recent_sessions ();
1753
1754         session_selector_window->run ();
1755
1756
1757         switch (session_selector_window->run_status()) {
1758         case 0:
1759                 break;
1760
1761         default:
1762                 return;
1763         }
1764
1765         Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected();
1766
1767         if (i == recent_session_model->children().end()) {
1768                 return;
1769         }
1770         
1771         Glib::ustring path = (*i)[recent_session_columns.fullpath];
1772         Glib::ustring state = (*i)[recent_session_columns.visible_name];
1773
1774         session_selector_window->response (RESPONSE_ACCEPT);
1775         _session_is_new = false;
1776
1777         load_session (path, state);
1778
1779 }
1780
1781 void
1782 ARDOUR_UI::fs_cancel_clicked (Gtk::FileSelection* fs)
1783 {
1784         fs->hide_all();
1785         fs->get_selection_entry()->set_text("");
1786         allow_focus (false);
1787 }
1788
1789 gint 
1790 ARDOUR_UI::fs_delete_event (GdkEventAny* ev, Gtk::FileSelection* fs)
1791 {
1792         fs_cancel_clicked (fs);
1793         return 1;
1794 }
1795
1796 bool
1797 ARDOUR_UI::filter_ardour_session_dirs (const FileFilter::Info& info) 
1798 {
1799         struct stat statbuf;
1800         
1801         if (stat (info.filename.c_str(), &statbuf) != 0) {
1802                 return false;
1803         }
1804
1805         if (!S_ISDIR(statbuf.st_mode)) {
1806                 return false;
1807         }
1808
1809         string session_file = info.filename;
1810         session_file += '/';
1811         session_file += PBD::basename (info.filename);
1812         session_file += ".ardour";
1813         
1814         if (stat (session_file.c_str(), &statbuf) != 0) {
1815                 return false;
1816         }
1817
1818         return S_ISREG (statbuf.st_mode);
1819 }
1820
1821 void
1822 ARDOUR_UI::open_session ()
1823 {
1824         /* popup selector window */
1825
1826         if (open_session_selector == 0) {
1827                 open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN);
1828                 open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1829                 open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
1830                 
1831                 FileFilter filter_ardour;
1832                 filter_ardour.set_name (_("Ardour sessions"));
1833                 filter_ardour.add_custom (FILE_FILTER_FILENAME, mem_fun (*this, &ARDOUR_UI::filter_ardour_session_dirs));
1834
1835                 open_session_selector->add_filter (filter_ardour);
1836         }
1837
1838         switch (open_session_selector->run ()) {
1839         case RESPONSE_OK:
1840                 break;
1841         default:
1842                 return;
1843         }
1844
1845         string session_path = open_session_selector->get_filename();
1846         string path, name;
1847         bool isnew;
1848
1849         if (session_path.length() > 0) {
1850                 if (Session::find_session (session_path, path, name, isnew) == 0) {
1851                         _session_is_new = isnew;
1852                         load_session (path, name);
1853                 }
1854         }
1855 }
1856
1857
1858 void
1859 ARDOUR_UI::session_add_midi_track ()
1860 {
1861         cerr << _("Patience is a virtue.\n");
1862 }
1863
1864 void
1865 ARDOUR_UI::session_add_audio_route (bool disk, int32_t input_channels, int32_t output_channels)
1866 {
1867         Route* route;
1868
1869         if (session == 0) {
1870                 warning << _("You cannot add a track without a session already loaded.") << endmsg;
1871                 return;
1872         }
1873
1874         try { 
1875                 if (disk) {
1876                         if ((route = session->new_audio_track (input_channels, output_channels)) == 0) {
1877                                 error << _("could not create new audio track") << endmsg;
1878                         }
1879                 } else {
1880                         if ((route = session->new_audio_route (input_channels, output_channels)) == 0) {
1881                                 error << _("could not create new audio bus") << endmsg;
1882                         }
1883                 }
1884                 
1885 #if CONTROLOUTS
1886                 if (need_control_room_outs) {
1887                         pan_t pans[2];
1888                         
1889                         pans[0] = 0.5;
1890                         pans[1] = 0.5;
1891                         
1892                         route->set_stereo_control_outs (control_lr_channels);
1893                         route->control_outs()->set_stereo_pan (pans, this);
1894                 }
1895 #endif /* CONTROLOUTS */
1896         }
1897
1898         catch (...) {
1899                 ArdourMessage msg (editor, X_("noport dialog"),
1900                                    _("There are insufficient JACK ports available\n\
1901 to create a new track or bus.\n\
1902 You should save Ardour, exit and\n\
1903 restart JACK with more ports."));
1904         }
1905 }
1906
1907 void
1908 ARDOUR_UI::diskstream_added (DiskStream* ds)
1909 {
1910         // meter_bridge_dialog_check->set_sensitive (true);
1911 }
1912
1913 void
1914 ARDOUR_UI::do_transport_locate (jack_nframes_t new_position)
1915 {
1916         jack_nframes_t _preroll;
1917
1918         if (session) {
1919                 _preroll = session->convert_to_frames_at (new_position, session->preroll);
1920
1921                 if (new_position > _preroll) {
1922                         new_position -= _preroll;
1923                 } else {
1924                         new_position = 0;
1925                 }
1926
1927                 session->request_locate (new_position);
1928         }
1929 }
1930
1931 void
1932 ARDOUR_UI::transport_goto_start ()
1933 {
1934         if (session) {
1935                 session->request_locate (0);
1936
1937                 
1938                 /* force displayed area in editor to start no matter
1939                    what "follow playhead" setting is.
1940                 */
1941                 
1942                 if (editor) {
1943                         editor->reposition_x_origin (0);
1944                 }
1945         }
1946 }
1947
1948 void
1949 ARDOUR_UI::transport_goto_end ()
1950 {
1951         if (session) {
1952                 jack_nframes_t frame = session->current_end_frame();
1953                 session->request_locate (frame);
1954
1955                 /* force displayed area in editor to start no matter
1956                    what "follow playhead" setting is.
1957                 */
1958                 
1959                 if (editor) {
1960                         editor->reposition_x_origin (frame);
1961                 }
1962         }
1963 }
1964
1965 gint 
1966 ARDOUR_UI::mouse_transport_stop (GdkEventButton *ev)
1967 {
1968
1969
1970         if (session) {
1971                         if (session->transport_stopped()) {
1972                         session->request_locate (session->last_transport_start());
1973                 } else {
1974                         if (session->get_auto_loop()) {
1975                                 session->request_auto_loop (false);
1976                         }
1977
1978                         Keyboard::ModifierMask mask = Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift);
1979                         session->request_stop (Keyboard::modifier_state_equals (ev->state, mask));
1980                         }
1981         }
1982
1983         return TRUE;
1984 }
1985
1986 gint
1987 ARDOUR_UI::mouse_transport_roll (GdkEventButton* ev)
1988 {
1989         transport_roll ();
1990         return TRUE;
1991 }
1992
1993 void
1994 ARDOUR_UI::transport_stop ()
1995 {
1996         if (!session) {
1997                 return;
1998         }
1999
2000         if (session->is_auditioning()) {
2001                 session->cancel_audition ();
2002                 return;
2003         }
2004         
2005         if (session->get_auto_loop()) {
2006                 session->request_auto_loop (false);
2007         }
2008         
2009         session->request_stop ();
2010 }
2011
2012 void
2013 ARDOUR_UI::transport_stop_and_forget_capture ()
2014 {
2015         if (session) {
2016                 session->request_stop (true);
2017         }
2018 }
2019
2020 void
2021 ARDOUR_UI::remove_last_capture()
2022 {
2023         if (editor) {
2024                 editor->remove_last_capture();
2025         }
2026 }
2027
2028 void
2029 ARDOUR_UI::transport_record ()
2030 {
2031         if (session) {
2032                 switch (session->record_status()) {
2033                 case Session::Disabled:
2034                         if (session->ntracks() == 0) {
2035                                 string txt = _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu.");
2036                                 ArdourMessage msg (editor, X_("cannotrecenable"), txt);
2037                                 return;
2038                         }
2039                         session->maybe_enable_record ();
2040                         break;
2041                 case Session::Recording:
2042                 case Session::Enabled:
2043                         session->disable_record ();
2044                 }
2045         }
2046 }
2047
2048 void
2049 ARDOUR_UI::transport_roll ()
2050 {
2051         bool rolling;
2052
2053         if (!session) {
2054                 return;
2055         }
2056
2057         rolling = session->transport_rolling ();
2058
2059         if (session->get_auto_loop()) {
2060                 session->request_auto_loop (false);
2061                 auto_loop_button.set_active (false);
2062                 roll_button.set_active (true);
2063         } else if (session->get_play_range ()) {
2064                 session->request_play_range (false);
2065                 play_selection_button.set_active (false);
2066         } else if (rolling) {
2067                 session->request_locate (session->last_transport_start(), true);
2068         }
2069
2070         session->request_transport_speed (1.0f);
2071 }
2072
2073 void
2074 ARDOUR_UI::transport_loop()
2075 {
2076         if (session) {
2077                 if (session->get_auto_loop()) {
2078                         if (session->transport_rolling()) {
2079                                 Location * looploc = session->locations()->auto_loop_location();
2080                                 if (looploc) {
2081                                         session->request_locate (looploc->start(), true);
2082                                 }
2083                         }
2084                 }
2085                 else {
2086                         session->request_auto_loop (true);
2087                 }
2088         }
2089 }
2090
2091 void
2092 ARDOUR_UI::transport_play_selection ()
2093 {
2094         if (!session) {
2095                 return;
2096         }
2097
2098         if (!session->get_play_range()) {
2099                 session->request_stop ();
2100         }
2101
2102         editor->play_selection ();
2103 }
2104
2105 void
2106 ARDOUR_UI::transport_rewind (int option)
2107 {
2108         float current_transport_speed;
2109  
2110         if (session) {
2111                 current_transport_speed = session->transport_speed();
2112                 
2113                 if (current_transport_speed >= 0.0f) {
2114                         switch (option) {
2115                         case 0:
2116                                 session->request_transport_speed (-1.0f);
2117                                 break;
2118                         case 1:
2119                                 session->request_transport_speed (-4.0f);
2120                                 break;
2121                         case -1:
2122                                 session->request_transport_speed (-0.5f);
2123                                 break;
2124                         }
2125                 } else {
2126                         /* speed up */
2127                         session->request_transport_speed (current_transport_speed * 1.5f);
2128                 }
2129         }
2130 }
2131
2132 void
2133 ARDOUR_UI::transport_forward (int option)
2134 {
2135         float current_transport_speed;
2136         
2137         if (session) {
2138                 current_transport_speed = session->transport_speed();
2139                 
2140                 if (current_transport_speed <= 0.0f) {
2141                         switch (option) {
2142                         case 0:
2143                                 session->request_transport_speed (1.0f);
2144                                 break;
2145                         case 1:
2146                                 session->request_transport_speed (4.0f);
2147                                 break;
2148                         case -1:
2149                                 session->request_transport_speed (0.5f);
2150                                 break;
2151                         }
2152                 } else {
2153                         /* speed up */
2154                         session->request_transport_speed (current_transport_speed * 1.5f);
2155                 }
2156         }
2157 }
2158
2159 void
2160 ARDOUR_UI::toggle_monitor_enable (guint32 dstream)
2161 {
2162         if (session == 0) {
2163                 return;
2164         }
2165
2166         DiskStream *ds;
2167
2168         if ((ds = session->diskstream_by_id (dstream)) != 0) {
2169                 Port *port = ds->io()->input (0);
2170                 port->request_monitor_input (!port->monitoring_input());
2171         }
2172 }
2173
2174 void
2175 ARDOUR_UI::toggle_record_enable (guint32 dstream)
2176 {
2177         if (session == 0) {
2178                 return;
2179         }
2180
2181         DiskStream *ds;
2182
2183         if ((ds = session->diskstream_by_id (dstream)) != 0) {
2184                 ds->set_record_enabled (!ds->record_enabled(), this);
2185         }
2186 }
2187
2188 void
2189 ARDOUR_UI::queue_transport_change ()
2190 {
2191         Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state));
2192 }
2193
2194 void
2195 ARDOUR_UI::map_transport_state ()
2196 {
2197         float sp = session->transport_speed();
2198
2199         if (sp == 1.0f) {
2200                 transport_rolling ();
2201         } else if (sp < 0.0f) {
2202                 transport_rewinding ();
2203         } else if (sp > 0.0f) {
2204                 transport_forwarding ();
2205         } else {
2206                 transport_stopped ();
2207         }
2208 }
2209
2210 void
2211 ARDOUR_UI::send_all_midi_feedback ()
2212 {
2213         if (session) {
2214                 session->send_all_midi_feedback();
2215         }
2216 }
2217
2218 void
2219 ARDOUR_UI::allow_local_only ()
2220 {
2221
2222 }
2223
2224 void
2225 ARDOUR_UI::allow_mmc_only ()
2226 {
2227
2228 }
2229
2230 void
2231 ARDOUR_UI::allow_mmc_and_local ()
2232 {
2233
2234 }
2235
2236 void
2237 ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg)
2238 {
2239         snprintf (buf, sizeof(buf), "%s", ((GlobalClickBox *) arg)->strings[
2240                 (int) adj.get_value()].c_str());
2241 }
2242
2243 void
2244 ARDOUR_UI::engine_stopped ()
2245 {
2246         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped));
2247
2248         jack_disconnect_item->set_sensitive (false);
2249         jack_reconnect_item->set_sensitive (true);
2250         jack_bufsize_menu->set_sensitive (false);
2251 }
2252
2253
2254 void
2255 ARDOUR_UI::engine_running ()
2256 {
2257         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running));
2258
2259         jack_disconnect_item->set_sensitive (true);
2260         jack_reconnect_item->set_sensitive (false);
2261         jack_bufsize_menu->set_sensitive (true);
2262 }
2263
2264 void
2265 ARDOUR_UI::engine_halted ()
2266 {
2267         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted));
2268
2269         jack_disconnect_item->set_sensitive (false);
2270         jack_reconnect_item->set_sensitive (true);
2271         jack_bufsize_menu->set_sensitive (false);
2272
2273         update_sample_rate (0);
2274
2275         ArdourMessage msg (editor, X_("halted"),
2276                            _("\
2277 JACK has either been shutdown or it\n\
2278 disconnected Ardour because Ardour\n\
2279 was not fast enough. You can save the\n\
2280 session and/or try to reconnect to JACK ."));
2281 }
2282
2283 int32_t
2284 ARDOUR_UI::do_engine_start ()
2285 {
2286         try { 
2287                 engine->start();
2288         }
2289
2290         catch (AudioEngine::PortRegistrationFailure& err) {
2291                 engine->stop ();
2292                 error << _("Unable to create all required ports")
2293                       << endmsg;
2294                 unload_session ();
2295                 return -1;
2296         }
2297
2298         catch (...) {
2299                 engine->stop ();
2300                 error << _("Unable to start the session running")
2301                       << endmsg;
2302                 unload_session ();
2303                 return -2;
2304         }
2305         
2306         return 0;
2307 }
2308
2309 gint
2310 ARDOUR_UI::start_engine ()
2311 {
2312         if (do_engine_start () == 0) {
2313                 if (session && _session_is_new) {
2314                         /* we need to retain initial visual 
2315                            settings for a new session 
2316                         */
2317                         session->save_state ("");
2318                 }
2319
2320                 /* there is too much going on, in too many threads, for us to 
2321                    end up with a clean session. So wait 1 second after loading,
2322                    and fix it up. its ugly, but until i come across a better
2323                    solution, its what we have.
2324                 */
2325
2326                 Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::make_session_clean), 1000);
2327         }
2328
2329         return FALSE;
2330 }
2331
2332 void
2333 ARDOUR_UI::update_clocks ()
2334 {
2335          Clock (session->audible_frame()); /* EMIT_SIGNAL */
2336 }
2337
2338 void
2339 ARDOUR_UI::start_clocking ()
2340 {
2341         clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks));
2342 }
2343
2344 void
2345 ARDOUR_UI::stop_clocking ()
2346 {
2347         clock_signal_connection.disconnect ();
2348 }
2349         
2350 void
2351 ARDOUR_UI::toggle_clocking ()
2352 {
2353 #if 0
2354         if (clock_button.get_active()) {
2355                 start_clocking ();
2356         } else {
2357                 stop_clocking ();
2358         }
2359 #endif
2360 }
2361
2362 gint
2363 ARDOUR_UI::_blink (void *arg)
2364
2365 {
2366         ((ARDOUR_UI *) arg)->blink ();
2367         return TRUE;
2368 }
2369
2370 void
2371 ARDOUR_UI::blink ()
2372 {
2373          Blink (blink_on = !blink_on); /* EMIT_SIGNAL */
2374 }
2375
2376 void
2377 ARDOUR_UI::start_blinking ()
2378 {
2379         /* Start the blink signal. Everybody with a blinking widget
2380            uses Blink to drive the widget's state.
2381         */
2382
2383         if (blink_timeout_tag < 0) {
2384                 blink_on = false;       
2385                 blink_timeout_tag = gtk_timeout_add (240, _blink, this);
2386         }
2387 }
2388
2389 void
2390 ARDOUR_UI::stop_blinking ()
2391 {
2392         if (blink_timeout_tag >= 0) {
2393                 gtk_timeout_remove (blink_timeout_tag);
2394                 blink_timeout_tag = -1;
2395         }
2396 }
2397
2398
2399 void
2400 ARDOUR_UI::add_diskstream_to_menu (DiskStream& dstream)
2401 {
2402         using namespace Gtk;
2403         using namespace Menu_Helpers;
2404
2405         if (dstream.hidden()) {
2406                 return;
2407         }
2408
2409         MenuList& items = diskstream_menu->items();
2410         items.push_back (MenuElem (dstream.name(), bind (mem_fun(*this, &ARDOUR_UI::diskstream_selected), (gint32) dstream.id())));
2411 }
2412         
2413 void
2414 ARDOUR_UI::diskstream_selected (gint32 id)
2415 {
2416         selected_dstream = id;
2417         Main::quit ();
2418 }
2419
2420 gint32
2421 ARDOUR_UI::select_diskstream (GdkEventButton *ev)
2422 {
2423         using namespace Gtk;
2424         using namespace Menu_Helpers;
2425
2426         if (session == 0) {
2427                 return -1;
2428         }
2429
2430         diskstream_menu = new Menu();
2431         diskstream_menu->set_name ("ArdourContextMenu");
2432         using namespace Gtk;
2433         using namespace Menu_Helpers;
2434
2435         MenuList& items = diskstream_menu->items();
2436         items.push_back (MenuElem (_("No Stream"), (bind (mem_fun(*this, &ARDOUR_UI::diskstream_selected), -1))));
2437
2438         session->foreach_diskstream (this, &ARDOUR_UI::add_diskstream_to_menu);
2439
2440         if (ev) {
2441                 diskstream_menu->popup (ev->button, ev->time);
2442         } else {
2443                 diskstream_menu->popup (0, 0);
2444         }
2445
2446         selected_dstream = -1;
2447
2448         Main::run ();
2449
2450         delete diskstream_menu;
2451
2452         return selected_dstream;
2453 }
2454
2455 void
2456 ARDOUR_UI::name_io_setup (AudioEngine& engine, 
2457                           string& buf,
2458                           IO& io,
2459                           bool in)
2460 {
2461         if (in) {
2462                 if (io.n_inputs() == 0) {
2463                         buf = _("none");
2464                         return;
2465                 }
2466                 
2467                 /* XXX we're not handling multiple ports yet. */
2468
2469                 const char **connections = io.input(0)->get_connections();
2470                 
2471                 if (connections == 0 || connections[0] == '\0') {
2472                         buf = _("off");
2473                 } else {
2474                         buf = connections[0];
2475                 }
2476
2477                 free (connections);
2478
2479         } else {
2480
2481                 if (io.n_outputs() == 0) {
2482                         buf = _("none");
2483                         return;
2484                 }
2485                 
2486                 /* XXX we're not handling multiple ports yet. */
2487
2488                 const char **connections = io.output(0)->get_connections();
2489                 
2490                 if (connections == 0 || connections[0] == '\0') {
2491                         buf = _("off");
2492                 } else {
2493                         buf = connections[0];
2494                 }
2495
2496                 free (connections);
2497         }
2498 }
2499
2500 void
2501 ARDOUR_UI::snapshot_session ()
2502 {
2503         ArdourPrompter prompter (true);
2504         string snapname;
2505         string now;
2506         time_t n;
2507
2508         time (&n);
2509         now = ctime (&n);
2510         now = now.substr (0, now.length() - 1);
2511
2512         prompter.set_name ("Prompter");
2513         prompter.set_prompt (_("Name for snapshot"));
2514         prompter.set_initial_text (now);
2515         
2516         switch (prompter.run()) {
2517         case RESPONSE_ACCEPT:
2518                 prompter.get_result (snapname);
2519                 if (snapname.length()){
2520                         save_state (snapname);
2521                 }
2522                 break;
2523
2524         default:
2525                 break;
2526         }
2527 }
2528
2529 void
2530 ARDOUR_UI::save_state (string name)
2531 {
2532         (void) save_state_canfail (name);
2533 }
2534                 
2535 int
2536 ARDOUR_UI::save_state_canfail (string name)
2537 {
2538         if (session) {
2539                 int ret;
2540
2541                 if (name.length() == 0) {
2542                         name = session->snap_name();
2543                 }
2544
2545                 if ((ret = session->save_state (name)) != 0) {
2546                         return ret;
2547                 }
2548         }
2549         save_ardour_state (); /* XXX cannot fail? yeah, right ... */
2550         return 0;
2551 }
2552
2553 void
2554 ARDOUR_UI::restore_state (string name)
2555 {
2556         if (session) {
2557                 if (name.length() == 0) {
2558                         name = session->name();
2559                 }
2560                 session->restore_state (name);
2561         }
2562 }
2563
2564 void
2565 ARDOUR_UI::allow_focus (bool yn)
2566 {
2567         if (keyboard) {
2568                 keyboard->allow_focus (yn);
2569         }
2570 }
2571
2572 void
2573 ARDOUR_UI::primary_clock_value_changed ()
2574 {
2575         if (session) {
2576                 session->request_locate (primary_clock.current_time ());
2577         }
2578 }
2579
2580 void
2581 ARDOUR_UI::secondary_clock_value_changed ()
2582 {
2583         if (session) {
2584                 session->request_locate (secondary_clock.current_time ());
2585         }
2586 }
2587
2588 void
2589 ARDOUR_UI::rec_enable_button_blink (bool onoff, DiskStream *dstream, Widget *w)
2590 {
2591         if (session && dstream && dstream->record_enabled()) {
2592
2593                 Session::RecordState rs;
2594                 
2595                 rs = session->record_status ();
2596
2597                 switch (rs) {
2598                 case Session::Disabled:
2599                 case Session::Enabled:
2600                         if (w->get_state() != STATE_SELECTED) {
2601                                 w->set_state (STATE_SELECTED);
2602                         }
2603                         break;
2604
2605                 case Session::Recording:
2606                         if (w->get_state() != STATE_ACTIVE) {
2607                                 w->set_state (STATE_ACTIVE);
2608                         }
2609                         break;
2610                 }
2611
2612         } else {
2613                 if (w->get_state() != STATE_NORMAL) {
2614                         w->set_state (STATE_NORMAL);
2615                 }
2616         }
2617 }
2618
2619 void
2620 ARDOUR_UI::transport_rec_enable_blink (bool onoff) 
2621 {
2622         if (session == 0) {
2623                 return;
2624         }
2625         
2626         switch (session->record_status()) {
2627         case Session::Enabled:
2628                 if (onoff) {
2629                         rec_button.set_state (STATE_ACTIVE);
2630                 } else {
2631                         rec_button.set_state (STATE_NORMAL);
2632                 }
2633                 break;
2634
2635         case Session::Recording:
2636                 rec_button.set_state (STATE_ACTIVE);
2637                 break;
2638
2639         default:
2640                 rec_button.set_active (false);
2641                 rec_button.set_state (STATE_NORMAL);
2642                 break;
2643         }
2644 }
2645
2646 gint
2647 ARDOUR_UI::generic_focus_in_event (GdkEventFocus *ev)
2648 {
2649         ARDOUR_UI::instance()->allow_focus (true);
2650         return FALSE;
2651 }
2652
2653 gint
2654 ARDOUR_UI::generic_focus_out_event (GdkEventFocus *ev)
2655 {
2656         ARDOUR_UI::instance()->allow_focus (false);
2657         return FALSE;
2658 }
2659
2660 gint
2661 ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window)
2662 {
2663         window->hide();
2664         Gtk::Main::quit ();
2665         return TRUE;
2666 }
2667
2668 void
2669 ARDOUR_UI::start_keyboard_prefix ()
2670 {
2671         keyboard->start_prefix();
2672 }
2673
2674 void
2675 ARDOUR_UI::save_template ()
2676
2677 {
2678         ArdourPrompter prompter (true);
2679         string name;
2680
2681         prompter.set_name (X_("Prompter"));
2682         prompter.set_prompt (_("Name for mix template:"));
2683         prompter.set_initial_text(session->name() + _("-template"));
2684         
2685         switch (prompter.run()) {
2686         case RESPONSE_ACCEPT:
2687                 prompter.get_result (name);
2688                 
2689                 if (name.length()) {
2690                         session->save_template (name);
2691                 }
2692                 break;
2693
2694         default:
2695                 break;
2696         }
2697 }
2698
2699 void
2700 ARDOUR_UI::new_session (bool startup, string predetermined_path)
2701 {
2702         if (new_session_window == 0){
2703                 new_session_window = new NewSessionDialog (*engine, startup, predetermined_path);
2704                 editor->ensure_float (*new_session_window);
2705         }
2706
2707         new_session_window->run ();
2708
2709 #if 0
2710         // GTK2FIX
2711         
2712         /* write favorites either way */
2713         Session::FavoriteDirs favs;
2714         new_session_window->file_selector.get_favorites (favs);
2715         Session::write_favorite_dirs (favs);
2716
2717         if (new_session_window->run_status()) {
2718                 return;
2719         }
2720 #endif
2721
2722         string session_path = new_session_window->file_selector.get_filename ();
2723         string session_name = PBD::basename (session_path);
2724
2725         // Check that it doesn't already exist.
2726         access(session_path.c_str(), R_OK); 
2727         if (errno != ENOENT){
2728                 error << string_compose(_("Session %1 already exists at %2"), session_name, session_path) << endmsg;
2729                 return;
2730         }
2731
2732         _session_is_new = true;
2733
2734         if (session_path[session_path.length()-1] != '/') {
2735
2736                 string template_name = new_session_window->get_template_name ();
2737
2738                 if (template_name.length()) {
2739
2740                         load_session (session_path, session_name, &template_name);
2741
2742                 } else {
2743
2744                         uint32_t cchns;
2745                         uint32_t mchns;
2746                         Session::AutoConnectOption iconnect;
2747                         Session::AutoConnectOption oconnect;
2748
2749                         if (new_session_window->use_control_button.get_active()) {
2750                                 cchns = (uint32_t) channel_combo_get_channel_count (new_session_window->control_out_channel_combo);
2751                         } else {
2752                                 cchns = 0;
2753                         }
2754                         if (new_session_window->use_master_button.get_active()) {
2755                                 mchns = (uint32_t) channel_combo_get_channel_count (new_session_window->master_out_channel_combo);
2756                         } else {
2757                                 mchns = 0;
2758                         }
2759
2760                         if (new_session_window->connect_to_physical_inputs_button.get_active()) {
2761                                 iconnect = Session::AutoConnectPhysical;
2762                         } else {
2763                                 iconnect = Session::AutoConnectOption (0);
2764                         }
2765
2766                         if (new_session_window->connect_to_master_button.get_active ()) {
2767                                 oconnect = Session::AutoConnectMaster;
2768                         } else if (new_session_window->connect_to_physical_outputs_button.get_active ()) {
2769                                 oconnect = Session::AutoConnectPhysical;
2770                         } else {
2771                                 oconnect = Session::AutoConnectOption (0);
2772                         } 
2773
2774                         uint32_t nphysin = (uint32_t) new_session_window->in_count_adjustment.get_value();
2775                         uint32_t nphysout = (uint32_t) new_session_window->out_count_adjustment.get_value();
2776
2777                         build_session (session_path, session_name, cchns, mchns, iconnect, oconnect, nphysin, nphysout, 
2778                                        engine->frame_rate() * 60 * 5);
2779                 }
2780         }
2781 }
2782
2783 int
2784 ARDOUR_UI::load_session (string path, string snap_name, string* mix_template)
2785 {
2786         Session *new_session;
2787         int x;
2788         session_loaded = false;
2789         x = unload_session ();
2790
2791         if (x < 0) {
2792                 return -1;
2793         } else if (x > 0) {
2794                 return 0;
2795         }
2796
2797         /* if it already exists, we must have write access */
2798
2799         if (::access (path.c_str(), F_OK) == 0 && ::access (path.c_str(), W_OK)) {
2800                 ArdourMessage msg (editor, X_("noaccess dialog"), _("\
2801 You do not have write access to this session.\n\
2802 This prevents the session from being loaded."));
2803                 return -1;
2804         }
2805
2806         try {
2807                 new_session = new Session (*engine, path, snap_name, mix_template);
2808         }
2809
2810         catch (...) {
2811
2812                 error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
2813                 return -1;
2814         }
2815
2816         connect_to_session (new_session);
2817
2818         //if (engine->running()) {
2819         //mixer->show_window();
2820         //}
2821         session_loaded = true;
2822         return 0;
2823 }
2824
2825 int
2826 ARDOUR_UI::make_session_clean ()
2827 {
2828         if (session) {
2829                 session->set_clean ();
2830         }
2831
2832         return FALSE;
2833 }
2834
2835 int
2836 ARDOUR_UI::build_session (string path, string snap_name, 
2837                           uint32_t control_channels,
2838                           uint32_t master_channels, 
2839                           Session::AutoConnectOption input_connect,
2840                           Session::AutoConnectOption output_connect,
2841                           uint32_t nphysin,
2842                           uint32_t nphysout,
2843                           jack_nframes_t initial_length)
2844 {
2845         Session *new_session;
2846         int x;
2847
2848         session_loaded = false;
2849         x = unload_session ();
2850         if (x < 0) {
2851                 return -1;
2852         } else if (x > 0) {
2853                 return 0;
2854         }
2855         
2856         _session_is_new = true;
2857
2858         try {
2859                 new_session = new Session (*engine, path, snap_name, input_connect, output_connect,
2860                                            control_channels, master_channels, nphysin, nphysout, initial_length);
2861         }
2862
2863         catch (...) {
2864
2865                 error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg;
2866                 return -1;
2867         }
2868
2869         connect_to_session (new_session);
2870
2871         //if (engine->running()) {
2872         //mixer->show_window();
2873         //}
2874         session_loaded = true;
2875         return 0;
2876 }
2877
2878 void
2879 ARDOUR_UI::hide_dialog (ArdourDialog *dialog)
2880 {
2881         dialog->hide_all();
2882 }
2883
2884 void
2885 ARDOUR_UI::show ()
2886 {
2887         if (editor) {
2888                 editor->show_window ();
2889                 shown_flag = true;
2890         }
2891
2892         if (session && mixer) {
2893                 mixer->show_window ();
2894         }
2895         
2896         if (about) {
2897                 about->present ();
2898         }
2899 }
2900
2901 void
2902 ARDOUR_UI::show_splash ()
2903 {
2904         if (about == 0) {
2905                 about = new About();
2906         }
2907         about->present();
2908 }
2909
2910 void
2911 ARDOUR_UI::hide_splash ()
2912 {
2913         if (about) {
2914                 // about->hide();
2915         }
2916 }
2917
2918 void
2919 ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, string msg)
2920 {
2921         size_t removed;
2922
2923         removed = rep.paths.size();
2924
2925         if (removed == 0) {
2926                 ArdourMessage msg (editor, X_("cleanupresults"),
2927                                    _("\
2928 No audio files were ready for cleanup\n\n\
2929 If this seems suprising, check for any existing\n\
2930 snapshots. These may still include regions that\n\
2931 require some unused files to continue to exist."));
2932                 return;
2933         } 
2934
2935         ArdourDialog results ("cleanup results");
2936         
2937         struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord {
2938             CleanupResultsModelColumns() { 
2939                     add (visible_name);
2940                     add (fullpath);
2941             }
2942             Gtk::TreeModelColumn<Glib::ustring> visible_name;
2943             Gtk::TreeModelColumn<Glib::ustring> fullpath;
2944         };
2945
2946         
2947         Glib::RefPtr<Gtk::ListStore> results_model;
2948         CleanupResultsModelColumns results_columns;
2949         Gtk::TreeView results_display;
2950         
2951         results_model = ListStore::create (results_columns);
2952         results_display.set_model (results_model);
2953         results_display.append_column (list_title, results_columns.visible_name);
2954         results_display.set_headers_visible (true);
2955
2956         Gtk::ScrolledWindow list_scroller;
2957         Gtk::Label txt;
2958         Gtk::Button ok_button (_("OK"));
2959         Gtk::VBox vpacker;
2960         
2961         vpacker.set_border_width (10);
2962         vpacker.set_spacing (10);
2963
2964         if (rep.space < 1048576.0f) {
2965                 if (removed > 1) {
2966                         txt.set_text (string_compose (msg, removed, _("files"), (float) rep.space / 1024.0f, "kilo"));
2967                 } else {
2968                         txt.set_text (string_compose (msg, removed, _("file"), (float) rep.space / 1024.0f, "kilo"));
2969                 }
2970         } else {
2971                 if (removed > 1) {
2972                         txt.set_text (string_compose (msg, removed, _("files"), (float) rep.space / 1048576.0f, "mega"));
2973                 } else {
2974                         txt.set_text (string_compose (msg, removed, _("file"), (float) rep.space / 1048576.0f, "mega"));
2975                 }
2976         }
2977
2978         vpacker.pack_start (txt, false, false);
2979         
2980         for (vector<string>::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) {
2981                 TreeModel::Row row = *(results_model->append());
2982                 row[results_columns.visible_name] = *i;
2983                 row[results_columns.fullpath] = *i;
2984         }
2985         
2986         list_scroller.add (results_display);
2987         list_scroller.set_size_request (-1, 250);
2988         list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
2989         
2990         vpacker.pack_start (list_scroller, true, true);
2991         vpacker.pack_start (ok_button, false, false);
2992         
2993         results.add (vpacker);
2994         
2995         results.set_position (Gtk::WIN_POS_MOUSE);
2996         results.set_title (_("ardour: cleanup"));
2997         results.set_modal (true);
2998
2999         results.run ();
3000 }
3001
3002 void
3003 ARDOUR_UI::cleanup ()
3004 {
3005         if (session == 0) {
3006                 /* shouldn't happen: menu item is insensitive */
3007                 return;
3008         }
3009
3010         ArdourDialog checker (X_("cleanup confirm dialog"));
3011         Gtk::Label label (_("\
3012 Cleanup is a destructive operation.\n\
3013 ALL undo/redo information will be lost if you cleanup.\n\
3014 Unused audio files will be moved to a \"dead sounds\" location."));
3015
3016         Gtk::Button ok_button (_("Proceed with cleanup"));
3017         Gtk::Button cancel_button (_("Cancel"));
3018         Gtk::HBox   bbox;
3019         Gtk::VBox   vbox;
3020
3021         bbox.set_border_width (6);
3022         bbox.set_spacing (12);
3023         bbox.pack_start (ok_button, true, false);
3024         bbox.pack_start (cancel_button, true, false);
3025         
3026         vbox.set_border_width (6);
3027         vbox.set_spacing (12);
3028         vbox.pack_start (label, false, false);
3029         vbox.pack_start (bbox, false, false);
3030         
3031         checker.add (vbox);
3032         checker.set_name (_("CleanupDialog"));
3033         checker.set_title (_("ardour cleanup"));
3034         checker.set_wmclass (_("ardour_cleanup"), "Ardour");
3035         checker.set_position (Gtk::WIN_POS_MOUSE);
3036
3037         ok_button.signal_clicked().connect (bind (mem_fun (checker, &ArdourDialog::stop), 1));
3038         cancel_button.signal_clicked().connect (bind (mem_fun (checker, &ArdourDialog::stop), 0));
3039
3040         checker.run ();
3041
3042         switch (checker.run_status()) {
3043         case 0:
3044                 break;
3045         default:
3046                 return;
3047         }
3048
3049         Session::cleanup_report rep;
3050
3051         editor->prepare_for_cleanup ();
3052
3053         if (session->cleanup_sources (rep)) {
3054                 return;
3055         }
3056
3057         display_cleanup_results (rep, 
3058                                  _("cleaned files"),
3059                                  _("\
3060 The following %1 %2 were not in use.\n\
3061 The next time you flush the wastebasket\n\
3062 it will release an additional %3 %4bytes\n\
3063 of disk space"
3064                                          ));
3065 }
3066
3067 void
3068 ARDOUR_UI::flush_trash ()
3069 {
3070         if (session == 0) {
3071                 /* shouldn't happen: menu item is insensitive */
3072                 return;
3073         }
3074
3075         Session::cleanup_report rep;
3076
3077         if (session->cleanup_trash_sources (rep)) {
3078                 return;
3079         }
3080
3081         display_cleanup_results (rep, 
3082                                  _("deleted file"),
3083                                  _("The following %1 file%2 were deleted, releasing %3 %4bytes of disk space"));
3084 }
3085
3086 void
3087 ARDOUR_UI::add_route ()
3088 {
3089         int count;
3090
3091         if (!session) {
3092                 return;
3093         }
3094
3095         if (add_route_dialog == 0) {
3096                 add_route_dialog = new AddRouteDialog;
3097                 editor->ensure_float (*add_route_dialog);
3098         }
3099
3100         if (add_route_dialog->is_visible()) {
3101                 /* we're already doing this */
3102                 return;
3103         }
3104
3105         add_route_dialog->run ();
3106
3107         if (add_route_dialog->run_status()) {
3108                 return;
3109         }
3110
3111         if ((count = add_route_dialog->count()) <= 0) {
3112                 return;
3113         }
3114
3115         uint32_t input_chan = add_route_dialog->channels ();
3116         uint32_t output_chan;
3117         string name_template = add_route_dialog->name_template ();
3118         bool track = add_route_dialog->track ();
3119
3120         Session::AutoConnectOption oac = session->get_output_auto_connect();
3121
3122         if (oac & Session::AutoConnectMaster) {
3123                 output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
3124         } else {
3125                 output_chan = input_chan;
3126         }
3127
3128         /* XXX do something with name template */
3129
3130         while (count) {
3131                 if (track) {
3132                         session_add_audio_track (input_chan, output_chan);
3133                 } else {
3134                         session_add_audio_bus (input_chan, output_chan);
3135                 }
3136                 --count;
3137                 
3138                 while (Main::events_pending()) {
3139                         Main::iteration ();
3140                 }
3141         }
3142 }
3143
3144 XMLNode*
3145 ARDOUR_UI::mixer_settings () const
3146 {
3147         XMLNode* node = 0;
3148
3149         if (session) {
3150                 node = session->instant_xml(X_("Mixer"), session->path());
3151         } else {
3152                 node = Config->instant_xml(X_("Mixer"), Config->get_user_ardour_path());
3153         }
3154
3155         if (!node) {
3156                 node = new XMLNode (X_("Mixer"));
3157         }
3158
3159         return node;
3160 }
3161
3162 XMLNode*
3163 ARDOUR_UI::editor_settings () const
3164 {
3165         XMLNode* node = 0;
3166
3167         if (session) {
3168                 node = session->instant_xml(X_("Editor"), session->path());
3169         } else {
3170                 node = Config->instant_xml(X_("Editor"), Config->get_user_ardour_path());
3171         }
3172
3173         if (!node) {
3174                 node = new XMLNode (X_("Editor"));
3175         }
3176         return node;
3177 }
3178
3179 XMLNode*
3180 ARDOUR_UI::keyboard_settings () const
3181 {
3182         XMLNode* node = 0;
3183
3184         node = Config->extra_xml(X_("Keyboard"));
3185         
3186         if (!node) {
3187                 node = new XMLNode (X_("Keyboard"));
3188         }
3189         return node;
3190 }
3191
3192 void
3193 ARDOUR_UI::halt_on_xrun_message ()
3194 {
3195         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::halt_on_xrun_message));
3196
3197         ArdourMessage msg (editor, X_("haltonxrun"),
3198                            _("Recording was stopped because your system could not keep up."));
3199 }
3200
3201 void 
3202 ARDOUR_UI::delete_sources_in_the_right_thread (list<ARDOUR::Source*>* deletion_list)
3203 {
3204         ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::delete_sources_in_the_right_thread), deletion_list));
3205
3206         for (list<Source*>::iterator i = deletion_list->begin(); i != deletion_list->end(); ++i) {
3207                 delete *i;
3208         }
3209
3210         delete deletion_list;
3211 }
3212
3213 void
3214 ARDOUR_UI::disk_overrun_handler ()
3215 {
3216         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
3217
3218         if (!have_disk_overrun_displayed) {
3219                 have_disk_overrun_displayed = true;
3220                 ArdourMessage msg (editor, X_("diskrate dialog"), _("\
3221 The disk system on your computer\n\
3222 was not able to keep up with Ardour.\n\
3223 \n\
3224 Specifically, it failed to write data to disk\n\
3225 quickly enough to keep up with recording.\n"));
3226                 have_disk_overrun_displayed = false;
3227         }
3228 }
3229
3230 void
3231 ARDOUR_UI::disk_underrun_handler ()
3232 {
3233         ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler));
3234
3235         if (!have_disk_underrun_displayed) {
3236                 have_disk_underrun_displayed = true;
3237                 ArdourMessage msg (editor, X_("diskrate2 dialog"),
3238                         (_("The disk system on your computer\n\
3239 was not able to keep up with Ardour.\n\
3240 \n\
3241 Specifically, it failed to read data from disk\n\
3242 quickly enough to keep up with playback.\n")));
3243                 have_disk_underrun_displayed = false;
3244         } 
3245 }
3246
3247 void
3248 ARDOUR_UI::disk_underrun_message_gone ()
3249 {
3250         have_disk_underrun_displayed = false;
3251 }
3252
3253 void
3254 ARDOUR_UI::disk_overrun_message_gone ()
3255 {
3256         have_disk_underrun_displayed = false;
3257 }
3258
3259 int
3260 ARDOUR_UI::pending_state_dialog ()
3261 {
3262         ArdourDialog dialog ("pending state dialog");
3263         Button use_button (_("Recover from crash"));
3264         Button cancel_button (_("Ignore crash data"));
3265         Label  message (_("\
3266 This session appears to have been in\n\
3267 middle of recording when ardour or\n\
3268 the computer was shutdown.\n\
3269 \n\
3270 Ardour can recover any captured audio for\n\
3271 you, or it can ignore it. Please decide\n\
3272 what you would like to do.\n"));
3273         HBox hpacker;
3274         VBox vpacker;
3275
3276         vpacker.set_border_width (12);
3277         vpacker.set_spacing (7);
3278         vpacker.pack_start (message);
3279         vpacker.pack_start (hpacker);
3280
3281         hpacker.set_spacing (7);
3282         hpacker.pack_start (use_button);
3283         hpacker.pack_start (cancel_button);
3284         
3285         use_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 0));
3286         cancel_button.signal_clicked().connect (bind (mem_fun (dialog, &ArdourDialog::stop), 1));
3287
3288         dialog.add (vpacker);
3289         dialog.set_position (WIN_POS_CENTER);
3290         dialog.show_all ();
3291         
3292         dialog.run ();
3293
3294         if (dialog.run_status () != 0) {
3295                 return 1;
3296         }
3297
3298         return 0;
3299 }
3300         
3301         
3302 void
3303 ARDOUR_UI::disconnect_from_jack ()
3304 {
3305         if (engine) {
3306                 if( engine->disconnect_from_jack ()) {
3307                         ArdourMessage msg (editor, X_("nojack dialog"),
3308                                            _("Could not disconnect from JACK"));
3309                 }
3310
3311                 update_sample_rate (0);
3312         }
3313 }
3314
3315 void
3316 ARDOUR_UI::reconnect_to_jack ()
3317 {
3318         if (engine) {
3319                 if (engine->reconnect_to_jack ()) {
3320                         ArdourMessage msg (editor, X_("nojack dialog"),
3321                                            _("Could not reconnect to JACK"));
3322                 }
3323
3324                 update_sample_rate (0);
3325         }
3326 }
3327
3328 void
3329 ARDOUR_UI::set_jack_buffer_size (jack_nframes_t nframes)
3330 {
3331         engine->request_buffer_size (nframes);
3332         update_sample_rate (0);
3333 }
3334
3335 int
3336 ARDOUR_UI::cmdline_new_session (string path)
3337 {
3338         if (path[0] != '/') {
3339                 char buf[PATH_MAX+1];
3340                 string str;
3341
3342                 getcwd (buf, sizeof (buf));
3343                 str = buf;
3344                 str += '/';
3345                 str += path;
3346                 path = str;
3347         }
3348
3349         new_session (false, path);
3350
3351         _will_create_new_session_automatically = false; /* done it */
3352         return FALSE; /* don't call it again */
3353 }