2 Copyright (C) 2015 Paul Davis
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.
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.
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.
20 #include <gtkmm/action.h>
21 #include <gtkmm/window.h>
23 #include "pbd/convert.h"
24 #include "pbd/xml++.h"
25 #include "pbd/stacktrace.h"
27 #include "gtkmm2ext/window_proxy.h"
28 #include "gtkmm2ext/visibility_tracker.h"
33 using namespace Gtkmm2ext;
36 WindowProxy::WindowProxy (const std::string& name)
45 , _state_mask (StateMask (Position|Size))
49 WindowProxy::WindowProxy (const std::string& name, const std::string& menu_name)
51 , _menu_name (menu_name)
59 , _state_mask (StateMask (Position|Size))
63 WindowProxy::WindowProxy (const std::string& name, const std::string& menu_name, const XMLNode& node)
65 , _menu_name (menu_name)
77 WindowProxy::~WindowProxy ()
84 WindowProxy::set_state (const XMLNode& node, int /* version */)
86 XMLNodeList children = node.children ();
87 XMLNode const * child;
88 XMLNodeList::const_iterator i = children.begin ();
90 while (i != children.end()) {
92 XMLProperty const * prop = child->property (X_("name"));
93 if (child->name() == X_("Window") && prop && prop->value() == _name) {
100 if (i != children.end()) {
102 XMLProperty const * prop;
105 if ((prop = child->property (X_("visible"))) != 0) {
106 _visible = PBD::string_is_affirmative (prop->value ());
109 if ((prop = child->property (X_("x-off"))) != 0) {
110 _x_off = atoi (prop->value());
112 if ((prop = child->property (X_("y-off"))) != 0) {
113 _y_off = atoi (prop->value());
115 if ((prop = child->property (X_("x-size"))) != 0) {
116 _width = atoi (prop->value());
118 if ((prop = child->property (X_("y-size"))) != 0) {
119 _height = atoi (prop->value());
131 WindowProxy::set_action (Glib::RefPtr<Gtk::Action> act)
137 WindowProxy::action_name() const
139 return string_compose (X_("toggle-%1"), _name);
143 WindowProxy::toggle()
149 /* XXX this is a hack - the window object should really
150 ensure its components are all visible. sigh.
153 /* we'd like to just call this and nothing else */
156 if (_window->is_mapped()) {
160 vistracker->cycle_visibility ();
162 if (_window->is_mapped()) {
163 if (_width != -1 && _height != -1) {
164 _window->set_default_size (_width, _height);
166 if (_x_off != -1 && _y_off != -1) {
167 _window->move (_x_off, _y_off);
174 WindowProxy::xml_node_name()
180 WindowProxy::get_state ()
182 XMLNode* node = new XMLNode (xml_node_name());
185 node->add_property (X_("name"), _name);
187 if (_window && vistracker) {
189 /* we have a window, so use current state */
191 _visible = vistracker->partially_visible ();
192 _window->get_position (_x_off, _y_off);
193 _window->get_size (_width, _height);
198 if (_state_mask & Position) {
206 if (_state_mask & Size) {
214 node->add_property (X_("visible"), _visible? X_("yes") : X_("no"));
215 snprintf (buf, sizeof (buf), "%d", x);
216 node->add_property (X_("x-off"), buf);
217 snprintf (buf, sizeof (buf), "%d", y);
218 node->add_property (X_("y-off"), buf);
219 snprintf (buf, sizeof (buf), "%d", w);
220 node->add_property (X_("x-size"), buf);
221 snprintf (buf, sizeof (buf), "%d", h);
222 node->add_property (X_("y-size"), buf);
228 WindowProxy::drop_window ()
231 delete_connection.disconnect ();
232 configure_connection.disconnect ();
242 WindowProxy::use_window (Gtk::Window& win)
250 WindowProxy::setup ()
254 vistracker = new Gtkmm2ext::VisibilityTracker (*_window);
256 delete_connection = _window->signal_delete_event().connect (sigc::mem_fun (*this, &WindowProxy::delete_event_handler));
257 configure_connection = _window->signal_configure_event().connect (sigc::mem_fun (*this, &WindowProxy::configure_handler), false);
263 WindowProxy::configure_handler (GdkEventConfigure* ev)
265 /* stupidly, the geometry data in the event isn't the same as we get
266 from the window geometry APIs.so we have to actively interrogate
267 them to get the new information.
269 the difference is generally down to window manager framing.
271 save_pos_and_size ();
277 WindowProxy::visible() const
280 /* update with current state */
281 _visible = vistracker->partially_visible();
287 WindowProxy::fully_visible () const
290 /* no vistracker .. no window .. cannot be fully visible */
293 return vistracker->fully_visible();
305 WindowProxy::maybe_show ()
313 WindowProxy::show_all ()
317 _window->show_all ();
321 WindowProxy::present ()
326 _window->show_all ();
329 /* turn off any mouse-based positioning */
330 _window->set_position (Gtk::WIN_POS_NONE);
343 WindowProxy::delete_event_handler (GdkEventAny* /*ev*/)
346 _action->activate ();
355 WindowProxy::save_pos_and_size ()
358 _window->get_position (_x_off, _y_off);
359 _window->get_size (_width, _height);
364 WindowProxy::set_pos_and_size ()
370 if ((_state_mask & Position) && (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1)) {
371 /* cancel any mouse-based positioning */
372 _window->set_position (Gtk::WIN_POS_NONE);
375 if ((_state_mask & Size) && _width != -1 && _height != -1) {
376 _window->resize (_width, _height);
379 if ((_state_mask & Position) && _x_off != -1 && _y_off != -1) {
380 _window->move (_x_off, _y_off);
385 WindowProxy::set_pos ()
391 if (!(_state_mask & Position)) {
395 if (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1) {
396 /* cancel any mouse-based positioning */
397 _window->set_position (Gtk::WIN_POS_NONE);
400 if (_x_off != -1 && _y_off != -1) {
401 _window->move (_x_off, _y_off);
406 WindowProxy::set_state_mask (StateMask sm)