X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fardour_ui.cc;h=de006a8fecab3eb4a3e40e723118bd4e35ef2f85;hb=b3fe7cfc892f7d5978ad14eb81e9305fa9c14d13;hp=37792a80190c40900abf82d7bd86955d2988c795;hpb=e493b2b7c4fbbbfc457f02babf9546289b430177;p=ardour.git diff --git a/gtk2_ardour/ardour_ui.cc b/gtk2_ardour/ardour_ui.cc index 37792a8019..de006a8fec 100644 --- a/gtk2_ardour/ardour_ui.cc +++ b/gtk2_ardour/ardour_ui.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 1999-2002 Paul Davis + Copyright (C) 1999-2007 Paul Davis This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,9 +15,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ +#define __STDC_FORMAT_MACROS 1 +#include + #include #include #include @@ -28,766 +30,80 @@ #include -#include +#include + +#include +#include + #include -#include +#include #include #include +#include +#include #include -#include #include #include -#include #include #include #include +#include #include #include #include +#include +#include #include #include #include #include -#include -#include +#include +#include #include -#include #include #include +#include +#include "actions.h" #include "ardour_ui.h" -#include "ardour_message.h" #include "public_editor.h" #include "audio_clock.h" #include "keyboard.h" #include "mixer_ui.h" #include "prompter.h" #include "opts.h" -#include "keyboard_target.h" #include "add_route_dialog.h" #include "new_session_dialog.h" #include "about.h" #include "utils.h" #include "gui_thread.h" +#include "color_manager.h" #include "i18n.h" using namespace ARDOUR; +using namespace PBD; using namespace Gtkmm2ext; using namespace Gtk; using namespace sigc; ARDOUR_UI *ARDOUR_UI::theArdourUI = 0; -SoundFileSelector* ARDOUR_UI::sfdb_window = 0; sigc::signal ARDOUR_UI::Blink; sigc::signal ARDOUR_UI::RapidScreenUpdate; sigc::signal ARDOUR_UI::SuperRapidScreenUpdate; -sigc::signal ARDOUR_UI::Clock; - -/* XPM */ -static const gchar *h_meter_strip_xpm[] = { -"186 5 187 2", -" c None", -". c #2BFE00", -"+ c #2DFE00", -"@ c #2FFE01", -"# c #32FE01", -"$ c #34FE02", -"% c #36FE02", -"& c #38FE03", -"* c #3BFE03", -"= c #3DFD04", -"- c #3FFD04", -"; c #41FD05", -"> c #44FD05", -", c #46FD06", -"' c #48FD06", -") c #4AFD07", -"! c #4DFD07", -"~ c #4FFD08", -"{ c #51FC08", -"] c #53FC09", -"^ c #56FC09", -"/ c #58FC09", -"( c #5AFC0A", -"_ c #5CFC0A", -": c #5FFC0B", -"< c #61FC0B", -"[ c #63FB0C", -"} c #65FB0C", -"| c #68FB0D", -"1 c #6AFB0D", -"2 c #6CFB0E", -"3 c #6EFB0E", -"4 c #71FB0F", -"5 c #73FB0F", -"6 c #75FB10", -"7 c #77FA10", -"8 c #7AFA11", -"9 c #7CFA11", -"0 c #7EFA12", -"a c #80FA12", -"b c #83FA12", -"c c #85FA13", -"d c #87FA13", -"e c #89FA14", -"f c #8CF914", -"g c #8EF915", -"h c #90F915", -"i c #92F916", -"j c #95F916", -"k c #97F917", -"l c #99F917", -"m c #9BF918", -"n c #9EF818", -"o c #A0F819", -"p c #A2F819", -"q c #A4F81A", -"r c #A7F81A", -"s c #A9F81A", -"t c #ABF81B", -"u c #ADF81B", -"v c #B0F81C", -"w c #B2F71C", -"x c #B4F71D", -"y c #B6F71D", -"z c #B9F71E", -"A c #BBF71E", -"B c #BDF71F", -"C c #BFF71F", -"D c #C2F720", -"E c #C4F720", -"F c #C6F621", -"G c #C8F621", -"H c #CBF622", -"I c #CDF622", -"J c #CFF623", -"K c #D1F623", -"L c #D4F624", -"M c #D6F624", -"N c #D8F524", -"O c #DAF525", -"P c #DDF525", -"Q c #DFF526", -"R c #E1F526", -"S c #E3F527", -"T c #E6F527", -"U c #E8F528", -"V c #EAF528", -"W c #ECF429", -"X c #EFF429", -"Y c #F1F42A", -"Z c #F3F42A", -"` c #F5F42B", -" . c #F8F42B", -".. c #FAF42C", -"+. c #FCF42C", -"@. c #FFF42D", -"#. c #FFF22C", -"$. c #FFF12B", -"%. c #FFF02A", -"&. c #FFEF2A", -"*. c #FFEE29", -"=. c #FFED28", -"-. c #FFEC28", -";. c #FFEB27", -">. c #FFE926", -",. c #FFE826", -"'. c #FFE725", -"). c #FFE624", -"!. c #FFE524", -"~. c #FFE423", -"{. c #FFE322", -"]. c #FFE222", -"^. c #FFE021", -"/. c #FFDF20", -"(. c #FFDE20", -"_. c #FFDD1F", -":. c #FFDC1E", -"<. c #FFDB1E", -"[. c #FFDA1D", -"}. c #FFD91C", -"|. c #FFD71B", -"1. c #FFD61B", -"2. c #FFD51A", -"3. c #FFD419", -"4. c #FFD319", -"5. c #FFD218", -"6. c #FFD117", -"7. c #FFD017", -"8. c #FFCF16", -"9. c #FFCD15", -"0. c #FFCC15", -"a. c #FFCB14", -"b. c #FFCA13", -"c. c #FFC913", -"d. c #FFC812", -"e. c #FFC711", -"f. c #FFC611", -"g. c #FFC410", -"h. c #FFC30F", -"i. c #FFC20F", -"j. c #FFC10E", -"k. c #FFC00D", -"l. c #FFBF0C", -"m. c #FFBE0C", -"n. c #FFBD0B", -"o. c #FFBB0A", -"p. c #FFBA0A", -"q. c #FFB909", -"r. c #FFB808", -"s. c #FFB708", -"t. c #FFB607", -"u. c #FFB506", -"v. c #FFB406", -"w. c #FFB205", -"x. c #FFB104", -"y. c #FFB004", -"z. c #FFAF03", -"A. c #FFAE02", -"B. c #FFAD02", -"C. c #FFAC01", -"D. c #FFAB00", -"E. c #FFA900", -"F. c #F11F00", -"G. c #F21E00", -"H. c #F21C00", -"I. c #F31B00", -"J. c #F31A00", -"K. c #F41800", -"L. c #F41700", -"M. c #F51600", -"N. c #F61400", -"O. c #F61300", -"P. c #F71100", -"Q. c #F71000", -"R. c #F80F00", -"S. c #F90D00", -"T. c #F90C00", -"U. c #FA0B00", -"V. c #FA0900", -"W. c #FB0800", -"X. c #FC0600", -"Y. c #FC0500", -"Z. c #FD0400", -"`. c #FD0200", -" + c #FE0100", -".+ c #FE0000", -"++ c #FF0000", -". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 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.`. +.+", -". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 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.`. +.+", -". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 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.`. +++", -". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 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.`. +++", -". + @ # $ % & * = - ; > , ' ) ! ~ { ] ^ / ( _ : < [ } | 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.`. +++"}; - -/* XPM */ -static const gchar * v_meter_strip_xpm[] = { -"5 250 230 2", -" c None", -". c #FE0000", -"+ c #FF0000", -"@ c #FE0100", -"# c #FD0200", -"$ c #FD0300", -"% c #FD0400", -"& c #FC0500", -"* c #FC0600", -"= c #FC0700", -"- c #FB0800", -"; c #FA0900", -"> c #FA0A00", -", c #FA0B00", -"' c #F90C00", -") c #F90D00", -"! c #F80E00", -"~ c #F80F00", -"{ c #F71000", -"] c #F71100", -"^ c #F61200", -"/ c #F61300", -"( c #F61400", -"_ c #F51600", -": c #F41700", -"< c #F41800", -"[ c #F31A00", -"} c #F31B00", -"| c #F21C00", -"1 c #F21E00", -"2 c #F11F00", -"3 c #F54A00", -"4 c #FFA900", -"5 c #FFAB00", -"6 c #FFAC01", -"7 c #FFAD02", -"8 c #FFAE02", -"9 c #FFAF03", -"0 c #FFB004", -"a c #FFB104", -"b c #FFB205", -"c c #FFB406", -"d c #FFB506", -"e c #FFB607", -"f c #FFB708", -"g c #FFB808", -"h c #FFB909", -"i c #FFBA0A", -"j c #FFBB0A", -"k c #FFBC0A", -"l c #FFBD0B", -"m c #FFBE0C", -"n c #FFBF0C", -"o c #FFC00D", -"p c #FFC10E", -"q c #FFC20F", -"r c #FFC30F", -"s c #FFC410", -"t c #FFC511", -"u c #FFC611", -"v c #FFC711", -"w c #FFC812", -"x c #FFC913", -"y c #FFCA13", -"z c #FFCB14", -"A c #FFCC15", -"B c #FFCD15", -"C c #FFCF16", -"D c #FFD017", -"E c #FFD117", -"F c #FFD218", -"G c #FFD319", -"H c #FFD419", -"I c #FFD51A", -"J c #FFD61B", -"K c #FFD71B", -"L c #FFD81C", -"M c #FFD91C", -"N c #FFDA1D", -"O c #FFDB1E", -"P c #FFDC1E", -"Q c #FFDD1F", -"R c #FFDE20", -"S c #FFDF20", -"T c #FFE021", -"U c #FFE222", -"V c #FFE322", -"W c #FFE423", -"X c #FFE524", -"Y c #FFE624", -"Z c #FFE725", -"` c #FFE826", -" . c #FFE926", -".. c #FFEA26", -"+. c #FFEB27", -"@. c #FFEC28", -"#. c #FFED28", -"$. c #FFEE29", -"%. c #FFEF2A", -"&. c #FFF02A", -"*. c #FFF12B", -"=. c #FFF22C", -"-. c #FFF32D", -";. c #FFF42D", -">. c #FDF42C", -",. c #FBF42C", -"'. c #FAF42C", -"). c #F8F42B", -"!. c #F6F42B", -"~. c #F4F42B", -"{. c #F3F42A", -"]. c #F1F42A", -"^. c #F0F429", -"/. c #EEF429", -"(. c #ECF429", -"_. c #EAF528", -":. c #E9F528", -"<. c #E7F528", -"[. c #E5F527", -"}. c #E3F527", -"|. c #E2F526", -"1. c #E0F526", -"2. c #DFF526", -"3. c #DDF525", -"4. c #DBF525", -"5. c #D9F525", -"6. c #D8F524", -"7. c #D6F624", -"8. c #D5F624", -"9. c #D3F624", -"0. c #D1F623", -"a. c #CFF623", -"b. c #CEF622", -"c. c #CCF622", -"d. c #CBF622", -"e. c #C9F621", -"f. c #C7F621", -"g. c #C5F621", -"h. c #C4F720", -"i. c #C2F720", -"j. c #C0F71F", -"k. c #BEF71F", -"l. c #BDF71F", -"m. c #BBF71E", -"n. c #BAF71E", -"o. c #B8F71E", -"p. c #B6F71D", -"q. c #B5F71D", -"r. c #B3F71D", -"s. c #B2F71C", -"t. c #B0F81C", -"u. c #AEF81B", -"v. c #ACF81B", -"w. c #ABF81B", -"x. c #A9F81A", -"y. c #A8F81A", -"z. c #A6F81A", -"A. c #A4F81A", -"B. c #A2F819", -"C. c #A1F819", -"D. c #9FF819", -"E. c #9EF818", -"F. c #9BF918", -"G. c #9AF917", -"H. c #98F917", -"I. c #97F917", -"J. c #95F916", -"K. c #93F916", -"L. c #91F916", -"M. c #90F915", -"N. c #8EF915", -"O. c #8DF914", -"P. c #8BF914", -"Q. c #89FA14", -"R. c #87FA13", -"S. c #86FA13", -"T. c #84FA13", -"U. c #83FA12", -"V. c #81FA12", -"W. c #7FFA12", -"X. c #7DFA12", -"Y. c #7CFA11", -"Z. c #7AFA11", -"`. c #78FA10", -" + c #76FA10", -".+ c #75FB10", -"++ c #73FB0F", -"@+ c #72FB0F", -"#+ c #70FB0F", -"$+ c #6EFB0E", -"%+ c #6DFB0E", -"&+ c #6BFB0E", -"*+ c #6AFB0D", -"=+ c #68FB0D", -"-+ c #66FB0C", -";+ c #64FB0C", -">+ c #63FB0C", -",+ c #61FC0B", -"'+ c #60FC0B", -")+ c #5EFC0B", -"!+ c #5CFC0A", -"~+ c #5AFC0A", -"{+ c #59FC09", -"]+ c #57FC09", -"^+ c #56FC09", -"/+ c #53FC09", -"(+ c #52FC08", -"_+ c #50FC08", -":+ c #4FFD08", -"<+ c #4DFD07", -"[+ c #4BFD07", -"}+ c #49FD07", -"|+ c #48FD06", -"1+ c #46FD06", -"2+ c #45FD05", -"3+ c #43FD05", -"4+ c #41FD05", -"5+ c #3FFD04", -"6+ c #3EFD04", -"7+ c #3CFD04", -"8+ c #3BFE03", -"9+ c #39FE03", -"0+ c #37FE02", -"a+ c #35FE02", -"b+ c #34FE02", -"c+ c #32FE01", -"d+ c #30FE01", -"e+ c #2EFE01", -"f+ c #2DFE00", -"g+ c #2BFE00", -". . + + + ", -". . + + + ", -"@ @ @ @ @ ", -"# # # # # ", -"$ $ $ $ $ ", -"% % % % % ", -"& & & & & ", -"* * * * * ", -"= = = = = ", -"- - - - - ", -"; ; ; ; ; ", -"> > > > > ", -", , , , , ", -"' ' ' ' ' ", -") ) ) ) ) ", -"! ! ! ! ! ", -"~ ~ ~ ~ ~ ", -"{ { { { { ", -"] ] ] ] ] ", -"^ ^ ^ ^ ^ ", -"/ / / / / ", -"( ( ( ( ( ", -"_ _ _ _ _ ", -": : : : : ", -": : : : : ", -"< < < < < ", -"[ [ [ [ [ ", -"} } } } } ", -"} } } } } ", -"| | | | | ", -"1 1 1 1 1 ", -"2 2 2 2 2 ", -"3 3 3 3 3 ", -"4 4 4 4 4 ", -"5 5 5 5 5 ", -"6 6 6 6 6 ", -"6 6 6 6 6 ", -"7 7 7 7 7 ", -"8 8 8 8 8 ", -"9 9 9 9 9 ", -"9 9 9 9 9 ", -"0 0 0 0 0 ", -"a a a a a ", -"a a a a a ", -"b b b b b ", -"c c c c c ", -"d d d d d ", -"d d d d d ", -"e e e e e ", -"f f f f f ", -"g g g g g ", -"g g g g g ", -"h h h h h ", -"i i i i i ", -"j j j j j ", -"k k k k k ", -"l l l l l ", -"m m m m m ", -"n n n n n ", -"n n n n n ", -"o o o o o ", -"p p p p p ", -"q q q q q ", -"q q q q q ", -"r r r r r ", -"s s s s s ", -"t t t t t ", -"u u u u u ", -"v v v v v ", -"w w w w w ", -"x x x x x ", -"x x x x x ", -"y y y y y ", -"z z z z z ", -"A A A A A ", -"A A A A A ", -"B B B B B ", -"C C C C C ", -"D D D D D ", -"D D D D D ", -"E E E E E ", -"F F F F F ", -"G G G G G ", -"G G G G G ", -"H H H H H ", -"I I I I I ", -"I I I I I ", -"J J J J J ", -"K K K K K ", -"L L L L L ", -"M M M M M ", -"N N N N N ", -"O O O O O ", -"P P P P P ", -"P P P P P ", -"Q Q Q Q Q ", -"R R R R R ", -"S S S S S ", -"S S S S S ", -"T T T T T ", -"U U U U U ", -"V V V V V ", -"V V V V V ", -"W W W W W ", -"X X X X X ", -"Y Y Y Y Y ", -"Y Y Y Y Y ", -"Z Z Z Z Z ", -"` ` ` ` ` ", -" . . . . .", -"..........", -"+.+.+.+.+.", -"@.@.@.@.@.", -"#.#.#.#.#.", -"#.#.#.#.#.", -"$.$.$.$.$.", -"%.%.%.%.%.", -"&.&.&.&.&.", -"&.&.&.&.&.", -"*.*.*.*.*.", -"=.=.=.=.=.", -"-.-.-.-.-.", -";.;.;.;.;.", -";.;.;.;.;.", -">.>.>.>.>.", -",.,.,.,.,.", -"'.'.'.'.'.", -").).).).).", -"!.!.!.!.!.", -"~.~.~.~.~.", -"{.{.{.{.{.", -"].].].].].", -"^.^.^.^.^.", -"/././././.", -"(.(.(.(.(.", -"_._._._._.", -":.:.:.:.:.", -"<.<.<.<.<.", -"[.[.[.[.[.", -"}.}.}.}.}.", -"|.|.|.|.|.", -"1.1.1.1.1.", -"2.2.2.2.2.", -"3.3.3.3.3.", -"4.4.4.4.4.", -"5.5.5.5.5.", -"6.6.6.6.6.", -"7.7.7.7.7.", -"8.8.8.8.8.", -"9.9.9.9.9.", -"0.0.0.0.0.", -"a.a.a.a.a.", -"b.b.b.b.b.", -"c.c.c.c.c.", -"d.d.d.d.d.", -"e.e.e.e.e.", -"f.f.f.f.f.", -"g.g.g.g.g.", -"h.h.h.h.h.", -"i.i.i.i.i.", -"j.j.j.j.j.", -"k.k.k.k.k.", -"l.l.l.l.l.", -"m.m.m.m.m.", -"n.n.n.n.n.", -"o.o.o.o.o.", -"p.p.p.p.p.", -"q.q.q.q.q.", -"r.r.r.r.r.", -"s.s.s.s.s.", -"t.t.t.t.t.", -"u.u.u.u.u.", -"v.v.v.v.v.", -"w.w.w.w.w.", -"x.x.x.x.x.", -"y.y.y.y.y.", -"z.z.z.z.z.", -"A.A.A.A.A.", -"B.B.B.B.B.", -"C.C.C.C.C.", -"D.D.D.D.D.", -"E.E.E.E.E.", -"F.F.F.F.F.", -"G.G.G.G.G.", -"H.H.H.H.H.", -"I.I.I.I.I.", -"J.J.J.J.J.", -"K.K.K.K.K.", -"L.L.L.L.L.", -"M.M.M.M.M.", -"N.N.N.N.N.", -"O.O.O.O.O.", -"P.P.P.P.P.", -"Q.Q.Q.Q.Q.", -"R.R.R.R.R.", -"S.S.S.S.S.", -"T.T.T.T.T.", -"U.U.U.U.U.", -"V.V.V.V.V.", -"W.W.W.W.W.", -"X.X.X.X.X.", -"Y.Y.Y.Y.Y.", -"Z.Z.Z.Z.Z.", -"`.`.`.`.`.", -" + + + + +", -".+.+.+.+.+", -"++++++++++", -"@+@+@+@+@+", -"#+#+#+#+#+", -"$+$+$+$+$+", -"%+%+%+%+%+", -"&+&+&+&+&+", -"*+*+*+*+*+", -"=+=+=+=+=+", -"-+-+-+-+-+", -";+;+;+;+;+", -">+>+>+>+>+", -",+,+,+,+,+", -"'+'+'+'+'+", -")+)+)+)+)+", -"!+!+!+!+!+", -"~+~+~+~+~+", -"{+{+{+{+{+", -"]+]+]+]+]+", -"^+^+^+^+^+", -"/+/+/+/+/+", -"(+(+(+(+(+", -"_+_+_+_+_+", -":+:+:+:+:+", -"<+<+<+<+<+", -"[+[+[+[+[+", -"}+}+}+}+}+", -"|+|+|+|+|+", -"1+1+1+1+1+", -"2+2+2+2+2+", -"3+3+3+3+3+", -"4+4+4+4+4+", -"5+5+5+5+5+", -"6+6+6+6+6+", -"7+7+7+7+7+", -"8+8+8+8+8+", -"9+9+9+9+9+", -"0+0+0+0+0+", -"a+a+a+a+a+", -"b+b+b+b+b+", -"c+c+c+c+c+", -"d+d+d+d+d+", -"e+e+e+e+e+", -"f+f+f+f+f+", -"g+g+g+g+g+"}; - -static const char* channel_setup_names[] = { - "mono", - "stereo", - "3 channels", - "4 channels", - "5 channels", - "8 channels", - "manual setup", - 0 -}; - -vector channel_combo_strings; +sigc::signal ARDOUR_UI::Clock; ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) - : Gtkmm2ext::UI ("ardour", argcp, argvp, rcfile), - - primary_clock (X_("TransportClockDisplay"), true, false, true), - secondary_clock (X_("SecondaryClockDisplay"), true, false, true), - preroll_clock (X_("PreRollClock"), true, true), - postroll_clock (X_("PostRollClock"), true, true), + : Gtkmm2ext::UI (X_("Ardour"), argcp, argvp, rcfile), + + primary_clock (X_("primary"), false, X_("TransportClockDisplay"), true, false, true), + secondary_clock (X_("secondary"), false, X_("SecondaryClockDisplay"), true, false, true), + preroll_clock (X_("preroll"), false, X_("PreRollClock"), true, true), + postroll_clock (X_("postroll"), false, X_("PostRollClock"), true, true), /* adjuster table */ @@ -800,42 +116,60 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) /* big clock */ - big_clock ("BigClockDisplay", true), + big_clock (X_("bigclock"), false, "BigClockNonRecording", false, false, true), /* transport */ - shuttle_units_button (_("% ")), - shuttle_style_button (_("spring")), + roll_controllable ("transport roll", *this, TransportControllable::Roll), + stop_controllable ("transport stop", *this, TransportControllable::Stop), + goto_start_controllable ("transport goto start", *this, TransportControllable::GotoStart), + goto_end_controllable ("transport goto end", *this, TransportControllable::GotoEnd), + auto_loop_controllable ("transport auto loop", *this, TransportControllable::AutoLoop), + play_selection_controllable ("transport play selection", *this, TransportControllable::PlaySelection), + rec_controllable ("transport rec-enable", *this, TransportControllable::RecordEnable), + shuttle_controllable ("shuttle", *this, TransportControllable::ShuttleControl), + shuttle_controller_binding_proxy (shuttle_controllable), + + roll_button (roll_controllable), + stop_button (stop_controllable), + goto_start_button (goto_start_controllable), + goto_end_button (goto_end_controllable), + auto_loop_button (auto_loop_controllable), + play_selection_button (play_selection_controllable), + rec_button (rec_controllable), - punch_in_button (_("punch\nin")), - punch_out_button (_("punch\nout")), - auto_return_button (_("auto\nreturn")), - auto_play_button (_("auto\nplay")), - auto_input_button (_("auto\ninput")), - click_button (_("click")), - follow_button (_("follow\nPH")), - auditioning_alert_button (_("AUDITIONING")), - solo_alert_button (_("SOLO")), + shuttle_units_button (_("% ")), - session_selector (1, 0), + punch_in_button (_("Punch In")), + punch_out_button (_("Punch Out")), + auto_return_button (_("Auto Return")), + auto_play_button (_("Auto Play")), + auto_input_button (_("Auto Input")), + click_button (_("Click")), + time_master_button (_("time\nmaster")), + auditioning_alert_button (_("AUDITION")), + solo_alert_button (_("SOLO")), shown_flag (false) - { using namespace Gtk::Menu_Helpers; Gtkmm2ext::init(); - - /* actually, its already loaded, but ... */ - - cerr << "Loading UI configuration file " << rcfile << endl; - + about = 0; if (theArdourUI == 0) { theArdourUI = this; } + /* load colors */ + + color_manager = new ColorManager(); + + std::string color_file = ARDOUR::find_config_file("ardour.colors"); + + color_manager->load (color_file); + editor = 0; mixer = 0; session = 0; @@ -846,93 +180,76 @@ ARDOUR_UI::ARDOUR_UI (int *argcp, char **argvp[], string rcfile) connection_editor = 0; add_route_dialog = 0; route_params = 0; - meter_bridge = 0; option_editor = 0; location_ui = 0; - sfdb_window = 0; - new_session_window = 0; open_session_selector = 0; have_configure_timeout = false; - have_disk_overrun_displayed = false; - have_disk_underrun_displayed = false; + have_disk_speed_dialog_displayed = false; _will_create_new_session_automatically = false; session_loaded = false; + last_speed_displayed = -1.0f; + keybindings_path = ARDOUR::find_config_file ("ardour.bindings"); + + can_save_keybindings = false; last_configure_time.tv_sec = 0; last_configure_time.tv_usec = 0; shuttle_grabbed = false; shuttle_fract = 0.0; + shuttle_max_speed = 8.0f; - set_shuttle_units (Percentage); - set_shuttle_behaviour (Sprung); - - shuttle_unit_menu.items().push_back (MenuElem (_("Percentage"), bind (slot (*this, &ARDOUR_UI::set_shuttle_units), - Percentage))); - shuttle_unit_menu.items().push_back (MenuElem (_("Semitones"), bind (slot (*this, &ARDOUR_UI::set_shuttle_units), - Semitones))); - - shuttle_style_menu.items().push_back (MenuElem (_("Sprung"), bind (slot (*this, &ARDOUR_UI::set_shuttle_behaviour), - Sprung))); - shuttle_style_menu.items().push_back (MenuElem (_("Wheel"), bind (slot (*this, &ARDOUR_UI::set_shuttle_behaviour), - Wheel))); + shuttle_style_menu = 0; + shuttle_unit_menu = 0; gettimeofday (&last_peak_grab, 0); gettimeofday (&last_shuttle_request, 0); - ARDOUR::DiskStream::CannotRecordNoInput.connect (slot (*this, &ARDOUR_UI::cannot_record_no_input)); - ARDOUR::DiskStream::DeleteSources.connect (slot (*this, &ARDOUR_UI::delete_sources_in_the_right_thread)); - ARDOUR::DiskStream::DiskOverrun.connect (slot (*this, &ARDOUR_UI::disk_overrun_handler)); - ARDOUR::DiskStream::DiskUnderrun.connect (slot (*this, &ARDOUR_UI::disk_underrun_handler)); + ARDOUR::Diskstream::DiskOverrun.connect (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler)); + ARDOUR::Diskstream::DiskUnderrun.connect (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler)); /* handle pending state with a dialog */ - ARDOUR::Session::AskAboutPendingState.connect (slot (*this, &ARDOUR_UI::pending_state_dialog)); + ARDOUR::Session::AskAboutPendingState.connect (mem_fun(*this, &ARDOUR_UI::pending_state_dialog)); - channel_combo_strings = internationalize (channel_setup_names); - /* have to wait for AudioEngine and Configuration before proceeding */ } -void -ARDOUR_UI::cannot_record_no_input (DiskStream* ds) -{ - ENSURE_GUI_THREAD (bind (slot (*this, &ARDOUR_UI::cannot_record_no_input), ds)); - - string msg = compose (_("\ -You cannot record-enable\n\ -track %1\n\ -because it has no input connections.\n\ -You would be wasting space recording silence."), - ds->name()); - - ArdourMessage message (editor, X_("cannotrecord"), msg); -} - void ARDOUR_UI::set_engine (AudioEngine& e) { engine = &e; - engine->Stopped.connect (slot (*this, &ARDOUR_UI::engine_stopped)); - engine->Running.connect (slot (*this, &ARDOUR_UI::engine_running)); - engine->Halted.connect (slot (*this, &ARDOUR_UI::engine_halted)); - engine->SampleRateChanged.connect (slot (*this, &ARDOUR_UI::update_sample_rate)); + engine->Stopped.connect (mem_fun(*this, &ARDOUR_UI::engine_stopped)); + engine->Running.connect (mem_fun(*this, &ARDOUR_UI::engine_running)); + engine->Halted.connect (mem_fun(*this, &ARDOUR_UI::engine_halted)); + engine->SampleRateChanged.connect (mem_fun(*this, &ARDOUR_UI::update_sample_rate)); + + ActionManager::init (); + new_session_dialog = new NewSessionDialog(); _tooltips.enable(); keyboard = new Keyboard; - install_keybindings (); - - FastMeter::set_vertical_xpm (v_meter_strip_xpm); - FastMeter::set_horizontal_xpm (h_meter_strip_xpm); if (setup_windows ()) { throw failed_constructor (); } if (GTK_ARDOUR::show_key_actions) { - KeyboardTarget::show_all_actions (); + vector names; + vector paths; + vector keys; + vector bindings; + + ActionManager::get_all_actions (names, paths, keys, bindings); + + vector::iterator n; + vector::iterator k; + for (n = names.begin(), k = keys.begin(); n != names.end(); ++n, ++k) { + cerr << "Action: " << (*n) << " bound to " << (*k) << endl; + } + exit (0); } @@ -941,26 +258,31 @@ ARDOUR_UI::set_engine (AudioEngine& e) blink_timeout_tag = -1; + /* the global configuration object is now valid */ + + use_config (); + /* this being a GUI and all, we want peakfiles */ - FileSource::set_build_peakfiles (true); - FileSource::set_build_missing_peakfiles (true); + AudioFileSource::set_build_peakfiles (true); + AudioFileSource::set_build_missing_peakfiles (true); - if (Source::start_peak_thread ()) { - throw failed_constructor(); - } + /* set default clock modes */ + + primary_clock.set_mode (AudioClock::SMPTE); + secondary_clock.set_mode (AudioClock::BBT); /* start the time-of-day-clock */ update_wall_clock (); - Main::timeout.connect (slot (*this, &ARDOUR_UI::update_wall_clock), 60000); + Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::update_wall_clock), 60000); update_disk_space (); update_cpu_load (); update_sample_rate (engine->frame_rate()); - starting.connect (slot (*this, &ARDOUR_UI::startup)); - stopping.connect (slot (*this, &ARDOUR_UI::shutdown)); + starting.connect (mem_fun(*this, &ARDOUR_UI::startup)); + stopping.connect (mem_fun(*this, &ARDOUR_UI::shutdown)); } ARDOUR_UI::~ARDOUR_UI () @@ -982,8 +304,6 @@ ARDOUR_UI::~ARDOUR_UI () if (add_route_dialog) { delete add_route_dialog; } - - Source::stop_peak_thread (); } gint @@ -1018,14 +338,70 @@ ARDOUR_UI::configure_handler (GdkEventConfigure* conf) if (have_configure_timeout) { gettimeofday (&last_configure_time, 0); } else { - TimeoutSig t; - t.connect (slot (*this, &ARDOUR_UI::configure_timeout), 100); + Glib::signal_timeout().connect (mem_fun(*this, &ARDOUR_UI::configure_timeout), 100); have_configure_timeout = true; } return FALSE; } +void +ARDOUR_UI::set_transport_controllable_state (const XMLNode& node) +{ + const XMLProperty* prop; + + if ((prop = node.property ("roll")) != 0) { + roll_controllable.set_id (prop->value()); + } + if ((prop = node.property ("stop")) != 0) { + stop_controllable.set_id (prop->value()); + } + if ((prop = node.property ("goto_start")) != 0) { + goto_start_controllable.set_id (prop->value()); + } + if ((prop = node.property ("goto_end")) != 0) { + goto_end_controllable.set_id (prop->value()); + } + if ((prop = node.property ("auto_loop")) != 0) { + auto_loop_controllable.set_id (prop->value()); + } + if ((prop = node.property ("play_selection")) != 0) { + play_selection_controllable.set_id (prop->value()); + } + if ((prop = node.property ("rec")) != 0) { + rec_controllable.set_id (prop->value()); + } + if ((prop = node.property ("shuttle")) != 0) { + shuttle_controllable.set_id (prop->value()); + } +} + +XMLNode& +ARDOUR_UI::get_transport_controllable_state () +{ + XMLNode* node = new XMLNode(X_("TransportControllables")); + char buf[64]; + + roll_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("roll"), buf); + stop_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("stop"), buf); + goto_start_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("goto_start"), buf); + goto_end_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("goto_end"), buf); + auto_loop_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("auto_loop"), buf); + play_selection_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("play_selection"), buf); + rec_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("rec"), buf); + shuttle_controllable.id().print (buf, sizeof (buf)); + node->add_property (X_("shuttle"), buf); + + return *node; +} + void ARDOUR_UI::save_ardour_state () { @@ -1039,33 +415,125 @@ ARDOUR_UI::save_ardour_state () XMLNode* node = new XMLNode (keyboard->get_state()); Config->add_extra_xml (*node); + Config->add_extra_xml (get_transport_controllable_state()); Config->save_state(); - XMLNode& enode (static_cast(editor)->get_state()); - XMLNode& mnode (mixer->get_state()); + XMLNode enode(static_cast(editor)->get_state()); + XMLNode mnode(mixer->get_state()); if (session) { - session->add_instant_xml(enode, session->path()); - session->add_instant_xml(mnode, session->path()); + session->add_instant_xml (enode, session->path()); + session->add_instant_xml (mnode, session->path()); } else { - Config->add_instant_xml(enode, Config->get_user_ardour_path()); - Config->add_instant_xml(mnode, Config->get_user_ardour_path()); + Config->add_instant_xml (enode, get_user_ardour_path()); + Config->add_instant_xml (mnode, get_user_ardour_path()); } + + save_keybindings (); +} + +gint +ARDOUR_UI::autosave_session () +{ + if (!Config->get_periodic_safety_backups()) + return 1; + + if (session) { + session->maybe_write_autosave(); + } + + return 1; +} + +void +ARDOUR_UI::update_autosave () +{ + ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::update_autosave)); + + if (session->dirty()) { + if (_autosave_connection.connected()) { + _autosave_connection.disconnect(); + } + + _autosave_connection = Glib::signal_timeout().connect (mem_fun (*this, &ARDOUR_UI::autosave_session), + Config->get_periodic_safety_backup_interval() * 1000); + + } else { + if (_autosave_connection.connected()) { + _autosave_connection.disconnect(); + } + } } void ARDOUR_UI::startup () { - /* Once the UI is up and running, start the audio engine. Doing - this before the UI is up and running can cause problems - when not running with SCHED_FIFO, because the amount of - CPU and disk work needed to get the UI started can interfere - with the scheduling of the audio thread. - */ + check_memory_locking(); +} + +void +ARDOUR_UI::no_memory_warning () +{ + XMLNode node (X_("no-memory-warning")); + Config->add_instant_xml (node, get_user_ardour_path()); +} + +void +ARDOUR_UI::check_memory_locking () +{ +#ifdef __APPLE__ + /* OS X doesn't support mlockall(2), and so testing for memory locking capability there is pointless */ + return; +#else // !__APPLE__ + + XMLNode* memory_warning_node = Config->instant_xml (X_("no-memory-warning"), get_user_ardour_path()); - Gtk::Main::idle.connect (slot (*this, &ARDOUR_UI::start_engine)); + if (engine->is_realtime() && memory_warning_node == 0) { + + struct rlimit limits; + int64_t ram; + long pages, page_size; + + if ((page_size = sysconf (_SC_PAGESIZE)) < 0 ||(pages = sysconf (_SC_PHYS_PAGES)) < 0) { + ram = 0; + } else { + ram = (int64_t) pages * (int64_t) page_size; + } + + if (getrlimit (RLIMIT_MEMLOCK, &limits)) { + return; + } + + if (limits.rlim_cur != RLIM_INFINITY) { + + if (ram == 0 || ((double) limits.rlim_cur / ram) < 0.75) { + + + MessageDialog msg (_("WARNING: Your system has a limit for maximum amount of locked memory. " + "This might cause Ardour to run out of memory before your system " + "runs out of memory. \n\n" + "You can view the memory limit with 'ulimit -l', " + "and it is normally controlled by /etc/security/limits.conf")); + + VBox* vbox = msg.get_vbox(); + HBox hbox; + CheckButton cb (_("Do not show this window again")); + + cb.signal_toggled().connect (mem_fun (*this, &ARDOUR_UI::no_memory_warning)); + + hbox.pack_start (cb, true, false); + vbox->pack_start (hbox); + hbox.show_all (); + + editor->ensure_float (msg); + msg.run (); + } + } + } +#endif // !__APPLE__ } + void ARDOUR_UI::finish() { @@ -1078,11 +546,12 @@ ARDOUR_UI::finish() /* use the default name */ if (save_state_canfail ("")) { /* failed - don't quit */ - ArdourMessage (editor, X_("badsave dialog"), + MessageDialog msg (*editor, _("\ Ardour was unable to save your session.\n\n\ If you still wish to quit, please use the\n\n\ \"Just quit\" option.")); + msg.run (); return; } break; @@ -1091,30 +560,32 @@ If you still wish to quit, please use the\n\n\ } } - quit(); + if (session) { + session->set_deletion_in_progress (); + } + engine->stop (true); + Config->save_state(); + quit (); } int -ARDOUR_UI::ask_about_saving_session (string what) +ARDOUR_UI::ask_about_saving_session (const string & what) { - ArdourDialog window ("saving dialog"); - Gtk::VBox packer; + ArdourDialog window (_("ardour: save session?")); + Gtk::HBox dhbox; // the hbox for the image and text Gtk::Label prompt_label; - Gtk::HBox button_packer; + Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_WARNING, Gtk::ICON_SIZE_DIALOG)); string msg; - msg = compose(_("Save and %1"), what); - - Gtk::Button save_button (msg); - save_button.set_name ("EditorGTKButton"); - - msg = compose(_("Just %1"), what); + msg = string_compose(_("Don't %1"), what); + window.add_button (msg, RESPONSE_REJECT); + msg = string_compose(_("Just %1"), what); + window.add_button (msg, RESPONSE_APPLY); + msg = string_compose(_("Save and %1"), what); + window.add_button (msg, RESPONSE_ACCEPT); - Gtk::Button nosave_button (msg); - nosave_button.set_name ("EditorGTKButton"); - - msg = compose(_("Don't %1"), what); + window.set_default_response (RESPONSE_ACCEPT); Gtk::Button noquit_button (msg); noquit_button.set_name ("EditorGTKButton"); @@ -1127,45 +598,45 @@ ARDOUR_UI::ask_about_saving_session (string what) } else { type = _("snapshot"); } - prompt = 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?"), + prompt = string_compose(_("The %1\"%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?"), type, session->snap_name()); prompt_label.set_text (prompt); - prompt_label.set_alignment (0.5, 0.5); prompt_label.set_name (X_("PrompterLabel")); + prompt_label.set_alignment(ALIGN_LEFT, ALIGN_TOP); - save_button.signal_clicked().connect (bind(slot(window,&ArdourDialog::stop), 1)); - nosave_button.signal_clicked().connect (bind(slot(window,&ArdourDialog::stop), 0)); - noquit_button.signal_clicked().connect (bind(slot(window,&ArdourDialog::stop), -1)); - - button_packer.set_spacing (10); - button_packer.pack_start (save_button); - button_packer.pack_start (nosave_button); - button_packer.pack_start (noquit_button); - - packer.set_spacing (10); - packer.set_border_width (10); - packer.pack_start (prompt_label); - packer.pack_start (button_packer); + dimage->set_alignment(ALIGN_CENTER, ALIGN_TOP) +; + dhbox.set_homogeneous (false); + dhbox.pack_start (*dimage, false, false, 5); + dhbox.pack_start (prompt_label, true, false, 5); + window.get_vbox()->pack_start (dhbox); window.set_name (_("Prompter")); - window.set_title (_("ardour: save session?")); window.set_position (Gtk::WIN_POS_MOUSE); window.set_modal (true); - window.add (packer); + window.set_resizable (false); window.show_all (); - window.realize(); - window.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH)); - window.set_keyboard_input (true); - save_the_session = 0; - editor->ensure_float (window); + window.set_keep_above (true); + window.present (); - window.run (); + ResponseType r = (ResponseType) window.run(); + + window.hide (); + + switch (r) { + case RESPONSE_ACCEPT: // save and get out of here + return 1; + case RESPONSE_APPLY: // get out of here + return 0; + default: + break; + } - return window.run_status(); + return -1; } gint @@ -1174,27 +645,12 @@ ARDOUR_UI::every_second () update_cpu_load (); update_buffer_load (); update_disk_space (); - // update_disk_rate (); return TRUE; } gint ARDOUR_UI::every_point_one_seconds () { - struct timeval now; - struct timeval diff; - - /* do not attempt to grab peak power more than once per cycle. - */ - - gettimeofday (&now, 0); - timersub (&now, &last_peak_grab, &diff); - - if ((diff.tv_usec + (diff.tv_sec * 1000000)) >= engine->usecs_per_cycle()) { - IO::GrabPeakPower(); /* EMIT_SIGNAL */ - last_peak_grab = now; - } - update_speed_display (); RapidScreenUpdate(); /* EMIT_SIGNAL */ return TRUE; @@ -1208,11 +664,11 @@ ARDOUR_UI::every_point_zero_one_seconds () } void -ARDOUR_UI::update_sample_rate (jack_nframes_t ignored) +ARDOUR_UI::update_sample_rate (nframes_t ignored) { char buf[32]; - ENSURE_GUI_THREAD (bind (slot (*this, &ARDOUR_UI::update_sample_rate), ignored)); + ENSURE_GUI_THREAD (bind (mem_fun(*this, &ARDOUR_UI::update_sample_rate), ignored)); if (!engine->connected()) { @@ -1220,14 +676,14 @@ ARDOUR_UI::update_sample_rate (jack_nframes_t ignored) } else { - jack_nframes_t rate = engine->frame_rate(); + nframes_t rate = engine->frame_rate(); if (fmod (rate, 1000.0) != 0.0) { - snprintf (buf, sizeof (buf), _("SR: %.1f kHz / %4.1f msecs"), + snprintf (buf, sizeof (buf), _("%.1f kHz / %4.1f ms"), (float) rate/1000.0f, (engine->frames_per_cycle() / (float) rate) * 1000.0f); } else { - snprintf (buf, sizeof (buf), _("SR: %u kHz / %4.1f msecs"), + snprintf (buf, sizeof (buf), _("%u kHz / %4.1f ms"), rate/1000, (engine->frames_per_cycle() / (float) rate) * 1000.0f); } @@ -1240,24 +696,10 @@ void ARDOUR_UI::update_cpu_load () { char buf[32]; - snprintf (buf, sizeof (buf), _("DSP Load: %.1f%%"), engine->get_cpu_load()); + snprintf (buf, sizeof (buf), _("DSP: %5.1f%%"), engine->get_cpu_load()); cpu_load_label.set_text (buf); } -void -ARDOUR_UI::update_disk_rate () -{ - char buf[64]; - - if (session) { - snprintf (buf, sizeof (buf), _("Disk r:%5.1f w:%5.1f MB/s"), - session->read_data_rate()/1048576.0f, session->write_data_rate()/1048576.0f); - disk_rate_label.set_text (buf); - } else { - disk_rate_label.set_text (""); - } -} - void ARDOUR_UI::update_buffer_load () { @@ -1273,10 +715,11 @@ ARDOUR_UI::update_buffer_load () } void -ARDOUR_UI::count_recenabled_diskstreams (DiskStream& ds) +ARDOUR_UI::count_recenabled_streams (Route& route) { - if (ds.record_enabled()) { - rec_enabled_diskstreams++; + Track* track = dynamic_cast(&route); + if (track && track->diskstream()->record_enabled()) { + rec_enabled_streams += track->n_inputs().get_total(); } } @@ -1287,32 +730,22 @@ ARDOUR_UI::update_disk_space() return; } - jack_nframes_t frames = session->available_capture_duration(); + nframes_t frames = session->available_capture_duration(); char buf[64]; if (frames == max_frames) { - strcpy (buf, _("space: 24hrs+")); + strcpy (buf, _("Disk: 24hrs+")); } else { int hrs; int mins; int secs; - jack_nframes_t fr = session->frame_rate(); + nframes_t fr = session->frame_rate(); - if (session->actively_recording()){ - - rec_enabled_diskstreams = 0; - session->foreach_diskstream (this, &ARDOUR_UI::count_recenabled_diskstreams); - - if (rec_enabled_diskstreams) { - frames /= rec_enabled_diskstreams; - } - - } else { - - /* hmmm. shall we divide by the route count? or the diskstream count? - or what? for now, do nothing ... - */ - + rec_enabled_streams = 0; + session->foreach_route (this, &ARDOUR_UI::count_recenabled_streams); + + if (rec_enabled_streams) { + frames /= rec_enabled_streams; } hrs = frames / (fr * 3600); @@ -1321,7 +754,7 @@ ARDOUR_UI::update_disk_space() frames -= mins * fr * 60; secs = frames / fr; - snprintf (buf, sizeof(buf), _("space: %02dh:%02dm:%02ds"), hrs, mins, secs); + snprintf (buf, sizeof(buf), _("Disk: %02dh:%02dm:%02ds"), hrs, mins, secs); } disk_space_label.set_text (buf); @@ -1343,520 +776,234 @@ ARDOUR_UI::update_wall_clock () return TRUE; } +gint +ARDOUR_UI::session_menu (GdkEventButton *ev) +{ + session_popup_menu->popup (0, 0); + return TRUE; +} + void -ARDOUR_UI::toggle_recording_plugins () +ARDOUR_UI::redisplay_recent_sessions () { - /* XXX use toggle_some_session_state */ + vector *sessions; + vector::iterator i; + RecentSessionsSorter cmp; + + recent_session_display.set_model (Glib::RefPtr(0)); + recent_session_model->clear (); - if (session == 0) { + RecentSessions rs; + ARDOUR::read_recent_sessions (rs); + + if (rs.empty()) { + recent_session_display.set_model (recent_session_model); return; } - session->set_recording_plugins (!session->get_recording_plugins()); -} - -void -ARDOUR_UI::toggle_auto_play () + /* sort them alphabetically */ + sort (rs.begin(), rs.end(), cmp); + sessions = new vector; -{ - toggle_some_session_state (auto_play_button, - &Session::get_auto_play, - &Session::set_auto_play); -} + for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) { + sessions->push_back (new string ((*i).second)); + } -void -ARDOUR_UI::toggle_auto_return () + for (i = sessions->begin(); i != sessions->end(); ++i) { -{ - toggle_some_session_state (auto_return_button, - &Session::get_auto_return, - &Session::set_auto_return); -} + vector* states; + vector item; + string fullpath = *(*i); + + /* remove any trailing / */ -void -ARDOUR_UI::toggle_click () -{ - toggle_some_session_state (click_button, - &Session::get_clicking, - &Session::set_clicking); -} + if (fullpath[fullpath.length()-1] == '/') { + fullpath = fullpath.substr (0, fullpath.length()-1); + } -void -ARDOUR_UI::follow_changed () -{ - bool x; + /* now get available states for this session */ - if (!editor) { - return; - } + if ((states = Session::possible_states (fullpath)) == 0) { + /* no state file? */ + continue; + } - if (follow_button.get_active() != (x = editor->follow_playhead())) { - follow_button.set_active (x); - } -} + TreeModel::Row row = *(recent_session_model->append()); -void -ARDOUR_UI::toggle_follow () -{ - bool x; + row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath); + row[recent_session_columns.fullpath] = fullpath; - if (!editor) { - return; - } + if (states->size() > 1) { - if (editor->follow_playhead() != (x = follow_button.get_active())) { - editor->set_follow_playhead (x); - } -} + /* add the children */ + + for (vector::iterator i2 = states->begin(); i2 != states->end(); ++i2) { + + TreeModel::Row child_row = *(recent_session_model->append (row.children())); -void -ARDOUR_UI::toggle_session_auto_loop () -{ - if (session) { - if (session->get_auto_loop()) { - if (session->transport_rolling()) { - transport_roll(); - } - else { - session->request_auto_loop (false); + child_row[recent_session_columns.visible_name] = **i2; + child_row[recent_session_columns.fullpath] = fullpath; + + delete *i2; } } - else { - session->request_auto_loop (true); - } - } -} -void -ARDOUR_UI::toggle_session_punch_in () -{ - if (session) { - session->set_punch_in (!session->get_punch_in()); + delete states; } -} -void -ARDOUR_UI::toggle_punch_out () -{ - toggle_some_session_state (punch_out_button, - &Session::get_punch_out, - &Session::set_punch_out); + recent_session_display.set_model (recent_session_model); + delete sessions; } void -ARDOUR_UI::toggle_punch_in () +ARDOUR_UI::build_session_selector () { - toggle_some_session_state (punch_in_button, - &Session::get_punch_in, - &Session::set_punch_in); -} + session_selector_window = new ArdourDialog ("session selector"); + + Gtk::ScrolledWindow *scroller = manage (new Gtk::ScrolledWindow); + + session_selector_window->add_button (Stock::CANCEL, RESPONSE_CANCEL); + session_selector_window->add_button (Stock::OPEN, RESPONSE_ACCEPT); + session_selector_window->set_default_response (RESPONSE_ACCEPT); + recent_session_model = TreeStore::create (recent_session_columns); + recent_session_display.set_model (recent_session_model); + recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name); + recent_session_display.set_headers_visible (false); + recent_session_display.get_selection()->set_mode (SELECTION_SINGLE); -void -ARDOUR_UI::map_button_state () + recent_session_display.signal_row_activated().connect (mem_fun (*this, &ARDOUR_UI::recent_session_row_activated)); -{ - map_some_session_state (auto_return_button, - &Session::get_auto_return); - map_some_session_state (auto_play_button, - &Session::get_auto_play); - map_some_session_state (auto_input_button, - &Session::get_auto_input); - map_some_session_state (punch_in_button, - &Session::get_punch_in); - map_some_session_state (punch_out_button, - &Session::get_punch_out); - map_some_session_state (click_button, - &Session::get_clicking); + scroller->add (recent_session_display); + scroller->set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + session_selector_window->set_name ("SessionSelectorWindow"); + session_selector_window->set_size_request (200, 400); + session_selector_window->get_vbox()->pack_start (*scroller); + session_selector_window->show_all_children(); } void -ARDOUR_UI::queue_map_control_change (Session::ControlType t) +ARDOUR_UI::recent_session_row_activated (const TreePath& path, TreeViewColumn* col) { - ENSURE_GUI_THREAD (bind (slot (*this, &ARDOUR_UI::map_control_change), t)); + session_selector_window->response (RESPONSE_ACCEPT); } void -ARDOUR_UI::map_control_change (Session::ControlType t) +ARDOUR_UI::open_recent_session () { - switch (t) { - case Session::AutoPlay: - map_some_session_state (auto_play_button, &Session::get_auto_play); - break; + /* popup selector window */ - case Session::AutoLoop: - break; + if (session_selector_window == 0) { + build_session_selector (); + } - case Session::AutoReturn: - map_some_session_state (auto_return_button, &Session::get_auto_return); - break; + redisplay_recent_sessions (); - case Session::AutoInput: - map_some_session_state (auto_input_button, &Session::get_auto_input); - break; + ResponseType r = (ResponseType) session_selector_window->run (); - case Session::PunchOut: - map_some_session_state (punch_in_button, &Session::get_punch_out); - break; + session_selector_window->hide(); - case Session::PunchIn: - map_some_session_state (punch_in_button, &Session::get_punch_in); + switch (r) { + case RESPONSE_ACCEPT: break; + default: + return; + } - case Session::Clicking: - map_some_session_state (click_button, &Session::get_clicking); - break; + Gtk::TreeModel::iterator i = recent_session_display.get_selection()->get_selected(); - case Session::SlaveType: -// map_some_session_state (mtc_slave_button, &Session::get_mtc_slave); - break; + if (i == recent_session_model->children().end()) { + return; + } + + Glib::ustring path = (*i)[recent_session_columns.fullpath]; + Glib::ustring state = (*i)[recent_session_columns.visible_name]; - case Session::SendMTC: -// map_some_session_state (send_mtc_button, &Session::get_send_mtc); - break; + _session_is_new = false; - case Session::SendMMC: -// map_some_session_state (send_mmc_button, &Session::get_send_mmc); - break; + load_session (path, state); +} - case Session::MMCControl: -// map_some_session_state (mmc_control_button, &Session::get_mmc_control); - break; +bool +ARDOUR_UI::filter_ardour_session_dirs (const FileFilter::Info& info) +{ + struct stat statbuf; - case Session::MidiFeedback: -// map_some_session_state (mmc_control_button, &Session::get_mmc_control); - break; - case Session::MidiControl: -// map_some_session_state (mmc_control_button, &Session::get_mmc_control); - break; - - case Session::Live: - break; - - case Session::RecordingPlugins: - break; - - case Session::CrossFadesActive: - break; - - case Session::EditingMode: - break; - - case Session::PlayRange: - break; - - case Session::AlignChoice: - /* don't care, this is handled by the options editor */ - break; - case Session::SeamlessLoop: - /* don't care, this is handled by the options editor */ - break; - + if (stat (info.filename.c_str(), &statbuf) != 0) { + return false; } -} - -void -ARDOUR_UI::control_methods_adjusted () - -{ - int which_method; - which_method = (int) online_control_button->adjustment.get_value(); - switch (which_method) { - case 0: - allow_mmc_and_local (); - break; - case 1: - allow_mmc_only (); - break; - case 2: - allow_local_only (); - break; - default: - fatal << _("programming error: impossible control method") << endmsg; + if (!S_ISDIR(statbuf.st_mode)) { + return false; } -} - -void -ARDOUR_UI::mmc_device_id_adjusted () - -{ -#if 0 - if (mmc) { - int dev_id = (int) mmc_id_button->adjustment.get_value(); - mmc->set_device_id (dev_id); - } -#endif -} - -void -ARDOUR_UI::map_some_session_state (ToggleButton& button, - bool (Session::*get)() const) + // XXX Portability + + string session_file = info.filename; + session_file += '/'; + session_file += Glib::path_get_basename (info.filename); + session_file += ".ardour"; -{ - bool x; - - if (session == 0) { - return; + if (stat (session_file.c_str(), &statbuf) != 0) { + return false; } - - if (button.get_active() != (x = (session->*get)())) { - button.set_active (x); - } -} - -void -ARDOUR_UI::toggle_some_session_state (ToggleButton& button, - bool (Session::*get)() const, - void (Session::*set)(bool)) - -{ - bool button_state; - bool session_state; - - if (session == 0) { - return; - } - - button_state = button.get_active (); - session_state = (session->*get)(); - if (button_state != session_state) { - (session->*set) (button_state); -#if 0 - - /* check that it worked, and reverse - the button state if it didn't - */ - - if ((session->*get)() != button_state) { - button->set_active (!button_state); - } -#endif - - } -} - -gint -ARDOUR_UI::session_menu (GdkEventButton *ev) -{ - session_popup_menu->popup (0, 0, 0, 0); - return TRUE; + return S_ISREG (statbuf.st_mode); } -void -ARDOUR_UI::redisplay_recent_sessions () +bool +ARDOUR_UI::check_audioengine () { - using namespace Gtkmm2ext; - using namespace Gtk::CTree_Helpers; - - vector *sessions; - vector::iterator i; - RecentSessionsSorter cmp; - - /* ---------------------------------------- */ - /* XXX MAKE ME A FUNCTION (no CTree::clear() in gtkmm 1.2) */ - - gtk_ctree_remove_node (session_selector.gobj(), NULL); - /* ---------------------------------------- */ - - - RecentSessions rs; - ARDOUR::read_recent_sessions (rs); - - if (rs.empty()) { - session_selector.thaw(); - return; - } - /* sort them alphabetically */ - sort(rs.begin(), rs.end(), cmp); - sessions = new vector; - for (RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) { - sessions->push_back (new string ((*i).second)); - } - - session_selector.freeze(); - - for (i = sessions->begin(); i != sessions->end(); ++i) { - - vector* states; - vector item; - string fullpath = *(*i); - - /* remove any trailing / */ - - if (fullpath[fullpath.length()-1] == '/') { - fullpath = fullpath.substr (0, fullpath.length()-1); - } - - /* now get available states for this session */ - - if ((states = Session::possible_states(fullpath)) == 0) { - /* no state file? */ - continue; - } - - /* OK, try to add entries for this session */ - - - /* add the parent */ - - item.clear (); - string basen = PBD::basename (fullpath); - item.push_back (basen.c_str()); - session_selector.rows().push_back (Element (item)); - - session_selector.rows().back().set_data (new string (fullpath), deferred_delete); - - if (states->size() == 1) { - - /* only 1 state, show it at the top level */ - - session_selector.rows().back().set_leaf (true); - - } else { - - session_selector.rows().back().set_leaf (false); - - vector::iterator i2; - - /* add the children */ - - for (i2 = states->begin(); i2 != states->end(); ++i2) { - - string statename = *(*i2); - - item.clear (); - item.push_back (statename.c_str()); - - session_selector.rows().back().subtree().push_back (Element (item)); - session_selector.rows().back().subtree().back().set_data (new string (statename), - deferred_delete); - session_selector.rows().back().subtree().back().set_leaf (true); - - delete *i2; - } + if (engine) { + if (!engine->connected()) { + MessageDialog msg (_("Ardour is not connected to JACK\n" + "You cannot open or close sessions in this condition")); + msg.run (); + return false; } - - delete states; + return true; + } else { + return false; } - - session_selector.thaw(); - delete sessions; } void -ARDOUR_UI::session_selection (Gtk::CTree_Helpers::Row row, gint column) +ARDOUR_UI::open_session () { - using namespace Gtk::CTree_Helpers; - - string session_name; - string session_path; - string session_state; - - if (!row.is_leaf()) { - row.expand(); + if (!check_audioengine()) { return; - } - - string *stp = static_cast (row.get_data()); - - if ((*stp)[0] != '/' && (*stp)[0] != '.') { - /* its a state file node, so get the parent for the session information, - and combine with the state file name. - */ - - string *spp = static_cast (row.get_parent().get_data()); - - session_name = *spp; - session_path = *spp; - session_state = *stp; - - } else { - - /* its a session directory node, so just get the session path, - and use "default" to load the state. - */ - - string *spp = static_cast (row.get_data()); - - session_name = *spp; - session_path = *spp; - session_state = PBD::basename (*spp); } - session_selector_window->hide (); - _session_is_new = false; - load_session (session_path, session_state); -} - -void -ARDOUR_UI::build_session_selector () -{ - session_selector_window = new ArdourDialog ("session selector"); - - Gtk::VBox *vpacker = new Gtk::VBox; - Gtk::ScrolledWindow *scroller = new Gtk::ScrolledWindow; - Gtk::HBox *button_packer = new Gtk::HBox; - Gtk::Button *cancel_button = new Gtk::Button (_("cancel")); - Gtk::Button *rescan_button = new Gtk::Button (_("rescan")); + /* popup selector window */ - button_packer->pack_start (*rescan_button); - button_packer->pack_start (*cancel_button); + if (open_session_selector == 0) { - vpacker->pack_start (*scroller); - vpacker->pack_start (*button_packer, false, false); + /* ardour sessions are folders */ - scroller->add (session_selector); - scroller->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + open_session_selector = new Gtk::FileChooserDialog (_("open session"), FILE_CHOOSER_ACTION_OPEN); + open_session_selector->add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + open_session_selector->add_button (Gtk::Stock::OPEN, Gtk::RESPONSE_ACCEPT); - session_selector_window->add (*vpacker); - session_selector_window->set_name ("SessionSelectorWindow"); - session_selector_window->set_size_request (200, 400); + FileFilter session_filter; + session_filter.add_pattern ("*.ardour"); + session_filter.set_name (_("Ardour sessions")); + open_session_selector->add_filter (session_filter); + open_session_selector->set_filter (session_filter); + } - session_selector_window->delete_event.connect (bind (slot (just_hide_it), static_cast(session_selector_window))); - cancel_button-.signal_clicked().connect (bind (slot (*this, &ARDOUR_UI::hide_dialog), session_selector_window)); - session_selector.tree_select_row.connect (slot (*this, &ARDOUR_UI::session_selection)); -} + int response = open_session_selector->run(); + open_session_selector->hide (); -void -ARDOUR_UI::fs_cancel_clicked (Gtk::FileSelection* fs) -{ - fs->hide_all(); - fs->get_selection_entry()->set_text(""); - allow_focus (false); -} - -gint -ARDOUR_UI::fs_delete_event (GdkEventAny* ev, Gtk::FileSelection* fs) -{ - fs_cancel_clicked (fs); - return 1; -} - -void -ARDOUR_UI::open_session () -{ - /* popup selector window */ - - if (open_session_selector == 0) { - open_session_selector = new Gtk::FileSelection(_("open session")); - open_session_selector->get_ok_button()-.signal_clicked().connect (slot (*this, &ARDOUR_UI::open_ok_clicked)); - open_session_selector->get_cancel_button()-.signal_clicked().connect (bind (slot (*this, &ARDOUR_UI::fs_cancel_clicked), open_session_selector)); - open_session_selector->delete_event.connect (bind (slot (*this, &ARDOUR_UI::fs_delete_event), open_session_selector)); + switch (response) { + case RESPONSE_ACCEPT: + break; + default: + open_session_selector->hide(); + return; } - open_session_selector->show_all (); - allow_focus (true); - - /* wait for selection */ -} - -void -ARDOUR_UI::open_ok_clicked () -{ - open_session_selector->hide_all(); + open_session_selector->hide(); string session_path = open_session_selector->get_filename(); string path, name; bool isnew; @@ -1867,56 +1014,83 @@ ARDOUR_UI::open_ok_clicked () load_session (path, name); } } - - open_session_selector->get_selection_entry()->set_text(""); - - /* XXX hack hack hack */ - - GtkCList* clist = (GtkCList*) open_session_selector->gobj()->file_list; - gtk_clist_unselect_all (clist); - - allow_focus(false); } + void -ARDOUR_UI::open_recent_session () +ARDOUR_UI::session_add_midi_route (bool disk, uint32_t how_many) { - /* popup selector window */ + list > tracks; - if (session_selector_window == 0) { - build_session_selector (); + if (session == 0) { + warning << _("You cannot add a track without a session already loaded.") << endmsg; + return; } - redisplay_recent_sessions (); - session_selector_window->show_all (); + try { + if (disk) { - /* wait for selection */ -} + tracks = session->new_midi_track (ARDOUR::Normal, how_many); -void -ARDOUR_UI::session_add_midi_track () -{ - cerr << _("Patience is a virtue.\n"); + if (tracks.size() != how_many) { + if (how_many == 1) { + error << _("could not create a new midi track") << endmsg; + } else { + error << string_compose (_("could not create %1 new midi tracks"), how_many) << endmsg; + } + } + } /*else { + if ((route = session->new_midi_route ()) == 0) { + error << _("could not create new midi bus") << endmsg; + } + }*/ + } + + catch (...) { + MessageDialog msg (*editor, + _("There are insufficient JACK ports available\n\ +to create a new track or bus.\n\ +You should save Ardour, exit and\n\ +restart JACK with more ports.")); + msg.run (); + } } + void -ARDOUR_UI::session_add_audio_route (bool disk, int32_t input_channels, int32_t output_channels) +ARDOUR_UI::session_add_audio_route (bool track, int32_t input_channels, int32_t output_channels, ARDOUR::TrackMode mode, uint32_t how_many) { - Route* route; + list > tracks; + Session::RouteList routes; if (session == 0) { - warning << _("You cannot add a track without a session already loaded.") << endmsg; + warning << _("You cannot add a track or bus without a session already loaded.") << endmsg; return; } try { - if (disk) { - if ((route = session->new_audio_track (input_channels, output_channels)) == 0) { - error << _("could not create new audio track") << endmsg; + if (track) { + tracks = session->new_audio_track (input_channels, output_channels, mode, how_many); + + if (tracks.size() != how_many) { + if (how_many == 1) { + error << _("could not create a new audio track") << endmsg; + } else { + error << string_compose (_("could only create %1 of %2 new audio %3"), + tracks.size(), how_many, (track ? _("tracks") : _("busses"))) << endmsg; + } } + } else { - if ((route = session->new_audio_route (input_channels, output_channels)) == 0) { - error << _("could not create new audio bus") << endmsg; + + routes = session->new_audio_route (input_channels, output_channels, how_many); + + if (routes.size() != how_many) { + if (how_many == 1) { + error << _("could not create a new audio track") << endmsg; + } else { + error << string_compose (_("could not create %1 new audio tracks"), how_many) << endmsg; + } } } @@ -1934,27 +1108,24 @@ ARDOUR_UI::session_add_audio_route (bool disk, int32_t input_channels, int32_t o } catch (...) { - ArdourMessage msg (editor, X_("noport dialog"), + cerr << "About to complain about JACK\n"; + MessageDialog msg (*editor, _("There are insufficient JACK ports available\n\ to create a new track or bus.\n\ You should save Ardour, exit and\n\ restart JACK with more ports.")); + msg.run (); } } void -ARDOUR_UI::diskstream_added (DiskStream* ds) +ARDOUR_UI::do_transport_locate (nframes_t new_position) { - // meter_bridge_dialog_check->set_sensitive (true); -} - -void -ARDOUR_UI::do_transport_locate (jack_nframes_t new_position) -{ - jack_nframes_t _preroll; + nframes_t _preroll = 0; if (session) { - _preroll = session->convert_to_frames_at (new_position, session->preroll); + // XXX CONFIG_CHANGE FIX - requires AnyTime handling + // _preroll = session->convert_to_frames_at (new_position, Config->get_preroll()); if (new_position > _preroll) { new_position -= _preroll; @@ -1970,7 +1141,7 @@ void ARDOUR_UI::transport_goto_start () { if (session) { - session->request_locate (0); + session->goto_start(); /* force displayed area in editor to start no matter @@ -1978,54 +1149,43 @@ ARDOUR_UI::transport_goto_start () */ if (editor) { - editor->reposition_x_origin (0); + editor->reset_x_origin (session->current_start_frame()); } } } void -ARDOUR_UI::transport_goto_end () +ARDOUR_UI::transport_goto_zero () { if (session) { - jack_nframes_t frame = session->current_end_frame(); - session->request_locate (frame); + session->request_locate (0); + /* force displayed area in editor to start no matter what "follow playhead" setting is. */ if (editor) { - editor->reposition_x_origin (frame); + editor->reset_x_origin (0); } } } -gint -ARDOUR_UI::mouse_transport_stop (GdkEventButton *ev) +void +ARDOUR_UI::transport_goto_end () { - - if (session) { - if (session->transport_stopped()) { - session->request_locate (session->last_transport_start()); - } else { - if (session->get_auto_loop()) { - session->request_auto_loop (false); - } + nframes_t frame = session->current_end_frame(); + session->request_locate (frame); - Keyboard::ModifierMask mask = Keyboard::ModifierMask (Keyboard::Control|Keyboard::Shift); - session->request_stop (Keyboard::modifier_state_equals (ev->state, mask)); - } + /* force displayed area in editor to start no matter + what "follow playhead" setting is. + */ + + if (editor) { + editor->reset_x_origin (frame); + } } - - return TRUE; -} - -gint -ARDOUR_UI::mouse_transport_roll (GdkEventButton* ev) -{ - transport_roll (); - return TRUE; } void @@ -2040,8 +1200,8 @@ ARDOUR_UI::transport_stop () return; } - if (session->get_auto_loop()) { - session->request_auto_loop (false); + if (session->get_play_loop ()) { + session->request_play_loop (false); } session->request_stop (); @@ -2070,15 +1230,15 @@ ARDOUR_UI::transport_record () switch (session->record_status()) { case Session::Disabled: if (session->ntracks() == 0) { - string txt = _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu."); - ArdourMessage msg (editor, X_("cannotrecenable"), txt); + MessageDialog msg (*editor, _("Please create 1 or more track\nbefore trying to record.\nCheck the Session menu.")); + msg.run (); return; } session->maybe_enable_record (); break; case Session::Recording: case Session::Enabled: - session->disable_record (); + session->disable_record (true); } } } @@ -2094,13 +1254,13 @@ ARDOUR_UI::transport_roll () rolling = session->transport_rolling (); - if (session->get_auto_loop()) { - session->request_auto_loop (false); - auto_loop_button.set_active (false); - roll_button.set_active (true); + if (session->get_play_loop()) { + session->request_play_loop (false); + auto_loop_button.set_visual_state (1); + roll_button.set_visual_state (1); } else if (session->get_play_range ()) { session->request_play_range (false); - play_selection_button.set_active (false); + play_selection_button.set_visual_state (0); } else if (rolling) { session->request_locate (session->last_transport_start(), true); } @@ -2112,7 +1272,7 @@ void ARDOUR_UI::transport_loop() { if (session) { - if (session->get_auto_loop()) { + if (session->get_play_loop()) { if (session->transport_rolling()) { Location * looploc = session->locations()->auto_loop_location(); if (looploc) { @@ -2121,7 +1281,7 @@ ARDOUR_UI::transport_loop() } } else { - session->request_auto_loop (true); + session->request_play_loop (true); } } } @@ -2195,38 +1355,31 @@ ARDOUR_UI::transport_forward (int option) } void -ARDOUR_UI::toggle_monitor_enable (guint32 dstream) +ARDOUR_UI::toggle_record_enable (uint32_t dstream) { if (session == 0) { return; } - DiskStream *ds; + boost::shared_ptr r; + + if ((r = session->route_by_remote_id (dstream)) != 0) { + + Track* t; - if ((ds = session->diskstream_by_id (dstream)) != 0) { - Port *port = ds->io()->input (0); - port->request_monitor_input (!port->monitoring_input()); + if ((t = dynamic_cast(r.get())) != 0) { + t->diskstream()->set_record_enabled (!t->diskstream()->record_enabled()); + } } -} - -void -ARDOUR_UI::toggle_record_enable (guint32 dstream) -{ if (session == 0) { return; } - - DiskStream *ds; - - if ((ds = session->diskstream_by_id (dstream)) != 0) { - ds->set_record_enabled (!ds->record_enabled(), this); - } } void ARDOUR_UI::queue_transport_change () { - Gtkmm2ext::UI::instance()->call_slot (slot (*this, &ARDOUR_UI::map_transport_state)); + Gtkmm2ext::UI::instance()->call_slot (mem_fun(*this, &ARDOUR_UI::map_transport_state)); } void @@ -2245,32 +1398,6 @@ ARDOUR_UI::map_transport_state () } } -void -ARDOUR_UI::send_all_midi_feedback () -{ - if (session) { - session->send_all_midi_feedback(); - } -} - -void -ARDOUR_UI::allow_local_only () -{ - -} - -void -ARDOUR_UI::allow_mmc_only () -{ - -} - -void -ARDOUR_UI::allow_mmc_and_local () -{ - -} - void ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg) { @@ -2281,41 +1408,79 @@ ARDOUR_UI::GlobalClickBox::printer (char buf[32], Adjustment &adj, void *arg) void ARDOUR_UI::engine_stopped () { - ENSURE_GUI_THREAD (slot (*this, &ARDOUR_UI::engine_stopped)); - - jack_disconnect_item->set_sensitive (false); - jack_reconnect_item->set_sensitive (true); - jack_bufsize_menu->set_sensitive (false); + ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_stopped)); + ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true); } - void ARDOUR_UI::engine_running () { - ENSURE_GUI_THREAD (slot (*this, &ARDOUR_UI::engine_running)); + ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_running)); + ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, true); + ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false); - jack_disconnect_item->set_sensitive (true); - jack_reconnect_item->set_sensitive (false); - jack_bufsize_menu->set_sensitive (true); + Glib::RefPtr action; + char* action_name = 0; + + switch (engine->frames_per_cycle()) { + case 32: + action_name = X_("JACKLatency32"); + break; + case 64: + action_name = X_("JACKLatency64"); + break; + case 128: + action_name = X_("JACKLatency128"); + break; + case 512: + action_name = X_("JACKLatency512"); + break; + case 1024: + action_name = X_("JACKLatency1024"); + break; + case 2048: + action_name = X_("JACKLatency2048"); + break; + case 4096: + action_name = X_("JACKLatency4096"); + break; + case 8192: + action_name = X_("JACKLatency8192"); + break; + default: + /* XXX can we do anything useful ? */ + break; + } + + if (action_name) { + + action = ActionManager::get_action (X_("JACK"), action_name); + + if (action) { + Glib::RefPtr ract = Glib::RefPtr::cast_dynamic (action); + ract->set_active (); + } + } } void ARDOUR_UI::engine_halted () { - ENSURE_GUI_THREAD (slot (*this, &ARDOUR_UI::engine_halted)); + ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::engine_halted)); - jack_disconnect_item->set_sensitive (false); - jack_reconnect_item->set_sensitive (true); - jack_bufsize_menu->set_sensitive (false); + ActionManager::set_sensitive (ActionManager::jack_sensitive_actions, false); + ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, true); update_sample_rate (0); - ArdourMessage msg (editor, X_("halted"), + MessageDialog msg (*editor, _("\ JACK has either been shutdown or it\n\ disconnected Ardour because Ardour\n\ was not fast enough. You can save the\n\ session and/or try to reconnect to JACK .")); + msg.run (); } int32_t @@ -2325,14 +1490,6 @@ ARDOUR_UI::do_engine_start () engine->start(); } - catch (AudioEngine::PortRegistrationFailure& err) { - engine->stop (); - error << _("Unable to create all required ports") - << endmsg; - unload_session (); - return -1; - } - catch (...) { engine->stop (); error << _("Unable to start the session running") @@ -2354,14 +1511,6 @@ ARDOUR_UI::start_engine () */ session->save_state (""); } - - /* there is too much going on, in too many threads, for us to - end up with a clean session. So wait 1 second after loading, - and fix it up. its ugly, but until i come across a better - solution, its what we have. - */ - - Main::timeout.connect (slot (*this, &ARDOUR_UI::make_session_clean), 1000); } return FALSE; @@ -2370,13 +1519,15 @@ ARDOUR_UI::start_engine () void ARDOUR_UI::update_clocks () { - Clock (session->audible_frame()); /* EMIT_SIGNAL */ + if (!editor || !editor->dragging_playhead()) { + Clock (session->audible_frame()); /* EMIT_SIGNAL */ + } } void ARDOUR_UI::start_clocking () { - clock_signal_connection = RapidScreenUpdate.connect (slot (*this, &ARDOUR_UI::update_clocks)); + clock_signal_connection = RapidScreenUpdate.connect (mem_fun(*this, &ARDOUR_UI::update_clocks)); } void @@ -2408,7 +1559,7 @@ ARDOUR_UI::_blink (void *arg) void ARDOUR_UI::blink () { - Blink (blink_on = !blink_on); /* EMIT_SIGNAL */ + Blink (blink_on = !blink_on); /* EMIT_SIGNAL */ } void @@ -2420,7 +1571,7 @@ ARDOUR_UI::start_blinking () if (blink_timeout_tag < 0) { blink_on = false; - blink_timeout_tag = gtk_timeout_add (240, _blink, this); + blink_timeout_tag = g_timeout_add (240, _blink, this); } } @@ -2428,68 +1579,11 @@ void ARDOUR_UI::stop_blinking () { if (blink_timeout_tag >= 0) { - gtk_timeout_remove (blink_timeout_tag); + g_source_remove (blink_timeout_tag); blink_timeout_tag = -1; } } - -void -ARDOUR_UI::add_diskstream_to_menu (DiskStream& dstream) -{ - using namespace Gtk; - using namespace Menu_Helpers; - - if (dstream.hidden()) { - return; - } - - MenuList& items = diskstream_menu->items(); - items.push_back (MenuElem (dstream.name(), bind (slot (*this, &ARDOUR_UI::diskstream_selected), (gint32) dstream.id()))); -} - -void -ARDOUR_UI::diskstream_selected (gint32 id) -{ - selected_dstream = id; - Main::quit (); -} - -gint32 -ARDOUR_UI::select_diskstream (GdkEventButton *ev) -{ - using namespace Gtk; - using namespace Menu_Helpers; - - if (session == 0) { - return -1; - } - - diskstream_menu = new Menu(); - diskstream_menu->set_name ("ArdourContextMenu"); - using namespace Gtk; - using namespace Menu_Helpers; - - MenuList& items = diskstream_menu->items(); - items.push_back (MenuElem (_("No Stream"), (bind (slot (*this, &ARDOUR_UI::diskstream_selected), -1)))); - - session->foreach_diskstream (this, &ARDOUR_UI::add_diskstream_to_menu); - - if (ev) { - diskstream_menu->popup (ev->button, ev->time); - } else { - diskstream_menu->popup (0, 0); - } - - selected_dstream = -1; - - Main::run (); - - delete diskstream_menu; - - return selected_dstream; -} - void ARDOUR_UI::name_io_setup (AudioEngine& engine, string& buf, @@ -2497,7 +1591,7 @@ ARDOUR_UI::name_io_setup (AudioEngine& engine, bool in) { if (in) { - if (io.n_inputs() == 0) { + if (io.n_inputs().get_total() == 0) { buf = _("none"); return; } @@ -2516,7 +1610,7 @@ ARDOUR_UI::name_io_setup (AudioEngine& engine, } else { - if (io.n_outputs() == 0) { + if (io.n_outputs().get_total() == 0) { buf = _("none"); return; } @@ -2535,37 +1629,41 @@ ARDOUR_UI::name_io_setup (AudioEngine& engine, } } +/** Ask the user for the name of a new shapshot and then take it. + */ void ARDOUR_UI::snapshot_session () { ArdourPrompter prompter (true); - string now; + string snapname; + char timebuf[128]; time_t n; + struct tm local_time; time (&n); - now = ctime (&n); - now = now.substr (0, now.length() - 1); + localtime_r (&n, &local_time); + strftime (timebuf, sizeof(timebuf), "%FT%T", &local_time); prompter.set_name ("Prompter"); - prompter.set_prompt (_("Name for snapshot")); - prompter.set_initial_text (now); - prompter.done.connect (Gtk::Main::quit.slot()); - prompter.show_all (); - - Gtk::Main::run (); - - if (prompter.status == Gtkmm2ext::Prompter::entered) { - string snapname; - + prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); + prompter.set_prompt (_("Name of New Snapshot")); + prompter.set_initial_text (timebuf); + + switch (prompter.run()) { + case RESPONSE_ACCEPT: prompter.get_result (snapname); if (snapname.length()){ save_state (snapname); } + break; + + default: + break; } } void -ARDOUR_UI::save_state (string name) +ARDOUR_UI::save_state (const string & name) { (void) save_state_canfail (name); } @@ -2599,14 +1697,6 @@ ARDOUR_UI::restore_state (string name) } } -void -ARDOUR_UI::allow_focus (bool yn) -{ - if (keyboard) { - keyboard->allow_focus (yn); - } -} - void ARDOUR_UI::primary_clock_value_changed () { @@ -2624,7 +1714,7 @@ ARDOUR_UI::secondary_clock_value_changed () } void -ARDOUR_UI::rec_enable_button_blink (bool onoff, DiskStream *dstream, Widget *w) +ARDOUR_UI::rec_enable_button_blink (bool onoff, AudioDiskstream *dstream, Widget *w) { if (session && dstream && dstream->record_enabled()) { @@ -2635,21 +1725,21 @@ ARDOUR_UI::rec_enable_button_blink (bool onoff, DiskStream *dstream, Widget *w) switch (rs) { case Session::Disabled: case Session::Enabled: - if (w->get_state() != GTK_STATE_SELECTED) { - w->set_state (GTK_STATE_SELECTED); + if (w->get_state() != STATE_SELECTED) { + w->set_state (STATE_SELECTED); } break; case Session::Recording: - if (w->get_state() != GTK_STATE_ACTIVE) { - w->set_state (GTK_STATE_ACTIVE); + if (w->get_state() != STATE_ACTIVE) { + w->set_state (STATE_ACTIVE); } break; } } else { - if (w->get_state() != Gtk::STATE_NORMAL) { - w->set_state (Gtk::STATE_NORMAL); + if (w->get_state() != STATE_NORMAL) { + w->set_state (STATE_NORMAL); } } } @@ -2664,37 +1754,22 @@ ARDOUR_UI::transport_rec_enable_blink (bool onoff) switch (session->record_status()) { case Session::Enabled: if (onoff) { - rec_button.set_state (GTK_STATE_ACTIVE); + rec_button.set_visual_state (2); } else { - rec_button.set_state (Gtk::STATE_NORMAL); + rec_button.set_visual_state (0); } break; case Session::Recording: - rec_button.set_state (GTK_STATE_ACTIVE); + rec_button.set_visual_state (1); break; default: - rec_button.set_active (false); - rec_button.set_state (Gtk::STATE_NORMAL); + rec_button.set_visual_state (0); break; } } -gint -ARDOUR_UI::generic_focus_in_event (GdkEventFocus *ev) -{ - ARDOUR_UI::instance()->allow_focus (true); - return FALSE; -} - -gint -ARDOUR_UI::generic_focus_out_event (GdkEventFocus *ev) -{ - ARDOUR_UI::instance()->allow_focus (false); - return FALSE; -} - gint ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window) { @@ -2703,123 +1778,266 @@ ARDOUR_UI::hide_and_quit (GdkEventAny *ev, ArdourDialog *window) return TRUE; } -void -ARDOUR_UI::start_keyboard_prefix () -{ - keyboard->start_prefix(); -} - void ARDOUR_UI::save_template () { ArdourPrompter prompter (true); - prompter.set_name ("Prompter"); + string name; + + prompter.set_name (X_("Prompter")); prompter.set_prompt (_("Name for mix template:")); prompter.set_initial_text(session->name() + _("-template")); + prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT); - prompter.done.connect(Gtk::Main::quit.slot()); - prompter.show_all(); - - Gtk::Main::run(); - - if (prompter.status == Gtkmm2ext::Prompter::entered) { - string name; - + switch (prompter.run()) { + case RESPONSE_ACCEPT: prompter.get_result (name); - + if (name.length()) { session->save_template (name); } + break; + + default: + break; } } -void -ARDOUR_UI::new_session (bool startup, string predetermined_path) +bool +ARDOUR_UI::new_session (std::string predetermined_path) { - if (new_session_window == 0){ - new_session_window = new NewSessionDialog (*engine, startup, predetermined_path); - editor->ensure_float (*new_session_window); + string session_name; + string session_path; + + if (!check_audioengine()) { + return false; } - new_session_window->run (); + int response = Gtk::RESPONSE_NONE; - /* write favorites either way */ - Session::FavoriteDirs favs; - new_session_window->file_selector.get_favorites (favs); - Session::write_favorite_dirs (favs); + new_session_dialog->set_modal(true); + new_session_dialog->set_name (predetermined_path); + new_session_dialog->reset_recent(); + new_session_dialog->show(); + new_session_dialog->set_current_page (0); - if (new_session_window->run_status()) { - return; - } + do { + response = new_session_dialog->run (); - string session_path = new_session_window->file_selector.get_path (); - string session_name = PBD::basename (session_path); + if (!check_audioengine()) { + new_session_dialog->hide (); + return false; + } + + _session_is_new = false; - // Check that it doesn't already exist. - access(session_path.c_str(), R_OK); - if (errno != ENOENT){ - error << compose(_("Session %1 already exists at %2"), session_name, session_path) << endmsg; - return; - } + if (response == Gtk::RESPONSE_CANCEL || response == Gtk::RESPONSE_DELETE_EVENT) { - _session_is_new = true; + if (!session) { + quit(); + } + new_session_dialog->hide (); + return false; + + } else if (response == Gtk::RESPONSE_NONE) { + + /* Clear was pressed */ + new_session_dialog->reset(); + + } else if (response == Gtk::RESPONSE_YES) { + + /* YES == OPEN, but there's no enum for that */ + + session_name = new_session_dialog->session_name(); + + if (session_name.empty()) { + response = Gtk::RESPONSE_NONE; + continue; + } + + if (session_name[0] == '/' || + (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') || + (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) { + load_session (Glib::path_get_dirname (session_name), session_name); + } else { + session_path = new_session_dialog->session_folder(); + load_session (session_path, session_name); + } + + } else if (response == Gtk::RESPONSE_OK) { - if (session_path[session_path.length()-1] != '/') { + session_name = new_session_dialog->session_name(); + + if (new_session_dialog->get_current_page() == 1) { + + /* XXX this is a bit of a hack.. + i really want the new sesion dialog to return RESPONSE_YES + if we're on page 1 (the load page) + Unfortunately i can't see how atm.. + */ + + if (session_name.empty()) { + response = Gtk::RESPONSE_NONE; + continue; + } + + if (session_name[0] == '/' || + (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') || + (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) { + load_session (Glib::path_get_dirname (session_name), session_name); + } else { + session_path = new_session_dialog->session_folder(); + load_session (session_path, session_name); + } + + } else { - string template_name = new_session_window->get_template_name (); + if (session_name.empty()) { + response = Gtk::RESPONSE_NONE; + continue; + } - if (template_name.length()) { + if (session_name[0] == '/' || + (session_name.length() > 2 && session_name[0] == '.' && session_name[1] == '/') || + (session_name.length() > 3 && session_name[0] == '.' && session_name[1] == '.' && session_name[2] == '/')) { - load_session (session_path, session_name, &template_name); + session_path = Glib::path_get_dirname (session_name); + session_name = Glib::path_get_basename (session_name); - } else { + } else { - uint32_t cchns; - uint32_t mchns; - Session::AutoConnectOption iconnect; - Session::AutoConnectOption oconnect; + session_path = new_session_dialog->session_folder(); - if (new_session_window->use_control_button.get_active()) { - cchns = (uint32_t) channel_combo_get_channel_count (new_session_window->control_out_channel_combo); - } else { - cchns = 0; - } - if (new_session_window->use_master_button.get_active()) { - mchns = (uint32_t) channel_combo_get_channel_count (new_session_window->master_out_channel_combo); - } else { - mchns = 0; - } + } + + //XXX This is needed because session constructor wants a + //non-existant path. hopefully this will be fixed at some point. + + session_path = Glib::build_filename (session_path, session_name); + + if (g_file_test (session_path.c_str(), GFileTest (G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))) { + + Glib::ustring str = string_compose (_("This session\n%1\nalready exists. Do you want to open it?"), session_path); + + MessageDialog msg (str, + false, + Gtk::MESSAGE_WARNING, + Gtk::BUTTONS_YES_NO, + true); + + + msg.set_name (X_("CleanupDialog")); + msg.set_wmclass (X_("existing_session"), "Ardour"); + msg.set_position (Gtk::WIN_POS_MOUSE); + + switch (msg.run()) { + case RESPONSE_YES: + load_session (session_path, session_name); + goto done; + break; + default: + response = RESPONSE_NONE; + new_session_dialog->reset (); + continue; + } + } - if (new_session_window->connect_to_physical_inputs_button.get_active()) { - iconnect = Session::AutoConnectPhysical; - } else { - iconnect = Session::AutoConnectOption (0); + _session_is_new = true; + + std::string template_name = new_session_dialog->session_template_name(); + + if (new_session_dialog->use_session_template()) { + + load_session (session_path, session_name, &template_name); + + } else { + + uint32_t cchns; + uint32_t mchns; + AutoConnectOption iconnect; + AutoConnectOption oconnect; + + if (new_session_dialog->create_control_bus()) { + cchns = (uint32_t) new_session_dialog->control_channel_count(); + } else { + cchns = 0; + } + + if (new_session_dialog->create_master_bus()) { + mchns = (uint32_t) new_session_dialog->master_channel_count(); + } else { + mchns = 0; + } + + if (new_session_dialog->connect_inputs()) { + iconnect = AutoConnectPhysical; + } else { + iconnect = AutoConnectOption (0); + } + + /// @todo some minor tweaks. + + if (new_session_dialog->connect_outs_to_master()) { + oconnect = AutoConnectMaster; + } else if (new_session_dialog->connect_outs_to_physical()) { + oconnect = AutoConnectPhysical; + } else { + oconnect = AutoConnectOption (0); + } + + uint32_t nphysin = (uint32_t) new_session_dialog->input_limit_count(); + uint32_t nphysout = (uint32_t) new_session_dialog->output_limit_count(); + + if (build_session (session_path, + session_name, + cchns, + mchns, + iconnect, + oconnect, + nphysin, + nphysout, + engine->frame_rate() * 60 * 5)) { + + response = Gtk::RESPONSE_NONE; + new_session_dialog->reset (); + continue; + } + } } + } + + } while (response == Gtk::RESPONSE_NONE); - if (new_session_window->connect_to_master_button.get_active ()) { - oconnect = Session::AutoConnectMaster; - } else if (new_session_window->connect_to_physical_outputs_button.get_active ()) { - oconnect = Session::AutoConnectPhysical; - } else { - oconnect = Session::AutoConnectOption (0); - } - - uint32_t nphysin = (uint32_t) new_session_window->in_count_adjustment.get_value(); - uint32_t nphysout = (uint32_t) new_session_window->out_count_adjustment.get_value(); + done: + show(); + new_session_dialog->get_window()->set_cursor(); + new_session_dialog->hide(); + return true; +} - build_session (session_path, session_name, cchns, mchns, iconnect, oconnect, nphysin, nphysout, - engine->frame_rate() * 60 * 5); - } +void +ARDOUR_UI::close_session() +{ + if (!check_audioengine()) { + return; } + + unload_session(); + new_session (); } int -ARDOUR_UI::load_session (string path, string snap_name, string* mix_template) +ARDOUR_UI::load_session (const string & path, const string & snap_name, string* mix_template) { Session *new_session; int x; session_loaded = false; + + if (!check_audioengine()) { + return -1; + } + x = unload_session (); if (x < 0) { @@ -2831,9 +2049,9 @@ ARDOUR_UI::load_session (string path, string snap_name, string* mix_template) /* if it already exists, we must have write access */ if (::access (path.c_str(), F_OK) == 0 && ::access (path.c_str(), W_OK)) { - ArdourMessage msg (editor, X_("noaccess dialog"), _("\ -You do not have write access to this session.\n\ -This prevents the session from being loaded.")); + MessageDialog msg (*editor, _("You do not have write access to this session.\n" + "This prevents the session from being loaded.")); + msg.run (); return -1; } @@ -2843,44 +2061,47 @@ This prevents the session from being loaded.")); catch (...) { - error << compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg; + error << string_compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg; return -1; } connect_to_session (new_session); - //if (engine->running()) { - //mixer->show_window(); - //} + Config->set_current_owner (ConfigVariableBase::Interface); + session_loaded = true; - return 0; -} + + goto_editor_window (); -int -ARDOUR_UI::make_session_clean () -{ if (session) { session->set_clean (); } - return FALSE; + editor->edit_cursor_position (true); + return 0; } int -ARDOUR_UI::build_session (string path, string snap_name, +ARDOUR_UI::build_session (const string & path, const string & snap_name, uint32_t control_channels, uint32_t master_channels, - Session::AutoConnectOption input_connect, - Session::AutoConnectOption output_connect, + AutoConnectOption input_connect, + AutoConnectOption output_connect, uint32_t nphysin, uint32_t nphysout, - jack_nframes_t initial_length) + nframes_t initial_length) { Session *new_session; int x; + if (!check_audioengine()) { + return -1; + } + session_loaded = false; + x = unload_session (); + if (x < 0) { return -1; } else if (x > 0) { @@ -2896,39 +2117,28 @@ ARDOUR_UI::build_session (string path, string snap_name, catch (...) { - error << compose(_("Session \"%1 (snapshot %2)\" did not load successfully"), path, snap_name) << endmsg; + MessageDialog msg (string_compose(_("Could not create session in \"%1\""), path)); + msg.run (); return -1; } connect_to_session (new_session); - //if (engine->running()) { - //mixer->show_window(); - //} session_loaded = true; return 0; } -void -ARDOUR_UI::hide_dialog (ArdourDialog *dialog) -{ - dialog->hide_all(); -} - void ARDOUR_UI::show () { if (editor) { editor->show_window (); - shown_flag = true; - } + + if (!shown_flag) { + editor->present (); + } - if (session && mixer) { - mixer->show_window (); - } - - if (about) { - about->get_window().raise (); + shown_flag = true; } } @@ -2936,98 +2146,124 @@ void ARDOUR_UI::show_splash () { if (about == 0) { - about = new About(this); - about->show_all(); - about->show_sub (true); - about->get_window().raise (); - } - else { - about->get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH)); - about->show_all (); - about->get_window().raise (); + about = new About(); + about->signal_response().connect(mem_fun (*this, &ARDOUR_UI::about_signal_response) ); } + about->present(); + flush_pending (); +} + +void +ARDOUR_UI::about_signal_response(int response) +{ + hide_splash(); } void ARDOUR_UI::hide_splash () { if (about) { - // about->hide(); + about->get_window()->set_cursor (); + about->hide(); } } void -ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, string msg) +ARDOUR_UI::display_cleanup_results (Session::cleanup_report& rep, const gchar* list_title, const string & msg) { size_t removed; removed = rep.paths.size(); if (removed == 0) { - ArdourMessage msg (editor, X_("cleanupresults"), - _("\ -No audio files were ready for cleanup\n\n\ -If this seems suprising, check for any existing\n\ -snapshots. These may still include regions that\n\ + MessageDialog msgd (*editor, + _("No audio files were ready for cleanup"), + true, + Gtk::MESSAGE_INFO, + (Gtk::ButtonsType)(Gtk::BUTTONS_OK) ); + msgd.set_secondary_text (_("If this seems suprising, \n\ +check for any existing snapshots.\n\ +These may still include regions that\n\ require some unused files to continue to exist.")); + + msgd.run (); return; } - ArdourDialog results ("cleanup results"); + ArdourDialog results (_("ardour: cleanup"), true, false); - const gchar* list_titles[] = { - list_title, - 0 + struct CleanupResultsModelColumns : public Gtk::TreeModel::ColumnRecord { + CleanupResultsModelColumns() { + add (visible_name); + add (fullpath); + } + Gtk::TreeModelColumn visible_name; + Gtk::TreeModelColumn fullpath; }; + + + CleanupResultsModelColumns results_columns; + Glib::RefPtr results_model; + Gtk::TreeView results_display; - Gtk::CList list (internationalize (list_titles)); + results_model = ListStore::create (results_columns); + results_display.set_model (results_model); + results_display.append_column (list_title, results_columns.visible_name); + + results_display.set_name ("CleanupResultsList"); + results_display.set_headers_visible (true); + results_display.set_headers_clickable (false); + results_display.set_reorderable (false); + Gtk::ScrolledWindow list_scroller; Gtk::Label txt; - Gtk::Button ok_button (_("OK")); - Gtk::VBox vpacker; - const char* rowtext[1]; - - list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - - vpacker.set_border_width (10); - vpacker.set_spacing (10); + Gtk::VBox dvbox; + Gtk::HBox dhbox; // the hbox for the image and text + Gtk::HBox ddhbox; // the hbox we eventually pack into the dialog's vbox + Gtk::Image* dimage = manage (new Gtk::Image(Stock::DIALOG_INFO, Gtk::ICON_SIZE_DIALOG)); + + dimage->set_alignment(ALIGN_LEFT, ALIGN_TOP); if (rep.space < 1048576.0f) { if (removed > 1) { - txt.set_text (compose (msg, removed, _("files"), (float) rep.space / 1024.0f, "kilo")); + txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo")); } else { - txt.set_text (compose (msg, removed, _("file"), (float) rep.space / 1024.0f, "kilo")); + txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1024.0f, "kilo")); } } else { if (removed > 1) { - txt.set_text (compose (msg, removed, _("files"), (float) rep.space / 1048576.0f, "mega")); + txt.set_text (string_compose (msg, removed, _("files were"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega")); } else { - txt.set_text (compose (msg, removed, _("file"), (float) rep.space / 1048576.0f, "mega")); + txt.set_text (string_compose (msg, removed, _("file was"), session->path() + "dead_sounds", (float) rep.space / 1048576.0f, "mega")); } } - vpacker.pack_start (txt, false, false); - + dhbox.pack_start (*dimage, true, false, 5); + dhbox.pack_start (txt, true, false, 5); + for (vector::iterator i = rep.paths.begin(); i != rep.paths.end(); ++i) { - rowtext[0] = (*i).c_str(); - list.rows().push_back (rowtext); + TreeModel::Row row = *(results_model->append()); + row[results_columns.visible_name] = *i; + row[results_columns.fullpath] = *i; } - list_scroller.add_with_viewport (list); - list_scroller.set_size_request (-1, 250); - - vpacker.pack_start (list_scroller, true, true); - vpacker.pack_start (ok_button, false, false); - - ok_button.signal_clicked().connect (Main::quit.slot ()); - results.Hiding.connect (Main::quit.slot ()); - - results.add (vpacker); - + list_scroller.add (results_display); + list_scroller.set_size_request (-1, 150); + list_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); + + dvbox.pack_start (dhbox, true, false, 5); + dvbox.pack_start (list_scroller, true, false, 5); + ddhbox.pack_start (dvbox, true, false, 5); + + results.get_vbox()->pack_start (ddhbox, true, false, 5); + results.add_button (Stock::CLOSE, RESPONSE_CLOSE); + results.set_default_response (RESPONSE_CLOSE); results.set_position (Gtk::WIN_POS_MOUSE); - results.set_title (_("ardour: cleanup")); - results.set_modal (true); + results.show_all_children (); + results.set_resizable (false); + results.run (); + } void @@ -3038,41 +2274,29 @@ ARDOUR_UI::cleanup () return; } - ArdourDialog checker (X_("cleanup confirm dialog")); - Gtk::Label label (_("\ -Cleanup is a destructive operation.\n\ -ALL undo/redo information will be lost if you cleanup.\n\ -Unused audio files will be moved to a \"dead sounds\" location.")); - Gtk::Button ok_button (_("Proceed with cleanup")); - Gtk::Button cancel_button (_("Cancel")); - Gtk::HBox bbox; - Gtk::VBox vbox; + MessageDialog checker (_("Are you sure you want to cleanup?"), + true, + Gtk::MESSAGE_QUESTION, + (Gtk::ButtonsType)(Gtk::BUTTONS_NONE)); - bbox.set_border_width (6); - bbox.set_spacing (12); - bbox.pack_start (ok_button, true, false); - bbox.pack_start (cancel_button, true, false); - - vbox.set_border_width (6); - vbox.set_spacing (12); - vbox.pack_start (label, false, false); - vbox.pack_start (bbox, false, false); + checker.set_secondary_text(_("Cleanup is a destructive operation.\n\ +ALL undo/redo information will be lost if you cleanup.\n\ +After cleanup, unused audio files will be moved to a \ +\"dead sounds\" location.")); - checker.add (vbox); + checker.add_button (Stock::CANCEL, RESPONSE_CANCEL); + checker.add_button (_("Clean Up"), RESPONSE_ACCEPT); + checker.set_default_response (RESPONSE_CANCEL); + checker.set_name (_("CleanupDialog")); - checker.set_title (_("ardour cleanup")); - checker.set_wmclass (_("ardour_cleanup"), "Ardour"); + checker.set_wmclass (X_("ardour_cleanup"), "Ardour"); checker.set_position (Gtk::WIN_POS_MOUSE); - checker.realize (); - checker.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH)); - - ok_button.signal_clicked().connect (bind (slot (checker, &ArdourDialog::stop), 1)); - cancel_button.signal_clicked().connect (bind (slot (checker, &ArdourDialog::stop), 0)); - checker.run (); - - if (checker.run_status() != 1) { + switch (checker.run()) { + case RESPONSE_ACCEPT: + break; + default: return; } @@ -3080,18 +2304,31 @@ Unused audio files will be moved to a \"dead sounds\" location.")); editor->prepare_for_cleanup (); + /* do not allow flush until a session is reloaded */ + + Glib::RefPtr act = ActionManager::get_action (X_("Main"), X_("FlushWastebasket")); + if (act) { + act->set_sensitive (false); + } + if (session->cleanup_sources (rep)) { return; } + checker.hide(); display_cleanup_results (rep, _("cleaned files"), _("\ -The following %1 %2 were not in use.\n\ -The next time you flush the wastebasket\n\ -it will release an additional %3 %4bytes\n\ -of disk space" +The following %1 %2 not in use and \n\ +have been moved to:\n\ +%3. \n\n\ +Flushing the wastebasket will \n\ +release an additional\n\ +%4 %5bytes of disk space.\n" )); + + + } void @@ -3110,11 +2347,13 @@ ARDOUR_UI::flush_trash () display_cleanup_results (rep, _("deleted file"), - _("The following %1 file%2 were deleted, releasing %3 %4bytes of disk space")); + _("The following %1 %2 deleted from\n\ +%3,\n\ +releasing %4 %5bytes of disk space")); } void -ARDOUR_UI::add_route () +ARDOUR_UI::add_route (Gtk::Window* float_window) { int count; @@ -3124,7 +2363,9 @@ ARDOUR_UI::add_route () if (add_route_dialog == 0) { add_route_dialog = new AddRouteDialog; - editor->ensure_float (*add_route_dialog); + if (float_window) { + add_route_dialog->set_transient_for (*float_window); + } } if (add_route_dialog->is_visible()) { @@ -3132,10 +2373,16 @@ ARDOUR_UI::add_route () return; } - add_route_dialog->run (); + ResponseType r = (ResponseType) add_route_dialog->run (); - if (add_route_dialog->run_status()) { - return; + add_route_dialog->hide(); + + switch (r) { + case RESPONSE_ACCEPT: + break; + default: + return; + break; } if ((count = add_route_dialog->count()) <= 0) { @@ -3147,26 +2394,30 @@ ARDOUR_UI::add_route () string name_template = add_route_dialog->name_template (); bool track = add_route_dialog->track (); - Session::AutoConnectOption oac = session->get_output_auto_connect(); + AutoConnectOption oac = Config->get_output_auto_connect(); - if (oac & Session::AutoConnectMaster) { - output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan); + if (oac & AutoConnectMaster) { + output_chan = (session->master_out() ? session->master_out()->n_inputs().get(DataType::AUDIO) : input_chan); } else { output_chan = input_chan; } /* XXX do something with name template */ - while (count) { + if (add_route_dialog->type() == ARDOUR::DataType::MIDI) { if (track) { - session_add_audio_track (input_chan, output_chan); - } else { - session_add_audio_bus (input_chan, output_chan); + session_add_midi_track(count); + } else { + MessageDialog msg (*editor, + _("Sorry, MIDI Busses are not supported at this time.")); + msg.run (); + //session_add_midi_bus(); } - --count; - - while (Main::events_pending()) { - Main::iteration (); + } else { + if (track) { + session_add_audio_track (input_chan, output_chan, add_route_dialog->mode(), count); + } else { + session_add_audio_bus (input_chan, output_chan, count); } } } @@ -3179,7 +2430,7 @@ ARDOUR_UI::mixer_settings () const if (session) { node = session->instant_xml(X_("Mixer"), session->path()); } else { - node = Config->instant_xml(X_("Mixer"), Config->get_user_ardour_path()); + node = Config->instant_xml(X_("Mixer"), get_user_ardour_path()); } if (!node) { @@ -3197,7 +2448,7 @@ ARDOUR_UI::editor_settings () const if (session) { node = session->instant_xml(X_("Editor"), session->path()); } else { - node = Config->instant_xml(X_("Editor"), Config->get_user_ardour_path()); + node = Config->instant_xml(X_("Editor"), get_user_ardour_path()); } if (!node) { @@ -3222,76 +2473,60 @@ ARDOUR_UI::keyboard_settings () const void ARDOUR_UI::halt_on_xrun_message () { - ENSURE_GUI_THREAD (slot (*this, &ARDOUR_UI::halt_on_xrun_message)); + ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::halt_on_xrun_message)); - ArdourMessage msg (editor, X_("haltonxrun"), + MessageDialog msg (*editor, _("Recording was stopped because your system could not keep up.")); -} - -void -ARDOUR_UI::delete_sources_in_the_right_thread (list* deletion_list) -{ - ENSURE_GUI_THREAD (bind (slot (*this, &ARDOUR_UI::delete_sources_in_the_right_thread), deletion_list)); - - for (list::iterator i = deletion_list->begin(); i != deletion_list->end(); ++i) { - delete *i; - } - - delete deletion_list; + msg.run (); } void ARDOUR_UI::disk_overrun_handler () { - ENSURE_GUI_THREAD (slot (*this, &ARDOUR_UI::disk_underrun_handler)); + ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_overrun_handler)); - if (!have_disk_overrun_displayed) { - have_disk_overrun_displayed = true; - ArdourMessage msg (editor, X_("diskrate dialog"), _("\ + if (!have_disk_speed_dialog_displayed) { + have_disk_speed_dialog_displayed = true; + MessageDialog* msg = new MessageDialog (*editor, _("\ The disk system on your computer\n\ was not able to keep up with Ardour.\n\ \n\ Specifically, it failed to write data to disk\n\ quickly enough to keep up with recording.\n")); - have_disk_overrun_displayed = false; + msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg)); + msg->show_all (); } } void ARDOUR_UI::disk_underrun_handler () { - ENSURE_GUI_THREAD (slot (*this, &ARDOUR_UI::disk_underrun_handler)); + ENSURE_GUI_THREAD (mem_fun(*this, &ARDOUR_UI::disk_underrun_handler)); - if (!have_disk_underrun_displayed) { - have_disk_underrun_displayed = true; - ArdourMessage msg (editor, X_("diskrate2 dialog"), - (_("The disk system on your computer\n\ + if (!have_disk_speed_dialog_displayed) { + have_disk_speed_dialog_displayed = true; + MessageDialog* msg = new MessageDialog (*editor, + _("The disk system on your computer\n\ was not able to keep up with Ardour.\n\ \n\ Specifically, it failed to read data from disk\n\ -quickly enough to keep up with playback.\n"))); - have_disk_underrun_displayed = false; +quickly enough to keep up with playback.\n")); + msg->signal_response().connect (bind (mem_fun (*this, &ARDOUR_UI::disk_speed_dialog_gone), msg)); + msg->show_all (); } } void -ARDOUR_UI::disk_underrun_message_gone () -{ - have_disk_underrun_displayed = false; -} - -void -ARDOUR_UI::disk_overrun_message_gone () +ARDOUR_UI::disk_speed_dialog_gone (int ignored_response, MessageDialog* msg) { - have_disk_underrun_displayed = false; + have_disk_speed_dialog_displayed = false; + delete msg; } int ARDOUR_UI::pending_state_dialog () { ArdourDialog dialog ("pending state dialog"); - Button use_button (_("Recover from crash")); - Button cancel_button (_("Ignore crash data")); Label message (_("\ This session appears to have been in\n\ middle of recording when ardour or\n\ @@ -3300,44 +2535,29 @@ the computer was shutdown.\n\ Ardour can recover any captured audio for\n\ you, or it can ignore it. Please decide\n\ what you would like to do.\n")); - HBox hpacker; - VBox vpacker; - - vpacker.set_border_width (12); - vpacker.set_spacing (7); - vpacker.pack_start (message); - vpacker.pack_start (hpacker); - hpacker.set_spacing (7); - hpacker.pack_start (use_button); - hpacker.pack_start (cancel_button); - - use_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 0)); - cancel_button.signal_clicked().connect (bind (slot (dialog, &ArdourDialog::stop), 1)); + dialog.get_vbox()->pack_start (message); + dialog.add_button (_("Recover from crash"), RESPONSE_ACCEPT); + dialog.add_button (_("Ignore crash data"), RESPONSE_REJECT); - dialog.add (vpacker); - dialog.set_position (GTK_WIN_POS_CENTER); + dialog.set_position (WIN_POS_CENTER); dialog.show_all (); - dialog.realize(); - dialog.get_window().set_decorations (GdkWMDecoration (GDK_DECOR_BORDER|GDK_DECOR_RESIZEH)); - dialog.run (); - - if (dialog.run_status () == 0) { + switch (dialog.run ()) { + case RESPONSE_ACCEPT: return 1; + default: + return 0; } - - return 0; } - void ARDOUR_UI::disconnect_from_jack () { if (engine) { if( engine->disconnect_from_jack ()) { - ArdourMessage msg (editor, X_("nojack dialog"), - _("Could not disconnect from JACK")); + MessageDialog msg (*editor, _("Could not disconnect from JACK")); + msg.run (); } update_sample_rate (0); @@ -3349,21 +2569,14 @@ ARDOUR_UI::reconnect_to_jack () { if (engine) { if (engine->reconnect_to_jack ()) { - ArdourMessage msg (editor, X_("nojack dialog"), - _("Could not reconnect to JACK")); + MessageDialog msg (*editor, _("Could not reconnect to JACK")); + msg.run (); } update_sample_rate (0); } } -void -ARDOUR_UI::set_jack_buffer_size (jack_nframes_t nframes) -{ - engine->request_buffer_size (nframes); - update_sample_rate (0); -} - int ARDOUR_UI::cmdline_new_session (string path) { @@ -3378,8 +2591,245 @@ ARDOUR_UI::cmdline_new_session (string path) path = str; } - new_session (false, path); + new_session (path); _will_create_new_session_automatically = false; /* done it */ return FALSE; /* don't call it again */ } + +void +ARDOUR_UI::use_config () +{ + Glib::RefPtr act; + + switch (Config->get_native_file_data_format ()) { + case FormatFloat: + act = ActionManager::get_action (X_("options"), X_("FileDataFormatFloat")); + break; + case FormatInt24: + act = ActionManager::get_action (X_("options"), X_("FileDataFormat24bit")); + break; + } + + if (act) { + Glib::RefPtr ract = Glib::RefPtr::cast_dynamic(act); + ract->set_active (); + } + + switch (Config->get_native_file_header_format ()) { + case BWF: + act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatBWF")); + break; + case WAVE: + act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE")); + break; + case WAVE64: + act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatWAVE64")); + break; + case iXML: + act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatiXML")); + break; + case RF64: + act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatRF64")); + break; + case CAF: + act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatCAF")); + break; + case AIFF: + act = ActionManager::get_action (X_("options"), X_("FileHeaderFormatAIFF")); + break; + } + + if (act) { + Glib::RefPtr ract = Glib::RefPtr::cast_dynamic(act); + ract->set_active (); + } + + XMLNode* node = Config->extra_xml (X_("TransportControllables")); + if (node) { + set_transport_controllable_state (*node); + } +} + +void +ARDOUR_UI::update_transport_clocks (nframes_t pos) +{ + primary_clock.set (pos); + secondary_clock.set (pos); + + if (big_clock_window) { + big_clock.set (pos); + } +} + +void +ARDOUR_UI::record_state_changed () +{ + ENSURE_GUI_THREAD (mem_fun (*this, &ARDOUR_UI::record_state_changed)); + + if (!session || !big_clock_window) { + /* why bother - the clock isn't visible */ + return; + } + + switch (session->record_status()) { + case Session::Recording: + big_clock.set_widget_name ("BigClockRecording"); + break; + default: + big_clock.set_widget_name ("BigClockNonRecording"); + break; + } +} + +void +ARDOUR_UI::set_keybindings_path (string path) +{ + keybindings_path = path; +} + +void +ARDOUR_UI::save_keybindings () +{ + if (can_save_keybindings) { + AccelMap::save (keybindings_path); + } +} + +bool +ARDOUR_UI::first_idle () +{ + if (session) { + session->allow_auto_play (true); + } + can_save_keybindings = true; + return false; +} + +void +ARDOUR_UI::store_clock_modes () +{ + XMLNode* node = new XMLNode(X_("ClockModes")); + + for (vector::iterator x = AudioClock::clocks.begin(); x != AudioClock::clocks.end(); ++x) { + node->add_property ((*x)->name().c_str(), enum_2_string ((*x)->mode())); + } + + session->add_extra_xml (*node); + session->set_dirty (); +} + + + +ARDOUR_UI::TransportControllable::TransportControllable (std::string name, ARDOUR_UI& u, ToggleType tp) + : Controllable (name), ui (u), type(tp) +{ + +} + +void +ARDOUR_UI::TransportControllable::set_value (float val) +{ + if (type == ShuttleControl) { + double fract; + + if (val == 0.5f) { + fract = 0.0; + } else { + if (val < 0.5f) { + fract = -((0.5f - val)/0.5f); + } else { + fract = ((val - 0.5f)/0.5f); + } + } + + ui.set_shuttle_fract (fract); + return; + } + + if (val < 0.5f) { + /* do nothing: these are radio-style actions */ + return; + } + + char *action = 0; + + switch (type) { + case Roll: + action = X_("Roll"); + break; + case Stop: + action = X_("Stop"); + break; + case GotoStart: + action = X_("Goto Start"); + break; + case GotoEnd: + action = X_("Goto End"); + break; + case AutoLoop: + action = X_("Loop"); + break; + case PlaySelection: + action = X_("Play Selection"); + break; + case RecordEnable: + action = X_("Record"); + break; + default: + break; + } + + if (action == 0) { + return; + } + + Glib::RefPtr act = ActionManager::get_action ("Transport", action); + + if (act) { + act->activate (); + } +} + +float +ARDOUR_UI::TransportControllable::get_value (void) const +{ + float val = 0.0f; + + switch (type) { + case Roll: + break; + case Stop: + break; + case GotoStart: + break; + case GotoEnd: + break; + case AutoLoop: + break; + case PlaySelection: + break; + case RecordEnable: + break; + case ShuttleControl: + break; + default: + break; + } + + return val; +} + +void +ARDOUR_UI::TransportControllable::set_id (const string& str) +{ + _id = str; +} + +void +ARDOUR_UI::setup_profile () +{ + if (gdk_screen_width() < 1200) { + Profile->set_small_screen (); + } +}