From df05e97288b48f10d9133d0dd9e56a156a5c3287 Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 1 Jul 2015 17:26:14 -0400 Subject: [PATCH] first version of Gtkmm2ext::WindowProxy --- libs/gtkmm2ext/gtkmm2ext/window_proxy.h | 95 ++++++++ libs/gtkmm2ext/window_proxy.cc | 303 ++++++++++++++++++++++++ 2 files changed, 398 insertions(+) create mode 100644 libs/gtkmm2ext/gtkmm2ext/window_proxy.h create mode 100644 libs/gtkmm2ext/window_proxy.cc diff --git a/libs/gtkmm2ext/gtkmm2ext/window_proxy.h b/libs/gtkmm2ext/gtkmm2ext/window_proxy.h new file mode 100644 index 0000000000..3ec2080928 --- /dev/null +++ b/libs/gtkmm2ext/gtkmm2ext/window_proxy.h @@ -0,0 +1,95 @@ +/* + Copyright (C) 2015 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __gtkmm2ext_window_proxy_h__ + +#include +#include +#include +#include + +class XMLNode; + +#include "gtkmm2ext/visibility.h" + +namespace Gtk { +class Window; +class Action; +} + +namespace Gtkmm2ext { + +class VisibilityTracker; + +class LIBGTKMM2EXT_API WindowProxy : public virtual sigc::trackable +{ + public: + WindowProxy (const std::string& name, const std::string& menu_name); + WindowProxy (const std::string& name, const std::string& menu_name, const XMLNode&); + virtual ~WindowProxy(); + + void show (); + void show_all (); + void hide (); + void present (); + void maybe_show (); + + bool visible() const { return _visible; } + const std::string& name() const { return _name; } + const std::string& menu_name() const { return _menu_name; } + + std::string action_name() const; + void set_action (Glib::RefPtr); + Glib::RefPtr action() const { return _action; }; + + void drop_window (); + void use_window (Gtk::Window&); + + virtual Gtk::Window* get (bool create = false) = 0; + + virtual void toggle (); + + virtual void set_state (const XMLNode&); + virtual XMLNode& get_state () const; + + operator bool() const { return _window != 0; } + + protected: + std::string _name; + std::string _menu_name; + Glib::RefPtr _action; + Gtk::Window* _window; + mutable bool _visible; ///< true if the window should be visible on startup + mutable int _x_off; ///< x position + mutable int _y_off; ///< y position + mutable int _width; ///< width + mutable int _height; ///< height + Gtkmm2ext::VisibilityTracker* vistracker; + + void save_pos_and_size (); + void set_pos_and_size (); + + virtual bool delete_event_handler (GdkEventAny *ev); + + virtual void setup (); +}; + +} + +#endif /* __gtkmm2ext_window_proxy_h__ */ diff --git a/libs/gtkmm2ext/window_proxy.cc b/libs/gtkmm2ext/window_proxy.cc new file mode 100644 index 0000000000..b01fc6c628 --- /dev/null +++ b/libs/gtkmm2ext/window_proxy.cc @@ -0,0 +1,303 @@ +/* + Copyright (C) 2015 Paul Davis + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include + +#include "pbd/convert.h" +#include "pbd/xml++.h" + +#include "gtkmm2ext/window_proxy.h" +#include "gtkmm2ext/visibility_tracker.h" + +#include "i18n.h" + +using namespace Gtk; +using namespace Gtkmm2ext; +using namespace PBD; + +WindowProxy::WindowProxy (const std::string& name, const std::string& menu_name) + : _name (name) + , _menu_name (menu_name) + , _window (0) + , _visible (false) + , _x_off (-1) + , _y_off (-1) + , _width (-1) + , _height (-1) + , vistracker (0) +{ +} + +WindowProxy::WindowProxy (const std::string& name, const std::string& menu_name, const XMLNode& node) + : _name (name) + , _menu_name (menu_name) + , _window (0) + , _visible (false) + , _x_off (-1) + , _y_off (-1) + , _width (-1) + , _height (-1) + , vistracker (0) +{ + set_state (node); +} + +WindowProxy::~WindowProxy () +{ + delete vistracker; + delete _window; +} + +void +WindowProxy::set_state (const XMLNode& node) +{ + XMLNodeList children = node.children (); + + 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) { + break; + } + + ++i; + } + + if (i != children.end()) { + + XMLProperty* prop; + + if ((prop = (*i)->property (X_("visible"))) != 0) { + _visible = PBD::string_is_affirmative (prop->value ()); + } + + 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()); + } + } + + /* if the window is marked visible but doesn't yet exist, create it */ + + if (_visible) { + if (!_window) { + _window = get (true); + } + } + + if (_window) { + setup (); + } +} + +void +WindowProxy::set_action (Glib::RefPtr act) +{ + _action = act; +} + +std::string +WindowProxy::action_name() const +{ + return string_compose (X_("toggle-%1"), _name); +} + +void +WindowProxy::toggle() +{ + if (!_window) { + (void) get (true); + assert (_window); + /* XXX this is a hack - the window object should really + ensure its components are all visible. sigh. + */ + _window->show_all(); + /* we'd like to just call this and nothing else */ + _window->present (); + + } else { + if (_window->is_mapped()) { + save_pos_and_size(); + } + vistracker->cycle_visibility (); + if (_window->is_mapped()) { + if (_width != -1 && _height != -1) { + _window->set_default_size (_width, _height); + } + if (_x_off != -1 && _y_off != -1) { + _window->move (_x_off, _y_off); + } + } + } +} + +XMLNode& +WindowProxy::get_state () const +{ + XMLNode* node = new XMLNode (X_("Window")); + char buf[32]; + + node->add_property (X_("name"), _name); + + if (_window && vistracker) { + + /* we have a window, so use current state */ + + _visible = vistracker->partially_visible (); + _window->get_position (_x_off, _y_off); + _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); + + return *node; +} + +void +WindowProxy::drop_window () +{ + if (_window) { + _window->hide (); + delete _window; + _window = 0; + delete vistracker; + vistracker = 0; + } +} + +void +WindowProxy::use_window (Gtk::Window& win) +{ + drop_window (); + _window = &win; + setup (); +} + +void +WindowProxy::setup () +{ + assert (_window); + + vistracker = new Gtkmm2ext::VisibilityTracker (*_window); + _window->signal_delete_event().connect (sigc::mem_fun (*this, &WindowProxy::delete_event_handler)); + + set_pos_and_size (); +} + +void +WindowProxy::show () +{ + get (true); + assert (_window); + _window->show (); +} + +void +WindowProxy::maybe_show () +{ + if (_visible) { + show (); + } +} + +void +WindowProxy::show_all () +{ + get (true); + assert (_window); + _window->show_all (); +} + +void +WindowProxy::present () +{ + get (true); + assert (_window); + + _window->show_all (); + _window->present (); + + /* turn off any mouse-based positioning */ + _window->set_position (Gtk::WIN_POS_NONE); +} + +void +WindowProxy::hide () +{ + if (_window) { + save_pos_and_size(); + _window->hide (); + } +} + +bool +WindowProxy::delete_event_handler (GdkEventAny* /*ev*/) +{ + hide(); + return true; +} + +void +WindowProxy::save_pos_and_size () +{ + if (_window) { + _window->get_position (_x_off, _y_off); + _window->get_size (_width, _height); + } +} + +void +WindowProxy::set_pos_and_size () +{ + if (!_window) { + return; + } + + if (_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) { + _window->set_default_size (_width, _height); + } + + if (_x_off != -1 && _y_off != -1) { + _window->move (_x_off, _y_off); + } +} +