Fix crash for external windows
[ardour.git] / libs / gtkmm2ext / window_proxy.cc
index 6ad6a4d86bab08d23f2c278de3eb9d87f55a61af..9ba0e320de6e27461aaf3ebd541011af1d42b4be 100644 (file)
 #include <gtkmm/action.h>
 #include <gtkmm/window.h>
 
-#include "pbd/convert.h"
 #include "pbd/xml++.h"
-#include "pbd/stacktrace.h"
 
 #include "gtkmm2ext/window_proxy.h"
 #include "gtkmm2ext/visibility_tracker.h"
 
-#include "i18n.h"
+#include "pbd/i18n.h"
 
 using namespace Gtk;
 using namespace Gtkmm2ext;
@@ -42,6 +40,7 @@ WindowProxy::WindowProxy (const std::string& name)
        , _width (-1)
        , _height (-1)
        , vistracker (0)
+       , _state_mask (StateMask (Position|Size))
 {
 }
 
@@ -55,6 +54,7 @@ WindowProxy::WindowProxy (const std::string& name, const std::string& menu_name)
        , _width (-1)
        , _height (-1)
        , vistracker (0)
+       , _state_mask (StateMask (Position|Size))
 {
 }
 
@@ -68,6 +68,7 @@ WindowProxy::WindowProxy (const std::string& name, const std::string& menu_name,
        , _width (-1)
        , _height (-1)
        , vistracker (0)
+       , _state_mask (StateMask (Position|Size))
 {
        set_state (node, 0);
 }
@@ -82,12 +83,14 @@ int
 WindowProxy::set_state (const XMLNode& node, int /* version */)
 {
        XMLNodeList children = node.children ();
-
+       XMLNode const * child;
        XMLNodeList::const_iterator i = children.begin ();
 
        while (i != children.end()) {
-               XMLProperty* prop = (*i)->property (X_("name"));
-               if ((*i)->name() == X_("Window") && prop && prop->value() == _name) {
+               child = *i;
+               std::string name;
+               if (child->name () == X_("Window") && child->get_property (X_("name"), name) &&
+                   name == _name) {
                        break;
                }
 
@@ -96,24 +99,13 @@ WindowProxy::set_state (const XMLNode& node, int /* version */)
 
        if (i != children.end()) {
 
-               XMLProperty* prop;
-
-               if ((prop = (*i)->property (X_("visible"))) != 0) {
-                       _visible = PBD::string_is_affirmative (prop->value ());
-               }
+               child = *i;
 
-               if ((prop = (*i)->property (X_("x-off"))) != 0) {
-                       _x_off = atoi (prop->value());
-               }
-               if ((prop = (*i)->property (X_("y-off"))) != 0) {
-                       _y_off = atoi (prop->value());
-               }
-               if ((prop = (*i)->property (X_("x-size"))) != 0) {
-                       _width = atoi (prop->value());
-               }
-               if ((prop = (*i)->property (X_("y-size"))) != 0) {
-                       _height = atoi (prop->value());
-               }
+               child->get_property (X_("visible"), _visible);
+               child->get_property (X_("x-off"), _x_off);
+               child->get_property (X_("y-off"), _y_off);
+               child->get_property (X_("x-size"), _width);
+               child->get_property (X_("y-size"), _height);
        }
 
        if (_window) {
@@ -153,7 +145,11 @@ WindowProxy::toggle()
                        save_pos_and_size();
                }
 
-               vistracker->cycle_visibility ();
+               if (vistracker) {
+                       vistracker->cycle_visibility ();
+               } else {
+                       _window->present ();
+               }
 
                if (_window->is_mapped()) {
                        if (_width != -1 && _height != -1) {
@@ -176,9 +172,8 @@ XMLNode&
 WindowProxy::get_state ()
 {
        XMLNode* node = new XMLNode (xml_node_name());
-       char buf[32];
 
-       node->add_property (X_("name"), _name);
+       node->set_property (X_("name"), _name);
 
        if (_window && vistracker) {
 
@@ -189,15 +184,29 @@ WindowProxy::get_state ()
                _window->get_size (_width, _height);
        }
 
-       node->add_property (X_("visible"), _visible? X_("yes") : X_("no"));
-       snprintf (buf, sizeof (buf), "%d", _x_off);
-       node->add_property (X_("x-off"), buf);
-       snprintf (buf, sizeof (buf), "%d", _y_off);
-       node->add_property (X_("y-off"), buf);
-       snprintf (buf, sizeof (buf), "%d", _width);
-       node->add_property (X_("x-size"), buf);
-       snprintf (buf, sizeof (buf), "%d", _height);
-       node->add_property (X_("y-size"), buf);
+       int x, y, w, h;
+
+       if (_state_mask & Position) {
+               x = _x_off;
+               y = _y_off;
+       } else {
+               x = -1;
+               y = -1;
+       }
+
+       if (_state_mask & Size) {
+               w = _width;
+               h = _height;
+       } else {
+               w = -1;
+               h = -1;
+       }
+
+       node->set_property (X_("visible"), _visible);
+       node->set_property (X_("x-off"), x);
+       node->set_property (X_("y-off"), y);
+       node->set_property (X_("x-size"), w);
+       node->set_property (X_("y-size"), h);
 
        return *node;
 }
@@ -207,6 +216,10 @@ WindowProxy::drop_window ()
 {
        if (_window) {
                _window->hide ();
+               delete_connection.disconnect ();
+               configure_connection.disconnect ();
+               map_connection.disconnect ();
+               unmap_connection.disconnect ();
                delete _window;
                _window = 0;
                delete vistracker;
@@ -227,12 +240,48 @@ WindowProxy::setup ()
 {
        assert (_window);
 
-       vistracker = new Gtkmm2ext::VisibilityTracker (*_window);
-       _window->signal_delete_event().connect (sigc::mem_fun (*this, &WindowProxy::delete_event_handler));
+       assert (_window);
+
+       delete_connection = _window->signal_delete_event().connect (sigc::mem_fun (*this, &WindowProxy::delete_event_handler));
+       configure_connection = _window->signal_configure_event().connect (sigc::mem_fun (*this, &WindowProxy::configure_handler), false);
+       map_connection = _window->signal_map().connect (sigc::mem_fun (*this, &WindowProxy::map_handler), false);
+       unmap_connection = _window->signal_unmap().connect (sigc::mem_fun (*this, &WindowProxy::unmap_handler), false);
 
        set_pos_and_size ();
 }
 
+void
+WindowProxy::map_handler ()
+{
+       vistracker = new Gtkmm2ext::VisibilityTracker (*_window);
+       /* emit our own signal */
+       signal_map ();
+}
+
+void
+WindowProxy::unmap_handler ()
+{
+       /* emit out own signal */
+       signal_unmap ();
+}
+
+bool
+WindowProxy::configure_handler (GdkEventConfigure* ev)
+{
+       /* stupidly, the geometry data in the event isn't the same as we get
+          from the window geometry APIs.so we have to actively interrogate
+          them to get the new information.
+
+          the difference is generally down to window manager framing.
+       */
+       if (!visible() || !_window->is_mapped()) {
+               return false;
+       }
+       save_pos_and_size ();
+       return false;
+}
+
+
 bool
 WindowProxy::visible() const
 {
@@ -327,16 +376,16 @@ WindowProxy::set_pos_and_size ()
                return;
        }
 
-       if (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1) {
+       if ((_state_mask & Position) && (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1)) {
                /* cancel any mouse-based positioning */
                _window->set_position (Gtk::WIN_POS_NONE);
        }
 
-       if (_width != -1 && _height != -1) {
+       if ((_state_mask & Size) && _width != -1 && _height != -1) {
                _window->resize (_width, _height);
        }
 
-       if (_x_off != -1 && _y_off != -1) {
+       if ((_state_mask & Position) && _x_off != -1 && _y_off != -1) {
                _window->move (_x_off, _y_off);
        }
 }
@@ -348,6 +397,10 @@ WindowProxy::set_pos ()
                return;
        }
 
+       if (!(_state_mask & Position)) {
+               return;
+       }
+
        if (_width != -1 || _height != -1 || _x_off != -1 || _y_off != -1) {
                /* cancel any mouse-based positioning */
                _window->set_position (Gtk::WIN_POS_NONE);
@@ -357,3 +410,9 @@ WindowProxy::set_pos ()
                _window->move (_x_off, _y_off);
        }
 }
+
+void
+WindowProxy::set_state_mask (StateMask sm)
+{
+       _state_mask = sm;
+}