Update classkeys to match new total LuaSignal count (windows only)
[ardour.git] / libs / gtkmm2ext / window_proxy.cc
1 /*
2     Copyright (C) 2015 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
20 #include <gtkmm/action.h>
21 #include <gtkmm/window.h>
22
23 #include "pbd/xml++.h"
24
25 #include "gtkmm2ext/window_proxy.h"
26 #include "gtkmm2ext/visibility_tracker.h"
27
28 #include "pbd/i18n.h"
29
30 using namespace Gtk;
31 using namespace Gtkmm2ext;
32 using namespace PBD;
33
34 WindowProxy::WindowProxy (const std::string& name)
35         : _name (name)
36         , _window (0)
37         , _visible (false)
38         , _x_off (-1)
39         , _y_off (-1)
40         , _width (-1)
41         , _height (-1)
42         , vistracker (0)
43         , _state_mask (StateMask (Position|Size))
44 {
45 }
46
47 WindowProxy::WindowProxy (const std::string& name, const std::string& menu_name)
48         : _name (name)
49         , _menu_name (menu_name)
50         , _window (0)
51         , _visible (false)
52         , _x_off (-1)
53         , _y_off (-1)
54         , _width (-1)
55         , _height (-1)
56         , vistracker (0)
57         , _state_mask (StateMask (Position|Size))
58 {
59 }
60
61 WindowProxy::WindowProxy (const std::string& name, const std::string& menu_name, const XMLNode& node)
62         : _name (name)
63         , _menu_name (menu_name)
64         , _window (0)
65         , _visible (false)
66         , _x_off (-1)
67         , _y_off (-1)
68         , _width (-1)
69         , _height (-1)
70         , vistracker (0)
71 {
72         set_state (node, 0);
73 }
74
75 WindowProxy::~WindowProxy ()
76 {
77         delete vistracker;
78         delete _window;
79 }
80
81 int
82 WindowProxy::set_state (const XMLNode& node, int /* version */)
83 {
84         XMLNodeList children = node.children ();
85         XMLNode const * child;
86         XMLNodeList::const_iterator i = children.begin ();
87
88         while (i != children.end()) {
89                 child = *i;
90                 std::string name;
91                 if (child->name () == X_("Window") && child->get_property (X_("name"), name) &&
92                     name == _name) {
93                         break;
94                 }
95
96                 ++i;
97         }
98
99         if (i != children.end()) {
100
101                 child = *i;
102
103                 child->get_property (X_("visible"), _visible);
104                 child->get_property (X_("x-off"), _x_off);
105                 child->get_property (X_("y-off"), _y_off);
106                 child->get_property (X_("x-size"), _width);
107                 child->get_property (X_("y-size"), _height);
108         }
109
110         if (_window) {
111                 setup ();
112         }
113
114         return 0;
115 }
116
117 void
118 WindowProxy::set_action (Glib::RefPtr<Gtk::Action> act)
119 {
120         _action = act;
121 }
122
123 std::string
124 WindowProxy::action_name() const
125 {
126         return string_compose (X_("toggle-%1"), _name);
127 }
128
129 void
130 WindowProxy::toggle()
131 {
132         if (!_window) {
133                 (void) get (true);
134                 setup ();
135                 assert (_window);
136                 /* XXX this is a hack - the window object should really
137                    ensure its components are all visible. sigh.
138                 */
139                 _window->show_all();
140                 /* we'd like to just call this and nothing else */
141                 _window->present ();
142         } else {
143                 if (_window->is_mapped()) {
144                         save_pos_and_size();
145                 }
146
147                 vistracker->cycle_visibility ();
148
149                 if (_window->is_mapped()) {
150                         if (_width != -1 && _height != -1) {
151                                 _window->set_default_size (_width, _height);
152                         }
153                         if (_x_off != -1 && _y_off != -1) {
154                                 _window->move (_x_off, _y_off);
155                         }
156                 }
157         }
158 }
159
160 std::string
161 WindowProxy::xml_node_name()
162 {
163         return X_("Window");
164 }
165
166 XMLNode&
167 WindowProxy::get_state ()
168 {
169         XMLNode* node = new XMLNode (xml_node_name());
170
171         node->set_property (X_("name"), _name);
172
173         if (_window && vistracker) {
174
175                 /* we have a window, so use current state */
176
177                 _visible = vistracker->partially_visible ();
178                 _window->get_position (_x_off, _y_off);
179                 _window->get_size (_width, _height);
180         }
181
182         int x, y, w, h;
183
184         if (_state_mask & Position) {
185                 x = _x_off;
186                 y = _y_off;
187         } else {
188                 x = -1;
189                 y = -1;
190         }
191
192         if (_state_mask & Size) {
193                 w = _width;
194                 h = _height;
195         } else {
196                 w = -1;
197                 h = -1;
198         }
199
200         node->set_property (X_("visible"), _visible);
201         node->set_property (X_("x-off"), x);
202         node->set_property (X_("y-off"), y);
203         node->set_property (X_("x-size"), w);
204         node->set_property (X_("y-size"), h);
205
206         return *node;
207 }
208
209 void
210 WindowProxy::drop_window ()
211 {
212         if (_window) {
213                 delete_connection.disconnect ();
214                 configure_connection.disconnect ();
215                 map_connection.disconnect ();
216                 unmap_connection.disconnect ();
217                 _window->hide ();
218                 delete _window;
219                 _window = 0;
220                 delete vistracker;
221                 vistracker = 0;
222         }
223 }
224
225 void
226 WindowProxy::use_window (Gtk::Window& win)
227 {
228         drop_window ();
229         _window = &win;
230         setup ();
231 }
232
233 void
234 WindowProxy::setup ()
235 {
236         assert (_window);
237
238         assert (_window);
239
240         delete_connection = _window->signal_delete_event().connect (sigc::mem_fun (*this, &WindowProxy::delete_event_handler));
241         configure_connection = _window->signal_configure_event().connect (sigc::mem_fun (*this, &WindowProxy::configure_handler), false);
242         map_connection = _window->signal_map().connect (sigc::mem_fun (*this, &WindowProxy::map_handler), false);
243         unmap_connection = _window->signal_unmap().connect (sigc::mem_fun (*this, &WindowProxy::unmap_handler), false);
244
245         set_pos_and_size ();
246 }
247
248 void
249 WindowProxy::map_handler ()
250 {
251         vistracker = new Gtkmm2ext::VisibilityTracker (*_window);
252         /* emit our own signal */
253         signal_map ();
254 }
255
256 void
257 WindowProxy::unmap_handler ()
258 {
259         /* emit out own signal */
260         signal_unmap ();
261 }
262
263 bool
264 WindowProxy::configure_handler (GdkEventConfigure* ev)
265 {
266         /* stupidly, the geometry data in the event isn't the same as we get
267            from the window geometry APIs.so we have to actively interrogate
268            them to get the new information.
269
270            the difference is generally down to window manager framing.
271         */
272         if (!visible() || !_window->is_mapped()) {
273                 return false;
274         }
275         save_pos_and_size ();
276         return false;
277 }
278
279
280 bool
281 WindowProxy::visible() const
282 {
283         if (vistracker) {
284                 /* update with current state */
285                 _visible = vistracker->partially_visible();
286         }
287         return _visible;
288 }
289
290 bool
291 WindowProxy::fully_visible () const
292 {
293         if (!vistracker) {
294                 /* no vistracker .. no window .. cannot be fully visible */
295                 return false;
296         }
297         return vistracker->fully_visible();
298 }
299
300 void
301 WindowProxy::show ()
302 {
303         get (true);
304         assert (_window);
305         _window->show ();
306 }
307
308 void
309 WindowProxy::maybe_show ()
310 {
311         if (_visible) {
312                 show ();
313         }
314 }
315
316 void
317 WindowProxy::show_all ()
318 {
319         get (true);
320         assert (_window);
321         _window->show_all ();
322 }
323
324 void
325 WindowProxy::present ()
326 {
327         get (true);
328         assert (_window);
329
330         _window->show_all ();
331         _window->present ();
332
333         /* turn off any mouse-based positioning */
334         _window->set_position (Gtk::WIN_POS_NONE);
335 }
336
337 void
338 WindowProxy::hide ()
339 {
340         if (_window) {
341                 save_pos_and_size();
342                 _window->hide ();
343         }
344 }
345
346 bool
347 WindowProxy::delete_event_handler (GdkEventAny* /*ev*/)
348 {
349         if (_action) {
350                 _action->activate ();
351         } else {
352                 hide();
353         }
354
355         return true;
356 }
357
358 void
359 WindowProxy::save_pos_and_size ()
360 {
361         if (_window) {
362                 _window->get_position (_x_off, _y_off);
363                 _window->get_size (_width, _height);
364         }
365 }
366
367 void
368 WindowProxy::set_pos_and_size ()
369 {
370         if (!_window) {
371                 return;
372         }
373
374         if ((_state_mask & Position) && (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1)) {
375                 /* cancel any mouse-based positioning */
376                 _window->set_position (Gtk::WIN_POS_NONE);
377         }
378
379         if ((_state_mask & Size) && _width != -1 && _height != -1) {
380                 _window->resize (_width, _height);
381         }
382
383         if ((_state_mask & Position) && _x_off != -1 && _y_off != -1) {
384                 _window->move (_x_off, _y_off);
385         }
386 }
387
388 void
389 WindowProxy::set_pos ()
390 {
391         if (!_window) {
392                 return;
393         }
394
395         if (!(_state_mask & Position)) {
396                 return;
397         }
398
399         if (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1) {
400                 /* cancel any mouse-based positioning */
401                 _window->set_position (Gtk::WIN_POS_NONE);
402         }
403
404         if (_x_off != -1 && _y_off != -1) {
405                 _window->move (_x_off, _y_off);
406         }
407 }
408
409 void
410 WindowProxy::set_state_mask (StateMask sm)
411 {
412         _state_mask = sm;
413 }