ardour
window_manager.cc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 Paul Davis
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; either version 2 of the License, or
7  (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 
19 #include <gtkmm/window.h>
20 
21 #include "pbd/xml++.h"
22 
23 #include "ardour/session_handle.h"
24 
26 
27 #include "actions.h"
28 #include "ardour_dialog.h"
29 #include "ardour_window.h"
30 #include "window_manager.h"
31 #include "processor_box.h"
32 
33 #include "i18n.h"
34 
35 using std::string;
36 using namespace WM;
37 using namespace PBD;
38 
40 
41 Manager&
43 {
44  if (!_instance) {
45  _instance = new Manager;
46  }
47  return *_instance;
48 }
49 
51  : current_transient_parent (0)
52 {
53 }
54 
56 {
57 }
58 
59 void
61 {
62  _windows.push_back (info);
63 
64  if (!info->menu_name().empty()) {
65 
66  if (!window_actions) {
67  window_actions = Gtk::ActionGroup::create (X_("Window"));
69  }
70 
71  info->set_action (ActionManager::register_action (window_actions, info->action_name().c_str(), info->menu_name().c_str(),
72  sigc::bind (sigc::mem_fun (*this, &Manager::toggle_window), info)));
73  }
74 }
75 
76 void
78 {
79  for (Windows::iterator i = _windows.begin(); i != _windows.end(); ++i) {
80  if ((*i) == info) {
81  _windows.erase (i);
82  return;
83  }
84  }
85 }
86 
87 void
89 {
90  if (proxy) {
91  proxy->toggle ();
92  }
93 }
94 
95 void
97 {
98  for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
99  if ((*i)->visible()) {
100  (*i)->show_all ();
101  (*i)->present ();
102  }
103  }
104 }
105 
106 void
108 {
109  for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
110  /* don't save state for temporary proxy windows
111  */
112  if (dynamic_cast<ProxyTemporary*> (*i)) {
113  continue;
114  }
115  if (dynamic_cast<ProcessorWindowProxy*> (*i)) {
116  ProcessorWindowProxy *pi = dynamic_cast<ProcessorWindowProxy*> (*i);
117  root.add_child_nocopy (pi->get_state());
118  } else {
119  root.add_child_nocopy ((*i)->get_state());
120  }
121  }
122 }
123 
124 void
126 {
127  SessionHandlePtr::set_session (s);
128  for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
129  (*i)->set_session(s);
130  }
131 }
132 
133 void
134 Manager::set_transient_for (Gtk::Window* parent)
135 {
136  /* OS X has a richer concept of window layering than X does (or
137  * certainly, than any accepted conventions on X), and so the use of
138  * Manager::set_transient_for() is not necessary on that platform.
139  *
140  * On OS X this is mostly taken care of by using the window type rather
141  * than explicit 1:1 transient-for relationships.
142  */
143 
144 #ifndef __APPLE__
145  if (parent) {
146  for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
147  Gtk::Window* win = (*i)->get();
148  if (win) {
149  win->set_transient_for (*parent);
150  }
151  }
152  } else {
153  for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
154  Gtk::Window* win = (*i)->get();
155  if (win) {
156  gtk_window_set_transient_for (win->gobj(), 0);
157  }
158  }
159  }
160 
161  current_transient_parent = parent;
162 #endif
163 }
164 
165 /*-------------------------*/
166 
167 ProxyBase::ProxyBase (const string& name, const std::string& menu_name)
168  : _name (name)
169  , _menu_name (menu_name)
170  , _window (0)
171  , _visible (false)
172  , _x_off (-1)
173  , _y_off (-1)
174  , _width (-1)
175  , _height (-1)
176  , vistracker (0)
177 {
178 }
179 
180 ProxyBase::ProxyBase (const string& name, const std::string& menu_name, const XMLNode& node)
181  : _name (name)
182  , _menu_name (menu_name)
183  , _window (0)
184  , _visible (false)
185  , _x_off (-1)
186  , _y_off (-1)
187  , _width (-1)
188  , _height (-1)
189  , vistracker (0)
190 {
191  set_state (node);
192 }
193 
195 {
196  delete vistracker;
197  delete _window;
198 }
199 
200 void
202 {
203  XMLNodeList children = node.children ();
204 
205  XMLNodeList::const_iterator i = children.begin ();
206 
207  while (i != children.end()) {
208  XMLProperty* prop = (*i)->property (X_("name"));
209  if ((*i)->name() == X_("Window") && prop && prop->value() == _name) {
210  break;
211  }
212 
213  ++i;
214  }
215 
216  if (i != children.end()) {
217 
218  XMLProperty* prop;
219 
220  if ((prop = (*i)->property (X_("visible"))) != 0) {
222  }
223 
224  if ((prop = (*i)->property (X_("x-off"))) != 0) {
225  _x_off = atoi (prop->value());
226  }
227  if ((prop = (*i)->property (X_("y-off"))) != 0) {
228  _y_off = atoi (prop->value());
229  }
230  if ((prop = (*i)->property (X_("x-size"))) != 0) {
231  _width = atoi (prop->value());
232  }
233  if ((prop = (*i)->property (X_("y-size"))) != 0) {
234  _height = atoi (prop->value());
235  }
236  }
237 
238  /* if we have a window already, reset its properties */
239 
240  if (_window) {
241  setup ();
242  }
243 }
244 
245 void
246 ProxyBase::set_action (Glib::RefPtr<Gtk::Action> act)
247 {
248  _action = act;
249 }
250 
251 std::string
253 {
254  return string_compose (X_("toggle-%1"), _name);
255 }
256 
257 void
259 {
260  if (!_window) {
261  (void) get (true);
262  assert (_window);
263  /* XXX this is a hack - the window object should really
264  ensure its components are all visible. sigh.
265  */
266  _window->show_all();
267  /* we'd like to just call this and nothing else */
268  _window->present ();
269 
270  if (_width != -1 && _height != -1) {
271  _window->set_default_size (_width, _height);
272  }
273  if (_x_off != -1 && _y_off != -1) {
274  _window->move (_x_off, _y_off);
275  }
276 
277  } else {
278  if (_window->is_mapped()) {
280  }
282  if (_window->is_mapped()) {
283  if (_width != -1 && _height != -1) {
284  _window->set_default_size (_width, _height);
285  }
286  if (_x_off != -1 && _y_off != -1) {
287  _window->move (_x_off, _y_off);
288  }
289  }
290  }
291 }
292 
293 XMLNode&
295 {
296  XMLNode* node = new XMLNode (X_("Window"));
297  char buf[32];
298 
299  node->add_property (X_("name"), _name);
300 
301  if (_window && vistracker) {
302 
303  /* we have a window, so use current state */
304 
306  if (_visible) {
307  _window->get_position (_x_off, _y_off);
308  _window->get_size (_width, _height);
309  }
310  }
311 
312  node->add_property (X_("visible"), _visible? X_("yes") : X_("no"));
313 
314  snprintf (buf, sizeof (buf), "%d", _x_off);
315  node->add_property (X_("x-off"), buf);
316  snprintf (buf, sizeof (buf), "%d", _y_off);
317  node->add_property (X_("y-off"), buf);
318  snprintf (buf, sizeof (buf), "%d", _width);
319  node->add_property (X_("x-size"), buf);
320  snprintf (buf, sizeof (buf), "%d", _height);
321  node->add_property (X_("y-size"), buf);
322 
323  return *node;
324 }
325 
326 void
328 {
329  if (_window) {
330  _window->hide ();
331  delete _window;
332  _window = 0;
333  delete vistracker;
334  vistracker = 0;
335  }
336 }
337 
338 void
339 ProxyBase::use_window (Gtk::Window& win)
340 {
341  drop_window ();
342  _window = &win;
343  setup ();
344 }
345 
346 void
348 {
349  assert (_window);
350 
352  _window->signal_delete_event().connect (sigc::mem_fun (*this, &ProxyBase::delete_event_handler));
353 
354  if (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1) {
355  /* cancel any mouse-based positioning */
356  _window->set_position (Gtk::WIN_POS_NONE);
357  }
358 
359  if (_width != -1 && _height != -1) {
360  _window->set_default_size (_width, _height);
361  }
362 
363  if (_x_off != -1 && _y_off != -1) {
364  _window->move (_x_off, _y_off);
365  }
367 }
368 
369 void
371 {
372  get (true);
373  assert (_window);
374  _window->show ();
375 }
376 
377 void
379 {
380  if (_visible) {
381  show ();
382  }
383 }
384 
385 void
387 {
388  get (true);
389  assert (_window);
390  _window->show_all ();
391 }
392 
393 void
395 {
396  get (true);
397  assert (_window);
398 
399  _window->show_all ();
400  _window->present ();
401 
402  /* turn off any mouse-based positioning */
403  _window->set_position (Gtk::WIN_POS_NONE);
404 }
405 
406 void
408 {
409  if (_window) {
411  _window->hide ();
412  }
413 }
414 
415 bool
416 ProxyBase::delete_event_handler (GdkEventAny* /*ev*/)
417 {
418  hide();
419  return true;
420 }
421 
422 void
424 {
425  if (_window) {
426  _window->get_position (_x_off, _y_off);
427  _window->get_size (_width, _height);
428  }
429 }
430 /*-----------------------*/
431 
432 ProxyTemporary::ProxyTemporary (const string& name, Gtk::Window* win)
433  : ProxyBase (name, string())
434 {
435  _window = win;
436 }
437 
439 {
440 }
441 
442 
445 {
446  /* may return null */
447  ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
448  if (aw) { return aw; }
449  ArdourDialog* ad = dynamic_cast<ArdourDialog*> (_window);
450  if (ad) { return ad; }
451  return 0;
452 }
int atoi(const string &s)
Definition: convert.cc:140
ProxyBase(const std::string &name, const std::string &menu_name)
const std::string & menu_name() const
const std::string & value() const
Definition: xml++.h:159
bool _visible
true if the window should be visible on startup
XMLNode & get_state() const
bool delete_event_handler(GdkEventAny *ev)
Glib::RefPtr< Gtk::ActionGroup > window_actions
void set_session(ARDOUR::Session *)
Gtk::Window * current_transient_parent
static Manager & instance()
void set_action(Glib::RefPtr< Gtk::Action >)
ARDOUR::SessionHandlePtr * session_handle()
const XMLNodeList & children(const std::string &str=std::string()) const
Definition: xml++.cc:329
void save_pos_and_size()
void show_visible() const
void register_window(ProxyBase *)
void use_window(Gtk::Window &)
std::string _name
std::list< XMLNode * > XMLNodeList
Definition: xml++.h:44
#define X_(Text)
Definition: i18n.h:13
virtual ~ProxyBase()
void set_transient_for(Gtk::Window *)
XMLNode & get_state() const
bool string_is_affirmative(const std::string &str)
Definition: convert.cc:282
Gtkmm2ext::VisibilityTracker * vistracker
std::string action_name() const
int _width
width
void remove(const ProxyBase *)
LIBPBD_API Transmitter info
void set_state(const XMLNode &)
XMLProperty * add_property(const char *name, const std::string &value)
Windows _windows
const char * name
void add_child_nocopy(XMLNode &)
Definition: xml++.cc:357
ProxyTemporary(const std::string &name, Gtk::Window *win)
int _height
height
Definition: xml++.h:95
Definition: debug.h:30
int _y_off
y position
virtual void toggle()
void toggle_window(ProxyBase *)
virtual void set_session(ARDOUR::Session *)
Glib::RefPtr< Gtk::Action > _action
Gtk::Window * _window
void add_state(XMLNode &) const
int _x_off
x position
LIBGTKMM2EXT_API void add_action_group(Glib::RefPtr< Gtk::ActionGroup >)
LIBGTKMM2EXT_API Glib::RefPtr< Gtk::Action > register_action(Glib::RefPtr< Gtk::ActionGroup > group, const char *name, const char *label)
ARDOUR::Session * _session
std::string string_compose(const std::string &fmt, const T1 &o1)
Definition: compose.h:208
static Manager * _instance