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