Update comments & icon of rubberband example Lua script
[ardour.git] / gtk2_ardour / window_manager.cc
1 /*
2  * Copyright (C) 2013-2018 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2013-2018 Robin Gareus <robin@gareus.org>
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 along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19
20 #include <gtkmm/window.h>
21
22 #include "pbd/xml++.h"
23
24 #include "ardour/session_handle.h"
25
26 #include "gtkmm2ext/bindings.h"
27 #include "gtkmm2ext/visibility_tracker.h"
28
29 #include "actions.h"
30 #include "ardour_dialog.h"
31 #include "ardour_ui.h"
32 #include "ardour_window.h"
33 #include "window_manager.h"
34 #include "processor_box.h"
35
36 #include "pbd/i18n.h"
37
38 using std::string;
39 using namespace WM;
40 using namespace PBD;
41
42 Manager* Manager::_instance = 0;
43
44 Manager&
45 Manager::instance ()
46 {
47         if (!_instance) {
48                 _instance = new Manager;
49         }
50         return *_instance;
51 }
52
53 Manager::Manager ()
54         : current_transient_parent (0)
55 {
56 }
57
58 Manager::~Manager ()
59 {
60 }
61
62 void
63 Manager::register_window (ProxyBase* info)
64 {
65         _windows.push_back (info);
66
67         if (!info->menu_name().empty()) {
68
69                 if (!window_actions) {
70                         window_actions = ActionManager::create_action_group (Gtkmm2ext::UI::instance()->global_bindings, X_("Window"));
71                 }
72
73                 ActionManager::register_toggle_action (window_actions,
74                                                        info->action_name().c_str(), info->menu_name().c_str(),
75                                                        sigc::bind (sigc::mem_fun (*this, &Manager::toggle_window), info));
76
77                 info->signal_map.connect (sigc::bind (sigc::mem_fun (*this, &Manager::window_proxy_was_mapped), info));
78                 info->signal_unmap.connect (sigc::bind (sigc::mem_fun (*this, &Manager::window_proxy_was_unmapped), info));
79
80         }
81 }
82
83 void
84 Manager::window_proxy_was_mapped (ProxyBase* proxy)
85 {
86         Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (string_compose ("%1/%2", window_actions->get_name(), proxy->action_name()));
87         if (!act) {
88                 return;
89         }
90         Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic (act);
91         if (!tact) {
92                 return;
93         }
94
95         tact->set_active (true);
96 }
97
98 void
99 Manager::window_proxy_was_unmapped (ProxyBase* proxy)
100 {
101         Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (string_compose ("%1/%2", window_actions->get_name(), proxy->action_name()));
102         if (!act) {
103                 return;
104         }
105         Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic (act);
106         if (!tact) {
107                 return;
108         }
109
110         tact->set_active (false);
111 }
112
113 void
114 Manager::remove (const ProxyBase* info)
115 {
116         for (Windows::iterator i = _windows.begin(); i != _windows.end(); ++i) {
117                 if ((*i) == info) {
118                         _windows.erase (i);
119                         return;
120                 }
121         }
122 }
123
124 void
125 Manager::toggle_window (ProxyBase* proxy)
126 {
127         Glib::RefPtr<Gtk::Action> act = ActionManager::get_action (string_compose ("%1/%2", window_actions->get_name(), proxy->action_name()));
128         if (!act) {
129                 return;
130         }
131         Glib::RefPtr<Gtk::ToggleAction> tact = Glib::RefPtr<Gtk::ToggleAction>::cast_dynamic (act);
132         if (!tact) {
133                 return;
134         }
135
136         if (tact->get_active()) {
137                 proxy->present ();
138         } else {
139                 proxy->hide ();
140         }
141 }
142
143 void
144 Manager::show_visible() const
145 {
146         for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
147                 if ((*i)->visible()) {
148                         Gtk::Window* win = (*i)->get (true);
149                         if (!win) {
150                                 /* the window may be a plugin GUI for a plugin which
151                                  * is disabled or longer present.
152                                  */
153                                 continue;
154                         }
155                         if (dynamic_cast<ArdourDialog*> (win)) {
156                                 /* do not show dialogs at startup. Most
157                                  * dialogs require some signal connection work
158                                  * because we are trying to avoid recursive
159                                  * event loops (connecting instead to
160                                  * ::signal_response(). This means we need to
161                                  * destroy the window as well, so that the code
162                                  * which checks if it should be created will
163                                  * find that it is missing and will create it
164                                  * and connect to any necessary signals.
165                                  */
166                                 (*i)->drop_window ();
167                                 continue;
168                         }
169                         (*i)->show_all ();
170                         (*i)->present ();
171                 }
172         }
173 }
174
175 void
176 Manager::add_state (XMLNode& root) const
177 {
178         for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
179                 /* don't save state for temporary proxy windows
180                  */
181
182                 if (dynamic_cast<ProxyTemporary*> (*i)) {
183                         continue;
184                 }
185
186                 root.add_child_nocopy ((*i)->get_state());
187         }
188 }
189
190 void
191 Manager::set_session (ARDOUR::Session* s)
192 {
193         SessionHandlePtr::set_session (s);
194         for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
195                 (*i)->set_session(s);
196         }
197 }
198
199 void
200 Manager::set_transient_for (Gtk::Window* parent)
201 {
202         /* OS X has a richer concept of window layering than X does (or
203          * certainly, than any accepted conventions on X), and so the use of
204          * Manager::set_transient_for() is not necessary on that platform.
205          *
206          * On OS X this is mostly taken care of by using the window type rather
207          * than explicit 1:1 transient-for relationships.
208          */
209
210 #ifndef __APPLE__
211         if (parent) {
212                 for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
213                         Gtk::Window* win = (*i)->get();
214                         if (win) {
215                                 win->set_transient_for (*parent);
216                         }
217                 }
218         } else {
219                 for (Windows::const_iterator i = _windows.begin(); i != _windows.end(); ++i) {
220                         Gtk::Window* win = (*i)->get();
221                         if (win) {
222                                 gtk_window_set_transient_for (win->gobj(), 0);
223                         }
224                 }
225         }
226
227         current_transient_parent = parent;
228 #endif
229 }
230
231 /*-------------------------*/
232
233 ProxyBase::ProxyBase (const std::string& name, const std::string& menu_name)
234         : WindowProxy (name, menu_name)
235 {
236 }
237
238 ProxyBase::ProxyBase (const std::string& name, const std::string& menu_name, const XMLNode& node)
239         : WindowProxy (name, menu_name, node)
240 {
241 }
242
243 void
244 ProxyBase::setup ()
245 {
246         WindowProxy::setup ();
247         set_session(_session);
248
249 }
250
251 /*-----------------------*/
252
253 ProxyTemporary::ProxyTemporary (const string& name, Gtk::Window* win)
254         : ProxyBase (name, string())
255 {
256         _window = win;
257 }
258
259 ARDOUR::SessionHandlePtr*
260 ProxyTemporary::session_handle()
261 {
262         /* may return null */
263         ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
264         if (aw) { return aw; }
265         ArdourDialog* ad = dynamic_cast<ArdourDialog*> (_window);
266         if (ad) { return ad; }
267         return 0;
268 }