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 ();
233 map_connection.disconnect ();
234 unmap_connection.disconnect ();
244 WindowProxy::use_window (Gtk::Window& win)
252 WindowProxy::setup ()
256 vistracker = new Gtkmm2ext::VisibilityTracker (*_window);
258 delete_connection = _window->signal_delete_event().connect (sigc::mem_fun (*this, &WindowProxy::delete_event_handler));
259 configure_connection = _window->signal_configure_event().connect (sigc::mem_fun (*this, &WindowProxy::configure_handler), false);
260 map_connection = _window->signal_map().connect (sigc::mem_fun (*this, &WindowProxy::map_handler), false);
261 unmap_connection = _window->signal_unmap().connect (sigc::mem_fun (*this, &WindowProxy::unmap_handler), false);
267 WindowProxy::map_handler ()
269 /* emit our own signal */
274 WindowProxy::unmap_handler ()
276 /* emit out own signal */
281 WindowProxy::configure_handler (GdkEventConfigure* ev)
283 /* stupidly, the geometry data in the event isn't the same as we get
284 from the window geometry APIs.so we have to actively interrogate
285 them to get the new information.
287 the difference is generally down to window manager framing.
289 if (!visible() || !_window->is_mapped()) {
292 save_pos_and_size ();
298 WindowProxy::visible() const
301 /* update with current state */
302 _visible = vistracker->partially_visible();
308 WindowProxy::fully_visible () const
311 /* no vistracker .. no window .. cannot be fully visible */
314 return vistracker->fully_visible();
326 WindowProxy::maybe_show ()
334 WindowProxy::show_all ()
338 _window->show_all ();
342 WindowProxy::present ()
347 _window->show_all ();
350 /* turn off any mouse-based positioning */
351 _window->set_position (Gtk::WIN_POS_NONE);
364 WindowProxy::delete_event_handler (GdkEventAny* /*ev*/)
367 _action->activate ();
376 WindowProxy::save_pos_and_size ()
379 _window->get_position (_x_off, _y_off);
380 _window->get_size (_width, _height);
385 WindowProxy::set_pos_and_size ()
391 if ((_state_mask & Position) && (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1)) {
392 /* cancel any mouse-based positioning */
393 _window->set_position (Gtk::WIN_POS_NONE);
396 if ((_state_mask & Size) && _width != -1 && _height != -1) {
397 _window->resize (_width, _height);
400 if ((_state_mask & Position) && _x_off != -1 && _y_off != -1) {
401 _window->move (_x_off, _y_off);
406 WindowProxy::set_pos ()
412 if (!(_state_mask & Position)) {
416 if (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1) {
417 /* cancel any mouse-based positioning */
418 _window->set_position (Gtk::WIN_POS_NONE);
421 if (_x_off != -1 && _y_off != -1) {
422 _window->move (_x_off, _y_off);
427 WindowProxy::set_state_mask (StateMask sm)