No more doxygen warnings for gtk2_arodur/*
[ardour.git] / libs / gtkmm2ext / window_proxy.cc
1 /*
2  * Copyright (C) 2015-2018 Paul Davis <paul@linuxaudiosystems.com>
3  * Copyright (C) 2017-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/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                 if (vistracker) {
149                         vistracker->cycle_visibility ();
150                 } else {
151                         _window->present ();
152                 }
153
154                 if (_window->is_mapped()) {
155                         if (_width != -1 && _height != -1) {
156                                 _window->set_default_size (_width, _height);
157                         }
158                         if (_x_off != -1 && _y_off != -1) {
159                                 _window->move (_x_off, _y_off);
160                         }
161                 }
162         }
163 }
164
165 std::string
166 WindowProxy::xml_node_name()
167 {
168         return X_("Window");
169 }
170
171 XMLNode&
172 WindowProxy::get_state ()
173 {
174         XMLNode* node = new XMLNode (xml_node_name());
175
176         node->set_property (X_("name"), _name);
177
178         if (_window && vistracker) {
179
180                 /* we have a window, so use current state */
181
182                 _visible = vistracker->partially_visible ();
183                 _window->get_position (_x_off, _y_off);
184                 _window->get_size (_width, _height);
185         }
186
187         int x, y, w, h;
188
189         if (_state_mask & Position) {
190                 x = _x_off;
191                 y = _y_off;
192         } else {
193                 x = -1;
194                 y = -1;
195         }
196
197         if (_state_mask & Size) {
198                 w = _width;
199                 h = _height;
200         } else {
201                 w = -1;
202                 h = -1;
203         }
204
205         node->set_property (X_("visible"), _visible);
206         node->set_property (X_("x-off"), x);
207         node->set_property (X_("y-off"), y);
208         node->set_property (X_("x-size"), w);
209         node->set_property (X_("y-size"), h);
210
211         return *node;
212 }
213
214 void
215 WindowProxy::drop_window ()
216 {
217         if (_window) {
218                 _window->hide ();
219                 delete_connection.disconnect ();
220                 configure_connection.disconnect ();
221                 map_connection.disconnect ();
222                 unmap_connection.disconnect ();
223                 delete _window;
224                 _window = 0;
225                 delete vistracker;
226                 vistracker = 0;
227         }
228 }
229
230 void
231 WindowProxy::use_window (Gtk::Window& win)
232 {
233         drop_window ();
234         _window = &win;
235         setup ();
236 }
237
238 void
239 WindowProxy::setup ()
240 {
241         assert (_window);
242
243         assert (_window);
244
245         delete_connection = _window->signal_delete_event().connect (sigc::mem_fun (*this, &WindowProxy::delete_event_handler));
246         configure_connection = _window->signal_configure_event().connect (sigc::mem_fun (*this, &WindowProxy::configure_handler), false);
247         map_connection = _window->signal_map().connect (sigc::mem_fun (*this, &WindowProxy::map_handler), false);
248         unmap_connection = _window->signal_unmap().connect (sigc::mem_fun (*this, &WindowProxy::unmap_handler), false);
249
250         set_pos_and_size ();
251 }
252
253 void
254 WindowProxy::map_handler ()
255 {
256         vistracker = new Gtkmm2ext::VisibilityTracker (*_window);
257         /* emit our own signal */
258         signal_map ();
259 }
260
261 void
262 WindowProxy::unmap_handler ()
263 {
264         /* emit out own signal */
265         signal_unmap ();
266 }
267
268 bool
269 WindowProxy::configure_handler (GdkEventConfigure* ev)
270 {
271         /* stupidly, the geometry data in the event isn't the same as we get
272            from the window geometry APIs.so we have to actively interrogate
273            them to get the new information.
274
275            the difference is generally down to window manager framing.
276         */
277         if (!visible() || !_window->is_mapped()) {
278                 return false;
279         }
280         save_pos_and_size ();
281         return false;
282 }
283
284
285 bool
286 WindowProxy::visible() const
287 {
288         if (vistracker) {
289                 /* update with current state */
290                 _visible = vistracker->partially_visible();
291         }
292         return _visible;
293 }
294
295 bool
296 WindowProxy::fully_visible () const
297 {
298         if (!vistracker) {
299                 /* no vistracker .. no window .. cannot be fully visible */
300                 return false;
301         }
302         return vistracker->fully_visible();
303 }
304
305 void
306 WindowProxy::show ()
307 {
308         get (true);
309         assert (_window);
310         _window->show ();
311 }
312
313 void
314 WindowProxy::maybe_show ()
315 {
316         if (_visible) {
317                 show ();
318         }
319 }
320
321 void
322 WindowProxy::show_all ()
323 {
324         get (true);
325         assert (_window);
326         _window->show_all ();
327 }
328
329 void
330 WindowProxy::present ()
331 {
332         get (true);
333         assert (_window);
334
335         _window->show_all ();
336         _window->present ();
337
338         /* turn off any mouse-based positioning */
339         _window->set_position (Gtk::WIN_POS_NONE);
340 }
341
342 void
343 WindowProxy::hide ()
344 {
345         if (_window) {
346                 save_pos_and_size();
347                 _window->hide ();
348         }
349 }
350
351 bool
352 WindowProxy::delete_event_handler (GdkEventAny* /*ev*/)
353 {
354         if (_action) {
355                 _action->activate ();
356         } else {
357                 hide();
358         }
359
360         return true;
361 }
362
363 void
364 WindowProxy::save_pos_and_size ()
365 {
366         if (_window) {
367                 _window->get_position (_x_off, _y_off);
368                 _window->get_size (_width, _height);
369         }
370 }
371
372 void
373 WindowProxy::set_pos_and_size ()
374 {
375         if (!_window) {
376                 return;
377         }
378
379         if ((_state_mask & Position) && (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1)) {
380                 /* cancel any mouse-based positioning */
381                 _window->set_position (Gtk::WIN_POS_NONE);
382         }
383
384         if ((_state_mask & Size) && _width != -1 && _height != -1) {
385                 _window->resize (_width, _height);
386         }
387
388         if ((_state_mask & Position) && _x_off != -1 && _y_off != -1) {
389                 _window->move (_x_off, _y_off);
390         }
391 }
392
393 void
394 WindowProxy::set_pos ()
395 {
396         if (!_window) {
397                 return;
398         }
399
400         if (!(_state_mask & Position)) {
401                 return;
402         }
403
404         if (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1) {
405                 /* cancel any mouse-based positioning */
406                 _window->set_position (Gtk::WIN_POS_NONE);
407         }
408
409         if (_x_off != -1 && _y_off != -1) {
410                 _window->move (_x_off, _y_off);
411         }
412 }
413
414 void
415 WindowProxy::set_state_mask (StateMask sm)
416 {
417         _state_mask = sm;
418 }