Guitarix
gx_main_window.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009, 2010 Hermann Meyer, James Warden, Andreas Degert
3  * Copyright (C) 2011 Pete Shorthose
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  * ---------------------------------------------------------------------------
19  *
20  * This is the gx_head GUI main class
21  *
22  * ----------------------------------------------------------------------------
23  */
24 
25 #include <guitarix.h>
26 #include <gxw/GxLevelSlider.h>
27 #include <gtkmm/accelmap.h>
28 #include "jsonrpc.h"
29 
30 /****************************************************************
31  ** class TextLoggingBox
32  */
33 
34 // color depending on msg type
35 TextLoggingBox::tab_table TextLoggingBox::tagdefs[] = {
36  {"colinfo", "#cccccc"},
37  {"colwarn", "#77994f"},
38  {"colerr", "#ff8800"},
39 };
40 
42  : box(),
43  ok_button(Gtk::Stock::OK),
44  buttonbox(),
45  scrollbox(),
46  tbox(),
47  highest_unseen_msg_level(-1),
48  msg_level_changed() {
49 
50  set_default_size(640, 320);
51  set_decorated(true);
52  set_resizable(true);
53  set_gravity(Gdk::GRAVITY_SOUTH);
54  set_keep_below(false);
55  set_title(_("Logging Window"));
56  set_type_hint(Gdk::WINDOW_TYPE_HINT_UTILITY);
57  set_border_width(4);
58 
59  box.set_border_width(0);
60  scrollbox.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
61 
62  add(box);
63 
64  tbox.set_wrap_mode(Gtk::WRAP_WORD_CHAR);
65  tbox.set_border_width(0);
66  tbox.set_editable(false);
67  tbox.set_cursor_visible(false);
68  tbox.set_pixels_above_lines(0);
69  tbox.set_pixels_below_lines(2);
70  tbox.set_justification(Gtk::JUSTIFY_LEFT);
71  tbox.set_left_margin(5);
72  tbox.set_indent(0);
73 
74  Glib::RefPtr<Gtk::TextBuffer> buffer = tbox.get_buffer();
75  for (int i = 0; i < GxLogger::kMessageTypeCount; i++) {
76  tags[i] = buffer->create_tag(tagdefs[i].tagname);
77  tags[i]->property_foreground() = tagdefs[i].tag_color;
78  }
79 
80  box.add(scrollbox);
81  box.pack_end(buttonbox, Gtk::PACK_SHRINK);
82  buttonbox.set_layout(Gtk::BUTTONBOX_END);
83  buttonbox.add(ok_button);
84  buttonbox.set_border_width(4);
85  ok_button.set_can_default();
86  ok_button.grab_default();
87  ok_button.signal_clicked().connect(sigc::mem_fun(this, &TextLoggingBox::hide));
88  //signal_activate().connect(sigc::mem_fun(this, &TextLoggingBox::hide));
89  scrollbox.add(tbox);
90  tbox.set_size_request(-1, 50);
91  box.show_all();
93  sigc::mem_fun(*this, &TextLoggingBox::show_msg));
95 }
96 
98 }
99 
100 bool TextLoggingBox::on_key_press_event(GdkEventKey *event) {
101  if (event->keyval == GDK_KEY_Escape && (event->state & Gtk::AccelGroup::get_default_mod_mask()) == 0) {
102  hide();
103  return true;
104  }
105  return Gtk::Window::on_key_press_event(event);
106 }
107 
108 void TextLoggingBox::on_show() {
109  highest_unseen_msg_level = GxLogger::kMessageTypeCount;
110  Gtk::Window::on_show();
111 }
112 
113 void TextLoggingBox::on_hide() {
114  highest_unseen_msg_level = -1;
115  Gtk::Window::on_hide();
116 }
117 
118 void TextLoggingBox::show_msg(string msgbuf, GxLogger::MsgType msgtype, bool plugged) {
119  assert(0 <= msgtype && msgtype < GxLogger::kMessageTypeCount);
120 
121  // retrieve gtk text buffer
122  Glib::RefPtr<Gtk::TextBuffer> buffer = tbox.get_buffer();
123 
124  // how many lines to keep
125  const int nlines = 50;
126 
127  // delete first line when window filled up
128  int linecount = buffer->get_line_count(); // empty buffer == 1 line
129  if (linecount >= nlines) {
130  Gtk::TextIter iter1 = buffer->get_iter_at_line(0);
131  Gtk::TextIter iter2 = buffer->get_iter_at_line(1);
132  buffer->erase(iter1, iter2);
133  }
134 
135  Gtk::TextIter iter = buffer->end();
136  if (buffer->get_char_count() > 0) {
137  iter = buffer->insert(iter, "\n");
138  }
139 
140  buffer->insert_with_tag(iter, msgbuf, tags[msgtype]);
141  scrollbox.get_vadjustment()->set_value(10000);
142  // scroll to end (big value, gets clamped to max)
143 
144  // modify expander bg color is closed
145  if (msgtype > highest_unseen_msg_level) {
146  highest_unseen_msg_level = msgtype;
147  msg_level_changed();
148  }
149 }
150 
151 #if false // unused
152 /****************************************************************
153  ** KeyFinder
154  ** finds next unused Key in a GtkAccelGroup
155  */
156 
157 class KeyFinder {
158 private:
159  typedef list<GtkAccelKey> accel_list;
160  unsigned int next_key;
161  accel_list l;
162  static gboolean add_keys_to_list(GtkAccelKey *key, GClosure *cl, gpointer data);
163 public:
164  KeyFinder(Glib::RefPtr<Gtk::AccelGroup> group);
165  ~KeyFinder();
166  int operator()();
167 };
168 
169 KeyFinder::KeyFinder(Glib::RefPtr<Gtk::AccelGroup> group) {
170  next_key = GDK_a;
171  gtk_accel_group_find(group->gobj(), add_keys_to_list, static_cast<gpointer>(&l));
172 }
173 
174 KeyFinder::~KeyFinder() {
175 }
176 
177 gboolean KeyFinder::add_keys_to_list(GtkAccelKey *key, GClosure *cl, gpointer data) {
178  accel_list* l = (accel_list*)data;
179  if (key->accel_mods == GDK_SHIFT_MASK) {
180  l->push_back(*key);
181  }
182  return false;
183 }
184 
185 int KeyFinder::operator()() {
186  while (next_key <= GDK_z) {
187  bool found = false;
188  for (accel_list::iterator i = l.begin(); i != l.end(); ++i) {
189  if (next_key == i->accel_key) {
190  found = true;
191  break;
192  }
193  }
194  if (!found) {
195  return next_key++;
196  }
197  next_key++;
198  }
199  return -1;
200 }
201 #endif
202 
203 /****************************************************************
204  ** GxUiRadioMenu
205  ** adds the values of an EnumParameter as Gtk::RadioMenuItem's
206  ** to a Gtk::MenuShell
207  */
208 
209 class TubeKeys {
210 private:
211  static unsigned int keysep[];
212  unsigned int ks;
213 public:
214  TubeKeys(): ks(0) {};
215  int operator()();
216 };
217 
218 unsigned int TubeKeys::keysep[] = {
219  GDK_a, GDK_b, GDK_c, GDK_d, GDK_e, 0,
220  GDK_f, 0,
221  GDK_g, GDK_h, GDK_i, GDK_j, 0,
222  GDK_k, GDK_l, GDK_m, GDK_n, 0,
223  GDK_o, GDK_p, GDK_q, GDK_r
224 };
225 
226 inline int TubeKeys::operator()() {
227  if (ks < sizeof(keysep)/sizeof(keysep[0])) {
228  return keysep[ks++];
229  }
230  return -1;
231 }
232 
233 GxUiRadioMenu::GxUiRadioMenu(gx_engine::GxMachineBase& machine_, const std::string& id_)
234  : machine(machine_),
235  id(id_) {
236  machine.signal_parameter_value<int>(id).connect(
237  sigc::mem_fun(this, &GxUiRadioMenu::set_value));
238 }
239 
240 void GxUiRadioMenu::setup(const Glib::ustring& prefix, const Glib::ustring& postfix,
241  Glib::RefPtr<Gtk::UIManager>& uimanager, Glib::RefPtr<Gtk::ActionGroup>& actiongroup) {
242  int i, c;
243  const value_pair *p;
244  TubeKeys next_key;
245  Glib::ustring s = prefix;
246  Gtk::RadioButtonGroup group;
247  gx_engine::IntParameter& param = machine.get_parameter(id).getInt();
248  for (p = param.getValueNames(), i = 0; p->value_id; p++, i++) {
249  c = next_key();
250  if (c == 0) {
251  s += "<separator/>";
252  c = next_key();
253  }
254  Glib::ustring actname = Glib::ustring::compose("Enum_%1.%2", param.id(), p->value_id);
255  s += Glib::ustring::compose("<menuitem action=\"%1\"/>", actname);
256  Glib::RefPtr<Gtk::RadioAction> act = Gtk::RadioAction::create(group, actname, param.value_label(*p));
257  act->property_value().set_value(static_cast<int>(param.getLowerAsFloat())+i);
258  if (c > 0) {
259  actiongroup->add(act, Gtk::AccelKey(Glib::ustring::compose("<shift>%1", (char)c)));
260  } else {
261  actiongroup->add(act);
262  }
263  if (i == 0) {
264  act->signal_changed().connect(
265  sigc::mem_fun(*this, &GxUiRadioMenu::on_changed));
266  action = act;
267  }
268  //fprintf(stderr, "%s \n", p->value_id);
269  }
270  s.append(postfix);
271  uimanager->add_ui_from_string(s);
272 }
273 
274 void GxUiRadioMenu::set_value(unsigned int v) {
275  action->set_current_value(v);
276 }
277 
278 void GxUiRadioMenu::on_changed(Glib::RefPtr<Gtk::RadioAction> act) {
279  machine.set_parameter_value(id, act->get_current_value());
280 }
281 
282 
283 /****************************************************************
284  ** class Freezer
285  */
286 
288  : window(0), tag(), need_thaw(false), size_x(-1), size_y(-1) {
289 }
290 
292  thaw();
293 }
294 
295 void Freezer::freeze(Gtk::Window *w, int width, int height) {
296  if (window) {
297  thaw();
298  }
299  size_x = width;
300  size_y = height;
301  window = w;
302  Glib::RefPtr<Gdk::Window> win = window->get_window();
303  if (win) {
304  need_thaw = true;
305  win->freeze_updates();
306  }
307 }
308 
309 void Freezer::set_slot(sigc::slot<void> w) {
310  if (size_x == -1) {
311  w();
312  } else {
313  work = w;
314  }
315 }
316 
317 void Freezer::freeze_until_width_update(Gtk::Window *w, int width) {
318  int wd, ht;
319  w->get_size(wd, ht);
320  if (wd == width) {
321  return;
322  }
323  freeze(w, width, -1);
324 }
325 
326 void Freezer::freeze_and_size_request(Gtk::Window *w, int width, int height) {
327  int wd, ht;
328  w->get_size(wd, ht);
329  if (wd >= width && ht == height) {
330  return;
331  }
332  freeze(w, width, height);
333  w->set_size_request(width, height);
334 }
335 
336 bool Freezer::thaw_timeout() {
337 #ifndef NDEBUG
338  gx_print_error("freezer", "timeout");
339 #else
340  gx_print_warning("freezer", "timeout");
341 #endif
342  if (size_y != -1) {
343  window->set_size_request(-1,-1);
344  }
345  do_thaw();
346  return false;
347 }
348 
349 void Freezer::do_thaw() {
350  size_x = size_y = -1;
351  Glib::RefPtr<Gdk::Window> win = window->get_window();
352  window = 0;
353  if (!win) {
354  return;
355  }
356  if (!work.empty()) {
357  Glib::signal_idle().connect_once(work);
358  work.disconnect();
359  }
360  if (need_thaw) {
361  win->thaw_updates();
362  }
363 }
364 
365 void Freezer::thaw() {
366  if (size_x != -1) {
367  tag.disconnect();
368  do_thaw();
369  }
370 }
371 
372 bool Freezer::check_thaw(int width, int height) {
373  if (size_x == -1) {
374  return true;
375  }
376  Glib::RefPtr<Gdk::Window> win = window->get_window();
377  if (win && win->get_state()) {
378  thaw();
379  return true;
380  }
381  if (size_y == -1) {
382  if (size_x == width) {
383  window->set_size_request(-1,-1);
384  thaw();
385  return true;
386  }
387  }
388  if (size_x <= width && size_y == height) {
389  window->set_size_request(-1,-1);
390  thaw();
391  return true;
392  }
393  if (!tag.connected()) {
394  tag = Glib::signal_timeout().connect(sigc::mem_fun(*this, &Freezer::thaw_timeout), 500);
395  }
396  return false;
397 }
398 
399 
400 /****************************************************************
401  ** class MainWindow
402  */
403 
404 template <class T>
406  gx_engine::GxMachineBase& machine_, const std::string& id_, const Glib::ustring& name, const Glib::ustring& icon_name,
407  const Glib::ustring& label, const Glib::ustring& tooltip,
408  bool is_active)
409  : Gtk::ToggleAction(name, icon_name, label, tooltip, is_active),
410  machine(machine_),
411  id(id_) {
412  set_active(machine.get_parameter_value<T>(id));
413  machine.signal_parameter_value<T>(id).connect(
414  sigc::mem_fun(this, &UiToggleAction::set_active));
415 }
416 
417 template <class T>
419 }
420 
421 template <class T>
423  machine.set_parameter_value(id, get_active());
424 }
425 
426 void update_scrolled_window(Gtk::ScrolledWindow& w) {
427  Gtk::PolicyType hp, vp;
428  w.get_policy(hp, vp);
429  w.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
430  w.set_policy(hp, vp);
431 }
432 
433 /*
434 ** moving / hiding / showing parts of the UI
435 */
436 
437 void MainWindow::maybe_shrink_horizontally(bool preset_no_rack) {
438  Glib::RefPtr<Gdk::Window> w = window->get_window();
439  if (!w) {
440  return;
441  }
442  int state = w->get_state();
443  if (state & (Gdk::WINDOW_STATE_MAXIMIZED | Gdk::WINDOW_STATE_FULLSCREEN)) {
444  return;
445  }
446  Gtk::Requisition req;
447  window->size_request(req);
448  int x, y;
449  window->get_position(x, y);
450  Gdk::Geometry geom;
451  geom.min_width = req.width;
452  geom.min_height = req.height;
453  w->set_geometry_hints(geom, Gdk::HINT_MIN_SIZE);
454  if (preset_no_rack) {
455  req.height += options.preset_window_height - preset_scrolledbox->size_request().height;
456  } else {
457  req.height = std::max(req.height, options.window_height);
458  }
459  w->move_resize(x, y, req.width, req.height);
460  if (!state) {
461  freezer.freeze_until_width_update(window, req.width);
462  }
463 }
464 
465 void MainWindow::on_show_tuner() {
466  bool v = actions.tuner->get_active();
467  on_livetuner_toggled();
468  tunerbox->set_visible(v);
469  update_scrolled_window(*vrack_scrolledbox);
470 }
471 
472 void MainWindow::load_widget_pointers() {
473  bld->get_toplevel("MainWindow", window);
474  bld->find_widget("tunerbox", tunerbox);
475  bld->find_widget("vrack_scrolledbox", vrack_scrolledbox);
476  bld->find_widget("stereorackcontainerH", stereorackcontainerH);
477  bld->find_widget("stereorackcontainerV", stereorackcontainerV);
478  bld->find_widget("rackcontainer", rackcontainer);
479  bld->find_widget("stereorackbox", stereorackbox);
480  bld->find_widget("monorackcontainer", monocontainer);
481  bld->find_widget("monoampcontainer:ampdetails", monoampcontainer);
482  bld->find_widget("main_vpaned", main_vpaned);
483  bld->find_widget("amp_toplevel_box", amp_toplevel_box);
484  bld->find_widget("monobox", monobox);
485  bld->find_widget("upper_rackbox", upper_rackbox);
486  bld->find_widget("preset_scrolledbox", preset_scrolledbox);
487  bld->find_widget("preset_box_no_rack", preset_box_no_rack);
488  bld->find_widget("effects_frame_paintbox", effects_frame_paintbox);
489  bld->find_widget("insert_image", insert_image);
490  bld->find_widget("status_image", status_image);
491  bld->find_widget("jackd_image", jackd_image);
492  bld->find_widget("logstate_image", logstate_image);
493  bld->find_widget("menubox", menubox);
494  bld->find_widget("show_rack:barbutton", show_rack_button);
495  bld->find_widget("rack_order_h:barbutton", rack_order_h_button);
496  bld->find_widget("config_mode:barbutton", config_mode_button);
497  bld->find_widget("liveplay:barbutton", liveplay_button);
498  bld->find_widget("tuner:barbutton", tuner_button);
499  bld->find_widget("effects:barbutton", effects_button);
500  bld->find_widget("presets:barbutton", presets_button);
501  bld->find_widget("compress:barbutton", compress_button);
502  bld->find_widget("expand:barbutton", expand_button);
503  bld->find_widget("effects_toolpalette", effects_toolpalette);
504  bld->find_widget("amp_background:ampbox", amp_background);
505  bld->find_widget("tuner_on_off", tuner_on_off);
506  bld->find_widget("tuner_mode", tuner_mode);
507  bld->find_widget("tuner_reference_pitch", tuner_reference_pitch);
508  bld->find_widget("tuner_tuning", tuner_tuning);
509  bld->find_widget("tuner_temperament", tuner_temperament);
510  bld->find_widget("racktuner", racktuner);
511  bld->find_widget("ampdetail_compress:effect_reset", ampdetail_compress);
512  bld->find_widget("ampdetail_expand:effect_reset", ampdetail_expand);
513  bld->find_widget("ampdetail_mini", ampdetail_mini);
514  bld->find_widget("ampdetail_normal", ampdetail_normal);
515  bld->find_widget("fastmeterL", fastmeter[0]);
516  bld->find_widget("fastmeterR", fastmeter[1]);
517  bld->find_widget("preset_status", preset_status);
518  bld->find_widget("midi_out_box", midi_out_box);
519  bld->find_widget("midi_out_normal", midi_out_normal);
520  bld->find_widget("midi_out_mini", midi_out_mini);
521  bld->find_widget("midi_out_compress:effect_reset", midi_out_compress);
522  bld->find_widget("midi_out_expand:effect_reset", midi_out_expand);
523  bld->find_widget("midi_out_presets_mini", midi_out_presets_mini);
524  bld->find_widget("midi_out_presets_normal", midi_out_presets_normal);
525  bld->find_widget("channel1_button", channel1_button);
526  bld->find_widget("channel1_box", channel1_box);
527  bld->find_widget("channel2_button", channel2_button);
528  bld->find_widget("channel2_box", channel2_box);
529  bld->find_widget("channel3_button", channel3_button);
530  bld->find_widget("channel3_box", channel3_box);
531 }
532 
533 void MainWindow::on_select_preset(int idx) {
534  keyswitch.process_preset_key(idx);
535 }
536 
537 void MainWindow::rebuild_preset_menu() {
538  if (preset_list_merge_id) {
539  uimanager->remove_ui(preset_list_merge_id);
540  uimanager->remove_action_group(preset_list_actiongroup);
541  preset_list_menu_bank.clear();
542  preset_list_merge_id = 0;
543  preset_list_actiongroup.reset();
544  uimanager->ensure_update();
545  }
546  if (!machine.setting_is_preset()) {
547  return;
548  }
550  if (!pf) {
551  return;
552  }
553  preset_list_actiongroup = Gtk::ActionGroup::create("PresetList");
554  preset_list_menu_bank = machine.get_current_bank();
555  Glib::ustring s = "<menubar><menu action=\"PresetsMenu\"><menu action=\"PresetListMenu\">";
556  int idx = 0;
557  for (gx_system::PresetFile::iterator i = pf->begin(); i != pf->end(); ++i, ++idx) {
558  Glib::ustring actname = "PresetList_" + i->name;
559  Glib::RefPtr<Gtk::Action> action = Gtk::Action::create(actname, i->name);
560  preset_list_actiongroup->add(
561  action, sigc::bind(sigc::mem_fun(*this, &MainWindow::on_select_preset), idx));
562  if (idx <= 9) {
563  char c = (idx == 9 ? '0' : '1'+idx);
564  Gtk::AccelMap::change_entry(action->get_accel_path(), c, Gdk::ModifierType(0), true);
565  }
566  s += Glib::ustring::compose("<menuitem action=\"%1\"/>", actname);
567  }
568  s += "</menu></menu></menubar>";
569  uimanager->insert_action_group(preset_list_actiongroup);
570  preset_list_merge_id = uimanager->add_ui_from_string(s);
571  dynamic_cast<Gtk::MenuItem*>(uimanager->get_widget("/menubar/PresetsMenu/PresetListMenu"))->set_label(_("_Bank: ")+preset_list_menu_bank);
572 }
573 
574 void MainWindow::show_selected_preset() {
575  keyswitch.deactivate();
576  Glib::ustring t;
577  if (machine.setting_is_preset()) {
578  t = machine.get_current_bank() + " / " + machine.get_current_name();
579  if (preset_list_menu_bank != machine.get_current_bank()) {
580  rebuild_preset_menu();
581  }
582  }
583  preset_status->set_text(t);
584 }
585 
586 bool MainWindow::is_variable_size() {
587  return actions.presets->get_active() || actions.show_rack->get_active();
588 }
589 
590 void MainWindow::maybe_change_resizable() {
591  Glib::RefPtr<Gdk::Window> w = window->get_window();
592  if (w && w->get_state() != 0) {
593  return;
594  }
595  if (!is_variable_size() && window->get_resizable()) {
596  window->set_resizable(false);
597  } else if (!window->get_resizable()) {
598  window->set_resizable(true);
599  }
600 }
601 
602 void MainWindow::set_vpaned_handle() {
603  int w, h;
604  main_vpaned->get_handle_window()->get_size(w, h);
605  int pos = main_vpaned->get_allocation().get_height() - options.preset_window_height - h;
606  main_vpaned->set_position(pos);
607 }
608 
609 void MainWindow::on_show_rack() {
610  Gtk::Widget *w;
611  if (rackbox_stacked_vertical()) {
612  w = stereorackcontainerV;
613  } else {
614  w = stereorackbox;
615  }
616  bool v = options.system_show_rack = actions.show_rack->get_active();
617  actions.rackh->set_sensitive(v);
618  stereorackcontainer.set_visible(v);
619  rack_order_h_button->set_visible(v);
620  compress_button->set_visible(v);
621  expand_button->set_visible(v);
622  if (actions.presets->get_active() && preset_scrolledbox->get_mapped()) {
623  options.preset_window_height = preset_scrolledbox->get_allocation().get_height();
624  }
625  if (v) {
626  midi_out_box->set_visible(actions.midi_out->get_active());
627  options.window_height = max(options.window_height, window->size_request().height);
628  main_vpaned->set_position(oldpos);
629  w->show();
630  monoampcontainer->show();
631  monorackcontainer.show_entries();
632  vrack_scrolledbox->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_ALWAYS);
633  vrack_scrolledbox->set_size_request(scrl_size_x, scrl_size_y);
634  if (preset_scrolledbox->get_parent() != main_vpaned) {
635  preset_box_no_rack->remove(*preset_scrolledbox);
636  main_vpaned->add(*preset_scrolledbox);
637  change_expand(*preset_box_no_rack, false);
638  change_expand(*main_vpaned, true);
639  }
640  Glib::RefPtr<Gdk::Window> win = window->get_window();
641  if (!win || win->get_state() == 0) {
642  Gtk::Requisition req;
643  window->size_request(req);
644  req.height = max(req.height, options.window_height);
645  freezer.freeze_and_size_request(window, req.width, req.height);
646  if (win && actions.presets->get_active()) {
647  freezer.set_slot(sigc::mem_fun(this, &MainWindow::set_vpaned_handle));
648  }
649  }
650  } else {
651  if (actions.midi_out->get_active()) {
652  midi_out_box->set_visible(false);
653  }
654  actions.show_plugin_bar->set_active(false);
655  oldpos = main_vpaned->get_position();
656  w->hide();
657  monoampcontainer->hide();
658  monorackcontainer.hide_entries();
659  if (preset_scrolledbox->get_parent() == main_vpaned) {
660  main_vpaned->remove(*preset_scrolledbox);
661  preset_box_no_rack->add(*preset_scrolledbox);
662  change_expand(*main_vpaned, false);
663  change_expand(*preset_box_no_rack, true);
664  }
665  preset_box_no_rack->set_visible(actions.presets->get_active());
666  vrack_scrolledbox->set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_NEVER);
667  vrack_scrolledbox->get_size_request(scrl_size_x, scrl_size_y);
668  vrack_scrolledbox->set_size_request(-1,-1);
669  if (actions.presets->get_active()) {
670  maybe_shrink_horizontally(true);
671  } else {
672  maybe_shrink_horizontally();
673  }
674  }
675  maybe_change_resizable();
676 }
677 
678 void MainWindow::on_compress_all() {
679  plugin_dict.compress(true);
680  on_ampdetail_switch(true, true);
681  actions.midi_out_plug->set_active(true);
682 }
683 
684 void MainWindow::on_expand_all() {
685  plugin_dict.compress(false);
686  on_ampdetail_switch(false, true);
687  actions.midi_out_plug->set_active(false);
688 }
689 
690 void MainWindow::on_rack_configuration() {
691  bool v = actions.rack_config->get_active();
692  actions.show_plugin_bar->set_sensitive(!v);
693  actions.show_rack->set_sensitive(!v);
694  actions.tuner->set_sensitive(!v);
695  actions.compress->set_sensitive(!v);
696  actions.expand->set_sensitive(!v);
697  actions.live_play->set_sensitive(!v);
698  Gtk::Requisition req;
699  monobox->size_request(req);
700  stereorackcontainer.set_config_mode(v);
701  monorackcontainer.set_config_mode(v);
702  szg_rack_units->set_ignore_hidden(v);
703  bool plugin_bar = actions.show_plugin_bar->get_active();
704  if (v) {
705  pre_act = actions.presets->get_active();
706  if (pre_act) {
707  actions.presets->set_active(false);
708  }
709  actions.show_rack->set_active(true);
710  effects_frame_paintbox->show();
711  upper_rackbox->hide();
712  Gtk::Requisition req2;
713  effects_frame_paintbox->size_request(req2);
714  int width = req.width;
715  if (!plugin_bar) {
716  if (rackbox_stacked_vertical()) {
717  width -= req2.width;
718  } else {
719  if (req2.width & 1) {
720  req2.width += 1;
721  }
722  width -= req2.width/2;
723  }
724  }
725  effects_frame_paintbox->set_size_request(req2.width, -1);
726  monobox->set_size_request(width,-1);
727  } else {
728  if (!plugin_bar) {
729  effects_frame_paintbox->hide();
730  }
731  upper_rackbox->show();
732  effects_frame_paintbox->set_size_request(-1,-1);
733  monobox->set_size_request(-1,-1);
734  if (pre_act) {
735  actions.presets->set_active(true);
736  }
737  }
738  if (!plugin_bar) {
739  update_width();
740  maybe_shrink_horizontally();
741  }
742 }
743 
744 void MainWindow::on_show_plugin_bar() {
745  bool v = options.system_show_toolbar = actions.show_plugin_bar->get_active();
746  if (v) {
747  actions.show_rack->set_active(true);
748  }
749  effects_frame_paintbox->set_visible(v);
750  if (!v) {
751  //update_scrolled_window(*vrack_scrolledbox);
752  //update_scrolled_window(*stereorackbox);
753  maybe_shrink_horizontally();
754  }
755 }
756 
757 void MainWindow::move_widget(Gtk::Widget& w, Gtk::Box& b1, Gtk::Box& b2) {
758  // reparent does not always work when child is hidden
759  // (sometimes wrong position when shown later),
760  // use remove / add
761  b1.remove(w);
762  b1.hide();
763  b2.pack_start(w);
764  b2.show();
765 }
766 
767 int MainWindow::rackbox_stacked_vertical() const {
768  return !actions.rackh->get_active();
769 }
770 
771 void MainWindow::change_expand(Gtk::Widget& w, bool value) {
772  Gtk::Box *p = dynamic_cast<Gtk::Box*>(w.get_parent());
773  int expand, fill;
774  unsigned int padding;
775  GtkPackType pack_type;
776  gtk_box_query_child_packing(p->gobj(), w.gobj(), &expand, &fill, &padding, &pack_type);
777  gtk_box_set_child_packing(p->gobj(), w.gobj(), value, value, padding, pack_type);
778 }
779 
780 double MainWindow::stop_at_stereo_bottom(double off, double step_size, double pagesize) {
781  Gtk::Allocation alloc = stereorackcontainer.get_allocation();
782  double lim = alloc.get_y() + alloc.get_height() - pagesize;
783  if (off >= lim) {
784  return off;
785  }
786  return min(off+step_size, lim);
787 }
788 
789 double MainWindow::stop_at_mono_top(double off, double step_size) {
790  Gtk::Allocation alloc = monorackcontainer.get_allocation();
791  if (off < alloc.get_y()) {
792  return off;
793  }
794  return max(off-step_size, double(alloc.get_y()));
795 }
796 
797 void MainWindow::on_dir_changed() {
798  bool v = options.system_order_rack_h = actions.rackh->get_active();
799  if (v) {
800  // horizontally
801  move_widget(stereorackcontainer, *stereorackcontainerV, *stereorackcontainerH);
802  change_expand(*monobox, true);
803  stereorackbox->show();
804  } else {
805  move_widget(stereorackcontainer, *stereorackcontainerH, *stereorackcontainerV);
806  change_expand(*monobox, false);
807  stereorackbox->hide();
808  maybe_shrink_horizontally();
809  }
810 }
811 
812 void MainWindow::on_configure_event(GdkEventConfigure *ev) {
813  if (freezer.check_thaw(ev->width, ev->height)) {
814  if (actions.show_rack->get_active()) {
815  options.window_height = ev->height;
816  }
817  }
818 }
819 
821 {
822  if (ch == &monorackcontainer && !actions.rackh->get_active()) {
823  stereorackcontainer.queue_draw();
824  }
825 }
826 
828  update_scrolled_window(*vrack_scrolledbox);
829  update_scrolled_window(*stereorackbox);
830 }
831 
832 RackBox *MainWindow::add_rackbox_internal(PluginUI& plugin, Gtk::Widget *mainwidget, Gtk::Widget *miniwidget,
833  bool mini, int pos, bool animate, Gtk::Widget *bare) {
834  RackBox *r = new RackBox(plugin, *this, bare);
835  if (mini) {
836  r->swtch(true);
837  }
838  r->pack(mainwidget, miniwidget, szg_rack_units);
839  update_width();
840  if (plugin.get_type() == PLUGIN_TYPE_MONO) {
841  monorackcontainer.add(*manage(r), pos);
842  } else {
843  stereorackcontainer.add(*manage(r), pos);
844  }
845  if (animate) {
846  r->animate_insert();
847  }
848  return r;
849 }
850 
851 RackBox *MainWindow::add_rackbox(PluginUI& pl, bool mini, int pos, bool animate) {
852  Gtk::Widget *mainwidget = 0;
853  Gtk::Widget *miniwidget = 0;
854  boxbuilder.get_box(pl.get_id(), mainwidget, miniwidget);
855  if (!mainwidget) {
856  gx_gui::UiBuilderImpl builder(this, &boxbuilder);
857 
858  if (machine.load_unit(builder, pl.plugin->get_pdef())) {
859  boxbuilder.fetch(mainwidget, miniwidget);
860  }
861  }
862  return add_rackbox_internal(pl, mainwidget, miniwidget, mini, pos, animate);
863 }
864 
865 void MainWindow::add_icon(const std::string& name) {
866  PluginUI *p = plugin_dict[name];
867  p->toolitem->show();
868 }
869 
870 void MainWindow::on_show_values() {
871  options.system_show_value = actions.show_values->get_active();
872  std::string s =
873  "style \"ShowValue\" {\n"
874  " GxRegler::show-value = " + gx_system::to_string(options.system_show_value) + "\n"
875  "}\n"
876  "class \"*GxRegler*\" style:highest \"ShowValue\"\n";
877  gtk_rc_parse_string(s.c_str());
878  gtk_rc_reset_styles(gtk_settings_get_default());
879 }
880 
881 void MainWindow::on_preset_action() {
882  bool v = options.system_show_presets = actions.presets->get_active();
883  if (!v && preset_scrolledbox->get_mapped()) {
884  options.preset_window_height = preset_scrolledbox->get_allocation().get_height();
885  }
886  maybe_change_resizable();
887  if (v && !actions.show_rack->get_active()) {
888  Glib::RefPtr<Gdk::Window> win = window->get_window();
889  if (!win || win->get_state() == 0) {
890  Gtk::Requisition req;
891  window->size_request(req);
892  freezer.freeze_and_size_request(window, req.width, req.height+options.preset_window_height);
893  }
894  }
895  preset_box_no_rack->set_visible(v);
896  preset_window->on_preset_select(v, use_animations() && actions.show_rack->get_active(), options.preset_window_height);
897 }
898 
899 /*
900 ** UI initialization
901 */
902 
903 bool MainWindow::on_my_leave_out(GdkEventCrossing *focus) {
904  Glib::RefPtr<Gdk::Window> wind = window->get_window();
905  wind->set_cursor();
906  return true;
907 }
908 
909 bool MainWindow::on_my_enter_in(GdkEventCrossing *focus) {
910  Glib::RefPtr<Gdk::Window> wind = window->get_window();
911  Gdk::Cursor cursor(Gdk::HAND1);
912  wind->set_cursor(cursor);
913  return true;
914 }
915 
916 void MainWindow::add_toolitem(PluginUI& pl, Gtk::ToolItemGroup *gw) {
917  Gtk::ToolItem *tb = new Gtk::ToolItem();
918  tb->set_use_drag_window(true);
919  tb->signal_drag_begin().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::on_ti_drag_begin), sigc::ref(pl)));
920  tb->signal_drag_end().connect(sigc::mem_fun(*this, &MainWindow::on_ti_drag_end));
921  tb->signal_drag_data_delete().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::on_ti_drag_data_delete), pl.get_id()));
922  tb->signal_button_press_event().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::on_ti_button_press), pl.get_id()));
923  tb->add_events(Gdk::ENTER_NOTIFY_MASK|Gdk::LEAVE_NOTIFY_MASK);
924  tb->signal_leave_notify_event().connect(sigc::mem_fun(*this, &MainWindow::on_my_leave_out));
925  tb->signal_enter_notify_event().connect(sigc::mem_fun(*this, &MainWindow::on_my_enter_in));
926  std::vector<Gtk::TargetEntry> listTargets;
927  if (pl.get_type() == PLUGIN_TYPE_MONO) {
928  listTargets.push_back(Gtk::TargetEntry("application/x-gtk-tool-palette-item-mono", Gtk::TARGET_SAME_APP, 0));
929  } else {
930  listTargets.push_back(Gtk::TargetEntry("application/x-gtk-tool-palette-item-stereo", Gtk::TARGET_SAME_APP, 0));
931  }
932  tb->drag_source_set(listTargets, Gdk::BUTTON1_MASK, Gdk::ACTION_MOVE);
933  tb->signal_drag_data_get().connect(sigc::bind(sigc::mem_fun(*this, &MainWindow::on_ti_drag_data_get), pl.get_id()));
934  Gtk::Image *img = new Gtk::Image(pl.icon);
935  if (!pl.tooltip.empty()) {
936  img->set_tooltip_text(pl.tooltip);
937  }
938  tb->add(*manage(img));
939  tb->show_all();
940  pl.toolitem = tb;
941  gw->add(*manage(tb));
942  pl.group = gw;
943 }
944 
945 bool MainWindow::on_visibility_notify(GdkEventVisibility *ev) {
946  bool v = ev->state != GDK_VISIBILITY_FULLY_OBSCURED;
947  if (v == is_visible) {
948  return false;
949  }
950  is_visible = v;
951  return false;
952 }
953 
954 void MainWindow::on_live_play() {
955  live_play->on_live_play(actions.live_play);
956 }
957 
958 void MainWindow::on_ti_drag_begin(const Glib::RefPtr<Gdk::DragContext>& context, const PluginUI& plugin) {
959  drag_icon = new DragIcon(plugin, context, options);
960 }
961 
962 void MainWindow::on_ti_drag_end(const Glib::RefPtr<Gdk::DragContext>& context) {
963  if (drag_icon) {
964  delete drag_icon;
965  drag_icon = 0;
966  }
967 }
968 
969 void MainWindow::on_ti_drag_data_get(const Glib::RefPtr<Gdk::DragContext>& context, Gtk::SelectionData& selection, int info, int timestamp, const char *effect_id) {
970  selection.set(*context->get_targets().begin(), effect_id);
971 }
972 
973 void MainWindow::hide_effect(const std::string& name) {
974  Gtk::ToolItem *toolitem = plugin_dict[name]->toolitem;
975  if (toolitem) {
976  toolitem->hide();
977  }
978 }
979 
980 void MainWindow::on_ti_drag_data_delete(const Glib::RefPtr<Gdk::DragContext>& context, const char *effect_id) {
981  hide_effect(effect_id);
982 }
983 
984 bool MainWindow::on_ti_button_press(GdkEventButton *ev, const char *effect_id) {
985  if (ev->type == GDK_2BUTTON_PRESS) {
986  get_plugin(effect_id)->display_new();
987  return true;
988  }
989  return false;
990 }
991 
992 void MainWindow::on_tp_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& context, int x, int y, const Gtk::SelectionData& data, int info, int timestamp) {
993  Glib::ustring id = data.get_data_as_string();
994  PluginUI *p = get_plugin(id);
995  p->display(false, false);
996  add_icon(id);
997  p->group->set_collapsed(false);
998 }
999 
1000 void MainWindow::jack_connection() {
1001  bool v = actions.jackserverconnection->get_active();
1002  if (!connect_jack(v)) {
1003  actions.jackserverconnection->set_active(!v);
1004  }
1005 }
1006 
1007 void MainWindow::on_portmap_response(int) {
1008  actions.jackports->set_active(false);
1009 }
1010 
1011 void MainWindow::on_portmap_activate() {
1012  gx_jack::GxJack *jack = machine.get_jack();
1013  if (!jack) {
1014  return;
1015  }
1016  if (actions.jackports->get_active()) {
1017  if (portmap_window) {
1018  return;
1019  }
1020  portmap_window = gx_portmap::PortMapWindow::create(machine, actions.accels);
1021  portmap_window->signal_response().connect(
1022  sigc::mem_fun(*this, &MainWindow::on_portmap_response));
1023  } else {
1024  if (!portmap_window) {
1025  return;
1026  }
1027  delete portmap_window;
1028  portmap_window = 0;
1029  }
1030 }
1031 
1032 void MainWindow::on_miditable_toggle() {
1033  gx_main_midi::MidiControllerTable::toggle(machine, actions.midicontroller);
1034 }
1035 
1036 void MainWindow::change_skin(Glib::RefPtr<Gtk::RadioAction> action) {
1037  set_new_skin(options.skin[action->get_current_value()]);
1038 }
1039 
1040 void MainWindow::set_new_skin(const Glib::ustring& skin_name) {
1041  if (!skin_name.empty()) {
1042  options.skin_name = skin_name;
1043  string rcfile = options.get_style_filepath(
1044  "gx_head_" + skin_name + ".rc");
1045  gtk_rc_parse(rcfile.c_str());
1046  gtk_rc_reset_styles(gtk_settings_get_default());
1047  make_icons();
1048  }
1049 }
1050 
1051 void MainWindow::add_skin_menu() {
1052  Glib::ustring s = "<menubar><menu action=\"OptionsMenu\"><menu action=\"SkinMenu\">";
1053  int idx = 0;
1054  Gtk::RadioButtonGroup sg;
1055  for (vector<Glib::ustring>::iterator i = options.skin.skin_list.begin();
1056  i != options.skin.skin_list.end();
1057  ++i) {
1058  Glib::ustring name = *i;
1059  Glib::ustring actname = Glib::ustring::compose("ChangeSkin_%1", name);
1060  s += Glib::ustring::compose("<menuitem action=\"%1\"/>", actname);
1061  Glib::RefPtr<Gtk::RadioAction> action = Gtk::RadioAction::create(sg, actname, name);
1062  if (name == options.skin_name) {
1063  action->set_active(true);
1064  }
1065  actions.group->add(action);
1066  if (idx == 0) {
1067  actions.skin = action;
1068  }
1069  action->property_value().set_value(idx++);
1070  }
1071  actions.skin->signal_changed().connect(
1072  sigc::mem_fun(*this, &MainWindow::change_skin));
1073  s.append("</menu></menu></menubar>");
1074  uimanager->add_ui_from_string(s);
1075 }
1076 
1080 };
1081 
1082 // check user's decision to turn off latency change warning
1083 void MainWindow::user_disable_latency_warn(Gtk::CheckButton* disable_warn) {
1084  options.no_warn_latency = disable_warn->get_active();
1085 }
1086 
1087 int MainWindow::gx_wait_latency_warn() {
1088  Gtk::Dialog warn_dialog;
1089  // no set_destroy_with_parent() ??
1090  warn_dialog.property_destroy_with_parent().set_value(true);
1091 
1092  Gtk::VBox box(0, 4);
1093  Gtk::Label labelt(_("\nWARNING\n"));
1094  Gtk::Label labelt1(
1095  _("CHANGING THE JACK_BUFFER_SIZE ON THE FLY \n"
1096  "MAY CAUSE UNPREDICTABLE EFFECTS \n"
1097  "TO OTHER RUNNING JACK APPLICATIONS. \n"
1098  "DO YOU WANT TO PROCEED ?"));
1099  Gdk::Color colorGreen("#969292");
1100  labelt1.modify_fg(Gtk::STATE_NORMAL, colorGreen);
1101  Pango::FontDescription font = labelt1.get_style()->get_font();
1102  font.set_size(10*Pango::SCALE);
1103  font.set_weight(Pango::WEIGHT_BOLD);
1104  labelt1.modify_font(font);
1105 
1106  Gdk::Color colorWhite("#ffffff");
1107  labelt.modify_fg(Gtk::STATE_NORMAL, colorWhite);
1108  font = labelt.get_style()->get_font();
1109  font.set_size(14*Pango::SCALE);
1110  font.set_weight(Pango::WEIGHT_BOLD);
1111  labelt.modify_font(font);
1112 
1113  warn_dialog.add_button(_("Yes"), kChangeLatency);
1114  warn_dialog.add_button(_("No"), kKeepLatency);
1115 
1116  Gtk::HBox box1(0, 4);
1117  Gtk::HBox box2(0, 4);
1118 
1119  Gtk::CheckButton disable_warn;
1120  disable_warn.signal_clicked().connect(
1121  sigc::bind(
1122  sigc::mem_fun(*this, &MainWindow::user_disable_latency_warn),
1123  &disable_warn));
1124 
1125  Gtk::Label labelt2(
1126  _("Don't bother me again with such a question, "
1127  "I know what I am doing"));
1128 
1129  box.add(labelt);
1130  box.add(labelt1);
1131  box.add(box2);
1132  box.add(box1);
1133  box1.add(disable_warn);
1134  box1.add(labelt2);
1135  warn_dialog.get_vbox()->add(box);
1136 
1137  labelt2.modify_fg(Gtk::STATE_NORMAL, colorWhite);
1138 
1139  font = labelt2.get_style()->get_font();
1140  font.set_size(8*Pango::SCALE);
1141  font.set_weight(Pango::WEIGHT_NORMAL);
1142  labelt2.modify_font(font);
1143 
1144  box.show_all();
1145 
1146  return warn_dialog.run();
1147 }
1148 
1149 void MainWindow::change_latency(Glib::RefPtr<Gtk::RadioAction> action) {
1150  // are we a proper jack gxjack.client ?
1151  gx_jack::GxJack *jack = machine.get_jack();
1152  if (!jack) {
1153  return;
1154  }
1155  if (!jack->client) {
1157  _("Jack Buffer Size setting"),
1158  _("we are not a jack gxjack.client, server may be down")
1159  );
1160  return;
1161  }
1162  jack_nframes_t buf_size = action->get_current_value();
1163  if (buf_size == jack->get_jack_bs()) {
1164  return;
1165  }
1166  if (!options.no_warn_latency && gx_wait_latency_warn() != kChangeLatency) {
1167  Glib::signal_idle().connect_once(
1168  sigc::bind(
1169  sigc::mem_fun(action.operator->(), &Gtk::RadioAction::set_current_value), jack->get_jack_bs()));
1170  } else {
1171  if (jack_set_buffer_size(jack->client, buf_size) != 0)
1172  gx_print_warning(_("Setting Jack Buffer Size"),
1173  _("Could not change latency"));
1174  }
1175  gx_print_info(
1176  _("Jack Buffer Size"),
1177  boost::format(_("latency is %1%")) % jack_get_buffer_size(jack->client));
1178 }
1179 
1180 void MainWindow::add_latency_menu() {
1181  Glib::ustring s = "<menubar><menu action=\"EngineMenu\"><menu action=\"JackLatency\">";
1182  Gtk::RadioButtonGroup group;
1183  const int min_pow = 4; // 2**4 = 16
1184  const int max_pow = 13; // 2**13 = 8192
1185  int jack_buffer_size = 16;
1186  for (int i = 0; i <= max_pow-min_pow; ++i) {
1187  Glib::ustring name = gx_system::to_string(jack_buffer_size);
1188  Glib::ustring actname = Glib::ustring::compose("Latency_%1", name);
1189  s += Glib::ustring::compose("<menuitem action=\"%1\"/>", actname);
1190  Glib::RefPtr<Gtk::RadioAction> action = Gtk::RadioAction::create(group, actname, name);
1191  actions.group->add(action);
1192  if (i == 0) {
1193  action->signal_changed().connect(
1194  sigc::mem_fun(*this, &MainWindow::change_latency));
1195  actions.latency = action;
1196  }
1197  action->property_value().set_value(jack_buffer_size);
1198  jack_buffer_size *= 2;
1199  }
1200  s.append("</menu></menu></menubar>");
1201  uimanager->add_ui_from_string(s);
1202 }
1203 
1204 void MainWindow::set_latency() {
1205  gx_jack::GxJack *jack = machine.get_jack();
1206  if (!jack) {
1207  return;
1208  }
1209  jack_nframes_t n = jack->get_jack_bs();
1210  if (n > 0) {
1211  actions.latency->set_current_value(n);
1212  }
1213  if (n > 1023) actions.osc_buffer_menu->set_sensitive(false);
1214  else actions.osc_buffer_menu->set_sensitive(true);
1215 }
1216 
1218  GError *error = NULL;
1219  gtk_show_uri(gdk_screen_get_default(), "http://guitarix.sourceforge.net/forum/",
1220  gtk_get_current_event_time(), &error);
1221  if (error)
1222  {
1223  gx_print_error("guitarix help",
1224  _("failed to load online help "));
1225  g_error_free(error);
1226  }
1227 }
1228 
1230  Glib::signal_idle().connect_once(sigc::ptr_fun( show_forum_help));
1231 }
1232 
1233 // ----menu funktion about
1235  static string about;
1236  if (about.empty()) {
1237  about +=_("<b>Guitarix:gx_head</b> (");
1238  about += GX_VERSION;
1239  about +=
1240  _(")\n\nThis Application is to a large extent provided"
1241  "\nwith the marvelous faust compiler.Yann Orlary"
1242  "\n(http://faust.grame.fr/)"
1243  "\n\nA large part is based on the work of Julius Orion Smith"
1244  "\n(htttp://ccrma.stanford.edu/realsimple/faust/)"
1245  "\nand Albert Graef\n(http://q-lang.sourceforge.net/examples.html#Faust)"
1246  "\n\n");
1247 
1248 
1249  about +=
1250  _("for impulse response it use zita-convolver"
1251  "\nby Fons Adriaensen"
1252  "\n(http://www.kokkinizita.net/linuxaudio/index.html)"
1253  "\n\nThe included IR-files are contributed by"
1254  "\nDavid Fau Casquel (BESTPLUGINS)"
1255  "\nhome: http://www.youtube.com/bestplugins"
1256  "\n\nauthors: Hermann Meyer &lt;brummer-@web.de&gt;"
1257  "\nauthors: James Warden &lt;warjamy@yahoo.com&gt;"
1258  "\nauthors: Andreas Degert &lt;andreas.degert@googlemail.com&gt;"
1259  "\nauthors: Pete Shorthose &lt;pshorthose@gmail.com&gt;"
1260  "\nauthors: Markus Schmidt &lt;schmidt@boomshop.net&gt;"
1261  "\n\nwebsite: http://guitarix.org/\n");
1262  }
1263 
1264  gx_gui::gx_message_popup(about.c_str());
1265 }
1266 
1267 void MainWindow::set_tooltips() {
1268  options.system_show_tooltips = actions.tooltips->get_active();
1269  gtk_settings_set_long_property(
1270  gtk_settings_get_default(), "gtk-enable-tooltips", options.system_show_tooltips,
1271  "gx_head menu-option");
1272 }
1273 
1274 void MainWindow::set_animations() {
1275  options.system_animations = actions.animations->get_active();
1276 }
1277 
1278 void MainWindow::on_select_jack_control() {
1279  if (select_jack_control) {
1280  select_jack_control->present();
1281  } else {
1282  select_jack_control = gx_gui::SelectJackControlPgm::create(options, machine);
1283  select_jack_control->signal_close().connect(
1284  sigc::mem_fun(*this, &MainWindow::delete_select_jack_control));
1285  select_jack_control->set_transient_for(*window);
1286  select_jack_control->show();
1287  }
1288 }
1289 
1290 void MainWindow::delete_select_jack_control() {
1291  delete select_jack_control;
1292  select_jack_control = 0;
1293 }
1294 
1295 // show loggingbox
1296 void MainWindow::on_log_activate() {
1297  if (actions.loggingbox->get_active()) {
1298  gint rxorg, ryorg;
1299  window->get_position(rxorg, ryorg);
1300  fLoggingWindow.move(rxorg+5, ryorg+272);
1301  fLoggingWindow.show_all();
1302  on_msg_level_changed();
1303  } else {
1304  fLoggingWindow.hide();
1305  }
1306 }
1307 // show loggingbox
1308 bool MainWindow::on_log_activated(GdkEventButton* ev) {
1309  if (ev->type == GDK_BUTTON_PRESS && ev->button == 1) {
1310  if (!actions.loggingbox->get_active()) {
1311  actions.loggingbox->set_active(true);
1312  gint rxorg, ryorg;
1313  window->get_position(rxorg, ryorg);
1314  fLoggingWindow.move(rxorg+5, ryorg+272);
1315  fLoggingWindow.show_all();
1316  on_msg_level_changed();
1317  } else {
1318  fLoggingWindow.hide();
1319  actions.loggingbox->set_active(false);
1320  }
1321  }
1322  return true;
1323 }
1324 
1325 void MainWindow::on_engine_toggled() {
1327  if (actions.engine_mute->get_active()) {
1329  } else if (actions.engine_bypass->get_active()) {
1331  } else {
1333  }
1334  machine.set_state(s);
1335 }
1336 
1337 void MainWindow::set_switcher_controller() {
1338  if (!machine.midi_get_config_mode()) {
1339  new gx_main_midi::MidiConnect(0, machine.get_parameter("ui.live_play_switcher"), machine);
1340  }
1341 }
1342 
1343 void MainWindow::on_show_midi_out() {
1344 #ifdef USE_MIDI_OUT
1345  if (actions.midi_out->get_active()) {
1346  actions.show_rack->set_active(true);
1347  midi_out_box->set_visible(true);
1348  } else {
1349  midi_out_box->set_visible(false);
1350  machine.pluginlist_lookup_plugin("midi_out")->set_on_off(false);
1351  }
1352 #endif
1353 }
1354 
1355 void MainWindow::on_show_midi_out_plug() {
1356  if (actions.midi_out_plug->get_active()) {
1357  midi_out_normal->hide();
1358  midi_out_mini->show();
1359  } else {
1360  midi_out_mini->hide();
1361  midi_out_normal->show();
1362  }
1363 }
1364 
1365 void MainWindow::on_midi_out_channel_toggled(Gtk::RadioButton *rb, Gtk::Container *c) {
1366  c->set_visible(rb->get_active());
1367 }
1368 
1369 void MainWindow::on_livetuner_toggled() {
1370  if (actions.livetuner->get_active()) {
1371  if (actions.live_play->get_active()) {
1372  live_play->display_tuner(true);
1373  racktuner->set_sensitive(false);
1374  machine.tuner_used_for_display(true);
1375  } else {
1376  live_play->display_tuner(false);
1377  if (actions.tuner->get_active()) {
1378  racktuner->set_sensitive(true);
1379  machine.tuner_used_for_display(true);
1380  } else {
1381  machine.tuner_used_for_display(false);
1382  }
1383  }
1384  } else {
1385  live_play->display_tuner(false);
1386  racktuner->set_sensitive(false);
1387  machine.tuner_used_for_display(false);
1388  }
1389 }
1390 
1391 void MainWindow::create_actions() {
1392  gx_jack::GxJack *jack = machine.get_jack();
1393  actions.group = Gtk::ActionGroup::create("Main");
1394  /*
1395  ** Menu actions
1396  */
1397  actions.group->add(Gtk::Action::create("EngineMenu",_("_Engine")));
1398  actions.jack_latency_menu = Gtk::Action::create("JackLatency",_("_Latency"));
1399  actions.group->add(actions.jack_latency_menu);
1400  actions.osc_buffer_menu = Gtk::Action::create("OscBuffer",_("Osc. Buffer-size"));
1401  actions.group->add(actions.osc_buffer_menu);
1402 
1403  actions.group->add(Gtk::Action::create("PresetsMenu",_("_Presets")));
1404  actions.group->add(Gtk::Action::create("PresetListMenu","--"));
1405  actions.group->add(Gtk::Action::create("PluginsMenu",_("P_lugins")));
1406  actions.group->add(Gtk::Action::create("MonoPlugins",_("_Mono Plugins")));
1407  actions.group->add(Gtk::Action::create("StereoPlugins",_("_Stereo Plugins")));
1408  actions.group->add(Gtk::Action::create("TubeMenu",_("_Tube")));
1409  actions.group->add(Gtk::Action::create("OptionsMenu",_("_Options")));
1410  actions.group->add(Gtk::Action::create("SkinMenu", _("_Skin...")));
1411  actions.group->add(Gtk::Action::create("AboutMenu",_("_About")));
1412 
1413  /*
1414  ** engine actions
1415  */
1416  actions.jackserverconnection = Gtk::ToggleAction::create("JackServerConnection", _("Jack Server _Connection"));
1417  actions.group->add(
1418  actions.jackserverconnection,
1419  sigc::mem_fun(*this, &MainWindow::jack_connection));
1420 
1421  actions.jackports = Gtk::ToggleAction::create("JackPorts", _("Jack _Ports"));
1422  actions.group->add(
1423  actions.jackports,
1424  sigc::mem_fun(*this, &MainWindow::on_portmap_activate));
1425 
1426  actions.midicontroller = Gtk::ToggleAction::create("MidiController", _("M_idi Controller"));
1427  actions.group->add(
1428  actions.midicontroller,
1429  sigc::mem_fun(*this, &MainWindow::on_miditable_toggle));
1430 
1431  actions.engine_mute = Gtk::ToggleAction::create("EngineMute", _("Engine _Mute"));
1432  actions.group->add(actions.engine_mute);
1433  actions.engine_mute_conn = actions.engine_mute->signal_toggled().connect(
1434  sigc::mem_fun(*this, &MainWindow::on_engine_toggled));
1435 
1436  actions.engine_bypass = Gtk::ToggleAction::create("EngineBypass", _("Engine _Bypass"));
1437  actions.group->add(actions.engine_bypass);
1438  actions.engine_bypass_conn = actions.engine_bypass->signal_toggled().connect(
1439  sigc::mem_fun(*this, &MainWindow::on_engine_toggled));
1440 
1441  actions.quit = Gtk::Action::create("Quit",_("_Quit"));
1442  actions.group->add(
1443  actions.quit,
1444  sigc::hide_return(sigc::mem_fun(this, &MainWindow::on_quit)));
1445 
1446  /*
1447  ** actions to open other (sub)windows
1448  */
1449  actions.presets = Gtk::ToggleAction::create(
1450  "Presets",_("_Preset Selection"));
1451  actions.group->add(actions.presets,
1452  sigc::mem_fun(*this, &MainWindow::on_preset_action));
1453 
1454  actions.show_plugin_bar = Gtk::ToggleAction::create(
1455  "ShowPluginBar",_("Show Plugin _Bar"));
1456  actions.group->add(actions.show_plugin_bar,
1457  sigc::mem_fun(*this, &MainWindow::on_show_plugin_bar));
1458 
1459  actions.show_rack = Gtk::ToggleAction::create(
1460  "ShowRack",_("Show _Rack"), "", true);
1461  actions.group->add(actions.show_rack,
1462  sigc::mem_fun(*this, &MainWindow::on_show_rack));
1463 
1464  actions.loggingbox = Gtk::ToggleAction::create("LoggingBox", _("Show _Logging Box"));
1465  actions.group->add(
1466  actions.loggingbox,
1467  sigc::mem_fun(*this, &MainWindow::on_log_activate));
1468 
1469  actions.live_play = Gtk::ToggleAction::create("Liveplay",_("Live _Display"));
1470  actions.group->add(actions.live_play,
1471  sigc::mem_fun(*this, &MainWindow::on_live_play));
1472 
1473  actions.meterbridge = Gtk::ToggleAction::create("Meterbridge", _("_Meterbridge"));
1474  if (jack) {
1475  actions.group->add(
1476  actions.meterbridge,
1477  sigc::bind(sigc::ptr_fun(gx_child_process::Meterbridge::start_stop),
1478  sigc::ref(actions.meterbridge), sigc::ref(*jack)));
1479  } else {
1480  actions.group->add(actions.meterbridge);
1481  }
1482 
1483  actions.livetuner = UiBoolToggleAction::create(
1484  machine, "ui.racktuner", "LiveTuner", "??");
1485  actions.group->add(actions.livetuner);
1486  actions.livetuner->signal_toggled().connect(
1487  sigc::mem_fun(this, &MainWindow::on_livetuner_toggled));
1488 
1489  actions.midi_out = UiBoolToggleAction::create(
1490  machine, "ui.midi_out", "MidiOut", _("M_idi Out"));
1491  actions.group->add(
1492  actions.midi_out,
1493  sigc::mem_fun(this, &MainWindow::on_show_midi_out));
1494 
1495  actions.midi_out_plug = UiBoolToggleAction::create(
1496  machine, "midi_out.s_h", "MidiOutSH", "??");
1497  actions.group->add(
1498  actions.midi_out_plug,
1499  sigc::mem_fun(this, &MainWindow::on_show_midi_out_plug));
1500 
1501  /*
1502  ** rack actions
1503  */
1504  actions.tuner = UiBoolToggleAction::create(
1505  machine, "system.show_tuner", "Tuner",_("_Tuner"));
1506  actions.group->add(actions.tuner,
1507  sigc::mem_fun(*this, &MainWindow::on_show_tuner));
1508 
1509  actions.rack_config = Gtk::ToggleAction::create("RackConfig", _("R_ack Configuration"));
1510  actions.group->add(actions.rack_config,
1511  sigc::mem_fun(*this, &MainWindow::on_rack_configuration));
1512 
1513  actions.compress = Gtk::Action::create("Compress",_("C_ompress all"));
1514  actions.group->add(actions.compress,
1515  sigc::mem_fun(*this, &MainWindow::on_compress_all));
1516 
1517  actions.expand = Gtk::Action::create("Expand",_("E_xpand all"));
1518  actions.group->add(actions.expand,
1519  sigc::mem_fun(*this, &MainWindow::on_expand_all));
1520 
1521  actions.rackh = Gtk::ToggleAction::create(
1522  "RackH", _("Order Rack _Horizontally"));
1523  actions.group->add(actions.rackh,
1524  sigc::mem_fun(*this, &MainWindow::on_dir_changed));
1525 
1526  /*
1527  ** option actions
1528  */
1529  actions.show_values = Gtk::ToggleAction::create(
1530  "ShowValues",_("_Show _Values"), "", true);
1531  actions.group->add(actions.show_values,
1532  sigc::mem_fun(*this, &MainWindow::on_show_values));
1533 
1534  actions.tooltips = Gtk::ToggleAction::create(
1535  "ShowTooltips", _("Show _Tooltips"), "", true);
1536  actions.group->add(
1537  actions.tooltips,
1538  sigc::mem_fun(this, &MainWindow::set_tooltips));
1539 
1540  actions.midi_in_presets = UiSwitchToggleAction::create(
1541  machine, "system.midi_in_preset", "MidiInPresets", _("Include MIDI in _presets"));
1542  actions.group->add(actions.midi_in_presets);
1543 
1544  actions.jackstartup = Gtk::Action::create("JackStartup", _("_Jack Startup Control"));
1545  actions.group->add(
1546  actions.jackstartup,
1547  sigc::mem_fun(*this, &MainWindow::on_select_jack_control));
1548 
1549  actions.loadladspa = Gtk::Action::create("LoadLADSPA", _("LADSPA/LV2 Pl_ugins"));
1550  actions.group->add(
1551  actions.loadladspa,
1552  sigc::mem_fun(this, &MainWindow::on_load_ladspa));
1553 
1554  actions.group->add(Gtk::Action::create("ResetAll", _("Reset _All Parameters")),
1555  sigc::mem_fun(machine, &gx_engine::GxMachineBase::set_init_values));
1556 
1557  actions.animations = Gtk::ToggleAction::create(
1558  "Animations", _("_Use Animations"),"",true);
1559  actions.group->add(actions.animations,
1560  sigc::mem_fun(this, &MainWindow::set_animations));
1561 
1562  actions.group->add(Gtk::Action::create("SetPresetSwitcher", _("L_iveplay Midi Switch")),
1563  sigc::mem_fun(this, &MainWindow::set_switcher_controller));
1564 
1565  /*
1566  ** Help and About
1567  */
1568  actions.group->add(Gtk::Action::create("Help", _("_Help")),
1569  sigc::ptr_fun(gx_show_help));
1570  actions.group->add(Gtk::Action::create("About", _("_About")),
1571  sigc::ptr_fun(gx_show_about));
1572 
1573  if (!jack) {
1574  actions.jack_latency_menu->set_visible(false);
1575  actions.jackserverconnection->set_visible(false);
1576  actions.jackports->set_visible(false);
1577  actions.meterbridge->set_visible(false);
1578  }
1579 }
1580 
1581 #if false // unused
1582 int get_current_workarea_height_from_desktop(GdkWindow *root) {
1583  // use "xprop -root" to view desktop properties
1584  GdkAtom actual_type, atom_cardinal;
1585  gint actual_format;
1586  gint num_items;
1587  int *ret_data_ptr;
1588  int idx;
1589  atom_cardinal = gdk_atom_intern("CARDINAL", false);
1590  if (!gdk_property_get(
1591  root, gdk_atom_intern("_NET_CURRENT_DESKTOP", false), atom_cardinal,
1592  0, 1, false, &actual_type, &actual_format, &num_items,
1593  (guchar**)&ret_data_ptr)) {
1594  return -1;
1595  }
1596  idx = *ret_data_ptr * 4 + 3; // [x, y, width, height] * desktop_count
1597  g_free(ret_data_ptr);
1598  if (!gdk_property_get(
1599  root, gdk_atom_intern("_NET_WORKAREA", false), atom_cardinal,
1600  idx, 1, false, &actual_type, &actual_format, &num_items,
1601  (guchar**)&ret_data_ptr)) {
1602  return -1;
1603  }
1604  if (idx >= num_items) {
1605  //??
1606  return -1;
1607  }
1608  int height = *ret_data_ptr;
1609  g_free(ret_data_ptr);
1610  return height;
1611 }
1612 
1613 int get_current_workarea_height() {
1614  // Helper fetching the current workarea (i.e. usable space) size
1615  GdkWindow *root = gdk_get_default_root_window();
1616  int height = get_current_workarea_height_from_desktop(root);
1617  if (height > 0) {
1618  return height;
1619  }
1620  int x, y, width, depth;
1621  gdk_window_get_geometry(root, &x, &y, &width, &height, &depth);
1622  return height;
1623 }
1624 #endif
1625 
1627  new PluginPresetPopup(pdef, machine);
1628 }
1629 
1630 void MainWindow::plugin_preset_popup(const PluginDef *pdef, const Glib::ustring& name) {
1631  new PluginPresetPopup(pdef, machine, name);
1632 }
1633 
1634 void MainWindow::clear_box(Gtk::Container& box) {
1635  std::vector<Gtk::Widget*> l = box.get_children();
1636  for (std::vector<Gtk::Widget*>::iterator p = l.begin(); p != l.end(); ++p) {
1637  box.remove(**p);
1638  }
1639 }
1640 
1641 void MainWindow::make_icons(bool force) {
1642  Gtk::OffscreenWindow w;
1643  w.set_type_hint(Gdk::WINDOW_TYPE_HINT_DOCK); // circumvent canberra-gtk-module bug on AV Linux
1644  Glib::RefPtr<Gdk::Screen> screen = w.get_screen();
1645  Glib::RefPtr<Gdk::Colormap> rgba = screen->get_rgba_colormap();
1646  if (rgba) {
1647  w.set_colormap(rgba);
1648  }
1649  Gtk::VBox vb;
1650  w.add(vb);
1651  Glib::RefPtr<Gtk::SizeGroup> sz = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_BOTH);
1652  std::vector<std::pair<PluginUI*,Gtk::Widget*> > l;
1653  for (std::map<std::string, PluginUI*>::iterator i = plugin_dict.begin(); i != plugin_dict.end(); ++i) {
1654  if (!force && i->second->icon) {
1655  continue;
1656  }
1657  Gtk::Widget *r = RackBox::create_icon_widget(*i->second, options);
1658  r->hide();
1659  r->set_no_show_all(true);
1660  vb.add(*manage(r));
1661  sz->add_widget(*r);
1662  l.push_back(std::pair<PluginUI*,Gtk::Widget*>(i->second, r));
1663  }
1664  //FIXME hack to set a minimum size
1665  l.begin()->second->show();
1666  if (vb.size_request().width < 110) {
1667  vb.set_size_request(110, -1);
1668  }
1669  w.show_all();
1670  for (std::vector<std::pair<PluginUI*,Gtk::Widget*> >::iterator i = l.begin(); i != l.end(); ++i) {
1671  i->second->show();
1672  w.show();
1673  w.get_window()->process_updates(true);
1674  i->first->icon = w.get_pixbuf();
1675  if (i->first->toolitem) {
1676  dynamic_cast<Gtk::Image*>(i->first->toolitem->get_child())->set(i->first->icon);
1677  }
1678  w.hide();
1679  i->second->hide();
1680  }
1681 
1682  // Amp padding
1683  hanl = gtk_widget_render_icon(GTK_WIDGET(window->gobj()), "handle_left", (GtkIconSize)-1, NULL);
1684  hanr = gtk_widget_render_icon(GTK_WIDGET(window->gobj()), "handle_right", (GtkIconSize)-1, NULL);
1685  gint wl = gdk_pixbuf_get_width(hanl);
1686  gint wr = gdk_pixbuf_get_width(hanr);
1687  g_object_unref(hanl);
1688  g_object_unref(hanr);
1689  bld->find_widget("amp_padding", vbam);
1690  vbam->set_padding(0, 4, wl, wr);
1691  bld->find_widget("tuner_padding", vbam);
1692  vbam->set_padding(0, 4, wl, wr);
1693  bld->find_widget("details_padding", vbam);
1694  vbam->set_padding(0, 4, wl, wr);
1695 }
1696 
1697 class JConvPluginUI: public PluginUI {
1698 private:
1699  virtual void on_plugin_preset_popup();
1700 public:
1701  JConvPluginUI(MainWindow& main, const char* id,
1702  const Glib::ustring& tooltip="")
1703  : PluginUI(main, id, tooltip) {
1704  }
1705 };
1706 
1707 void JConvPluginUI::on_plugin_preset_popup() {
1709  &main.get_machine().get_parameter(std::string(get_id())+".convolver"));
1710  assert(jcp);
1711  Glib::ustring name = jcp->get_value().getIRFile();
1712  Glib::ustring::size_type n = name.find_last_of('.');
1713  if (n != Glib::ustring::npos) {
1714  name.erase(n);
1715  }
1716  main.plugin_preset_popup(plugin->get_pdef(), name);
1717 }
1718 
1719 void MainWindow::on_plugin_changed(gx_engine::Plugin *pl, gx_engine::PluginChange::pc c) {
1720  if (!pl) { // end of update sequence
1721  make_icons(true); // re-create all icons, width might have changed
1722  } else if (c == gx_engine::PluginChange::add) {
1723  register_plugin(new PluginUI(*this, pl->get_pdef()->id, ""));
1724  } else {
1725  PluginUI *pui = plugin_dict[pl->get_pdef()->id];
1727  plugin_dict.remove(pui);
1728  pui->unset_ui_merge_id(uimanager);
1729  uimanager->ensure_update();
1730  actions.group->remove(pui->get_action());
1731  machine.remove_rack_unit(pui->get_id(), pui->get_type());
1732  std::string group_id = pui->get_category();
1733  delete pui;
1734  Gtk::ToolItemGroup * group = groupmap[group_id];
1735  if (group->get_n_items() == 0) {
1736  Glib::ustring groupname = Glib::ustring::compose("PluginCategory_%1", group_id);
1737  Glib::RefPtr<Gtk::Action> act = actions.group->get_action(groupname);
1738  actions.group->remove(actions.group->get_action(groupname));
1739  groupmap.erase(group_id);
1740  delete group;
1741  }
1742  } else {
1744  //if (!pui->plugin->get_box_visible())
1745  bool state = pui->plugin->get_on_off();
1746  pui->update_rackbox();
1747  pui->plugin->set_on_off(state);
1749  pui->unset_ui_merge_id(uimanager);
1750  pui->group = add_plugin_category(pui->get_category());
1751  pui->toolitem->reparent(*pui->group);
1752  add_plugin_menu_entry(pui);
1753  }
1754  }
1755  }
1756 }
1757 
1758 void MainWindow::on_ladspa_finished(bool reload, bool quit) {
1759  if (reload) {
1760  machine.commit_ladspa_changes();
1761  }
1762  if (quit) {
1763  Glib::signal_idle().connect(sigc::mem_fun(this, &MainWindow::delete_ladspalist_window));
1764  }
1765 }
1766 
1767 bool MainWindow::delete_ladspalist_window() {
1768  if (ladspalist_window) {
1769  //ladspalist_window->hide();
1770  delete ladspalist_window;
1771  ladspalist_window = 0;
1772  }
1773  return false;
1774 }
1775 
1776 void MainWindow::on_load_ladspa() {
1777  if (ladspalist_window) {
1778  ladspalist_window->present();
1779  } else {
1780  ladspalist_window = new ladspa::PluginDisplay(machine, gx_head_icon, sigc::mem_fun(this, &MainWindow::on_ladspa_finished));
1781  }
1782 }
1783 
1784 void MainWindow::add_plugin(std::vector<PluginUI*>& p, const char *id, const Glib::ustring& tooltip) {
1785  if (PluginUI::is_registered(machine, id)) {
1786  return;
1787  }
1788  p.push_back(new PluginUI(*this, id, tooltip));
1789 }
1790 
1791 #ifdef accel_keys_for_plugins
1792 struct accel_search {
1793  unsigned int key;
1794  bool res;
1795 };
1796 
1797 static void accel_search_callback(gpointer data, const gchar *accel_path, guint accel_key, GdkModifierType accel_mods, gboolean changed) {
1798  accel_search *s = static_cast<accel_search*>(data);
1799  if (accel_key == s->key && accel_mods == 0) {
1800  s->res = true;
1801  }
1802 }
1803 
1804 static bool accel_map_has_key(unsigned int accel_key) {
1805  accel_search s;
1806  s.key = accel_key;
1807  s.res = false;
1808  gtk_accel_map_foreach_unfiltered(gpointer(&s), accel_search_callback);
1809  return s.res;
1810 }
1811 
1812 static bool accel_map_next_key(unsigned int *accel_key) {
1813  while (*accel_key <= GDK_z) {
1814  if (!accel_map_has_key(*accel_key)) {
1815  return true;
1816  }
1817  *accel_key += 1;
1818  }
1819  return false;
1820 }
1821 #endif
1822 
1823 struct PluginDesc {
1824  Glib::ustring group;
1825  std::vector<PluginUI*> *plugins;
1826  PluginDesc(const Glib::ustring& g, std::vector<PluginUI*> *p)
1827  : group(g), plugins(p) {}
1828 };
1829 
1830 Gtk::ToolItemGroup *MainWindow::add_plugin_category(const char *group, bool collapse) {
1831  std::map<Glib::ustring, Gtk::ToolItemGroup*>::iterator it = groupmap.find(group);
1832  if (it != groupmap.end()) {
1833  return it->second;
1834  }
1835  Glib::ustring ui_template =
1836  "<menubar><menu action=\"PluginsMenu\"><menu action=\"%1Plugins\"><menu action=\"%2\">"
1837  "</menu></menu></menu></menubar>";
1838  Glib::ustring groupname = Glib::ustring::compose("PluginCategory_%1", group);
1839  uimanager->add_ui_from_string(Glib::ustring::compose(ui_template, "Mono", groupname));
1840  uimanager->add_ui_from_string(Glib::ustring::compose(ui_template, "Stereo", groupname));
1841  actions.group->add(Gtk::Action::create(groupname, gettext(group)));
1842  Gtk::ToolItemGroup *gw = new Gtk::ToolItemGroup(gettext(group));
1843  groupmap[group] = gw;
1844  gw->set_collapsed(collapse);
1845  effects_toolpalette->add(*manage(gw));
1846  effects_toolpalette->set_exclusive(*gw, true);
1847  effects_toolpalette->set_expand(*gw, true);
1848  return gw;
1849 }
1850 
1851 Glib::ustring MainWindow::add_plugin_menu_entry(PluginUI *pui) {
1852  Glib::ustring ui_template =
1853  "<menubar><menu action=\"PluginsMenu\"><menu action=\"%1Plugins\"><menu action=\"%2\">"
1854  "<menuitem action=\"%3\"/>"
1855  "</menu></menu></menu></menubar>";
1856  const char *group = pui->get_category();
1857  Glib::ustring groupname = Glib::ustring::compose("PluginCategory_%1", group);
1858  Glib::ustring actionname = Glib::ustring::compose("Plugin_%1", pui->get_id());
1859  const char *tp = (pui->get_type() == PLUGIN_TYPE_MONO ? "Mono" : "Stereo");
1860  pui->set_ui_merge_id(uimanager->add_ui_from_string(Glib::ustring::compose(ui_template, tp, groupname, actionname)));
1861  //fprintf(stderr, "%s : %s : %s \n", tp, group, pui->get_name());
1862  return actionname;
1863 }
1864 
1865 void MainWindow::register_plugin(PluginUI *pui) {
1866  plugin_dict.add(pui);
1867  Gtk::ToolItemGroup *gw = add_plugin_category(pui->get_category());
1868  Glib::ustring actionname = add_plugin_menu_entry(pui);
1869  add_toolitem(*pui, gw);
1870  Glib::RefPtr<Gtk::ToggleAction> act = Gtk::ToggleAction::create(actionname, pui->get_name());
1871  actions.group->add(act);
1872 #ifdef accel_keys_for_plugins
1873  unsigned int key = GDK_a;
1874  if (accel_map_next_key(&key)) {
1875  Gtk::AccelMap::add_entry(act->get_accel_path(), key, Gdk::ModifierType(0));
1876  ++key;
1877  }
1878 #endif
1879  if (pui->rackbox && pui->rackbox->get_box_visible()) {
1880  act->set_active(true);
1881  }
1882  pui->set_action(act);
1883 }
1884 
1885 void MainWindow::fill_pluginlist() {
1886  // define order of categories by registering
1887  // them first
1888  add_plugin_category(N_("Tone Control"), false);
1889  add_plugin_category(N_("Distortion"));
1890  add_plugin_category(N_("Fuzz"));
1891  add_plugin_category(N_("Reverb"));
1892  add_plugin_category(N_("Echo / Delay"));
1893  add_plugin_category(N_("Modulation"));
1894  add_plugin_category(N_("Guitar Effects"));
1895  add_plugin_category(N_("Misc"));
1896 
1897  std::vector<PluginUI*> p;
1898  p.push_back(new JConvPluginUI(*this, "jconv"));
1899  p.push_back(new JConvPluginUI(*this, "jconv_mono"));
1900 
1901  gx_gui::UiBuilderImpl builder(this, &boxbuilder, &p);
1902  machine.pluginlist_append_rack(builder);
1903 
1904  std::sort(p.begin(), p.end(), plugins_by_name_less);
1905  for (std::vector<PluginUI*>::iterator v = p.begin(); v != p.end(); ++v) {
1906  register_plugin(*v);
1907  }
1908 }
1909 
1910 // start_jack() returns:
1911 // 1: success
1912 // 0: fail
1913 // -1: no start command configured
1914 int MainWindow::start_jack() {
1915  gx_jack::GxJack *jack = machine.get_jack();
1916  if (!jack) {
1917  return -1;
1918  }
1919  int wait_after_connect = 0;
1920  gx_engine::EnumParameter& jack_starter = machine.get_parameter("ui.jack_starter_idx").getEnum();
1921  string v_id = jack_starter.get_pair().value_id;
1922  if (v_id == "autostart") {
1923  return jack->gx_jack_connection(true, true, wait_after_connect, options) ? 1 : 0;
1924  }
1925  string cmd;
1926  if (v_id == "other") {
1927  cmd = machine.get_parameter("ui.jack_starter").getString().get_value();
1928  if (cmd.empty()) {
1929  return -1;
1930  }
1931  } else if (v_id == "qjackctl") {
1932  wait_after_connect = 500000;
1933  cmd = "qjackctl --start";
1934  } else {
1935  assert(false);
1936  }
1937  gx_system::gx_system_call(cmd, true, true);
1938  for (int i = 0; i < 10; i++) {
1939  if (jack->gx_jack_connection(true,false,wait_after_connect, options)) {
1940  return 1;
1941  }
1942  usleep(500000);
1943  }
1945  _("main"),
1946  string(_("I really tried to get jack up and running, sorry ... ")));
1947  return 0;
1948 }
1949 
1950 bool MainWindow::connect_jack(bool v, Gtk::Window *splash) {
1951  gx_jack::GxJack *jack = machine.get_jack();
1952  if (!jack) {
1953  return false;
1954  }
1955  if (jack->gx_jack_connection(v, false, 0, options)) {
1956  return true;
1957  }
1958  if (!v) {
1959  gx_print_error(_("main"), _("can't disconnect jack"));
1960  return false;
1961  }
1962  bool ask = machine.get_parameter_value<bool>("ui.ask_for_jack_starter");
1963  if (!ask) {
1964  switch (start_jack()) {
1965  case 1: return true; // connected
1966  case -1: return false; // no starter, do nothing
1967  default: break; // failed, ask user
1968  }
1969  }
1970  if (splash) {
1971  splash->hide();
1972  }
1973  if (!gx_gui::gx_start_jack_dialog(gx_head_icon)) {
1974  gx_print_warning(_("main"), string(_("Ignoring jackd ...")));
1975  return false;
1976  }
1977  return start_jack() == 1;
1978 }
1979 
1980 void MainWindow::on_jack_client_changed() {
1981  if (!window) {
1982  return;
1983  }
1984  gx_jack::GxJack *jack = machine.get_jack();
1985  if (!jack) {
1986  return;
1987  }
1988  bool v = (jack->client != 0);
1989  if (!v) {
1991  }
1992  actions.jackserverconnection->set_active(v);
1993  Glib::ustring s = "Guitarix: ";
1994  if (v) {
1995  s += jack->get_instancename();
1996  } else {
1997  s += "("+jack->get_instancename()+")";
1998  }
1999  window->set_title(s);
2000  actions.jack_latency_menu->set_sensitive(v);
2001  actions.engine_mute->set_sensitive(v);
2002  actions.engine_bypass->set_sensitive(v);
2003  status_image->set_sensitive(v);
2004  if (!v) {
2005  jackd_image->set(pixbuf_jack_disconnected);
2006  } else {
2007  jackd_image->set(pixbuf_jack_connected);
2008  }
2009 }
2010 
2011 void MainWindow::on_engine_state_change(gx_engine::GxEngineState state) {
2012  switch (state) {
2013  case gx_engine::kEngineOff:
2014  actions.engine_mute_conn.block();
2015  actions.engine_mute->set_active(true);
2016  actions.engine_mute_conn.unblock();
2017  status_image->set(pixbuf_off);
2018  machine.msend_midi_cc(0xB0,120,127,3);
2019  break;
2020  case gx_engine::kEngineOn:
2021  actions.engine_mute_conn.block();
2022  actions.engine_bypass_conn.block();
2023  actions.engine_mute->set_active(false);
2024  actions.engine_bypass->set_active(false);
2025  actions.engine_mute_conn.unblock();
2026  actions.engine_bypass_conn.unblock();
2027  status_image->set(pixbuf_on);
2028  machine.msend_midi_cc(0xB0,120,0,3);
2029  break;
2031  actions.engine_mute_conn.block();
2032  actions.engine_bypass_conn.block();
2033  actions.engine_mute->set_active(false);
2034  actions.engine_bypass->set_active(true);
2035  actions.engine_mute_conn.unblock();
2036  actions.engine_bypass_conn.unblock();
2037  status_image->set(pixbuf_bypass);
2038  break;
2039  }
2040 }
2041 
2042 void MainWindow::set_tuning(Gxw::RackTuner& tuner) {
2043  static struct TuningTab {
2044  const char *name;
2045  const char* key;
2046  bool flat;
2047  int notes[6];
2048  } tuning_tab[] = {
2049  { "Standard", "E", false, {40, 45, 50, 55, 59, 64}},
2050  { "Standard/Es", "Es", true, {39, 44, 49, 54, 58, 63}},
2051  { "Open E", "E", false, {40, 47, 52, 56, 59, 64}},
2052  { "Drop D", "D", false, {38, 45, 50, 55, 59, 64}},
2053  { "Half Step Down", "E", false, {39, 44, 49, 54, 58, 63}},
2054  { "Full Step Down", "D", false, {38, 43, 48, 53, 57, 62}},
2055  { "1 and 1/2 Steps Down", "E", false, {37, 42, 47, 52, 56, 61}},
2056  { "Double Drop D", "D", false, {38, 45, 50, 55, 59, 62}},
2057  { "Drop C", "C", false, {36, 43, 48, 53, 57, 62}},
2058  { "Drop C#", "C#", false, {37, 44, 49, 54, 58, 63}},
2059  { "Drop B", "B", false, {35, 42, 47, 52, 56, 61}},
2060  { "Drop A#", "A#", false, {34, 41, 46, 51, 55, 60}},
2061  { "Drop A", "A", false, {33, 40, 45, 50, 54, 59}},
2062  { "Open D", "D", false, {38, 45, 50, 54, 57, 62}},
2063  { "Open D Minor", "D", false, {38, 45, 50, 53, 57, 62}},
2064  { "Open G", "G", false, {38, 43, 50, 55, 59, 62}},
2065  { "Open G Minor", "G", false, {38, 43, 50, 55, 58, 62}},
2066  { "Open C", "C", false, {36, 43, 48, 55, 60, 64}},
2067  { "Open C#", "C#", false, {37, 42, 59, 52, 56, 61}},
2068  { "Open C Minor", "C", false, {36, 43, 48, 55, 60, 63}},
2069  { "Open E7", "E7", false, {40, 44, 50, 52, 59, 64}},
2070  { "Open E Minor7", "E", false, {40, 47, 50, 55, 59, 64}},
2071  { "Open G Major7", "G", false, {38, 43, 50, 54, 59, 62}},
2072  { "Open A Minor", "A", false, {40, 45, 52, 57, 60, 64}},
2073  { "Open A Minor7", "A", false, {40, 45, 52, 55, 60, 64}},
2074  { "Open A", "A", false, {40, 45, 49, 52, 57, 64}},
2075  { "C Tuning", "C", false, {36, 41, 46, 51, 55, 60}},
2076  { "C# Tuning", "C#", false, {37, 42, 47, 52, 56, 61}},
2077  { "Bb Tuning", "Bb", false, {34, 39, 44, 49, 53, 58}},
2078  { "A to A (Baritone)", "A", false, {33, 38, 43, 48, 52, 57}},
2079  { "Open Dsus2", "D", false, {38, 45, 50, 55, 57, 62}},
2080  { "Open Gsus2", "G", false, {38, 43, 50, 55, 60, 62}},
2081  { "G6", "G6", false, {38, 43, 50, 55, 59, 64}},
2082  { "Modal G", "G", false, {38, 43, 50, 55, 60, 62}},
2083  { "Overtone", "E", false, {48, 52, 55, 58, 60, 62}},
2084  { "Pentatonic", "E", false, {45, 48, 50, 52, 55, 69}},
2085  { "Minor Third", "E", false, {48, 51, 54, 57, 60, 63}},
2086  { "Major Third", "E", false, {48, 52, 56, 60, 64, 68}},
2087  { "All Fourths", "E", false, {40, 45, 50, 55, 60, 65}},
2088  { "Augmented Fourths", "E", false, {36, 42, 48, 54, 60, 66}},
2089  { "Slow Motion", "E", false, {38, 43, 50, 53, 60, 62}},
2090  { "Admiral", "E", false, {36, 43, 50, 55, 59, 60}},
2091  { "Buzzard", "E", false, {36, 41, 48, 55, 58, 65}},
2092  { "Face", "E", false, {36, 43, 50, 55, 57, 62}},
2093  { "Four and Twenty", "E", false, {38, 45, 50, 50, 57, 62}},
2094  { "Ostrich", "E", false, {38, 50, 50, 50, 62, 62}},
2095  { "Capo 200", "E", false, {36, 43, 50, 51, 62, 63}},
2096  { "Balalaika", "E", false, {40, 45, 50, 52, 52, 57}},
2097  { "Cittern One", "E", false, {36, 41, 48, 55, 60, 62}},
2098  { "Cittern Two", "E", false, {36, 43, 48, 55, 60, 67}},
2099  { "Dobro", "E", false, {43, 47, 50, 55, 59, 62}},
2100  { "Lefty", "E", false, {64, 59, 55, 50, 45, 40}},
2101  { "Mandoguitar", "E", false, {36, 43, 50, 57, 64, 71}},
2102  { "Rusty Cage", "E", false, {35, 45, 50, 55, 59, 64}},
2103  { "Hardcore", "C", false, {36, 43, 48, 53, 57, 58}},
2104  };
2105  int mode = tuner_tuning->get_value();
2106  tuner.clear_notes();
2107  if (mode > 0) {
2108  tuner.set_display_flat(tuning_tab[mode-1].flat);
2109  for (int i = 0; i < 6; ++i) {
2110  tuner.push_note(tuning_tab[mode-1].notes[i], 69, 12);
2111  }
2112  } else {
2113  tuner.set_display_flat(false);
2114  }
2115 }
2116 
2117 void MainWindow::set_tuner_tet(Gxw::RackTuner& tuner) {
2118  Glib::ustring tet = options.get_tuner_tet();
2119  int t = 0;
2120  if (tet.find("12") !=Glib::ustring::npos) t=0;
2121  else if (tet.find("19") !=Glib::ustring::npos) t=1;
2122  else if (tet.find("24") !=Glib::ustring::npos) t=2;
2123  else if (tet.find("31") !=Glib::ustring::npos) t=3;
2124  else if (tet.find("53") !=Glib::ustring::npos) t=4;
2125  else t = tuner_temperament->get_value();
2126  machine.set_parameter_value("racktuner.temperament", t);
2127  tuner.set_temperament(tuner_temperament->get_value());
2128  set_tuning(tuner);
2129 }
2130 
2131 void MainWindow::set_tuner_ref(Gxw::RackTuner& tuner) {
2132  Glib::ustring ref = options.get_tuner_ref();
2133  float t = atof(ref.c_str());
2134  machine.set_parameter_value("ui.tuner_reference_pitch", t);
2135  tuner.set_reference_pitch(tuner_reference_pitch->get_value());
2136  set_tuning(tuner);
2137 }
2138 
2139 void MainWindow::setup_tuner_temperament(Gxw::RackTuner& tuner) {
2140  tuner.set_temperament(tuner_temperament->get_value());
2141  set_tuning(tuner);
2142 }
2143 
2144 void MainWindow::setup_tuner(Gxw::RackTuner& tuner) {
2145  tuner.signal_frequency_poll().connect(
2146  sigc::compose(
2147  sigc::mem_fun(tuner, &Gxw::RackTuner::set_freq),
2148  sigc::mem_fun(machine, &gx_engine::GxMachineBase::get_tuner_freq)));
2149  tuner_mode->signal_value_changed().connect(
2150  sigc::compose(
2151  sigc::mem_fun(tuner, &Gxw::RackTuner::set_streaming),
2152  sigc::mem_fun(*tuner_mode, &Gxw::Selector::get_value)));
2153  tuner_reference_pitch->signal_value_changed().connect(
2154  sigc::compose(
2155  sigc::mem_fun(tuner, &Gxw::RackTuner::set_reference_pitch),
2156  sigc::mem_fun(*tuner_reference_pitch, &Gxw::ValueDisplay::get_value)));
2157  tuner_tuning->signal_value_changed().connect(
2158  sigc::bind(sigc::mem_fun(*this, &MainWindow::set_tuning), sigc::ref(tuner)));
2159  tuner_temperament->signal_value_changed().connect(
2160  sigc::bind(sigc::mem_fun(*this, &MainWindow::setup_tuner_temperament), sigc::ref(tuner)));
2161  tuner.set_temperament(tuner_temperament->get_value());
2162 }
2163 
2164 bool MainWindow::on_toggle_mute(GdkEventButton* ev) {
2165  if (ev->type == GDK_BUTTON_PRESS && ev->button == 1) {
2166  if (machine.get_state() == gx_engine::kEngineOff) {
2167  machine.set_state(gx_engine::kEngineOn);
2168  } else {
2169  machine.set_state(gx_engine::kEngineOff);
2170  }
2171  }
2172  return true;
2173 }
2174 
2175 bool MainWindow::on_toggle_insert(GdkEventButton* ev) {
2176  if (ev->type == GDK_BUTTON_PRESS && ev->button == 1) {
2177  if (machine.get_parameter_value<bool>("engine.insert")) {
2178  insert_image->set(pixbuf_insert_off);
2179  machine.set_parameter_value("engine.insert",false);
2180  machine.set_jack_insert(true);
2181  } else {
2182  insert_image->set(pixbuf_insert_on);
2183  machine.set_parameter_value("engine.insert",true);
2184  machine.set_jack_insert(false);
2185  }
2186  }
2187  return true;
2188 }
2189 
2190 bool MainWindow::on_jackserverconnection(GdkEventButton* ev) {
2191  if (ev->type == GDK_BUTTON_PRESS && ev->button == 1) {
2192  bool v = actions.jackserverconnection->get_active();
2193  actions.jackserverconnection->set_active(!v);
2194  }
2195  return true;
2196 }
2197 
2198 void MainWindow::on_msg_level_changed() {
2199  switch (fLoggingWindow.get_unseen_msg_level()) {
2200  case GxLogger::kWarning: logstate_image->set(pixbuf_log_yellow); break;
2201  case GxLogger::kError: logstate_image->set(pixbuf_log_red); break;
2202  default: logstate_image->set(pixbuf_log_grey); break;
2203  }
2204 }
2205 
2206 //static void toggle_action(Glib::RefPtr<Gtk::ToggleAction> act) {
2207 // act->set_active(!act->get_active());
2208 //}
2209 
2210 void MainWindow::on_ampdetail_switch(bool compress, bool setparam) {
2211  if (compress) {
2212  ampdetail_normal->hide();
2213  ampdetail_mini->show();
2214  } else {
2215  ampdetail_mini->hide();
2216  ampdetail_normal->show();
2217  }
2218  if (setparam) {
2219  machine.set_parameter_value("ui.mp_s_h", compress);
2220  }
2221 }
2222 
2223 /****************************************************************
2224  ** oscilloscope handling
2225  */
2226 
2227 void MainWindow::set_osc_size() {
2228  //int osc_size = engine.oscilloscope.get_mul_buffer();
2229  if (options.mul_buffer > 0) {
2230  actions.osc_buffer_size->set_current_value(options.mul_buffer);
2231  }
2232 }
2233 
2234 void MainWindow::change_osc_buffer(Glib::RefPtr<Gtk::RadioAction> action) {
2235  gx_jack::GxJack *jack = machine.get_jack();
2236  if (!jack || jack->client) {
2237  options.mul_buffer = action->get_current_value();
2238  on_oscilloscope_activate(false);
2239  machine.set_oscilloscope_mul_buffer(options.mul_buffer);
2240  on_oscilloscope_activate(true);
2241  } else {
2242  set_osc_size();
2243  }
2244 }
2245 
2246 void MainWindow::add_osc_size_menu() {
2247  Glib::ustring s = "<menubar><menu action=\"OptionsMenu\"><menu action=\"OscBuffer\">";
2248  Gtk::RadioButtonGroup group;
2249  int osc_buffer_size = 1;
2250  for (int i = 1; i <= 6; ++i) {
2251  Glib::ustring name = "*" + gx_system::to_string(osc_buffer_size);
2252  Glib::ustring actname = Glib::ustring::compose("buffer size %1", name);
2253  s += Glib::ustring::compose("<menuitem action=\"%1\"/>", actname);
2254  Glib::RefPtr<Gtk::RadioAction> action = Gtk::RadioAction::create(group, actname, name);
2255  actions.group->add(action);
2256  if (i == 1) {
2257  action->signal_changed().connect(
2258  sigc::mem_fun(*this, &MainWindow::change_osc_buffer));
2259  actions.osc_buffer_size = action;
2260  }
2261  action->property_value().set_value(osc_buffer_size);
2262  osc_buffer_size++;
2263  }
2264  s.append("</menu></menu></menubar>");
2265  uimanager->add_ui_from_string(s);
2266 }
2267 
2268 void MainWindow::on_show_oscilloscope(bool v) {
2269  if (v) {
2270  // FIXME G_PRIORITY_DEFAULT_IDLE??
2271  Glib::signal_timeout().connect(
2272  sigc::mem_fun(*this, &MainWindow::on_refresh_oscilloscope), 60);
2273  }
2274 }
2275 
2276 void MainWindow::set_waveview_buffer(unsigned int size) {
2277  fWaveView.set_frame(machine.get_oscilloscope_buffer(), size);
2278 }
2279 
2280 void MainWindow::on_oscilloscope_post_pre(int post_pre) {
2281  // if (post_pre) {
2282  // fWaveView.set_multiplicator(150.,250.);
2283  // } else {
2284  fWaveView.set_multiplicator(20.,60.);
2285  // }
2286 }
2287 
2288 int MainWindow::on_oscilloscope_activate(bool start) {
2289  if (!start) {
2290  machine.clear_oscilloscope_buffer();
2291  fWaveView.queue_draw();
2292  }
2293  return 0;
2294 }
2295 
2296 bool MainWindow::on_refresh_oscilloscope() {
2297  int load, frames;
2298  bool is_rt;
2299  jack_nframes_t bsize;
2300  machine.get_oscilloscope_info(load, frames, is_rt, bsize);
2301  static struct {
2302  int load, frames;
2303  jack_nframes_t bsize;
2304  bool rt;
2305  } oc;
2306  if (!oc.bsize || oc.load != load) {
2307  oc.load = load;
2308  fWaveView.set_text(
2309  (boost::format(_("DSP Load %1% %%")) % oc.load).str().c_str(),
2310  Gtk::CORNER_TOP_LEFT);
2311  }
2312  if (!oc.bsize || oc.frames != frames) {
2313  oc.frames = frames;
2314  fWaveView.set_text(
2315  (boost::format(_("HT Frames %1%")) % oc.frames).str().c_str(),
2316  Gtk::CORNER_BOTTOM_LEFT);
2317  }
2318  if (!oc.bsize || oc.rt != is_rt) {
2319  oc.rt = is_rt;
2320  fWaveView.set_text(
2321  oc.rt ? _("RT Mode YES ") : _("RT mode <span color=\"#cc1a1a\">NO</span>"),
2322  Gtk::CORNER_BOTTOM_RIGHT);
2323  }
2324  if (!oc.bsize || oc.bsize != bsize) {
2325  oc.bsize = bsize;
2326  fWaveView.set_text(
2327  (boost::format(_("Latency %1%")) % oc.bsize).str().c_str(),
2328  Gtk::CORNER_TOP_RIGHT);
2329  }
2330  fWaveView.queue_draw();
2331  return machine.oscilloscope_plugin_box_visible();
2332 }
2333 
2334 /* --------- calculate power (percent) to decibel -------- */
2335 // Note: could use fast_log10 (see ardour code) to make it faster
2336 inline float power2db(float power) {
2337  return 20.*log10(power);
2338 }
2339 
2340 bool MainWindow::refresh_meter_level(float falloff) {
2341  const unsigned int channels = sizeof(fastmeter)/sizeof(fastmeter[0]);
2342  gx_jack::GxJack *jack = machine.get_jack();
2343  if (jack && !jack->client) {
2344  return true;
2345  }
2346 
2347  // Note: removed RMS calculation, we will only focus on max peaks
2348  static float old_peak_db[channels] = {-INFINITY, -INFINITY};
2349 
2350  // fill up from engine buffers
2351  float level[channels];
2352  machine.maxlevel_get(channels, level);
2353  for (unsigned int c = 0; c < channels; c++) {
2354  // update meters (consider falloff as well)
2355  // calculate peak dB and translate into meter
2356  float peak_db = -INFINITY;
2357  if (level[c] > 0) {
2358  peak_db = power2db(level[c]);
2359  }
2360  // retrieve old meter value and consider falloff
2361  if (peak_db < old_peak_db[c]) {
2362  peak_db = max(peak_db, old_peak_db[c] - falloff);
2363  }
2364  fastmeter[c]->set(log_meter(peak_db));
2365  old_peak_db[c] = peak_db;
2366  }
2367  return true;
2368 }
2369 
2370 bool MainWindow::survive_jack_shutdown() {
2371  gx_jack::GxJack *jack = machine.get_jack();
2372  if (!jack) {
2373  return false;
2374  }
2375  // return if jack is not down
2376  if (gx_system::gx_system_call("pgrep jackd", true) == SYSTEM_OK) {
2377  if (jack->is_jack_down()) {
2378  sleep(2);
2379  jack->set_jack_down(false);
2380  }
2381  // let's make sure we get out of here
2382  gx_print_warning("Jack Shutdown",
2383  _("jack has bumped us out!! "));
2384  actions.jackserverconnection->set_active(true);
2385  // run only one time whem jackd is running
2386  return false;
2387  } else if (!jack->is_jack_down()) {
2388  // refresh some stuff. Note that it can be executed
2389  // more than once, no harm here
2390  actions.jackserverconnection->set_active(false);
2391  jack->set_jack_down(true);
2392  gx_print_error("Jack Shutdown",
2393  _("jack has bumped us out!! "));
2394  }
2395  // run as long jackd is down
2396  return true;
2397 }
2398 
2399 void MainWindow::gx_jack_is_down() {
2400  actions.jackserverconnection->set_active(false);
2401  Glib::signal_timeout().connect(
2402  sigc::mem_fun(*this, &MainWindow::survive_jack_shutdown),
2403  200, Glib::PRIORITY_LOW);
2404 }
2405 
2406 #ifdef HAVE_JACK_SESSION
2407 void MainWindow::jack_session_event() {
2408  gx_jack::GxJack *jack = machine.get_jack();
2409  if (!jack) {
2410  return;
2411  }
2412  const char *statefile = "gx_head.state";
2413  jack_session_event_t *event = jack->get_last_session_event();
2414  set_in_session();
2415  machine.set_statefilename(string(event->session_dir) + statefile);
2416  machine.save_to_state();
2417 
2418 #ifndef NDEBUG
2419  string cmd(options.get_path_to_program());
2420 #else
2421  string cmd("guitarix");
2422 #endif
2423  cmd += " -U ";
2424  cmd += event->client_uuid;
2425  cmd += " -A ";
2426  cmd += jack->get_uuid_insert();
2427  cmd += " -f ${SESSION_DIR}";
2428  cmd += statefile; // no space after SESSION_DIR
2429  event->command_line = strdup(cmd.c_str());
2430 
2431  JackSessionEventType tp = event->type;
2432  if (jack->return_last_session_event() == 0) {
2433  if (tp == JackSessionSaveAndQuit) {
2434  GxExit::get_instance().exit_program("** session exit **");
2435  }
2436  }
2437 }
2438 
2439 void MainWindow::jack_session_event_ins() {
2440  gx_jack::GxJack *jack = machine.get_jack();
2441  if (!jack) {
2442  return;
2443  }
2444  jack_session_event_t *event = jack->get_last_session_event_ins();
2445  set_in_session();
2446  event->command_line = strdup("true ${SESSION_DIR}");
2447  JackSessionEventType tp = event->type;
2448  if (jack->return_last_session_event_ins() == 0) {
2449  if (tp == JackSessionSaveAndQuit) {
2450  GxExit::get_instance().exit_program("** session exit **");
2451  }
2452  }
2453 }
2454 #endif
2455 
2456 void MainWindow::set_in_session() {
2457  if (!in_session) {
2458  in_session = true;
2459  // it seems in a session we generally don't know
2460  // where to save and from where to recall data
2461  // it's all controlled by the session manager
2462  machine.disable_autosave(true);
2463  }
2464 }
2465 
2466 void MainWindow::systray_menu(guint button, guint32 activate_time) {
2467  Gtk::Menu *menu = dynamic_cast<Gtk::MenuItem*>(uimanager->get_widget("/menubar/EngineMenu"))->get_submenu();
2468  menu->popup(2, gtk_get_current_event_time());
2469 }
2470 
2471 void MainWindow::overload_status_changed(gx_engine::MidiAudioBuffer::Load l) {
2472  switch (l) {
2474  status_icon->set(gx_head_midi);
2475  break;
2478  status_icon->set(gx_head_icon);
2479  break;
2481  status_icon->set(gx_head_warn);
2482  break;
2483  default:
2484  assert(false);
2485  }
2486 }
2487 
2488 bool MainWindow::on_window_state_changed(GdkEventWindowState* event) {
2489  if (event->changed_mask & event->new_window_state & (Gdk::WINDOW_STATE_ICONIFIED|Gdk::WINDOW_STATE_WITHDRAWN)) {
2490  window->get_window()->get_root_origin(options.mainwin_x, options.mainwin_y);
2491  }
2492  return false;
2493 }
2494 
2495 void MainWindow::hide_extended_settings() {
2496  if (!is_visible ||
2497  (window->get_window()->get_state()
2498  & (Gdk::WINDOW_STATE_ICONIFIED|Gdk::WINDOW_STATE_WITHDRAWN))) {
2499  window->move(options.mainwin_x, options.mainwin_y);
2500  window->present();
2501  //window->deiconify();
2502  } else {
2503  window->hide();
2504  //window->iconify();
2505  }
2506 }
2507 
2508 //bool MainWindow::ui_sleep() {
2509 // usleep(1900);
2510  //cout<<"timeout"<<endl;
2511 // return true;
2512 //}
2513 
2515  int port = options.get_rpcport();
2516  if (machine.get_jack() && port != RPCPORT_DEFAULT && port != RPCPORT_NONE) {
2517  machine.start_socket(sigc::ptr_fun(Gtk::Main::quit), options.get_rpcaddress(), port);
2518  window->show();
2519  if (options.get_liveplaygui()) liveplay_button->set_active();
2520  Gtk::Main::run();
2521  } else {
2522  window->show();
2523  if (options.get_liveplaygui()) liveplay_button->set_active();
2524  // Glib::signal_timeout().connect (mem_fun (*this, &MainWindow::ui_sleep), 2);
2525  Gtk::Main::run();
2526  }
2527 }
2528 
2529 bool MainWindow::on_meter_button_release(GdkEventButton* ev) {
2530  if (ev->button == 1) {
2531  for (unsigned int i = 0; i < sizeof(fastmeter)/sizeof(fastmeter[0]); i++) {
2532  fastmeter[i]->clear();
2533  }
2534  return true;
2535  }
2536  return false;
2537 }
2538 
2539 void MainWindow::display_preset_msg(const Glib::ustring& bank, const Glib::ustring& preset) {
2540  preset_status->set_text(bank + " / " + preset);
2541 }
2542 
2543 bool MainWindow::on_key_press_event(GdkEventKey *event) {
2544  if ((event->state & Gtk::AccelGroup::get_default_mod_mask()) != 0) {
2545  return false;
2546  }
2547  if (event->keyval >= GDK_KEY_0 && event->keyval <= GDK_KEY_9) {
2548  keyswitch.process_preset_key(event->keyval == GDK_KEY_0 ? 9 : event->keyval - GDK_KEY_1);
2549  return true;
2550  }
2551  if (event->keyval >= GDK_KEY_KP_0 && event->keyval <= GDK_KEY_KP_9) {
2552  keyswitch.process_preset_key(event->keyval == GDK_KEY_KP_0 ? 9 : event->keyval - GDK_KEY_KP_1);
2553  return true;
2554  }
2555  if (event->keyval >= GDK_KEY_a && event->keyval <= GDK_KEY_z) {
2556  keyswitch.process_bank_key(event->keyval - GDK_KEY_a);
2557  return true;
2558  }
2559  return false;
2560 }
2561 
2562 bool MainWindow::on_quit() {
2563  if (ladspalist_window && !ladspalist_window->check_exit()) {
2564  return true;
2565  }
2566  machine.stop_socket();
2567  Gtk::Main::quit();
2568  return false;
2569 }
2570 
2571 void MainWindow::amp_controls_visible(Gtk::Range *rr) {
2572  //FIXME
2573  bool v = abs(rr->get_value() - machine.get_parameter("tube.select").getUpperAsFloat()) < 0.5;
2574  const char *knobs1[] = {"gxmediumknobpregain","gxmediumknobdrive","gxmediumknobdist","gxmediumknobgain", "labelpregain:effekt_label", "labeldrive:effekt_label", "labeldist:effekt_label", "labelgain:effekt_label"};
2575  const char *knobs2[] = {"gxbigknobgain", "labelgain2:effekt_label"};
2576  for (unsigned int i = 0; i < sizeof(knobs1)/sizeof(knobs1[1]); ++i) {
2577  Gtk::Widget *w;
2578  bld->find_widget(knobs1[i], w);
2579  w->set_visible(!v);
2580  }
2581  for (unsigned int i = 0; i < sizeof(knobs2)/sizeof(knobs2[1]); ++i) {
2582  Gtk::Widget *w;
2583  bld->find_widget(knobs2[i], w);
2584  w->set_visible(v);
2585  }
2586 }
2587 
2589  Gtk::Window *splash, const Glib::ustring& title)
2590  : sigc::trackable(),
2591  options(options_),
2592  machine(machine_),
2593  bld(),
2594  freezer(),
2595  plugin_dict(),
2596  oldpos(0),
2597  scrl_size_x(-1),
2598  scrl_size_y(-1),
2599  monorackcontainer(PLUGIN_TYPE_MONO, *this),
2600  stereorackcontainer(PLUGIN_TYPE_STEREO, *this),
2601  pre_act(false),
2602  is_visible(false),
2603  drag_icon(0),
2604  preset_list_menu_bank(),
2605  preset_list_merge_id(0),
2606  preset_list_actiongroup(),
2607  uimanager(),
2608  live_play(),
2609  preset_window(),
2610  fWaveView(),
2611  convolver_filename_label(),
2612  convolver_mono_filename_label(),
2613  gx_head_icon(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("gx_head.png"))),
2614  boxbuilder(machine_, fWaveView, convolver_filename_label, convolver_mono_filename_label, gx_head_icon),
2615  portmap_window(0),
2616  select_jack_control(0),
2617  fLoggingWindow(),
2618  amp_radio_menu(machine_, "tube.select"),
2619  pixbuf_insert_on(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("insert_on.png"))),
2620  pixbuf_insert_off(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("insert_off.png"))),
2621  pixbuf_on(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("gx_on.png"))),
2622  pixbuf_off(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("gx_off.png"))),
2623  pixbuf_bypass(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("gx_bypass.png"))),
2624  pixbuf_jack_connected(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("jackd_on.png"))),
2625  pixbuf_jack_disconnected(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("jackd_off.png"))),
2626  pixbuf_log_grey(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("gx_log_grey.png"))),
2627  pixbuf_log_yellow(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("gx_log_yellow.png"))),
2628  pixbuf_log_red(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("gx_log_red.png"))),
2629  in_session(false),
2630  status_icon(Gtk::StatusIcon::create(gx_head_icon)),
2631  gx_head_midi(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("gx_head-midi.png"))),
2632  gx_head_warn(Gdk::Pixbuf::create_from_file(options.get_pixmap_filepath("gx_head-warn.png"))),
2633  actions(),
2634  keyswitch(machine, sigc::mem_fun(this, &MainWindow::display_preset_msg)),
2635  groupmap(),
2636  ladspalist_window(),
2637  szg_rack_units(Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL)) {
2638 
2639  convolver_filename_label.set_ellipsize(Pango::ELLIPSIZE_END);
2640  convolver_mono_filename_label.set_ellipsize(Pango::ELLIPSIZE_END);
2641 
2642  /*
2643  ** create actions and some parameters
2644  */
2645  create_actions();
2646 
2647  /*
2648  ** load key accelerator table and glade window definition
2649  **
2650  ** at this point all parameters that are used in the main window glade file must be defined
2651  */
2652  Gtk::AccelMap::load(options.get_builder_filepath("accels_rc"));
2653 
2654  const char *id_list[] = { "MainWindow", "amp_background:ampbox", "bank_liststore", "target_liststore",
2655  "bank_combo_liststore", 0 };
2656  bld = gx_gui::GxBuilder::create_from_file(options_.get_builder_filepath("mainpanel.glade"), &machine, id_list);
2657  load_widget_pointers();
2658  rackcontainer->set_homogeneous(true); // setting it in glade is awkward to use with glade tool
2659  szg_rack_units->add_widget(*ampdetail_mini);
2660  szg_rack_units->add_widget(*ampdetail_normal);
2661 
2662  // remove marker labels from boxes (used in glade to make display clearer)
2663  clear_box(*monocontainer);
2664  clear_box(*stereorackcontainerH);
2665  clear_box(*stereorackcontainerV);
2666  clear_box(*preset_box_no_rack);
2667 
2668  // create left column for equal width
2669  left_column = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
2670  Gtk::ScrolledWindow *swe;
2671  bld->find_widget("scrolledwindow_effects", swe);
2672  gtk_size_group_add_widget(left_column, GTK_WIDGET(swe->gobj()));
2673  Gtk::Button *pb;
2674  bld->find_widget("presets:barbutton", pb);
2675  gtk_size_group_add_widget(left_column, GTK_WIDGET(pb->gobj()));
2676 
2677  // preset window also creates some actions
2678  preset_window = new PresetWindow(bld, machine, options, actions, left_column);
2679 
2680  // create uimanager and load menu
2681  uimanager = Gtk::UIManager::create();
2682  uimanager->insert_action_group(actions.group);
2683  uimanager->add_ui_from_file(options.get_builder_filepath("menudef.xml"));
2684 
2685  // add dynamic submenus
2686  if (!options.get_clear_rc()) {
2687  add_skin_menu();
2688  }
2689  add_latency_menu();
2690  add_osc_size_menu();
2691  amp_radio_menu.setup("<menubar><menu action=\"TubeMenu\">","</menu></menubar>",uimanager,actions.group);
2692 
2693  // add menubar, accelgroup and icon to main window
2694  Gtk::Widget *menubar = uimanager->get_widget("/menubar");
2695  actions.accels = uimanager->get_accel_group();
2696  menubox->pack_start(*menubar);
2697  window->add_accel_group(actions.accels);
2698  window->set_icon(gx_head_icon);
2699  boxbuilder.set_accelgroup(actions.accels);
2700 
2701  /*
2702  ** connect main window signals
2703  */
2704  window->signal_window_state_event().connect(
2705  sigc::mem_fun(*this, &MainWindow::on_window_state_changed));
2706  window->signal_delete_event().connect(
2707  sigc::hide(sigc::mem_fun(this, &MainWindow::on_quit)));
2708  window->signal_configure_event().connect_notify(
2709  sigc::mem_fun(*this, &MainWindow::on_configure_event));
2710  window->signal_visibility_notify_event().connect(
2711  sigc::mem_fun(*this, &MainWindow::on_visibility_notify));
2712  window->signal_key_press_event().connect(
2713  sigc::mem_fun(*this, &MainWindow::on_key_press_event));
2714 
2715  /*
2716  ** status icon signal connections
2717  */
2718  status_icon->signal_activate().connect(
2719  sigc::mem_fun(*this, &MainWindow::hide_extended_settings));
2720  status_icon->signal_popup_menu().connect(
2721  sigc::mem_fun(*this, &MainWindow::systray_menu));
2722 
2723  // add rack container
2724  stereorackcontainerV->pack_start(stereorackcontainer, Gtk::PACK_EXPAND_WIDGET);
2725  monocontainer->pack_start(monorackcontainer, Gtk::PACK_EXPAND_WIDGET);
2726 
2727  /*
2728  ** jack, engine, and controller_map signal connections and related settings
2729  */
2731  gx_jack::GxJack *jack = machine.get_jack();
2732  if (jack) {
2733  jack->shutdown.connect(sigc::mem_fun(*this, &MainWindow::gx_jack_is_down));
2734  jack->signal_buffersize_change().connect(
2735  sigc::mem_fun(*this, &MainWindow::set_latency));
2736  jack->signal_client_change().connect(
2737  sigc::mem_fun(*this, &MainWindow::on_jack_client_changed));
2738 #ifdef HAVE_JACK_SESSION
2739  jack->session.connect(sigc::mem_fun(*this, &MainWindow::jack_session_event));
2740  jack->session_ins.connect(sigc::mem_fun(*this, &MainWindow::jack_session_event_ins));
2741  if (!options.get_jack_uuid().empty()) {
2742  set_in_session();
2743  }
2744 #endif
2745  }
2746 
2747  machine.signal_state_change().connect(
2748  sigc::mem_fun(*this, &MainWindow::on_engine_state_change));
2749  machine.signal_jack_load_change().connect(
2750  sigc::mem_fun(*this, &MainWindow::overload_status_changed));
2751  machine.signal_plugin_changed().connect(
2752  sigc::mem_fun(this, &MainWindow::on_plugin_changed));
2753  /*
2754  ** GxSettings signal connections
2755  */
2756  machine.signal_presetlist_changed().connect(
2757  sigc::mem_fun(*this, &MainWindow::rebuild_preset_menu));
2758  machine.signal_selection_changed().connect(
2759  sigc::mem_fun(*this, &MainWindow::show_selected_preset));
2760  machine.signal_selection_changed().connect(
2761  sigc::mem_fun(monorackcontainer, &RackContainer::check_order));
2762  machine.signal_selection_changed().connect(
2763  sigc::mem_fun(stereorackcontainer, &RackContainer::check_order));
2764 
2765  /*
2766  ** DnD setup for effects toolpalette
2767  */
2768  std::vector<Gtk::TargetEntry> listTargets;
2769  listTargets.push_back(Gtk::TargetEntry("application/x-guitarix-mono", Gtk::TARGET_SAME_APP, 1));
2770  listTargets.push_back(Gtk::TargetEntry("application/x-guitarix-stereo", Gtk::TARGET_SAME_APP, 2));
2771  effects_toolpalette->drag_dest_set(listTargets, Gtk::DEST_DEFAULT_ALL, Gdk::ACTION_MOVE);
2772  effects_toolpalette->signal_drag_data_received().connect(sigc::mem_fun(*this, &MainWindow::on_tp_drag_data_received));
2773 
2774  /*
2775  ** init jack connection image widget
2776  */
2777  if (jack) {
2778  jackd_image->set(pixbuf_jack_disconnected);
2779  jackd_image->get_parent()->signal_button_press_event().connect(
2780  sigc::mem_fun(*this, &MainWindow::on_jackserverconnection));
2781  //jackd_image->get_parent()->signal_button_press_event().connect(
2782  // sigc::bind_return(
2783  // sigc::group(
2784  // sigc::ptr_fun(toggle_action),
2785  // actions.jackserverconnection),
2786  // true));
2787  } else {
2788  jackd_image->hide();
2789  }
2790 
2791  /*
2792  ** setup racktuner parameter and signals
2793  */
2794  setup_tuner(*racktuner);
2795  tuner_on_off->set_name("effect_on_off");
2796  tuner_on_off->signal_toggled().connect(
2797  sigc::compose(
2798  sigc::mem_fun(*racktuner, &Gxw::RackTuner::set_sensitive),
2799  sigc::mem_fun(*tuner_on_off, &Gxw::Switch::get_active)));
2800  racktuner->signal_poll_status_changed().connect(
2801  sigc::mem_fun(machine, &gx_engine::GxMachineBase::tuner_used_for_display));
2802 
2803  /*
2804  ** oscilloscope signal connections
2805  */
2806  machine.signal_oscilloscope_post_pre().connect(
2807  sigc::mem_fun(*this, &MainWindow::on_oscilloscope_post_pre));
2808  machine.signal_oscilloscope_visible().connect(
2809  sigc::mem_fun(*this, &MainWindow::on_show_oscilloscope));
2810  machine.signal_oscilloscope_activation().connect(
2811  sigc::mem_fun(*this, &MainWindow::on_oscilloscope_activate));
2812  machine.signal_oscilloscope_size_change().connect(
2813  sigc::mem_fun(*this, &MainWindow::set_waveview_buffer));
2814 
2815  /*
2816  ** fastmeter initialization and signal connections
2817  */
2818  for (unsigned int i = 0; i < sizeof(fastmeter)/sizeof(fastmeter[0]); ++i) {
2819  fastmeter[i]->signal_button_release_event().connect(
2820  sigc::mem_fun(*this, &MainWindow::on_meter_button_release));
2821  fastmeter[i]->set_tooltip_text(_("Overall Rack output"));
2822  }
2823  const float meter_falloff = 27; // in dB/sec.
2824  const float meter_display_timeout = 60; // in millisec
2825  const float falloff = meter_falloff * meter_display_timeout * 0.001;
2826  Glib::signal_timeout().connect(
2827  sigc::bind(sigc::mem_fun(this, &MainWindow::refresh_meter_level), falloff),
2828  meter_display_timeout);
2829 
2830  /*
2831  ** amp top box signal connections
2832  */
2833  ampdetail_compress->signal_clicked().connect(
2834  sigc::bind(sigc::mem_fun(*this, &MainWindow::on_ampdetail_switch), true, true));
2835  ampdetail_expand->signal_clicked().connect(
2836  sigc::bind(sigc::mem_fun(*this, &MainWindow::on_ampdetail_switch), false, true));
2837  machine.signal_parameter_value<bool>("ui.mp_s_h").connect(
2838  sigc::bind(sigc::mem_fun(*this, &MainWindow::on_ampdetail_switch), false));
2839 
2840  /*
2841  ** midi out signal connections
2842  */
2843  midi_out_compress->signal_clicked().connect(
2844  sigc::bind(
2845  sigc::mem_fun(actions.midi_out_plug.operator->(), &Gtk::ToggleAction::set_active),
2846  true));
2847  midi_out_expand->signal_clicked().connect(
2848  sigc::bind(
2849  sigc::mem_fun(actions.midi_out_plug.operator->(), &Gtk::ToggleAction::set_active),
2850  false));
2851  midi_out_presets_mini->signal_clicked().connect(
2852  sigc::bind(
2853  sigc::mem_fun1(this, &MainWindow::plugin_preset_popup),
2854  machine.pluginlist_lookup_plugin("midi_out")->get_pdef()));
2855  midi_out_presets_normal->signal_clicked().connect(
2856  sigc::bind(
2857  sigc::mem_fun1(this, &MainWindow::plugin_preset_popup),
2858  machine.pluginlist_lookup_plugin("midi_out")->get_pdef()));
2859  channel1_button->signal_toggled().connect(
2860  sigc::bind(
2861  sigc::mem_fun(this, &MainWindow::on_midi_out_channel_toggled),
2862  channel1_button, channel1_box));
2863  channel2_button->signal_toggled().connect(
2864  sigc::bind(
2865  sigc::mem_fun(this, &MainWindow::on_midi_out_channel_toggled),
2866  channel2_button, channel2_box));
2867  channel3_button->signal_toggled().connect(
2868  sigc::bind(
2869  sigc::mem_fun(this, &MainWindow::on_midi_out_channel_toggled),
2870  channel3_button, channel3_box));
2871 
2872  /*
2873  ** init status image widget
2874  */
2875  status_image->set(pixbuf_on);
2876  gx_gui::connect_midi_controller(status_image->get_parent(), "engine.mute", machine);
2877  status_image->get_parent()->signal_button_press_event().connect(
2878  sigc::mem_fun(*this, &MainWindow::on_toggle_mute));
2879  on_engine_state_change(machine.get_state());
2880 
2881  /*
2882  ** init insert image widget
2883  */
2884  insert_image->set(pixbuf_insert_on);
2885  gx_gui::connect_midi_controller(insert_image->get_parent(), "engine.insert", machine);
2886  insert_image->get_parent()->signal_button_press_event().connect(
2887  sigc::mem_fun(*this, &MainWindow::on_toggle_insert));
2888 
2889  /*
2890  ** connect buttons with actions
2891  */
2892  gtk_activatable_set_related_action(GTK_ACTIVATABLE(show_rack_button->gobj()), GTK_ACTION(actions.show_rack->gobj()));
2893  gtk_activatable_set_related_action(GTK_ACTIVATABLE(rack_order_h_button->gobj()), GTK_ACTION(actions.rackh->gobj()));
2894  gtk_activatable_set_related_action(GTK_ACTIVATABLE(config_mode_button->gobj()), GTK_ACTION(actions.rack_config->gobj()));
2895  gtk_activatable_set_related_action(GTK_ACTIVATABLE(liveplay_button->gobj()),GTK_ACTION(actions.live_play->gobj()));
2896  gtk_activatable_set_related_action(GTK_ACTIVATABLE(tuner_button->gobj()),GTK_ACTION(actions.tuner->gobj()));
2897  gtk_activatable_set_related_action(GTK_ACTIVATABLE(effects_button->gobj()), GTK_ACTION(actions.show_plugin_bar->gobj()));
2898  gtk_activatable_set_related_action(GTK_ACTIVATABLE(presets_button->gobj()), GTK_ACTION(actions.presets->gobj()));
2899  gtk_activatable_set_related_action(GTK_ACTIVATABLE(compress_button->gobj()), GTK_ACTION(actions.compress->gobj()));
2900  gtk_activatable_set_related_action(GTK_ACTIVATABLE(expand_button->gobj()), GTK_ACTION(actions.expand->gobj()));
2901 
2902  /*
2903  ** setup window initial configuration
2904  */
2905  tunerbox->set_visible(machine.get_parameter_value<bool>("system.show_tuner"));
2906  racktuner->set_sensitive(machine.get_parameter_value<bool>("ui.racktuner"));
2907  actions.show_plugin_bar->set_active(false);
2908 
2909  /*
2910  ** create liveplay and setup liveplay racktuner
2911  */
2912  live_play = new Liveplay(options, machine, options.get_builder_filepath("mainpanel.glade"), actions);
2913  setup_tuner(live_play->get_tuner());
2914  live_play->get_tuner().signal_poll_status_changed().connect(
2915  sigc::mem_fun1(machine, &gx_engine::GxMachineBase::tuner_used_for_display));
2916 
2917  /*
2918  ** init logging window and logstate image widget
2919  */
2920  fLoggingWindow.set_transient_for(*window);
2921  fLoggingWindow.set_icon(gx_head_icon);
2922  fLoggingWindow.signal_msg_level_changed().connect(
2923  sigc::mem_fun(*this, &MainWindow::on_msg_level_changed));
2924  fLoggingWindow.signal_hide().connect(
2925  sigc::bind(
2926  sigc::mem_fun(actions.loggingbox.operator->(), &Gtk::ToggleAction::set_active),
2927  false));
2928  on_msg_level_changed();
2929  logstate_image->get_parent()->signal_button_press_event().connect(
2930  sigc::mem_fun(*this, &MainWindow::on_log_activated));
2931 
2932  //logstate_image->get_parent()->signal_button_press_event().connect(
2933  //sigc::bind_return(
2934  // sigc::group(
2935  // sigc::ptr_fun(toggle_action),
2936  // actions.loggingbox),
2937  // true));
2938 
2939  /*
2940  ** load plugin definitions into plugin_dict, add to effects_toolpalette
2941  **
2942  ** icons will be added after state loading when we know the skin
2943  ** UI definitions will be loaded on demand
2944  */
2945  fill_pluginlist();
2946  PluginUI *mainamp_plugin = new PluginUI(*this, "ampstack");
2947  plugin_dict.add(mainamp_plugin);
2948  mainamp_plugin->rackbox = add_rackbox_internal(*mainamp_plugin, 0, 0, false, -1, false, amp_background);
2949  //effects_toolpalette->set_name("effects_toolpalette");
2950  effects_toolpalette->show();
2951  if (!options.get_clear_rc()) {
2952  //g_object_set (gtk_settings_get_default (),"gtk-theme-name",NULL, NULL);
2953  set_new_skin(options.skin_name);
2954  } else {
2955  gtk_rc_parse(
2956  (options.get_style_filepath("clear.rc")).c_str());
2957  make_icons();
2958  }
2959 
2960  // call some action functions to sync state
2961  // with settings defined in create_actions()
2962  actions.rackh->set_active(options.system_order_rack_h);
2963  actions.presets->set_active(options.system_show_presets);
2964  actions.show_plugin_bar->set_active(options.system_show_toolbar);
2965  actions.show_rack->set_active(options.system_show_rack);
2966  actions.show_values->set_active(options.system_show_value);
2967  actions.tooltips->set_active(options.system_show_tooltips);
2968  actions.animations->set_active(options.system_animations);
2969 
2970  if (!title.empty()) {
2971  window->set_title(title);
2972  }
2973 
2974  /*
2975  ** Jack client connection and subsequent initalizations
2976  */
2977 
2978  // state must be loaded before starting jack because connect_jack() uses
2979  // some settings. If the jack client name changes (from the predefined value)
2980  // on connect the jack client-change signal will trigger the load of another
2981  // state file, which means that the jack starter options are read from the
2982  // standard state file (gx_head_rc or similar if -n is used)
2983  machine.loadstate();
2984  if (!in_session) {
2985  machine.disable_autosave(options.get_opt_save_on_exit());
2986  }
2987  if (!connect_jack(true, splash)) {
2988  // not connected, must synthesize signal for initialization
2989  if (jack) {
2990  jack->signal_client_change()();
2991  }
2992  }
2993  set_latency(); // make sure latency menu is updated
2994  set_osc_size();
2995 
2996  if (options.mainwin_height > 0) { // initially use the default set in mainpanel.glade
2997  window->set_default_size(-1, min(options.window_height, options.mainwin_height));
2998  }
2999 
3000  // set window position (make this optional??)
3001  if (options.mainwin_x > 0) {
3002  window->move(options.mainwin_x, options.mainwin_y);
3003  }
3004 
3005  Gtk::Range *rr;
3006  bld->find_widget("gxselector1:amp_selector", rr);
3007  rr->signal_value_changed().connect(
3008  sigc::bind(
3009  sigc::mem_fun(this, &MainWindow::amp_controls_visible),
3010  rr));
3011  amp_controls_visible(rr);
3012 
3013  // set insert_image state
3014  if (machine.get_parameter_value<bool>("engine.insert")) {
3015  insert_image->set(pixbuf_insert_on);
3016  machine.set_jack_insert(false);
3017  } else {
3018  insert_image->set(pixbuf_insert_off);
3019  machine.set_jack_insert(true);
3020  }
3021  if (!options.get_tuner_tet().empty()) set_tuner_tet(*racktuner);
3022  if (!options.get_tuner_ref().empty()) set_tuner_ref(*racktuner);
3023 
3024  }
3025 
3027 #if false // set true to generate a new keyboard accel file
3028  gtk_accel_map_add_filter("<Actions>/Main/ChangeSkin_*");
3029  gtk_accel_map_add_filter("<Actions>/Main/Enum_tube.select.*");
3030  gtk_accel_map_add_filter("<Actions>/Main/Latency_*");
3031  gtk_accel_map_add_filter("<Actions>/Main/Plugin_*");
3032  gtk_accel_map_add_filter("<Actions>/PresetList/PresetList_*");
3033  Gtk::AccelMap::save(options.get_user_filepath("accels_rc"));
3034 #endif
3035 
3036  int mainwin_width;
3037  window->get_size(mainwin_width, options.mainwin_height);
3038  Glib::RefPtr<Gdk::Window> win = window->get_window();
3039  if (win) {
3040  win->get_root_origin(options.mainwin_x, options.mainwin_y);
3041  }
3042  if (actions.presets->get_active()) {
3043  options.preset_window_height = preset_scrolledbox->get_allocation().get_height();
3044  }
3045  plugin_dict.cleanup();
3046  delete live_play;
3047  delete preset_window;
3048  delete window;
3049  window = 0;
3050  //if (ladspalist_window) {
3051  //delete ladspalist_window;
3052  //ladspalist_window = 0;
3053  //}
3054 }
iterator end()
Definition: gx_json.h:366
virtual GxEngineState get_state()=0
virtual gx_system::PresetFileGui * get_current_bank_file()=0
void gx_print_info(const char *, const std::string &)
Definition: gx_logging.cpp:183
void check_order()
Definition: rack.cpp:1615
void cleanup()
Definition: rack.cpp:213
CmdConnection::msg_type start
Definition: jsonrpc.cpp:255
void set_jack_down(bool v)
Definition: gx_jack.h:187
double stop_at_mono_top(double off, double step_size)
#define GDK_KEY_Escape
Definition: guitarix.h:53
void set_streaming(bool p1)
Definition: racktuner.cc:290
Glib::RefPtr< Gtk::ToggleAction > get_action()
virtual sigc::signal< void, int > & signal_oscilloscope_post_pre()=0
int get_idle_thread_timeout() const
Definition: gx_system.h:503
PluginDef * get_pdef()
void set_display_flat(bool p1)
Definition: racktuner.cc:300
Glib::RefPtr< UiBoolToggleAction > midi_out_plug
void freeze_and_size_request(Gtk::Window *w, int width, int height)
void add_icon(const std::string &name)
bool get_clear_rc() const
Definition: gx_system.h:481
#define RPCPORT_DEFAULT
Definition: gx_system.h:350
#define GDK_KEY_KP_1
Definition: guitarix.h:55
virtual sigc::signal< void, GxEngineState > & signal_state_change()=0
static Glib::RefPtr< UiToggleAction > create(gx_engine::GxMachineBase &machine, const std::string &id, const Glib::ustring &name, const Glib::ustring &label=Glib::ustring(), const Glib::ustring &tooltip=Glib::ustring(), bool is_active=false)
virtual sigc::signal< void > & signal_presetlist_changed()=0
virtual sigc::signal< void, bool > & signal_oscilloscope_visible()=0
void display(bool v, bool animate)
Definition: rack.cpp:137
int operator()()
#define GDK_KEY_9
Definition: guitarix.h:48
const char * value_id
Definition: gx_plugin.h:118
virtual Parameter & get_parameter(const std::string &id)=0
void set_temperament(int p1)
Definition: racktuner.cc:330
bool get_box_visible()
void set_ui_merge_id(Gtk::UIManager::ui_merge_id id)
Glib::ustring tooltip
#define N_(String)
GxJackLatencyChange
Glib::ustring skin_name
Definition: gx_system.h:445
virtual void set_state(GxEngineState state)=0
int gx_system_call(const std::string &, bool devnull=false, bool escape=false)
Definition: gx_system.cpp:948
static void rt_watchdog_set_limit(int limit)
Definition: gx_jack.cpp:146
static bool is_registered(gx_engine::GxMachineBase &m, const char *name)
Definition: rack.cpp:86
Glib::RefPtr< Gtk::ToggleAction > show_values
virtual sigc::signal< void, unsigned int > & signal_oscilloscope_size_change()=0
Glib::RefPtr< Gdk::Pixbuf > icon
void plugin_preset_popup(const PluginDef *pdef)
GxUiRadioMenu(gx_engine::GxMachineBase &machine, const std::string &id)
virtual void set_init_values()=0
bool check_thaw(int width, int height)
void set_reference_pitch(double p1)
Definition: tuner.cc:137
GtkSizeGroup * left_column
virtual void tuner_used_for_display(bool on)=0
Glib::RefPtr< Gtk::ToggleAction > tooltips
virtual gx_jack::GxJack * get_jack()=0
jack_nframes_t get_jack_bs()
Definition: gx_jack.h:178
std::vector< Position >::iterator iterator
Definition: gx_json.h:321
Glib::RefPtr< Gtk::ToggleAction > rackh
void set_freq(double p1)
Definition: racktuner.cc:265
void hide_effect(const std::string &name)
UiToggleAction(gx_engine::GxMachineBase &machine_, const std::string &id, const Glib::ustring &name, const Glib::ustring &icon_name, const Glib::ustring &label=Glib::ustring(), const Glib::ustring &tooltip=Glib::ustring(), bool is_active=false)
const Glib::ustring & get_jack_uuid() const
Definition: gx_system.h:494
void set_on_off(bool v) const
const string & id() const
Definition: gx_parameter.h:169
void pack(Gtk::Widget *mainbox, Gtk::Widget *minibox, const Glib::RefPtr< Gtk::SizeGroup > &szg)
Definition: rack.cpp:1204
virtual bool setting_is_preset()=0
double stop_at_stereo_bottom(double off, double step_size, double pagesize)
Glib::RefPtr< Gtk::ToggleAction > rack_config
const char * get_name() const
Glib::RefPtr< Gtk::ToggleAction > show_rack
jack_client_t * client
Definition: gx_jack.h:170
static Gtk::Widget * create_icon_widget(const PluginUI &plugin, gx_system::CmdlineOptions &options)
Definition: rack.cpp:890
Glib::RefPtr< Gtk::ToggleAction > animations
std::string get_style_filepath(const std::string &basename) const
Definition: gx_system.h:461
void gx_print_error(const char *, const std::string &)
Definition: gx_logging.cpp:166
Gtk::ToolItemGroup * group
gx_engine::Plugin * plugin
#define RPCPORT_NONE
Definition: gx_system.h:351
Glib::RefPtr< Gtk::ActionGroup > group
static GxLogger & get_logger()
Definition: gx_logging.cpp:50
void update_width()
Glib::SignalProxy1< void, bool > signal_poll_status_changed()
Definition: racktuner.cc:357
Glib::RefPtr< Gtk::Action > expand
void add_plugin(std::vector< PluginUI * > &p, const char *id, const Glib::ustring &tooltip_="")
virtual bool load_unit(gx_gui::UiBuilderImpl &builder, PluginDef *pdef)=0
#define GDK_KEY_0
Definition: guitarix.h:46
void gx_show_about()
Glib::SignalProxy0< void > signal_frequency_poll()
Definition: racktuner.cc:351
float power2db(float power)
#define min(x, y)
const std::string & getIRFile() const
bool is_jack_down()
Definition: gx_jack.h:207
void clear_notes()
Definition: racktuner.cc:340
T get_parameter_value(const std::string &id)
const char * id
Definition: gx_plugin.h:185
void animate_insert()
Definition: rack.cpp:1074
virtual const Glib::ustring & get_current_bank()=0
std::string get_user_filepath(const std::string &basename) const
Definition: gx_system.h:371
void show_forum_help()
#define max(x, y)
RackBox * add_rackbox(PluginUI &pl, bool mini=false, int pos=-1, bool animate=false)
sigc::signal< void > & signal_msg_level_changed()
virtual float get_tuner_freq()=0
#define SYSTEM_OK
Definition: gx_system.h:81
MainWindow(gx_engine::GxMachineBase &machine, gx_system::CmdlineOptions &options, Gtk::Window *splash, const Glib::ustring &title)
static GxExit & get_instance()
Definition: gx_logging.cpp:205
static void toggle(gx_engine::GxMachineBase &machine, Glib::RefPtr< Gtk::ToggleAction > item)
msg_signal & signal_message()
Definition: gx_logging.cpp:77
virtual sigc::signal< void, Plugin *, PluginChange::pc > & signal_plugin_changed()=0
JConvPluginUI(MainWindow &main, const char *id, const Glib::ustring &tooltip="")
virtual void set_parameter_value(const std::string &id, int value)=0
void set_action(Glib::RefPtr< Gtk::ToggleAction > &act)
Definition: rack.cpp:99
virtual sigc::signal< void > & signal_selection_changed()=0
const Glib::ustring & get_tuner_ref()
Definition: gx_system.h:487
std::string to_string(const T &t)
Definition: gx_system.h:523
std::vector< PluginUI * > * plugins
Glib::RefPtr< Gtk::ToggleAction > live_play
void connect_midi_controller(Gtk::Widget *w, const std::string &id, gx_engine::GxMachineBase &machine)
PluginType get_type() const
bool plugins_by_name_less(PluginUI *a, PluginUI *b)
Definition: rack.cpp:186
Glib::RefPtr< Gtk::AccelGroup > accels
Glib::ustring group
void set_slot(sigc::slot< void > w)
Gtk::ToolItem * toolitem
bool get_opt_save_on_exit() const
Definition: gx_system.h:500
const GxJConvSettings & get_value() const
const char * get_id() const
#define GDK_KEY_1
Definition: guitarix.h:47
void unset_ui_merge_id(Glib::RefPtr< Gtk::UIManager > uimanager)
Definition: rack.cpp:75
void gx_print_warning(const char *, const std::string &)
Definition: gx_logging.cpp:161
Glib::RefPtr< UiBoolToggleAction > tuner
const Glib::ustring & get_tuner_tet()
Definition: gx_system.h:486
virtual void disable_autosave(bool v)=0
bool gx_start_jack_dialog(Glib::RefPtr< Gdk::Pixbuf > gw_ib)
void update_rackbox()
Definition: rack.cpp:164
void exit_program(std::string msg="", int errcode=1)
Definition: gx_logging.cpp:196
const string & get_instancename()
Definition: gx_jack.h:201
int main(int argc, char *argv[])
Definition: gxw_demo.cc:62
#define GDK_KEY_z
Definition: guitarix.h:63
void swtch(bool mini)
Definition: rack.cpp:1123
void add(PluginUI *p)
Definition: rack.cpp:203
void setup(const Glib::ustring &prefix, const Glib::ustring &postfix, Glib::RefPtr< Gtk::UIManager > &uimanager, Glib::RefPtr< Gtk::ActionGroup > &actiongroup)
static void start_stop(Glib::RefPtr< Gtk::ToggleAction > &action, gx_jack::GxJack &jack)
Glib::Dispatcher shutdown
Definition: gx_jack.h:206
void gx_show_help()
IntParameter & getInt()
Definition: gx_parameter.h:452
Glib::RefPtr< Gtk::ToggleAction > presets
virtual Plugin * pluginlist_lookup_plugin(const std::string &id) const =0
std::string get_builder_filepath(const std::string &basename) const
Definition: gx_system.h:373
EnumParameter & getEnum()
Definition: gx_parameter.h:457
bool gx_jack_connection(bool connect, bool startserver, int wait_after_connect, const gx_system::CmdlineOptions &opt)
Definition: gx_jack.cpp:425
#define GDK_KEY_KP_9
Definition: guitarix.h:56
Glib::RefPtr< Gtk::ToggleAction > show_plugin_bar
virtual void set_jack_insert(bool v)=0
void push_note(int p1, int p2, int p3)
Definition: racktuner.cc:345
virtual const Glib::ustring & get_current_name()=0
Gxw::RackTuner & get_tuner()
const char * get_category()
virtual sigc::signal< int, bool > & signal_oscilloscope_activation()=0
static const char * value_label(const value_pair &vp)
Definition: gx_parameter.h:193
virtual bool midi_get_config_mode(int *ctl=0)=0
virtual const value_pair * getValueNames() const
sigc::signal< void, T > & signal_parameter_value(const std::string &id)
bool get_on_off() const
void update_scrolled_window(Gtk::ScrolledWindow &w)
int gx_message_popup(const char *)
void resize_finished(RackContainer *ch)
const value_pair & get_pair()
Definition: gx_parameter.h:334
#define GDK_KEY_a
Definition: guitarix.h:49
RackBox * rackbox
void set_accelgroup(Glib::RefPtr< Gtk::AccelGroup > accels_)
virtual void loadstate()=0
#define GDK_KEY_KP_0
Definition: guitarix.h:54
void unplug_queue()
Definition: gx_logging.cpp:82
PluginDesc(const Glib::ustring &g, std::vector< PluginUI * > *p)
Glib::RefPtr< Gtk::Action > compress
Glib::RefPtr< Gtk::ToggleAction > loggingbox
static PortMapWindow * create(gx_engine::GxMachineBase &machine, Glib::RefPtr< Gtk::AccelGroup > ag)
Definition: gx_portmap.cpp:549
sigc::signal< void, MidiAudioBuffer::Load > & signal_jack_load_change()
Definition: machine.h:93
static SelectJackControlPgm * create(gx_system::CmdlineOptions &opt, gx_engine::GxMachineBase &machine)
virtual float getLowerAsFloat() const
void freeze_until_width_update(Gtk::Window *w, int width)