From: Braden M. <br...@us...> - 2007-09-02 18:28:03
|
Update of /cvsroot/openvrml/openvrml/src/openvrml-xembed In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv4802/src/openvrml-xembed Modified Files: Makefile.am gtkvrmlbrowser.cpp gtkvrmlbrowser.h main.cpp Added Files: request_channel.h Log Message: Changes to facilitate setting openvrml-player's location entry after the world has been loaded. Significantly, access to the GIOChannel used by the GtkVrmlBrowser (i.e., the request channel) needed to be made thread-safe. Accordingly, all access to the request channel now goes through the function openvrml_xembed::write_request_chars. --- NEW FILE: request_channel.h --- // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 78 -*- // // OpenVRML XEmbed control // Copyright 2007 Braden N. McDaniel // // 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // # ifndef OPENVRML_XEMBED_REQUEST_CHANNEL_H # define OPENVRML_XEMBED_REQUEST_CHANNEL_H namespace openvrml_xembed { bool write_request_chars(const gchar * buf, gssize count, gsize * bytes_written); } # endif // ifndef OPENVRML_XEMBED_REQUEST_CHANNEL_H Index: main.cpp =================================================================== RCS file: /cvsroot/openvrml/openvrml/src/openvrml-xembed/main.cpp,v retrieving revision 1.7 retrieving revision 1.8 diff -C2 -d -r1.7 -r1.8 *** main.cpp 12 May 2007 03:29:41 -0000 1.7 --- main.cpp 2 Sep 2007 18:27:55 -0000 1.8 *************** *** 1,6 **** // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 78 -*- // ! // OpenVRML Mozilla plug-in ! // Copyright 2004, 2005, 2006 Braden N. McDaniel // // This program is free software; you can redistribute it and/or modify --- 1,6 ---- // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 78 -*- // ! // OpenVRML XEmbed control ! // Copyright 2004, 2005, 2006, 2007 Braden N. McDaniel // // This program is free software; you can redistribute it and/or modify *************** *** 34,37 **** --- 34,38 ---- # endif + # include "request_channel.h" # include "gtkvrmlbrowser.h" # include "command_istream.h" *************** *** 54,60 **** } namespace openvrml_xembed { ! struct command_istream_reader { command_istream_reader(command_istream & in, GtkVrmlBrowser & vrml_browser, --- 55,118 ---- } + extern "C" G_GNUC_INTERNAL + void openvrml_xembed_browser_event_func(GtkVrmlBrowser * source, + GtkVrmlBrowserEvent event, + gpointer data); + namespace openvrml_xembed { ! G_GNUC_INTERNAL GIOChannel * request_channel; ! G_GNUC_INTERNAL boost::mutex request_channel_mutex; ! ! // ! // Map a listener identifier from the client to a listener identifier ! // gotten from the GtkVrmlBrowser. ! // ! class G_GNUC_INTERNAL event_listener_id_map : std::map<gulong, gulong> { ! openvrml::read_write_mutex mutex_; ! ! public: ! using std::map<gulong, gulong>::iterator; ! using std::map<gulong, gulong>::value_type; ! ! using std::map<gulong, gulong>::end; ! ! value_type * insert(gulong command_listener_id, ! gulong widget_listener_id); ! void erase(iterator pos); ! iterator find(gulong command_listener_id); ! } event_listener_id_map_; ! ! event_listener_id_map::value_type * ! event_listener_id_map::insert(const gulong command_listener_id, ! const gulong widget_listener_id) ! { ! using std::pair; ! using std::make_pair; ! using std::map; ! ! openvrml::read_write_mutex::scoped_write_lock lock(this->mutex_); ! pair<map<gulong, gulong>::iterator, bool> result = ! this->map<gulong, gulong>::insert(make_pair(widget_listener_id, ! command_listener_id)); ! return result.second ! ? &(*result.first) ! : 0; ! } ! ! void event_listener_id_map::erase(iterator pos) ! { ! openvrml::read_write_mutex::scoped_write_lock lock(this->mutex_); ! this->std::map<gulong, gulong>::erase(pos); ! } ! ! event_listener_id_map::iterator ! event_listener_id_map::find(const gulong command_listener_id) ! { ! openvrml::read_write_mutex::scoped_read_lock lock(this->mutex_); ! return this->std::map<gulong, gulong>::find(command_listener_id); ! } ! ! struct G_GNUC_INTERNAL command_istream_reader { command_istream_reader(command_istream & in, GtkVrmlBrowser & vrml_browser, *************** *** 145,148 **** --- 203,251 ---- gtk_vrml_browser_load_url(this->vrml_browser_, urls, 0); + } else if (command == "add-browser-event-listener") { + size_t listener_id; + command_line_stream >> listener_id; + event_listener_id_map::value_type * const map_entry = + event_listener_id_map_.insert(listener_id, 0); + map_entry->second = + gtk_vrml_browser_add_listener( + this->vrml_browser_, + openvrml_xembed_browser_event_func, + &map_entry->second); + } else if (command == "remove-browser-event-listener") { + size_t listener_id; + command_line_stream >> listener_id; + const event_listener_id_map::iterator pos = + event_listener_id_map_.find(listener_id); + if (pos == event_listener_id_map_.end()) { + g_warning("Listener %lu not found", listener_id); + continue; + } + gboolean removed = + gtk_vrml_browser_remove_listener(this->vrml_browser_, + pos->second); + if (!removed) { + g_warning("No listener associated with %lu to be " + "removed", listener_id); + } + event_listener_id_map_.erase(pos); + } else if (command == "get-world-url") { + const gchar * const world_url = + gtk_vrml_browser_get_world_url(this->vrml_browser_); + scope_guard world_url_guard = + make_guard(g_free, const_cast<gchar *>(world_url)); + boost::ignore_unused_variable_warning(world_url_guard); + + std::ostringstream request; + request << "world-url " << world_url << '\n'; + gsize bytes_written; + const bool write_succeeded = + write_request_chars(request.str().data(), + request.str().length(), + &bytes_written); + if (!write_succeeded) { + g_warning("Failed to write world-url request: %s", + world_url); + } } } *************** *** 387,391 **** } ! GIOChannel * const request_channel = g_io_channel_unix_new(1); // stdout g_return_val_if_fail(request_channel, EXIT_FAILURE); scope_guard request_channel_guard = make_guard(request_channel_shutdown, --- 490,494 ---- } ! ::request_channel = g_io_channel_unix_new(1); // stdout g_return_val_if_fail(request_channel, EXIT_FAILURE); scope_guard request_channel_guard = make_guard(request_channel_shutdown, *************** *** 403,407 **** g_return_val_if_fail(window, EXIT_FAILURE); ! GtkWidget * const vrml_browser = gtk_vrml_browser_new(request_channel); g_return_val_if_fail(vrml_browser, EXIT_FAILURE); gtk_container_add(GTK_CONTAINER(window), vrml_browser); --- 506,510 ---- g_return_val_if_fail(window, EXIT_FAILURE); ! GtkWidget * const vrml_browser = gtk_vrml_browser_new(); g_return_val_if_fail(vrml_browser, EXIT_FAILURE); gtk_container_add(GTK_CONTAINER(window), vrml_browser); *************** *** 452,455 **** --- 555,576 ---- } + void openvrml_xembed_browser_event_func(GtkVrmlBrowser * /* source */, + GtkVrmlBrowserEvent event, + gpointer data) + { + using std::ostringstream; + + const gulong * listener_id = static_cast<gulong *>(data); + + ostringstream request; + request << "browser-event " << *listener_id << ' ' << event << '\n'; + gsize bytes_written; + const bool write_succeeded = + openvrml_xembed::write_request_chars(request.str().data(), + request.str().length(), + &bytes_written); + g_return_if_fail(write_succeeded); + } + namespace { *************** *** 488,489 **** --- 609,645 ---- } } + + namespace openvrml_xembed { + + bool write_request_chars(const gchar * const buf, + const gssize count, + gsize * const bytes_written) + { + g_assert(::request_channel); + + boost::mutex::scoped_lock lock(::request_channel_mutex); + + using boost::ref; + + GError * error = 0; + scope_guard error_guard = make_guard(g_error_free, ref(error)); + boost::ignore_unused_variable_warning(error_guard); + + GIOStatus status = + g_io_channel_write_chars(::request_channel, buf, count, + bytes_written, &error); + if (status != G_IO_STATUS_NORMAL) { + g_warning(error->message); + return false; + } + + status = g_io_channel_flush(::request_channel, &error); + if (status != G_IO_STATUS_NORMAL) { + g_warning(error->message); + return false; + } + + error_guard.dismiss(); + return true; + } + } Index: Makefile.am =================================================================== RCS file: /cvsroot/openvrml/openvrml/src/openvrml-xembed/Makefile.am,v retrieving revision 1.3 retrieving revision 1.4 diff -C2 -d -r1.3 -r1.4 *** Makefile.am 28 Apr 2007 19:12:23 -0000 1.3 --- Makefile.am 2 Sep 2007 18:27:55 -0000 1.4 *************** *** 9,14 **** -I$(mozincludedir) \ -DGTK_DISABLE_DEPRECATED ! AM_CXXFLAGS = @PTHREAD_CFLAGS@ @GTK_CFLAGS@ @GL_CFLAGS@ ! AM_LDFLAGS = @OPENVRML_RPATH@ $(GTK_LIBS) LDADD = $(top_builddir)/src/libopenvrml-gl/libopenvrml-gl.la \ $(top_builddir)/src/libopenvrml/libopenvrml.la \ --- 9,14 ---- -I$(mozincludedir) \ -DGTK_DISABLE_DEPRECATED ! AM_CXXFLAGS = $(PTHREAD_CFLAGS) $(GTK_CFLAGS) $(GL_CFLAGS) ! AM_LDFLAGS = $(OPENVRML_RPATH) $(GTK_LIBS) LDADD = $(top_builddir)/src/libopenvrml-gl/libopenvrml-gl.la \ $(top_builddir)/src/libopenvrml/libopenvrml.la \ *************** *** 23,27 **** command_istream.h \ plugin_streambuf.h \ ! gtkvrmlbrowser.h openvrml_xembed_SOURCES = \ main.cpp \ --- 23,28 ---- command_istream.h \ plugin_streambuf.h \ ! gtkvrmlbrowser.h \ ! request_channel.h openvrml_xembed_SOURCES = \ main.cpp \ Index: gtkvrmlbrowser.cpp =================================================================== RCS file: /cvsroot/openvrml/openvrml/src/openvrml-xembed/gtkvrmlbrowser.cpp,v retrieving revision 1.9 retrieving revision 1.10 diff -C2 -d -r1.9 -r1.10 *** gtkvrmlbrowser.cpp 15 May 2007 04:06:11 -0000 1.9 --- gtkvrmlbrowser.cpp 2 Sep 2007 18:27:55 -0000 1.10 *************** *** 24,31 **** --- 24,33 ---- // Must include before X11 headers. # include <boost/numeric/conversion/converter.hpp> + # include <boost/ptr_container/ptr_map.hpp> # include <X11/keysym.h> # include <gdk/gdkx.h> # include <openvrml/browser.h> # include <openvrml/gl/viewer.h> + # include "request_channel.h" # include "gtkvrmlbrowser.h" # include "plugin_streambuf.h" *************** *** 101,110 **** class G_GNUC_INTERNAL resource_fetcher : public openvrml::resource_fetcher { - GIOChannel * request_channel_; boost::mutex request_channel_mutex_; boost::thread_group thread_group_; public: - explicit resource_fetcher(GIOChannel & request_channel); virtual ~resource_fetcher() OPENVRML_NOTHROW; --- 103,110 ---- *************** *** 114,120 **** virtual std::auto_ptr<openvrml::resource_istream> do_get_resource(const std::string & uri); - - bool write_request_chars(const gchar * buf, gssize count, - gsize * bytes_written); }; --- 114,117 ---- *************** *** 122,126 **** class GtkGLViewer; ! class G_GNUC_INTERNAL browser_listener : public openvrml::browser_listener { --- 119,123 ---- class GtkGLViewer; ! class G_GNUC_INTERNAL redraw_listener : public openvrml::browser_listener { *************** *** 128,132 **** public: ! explicit browser_listener(GtkGLViewer & viewer); private: --- 125,129 ---- public: ! explicit redraw_listener(GtkGLViewer & viewer); private: *************** *** 134,143 **** }; class G_GNUC_INTERNAL GtkGLViewer : public openvrml::gl::viewer { ! friend class browser_listener; friend void (::gtk_vrml_browser_load_url)(GtkVrmlBrowser * vrml_browser, const gchar ** url, const gchar ** parameter); friend void (::gtk_vrml_browser_set_world)(GtkVrmlBrowser * vrml_browser, --- 131,191 ---- }; + + BOOST_STATIC_ASSERT(GTK_VRML_BROWSER_INITIALIZED + == GtkVrmlBrowserEvent( + openvrml::browser_event::initialized)); + BOOST_STATIC_ASSERT(GTK_VRML_BROWSER_SHUTDOWN + == GtkVrmlBrowserEvent( + openvrml::browser_event::shutdown)); + + class G_GNUC_INTERNAL event_func_listener : + boost::noncopyable, + public openvrml::browser_listener { + + GtkVrmlBrowser & vrml_browser_; + GtkVrmlBrowserEventFunc func_; + gpointer user_data_; + + public: + event_func_listener(GtkVrmlBrowser & vrml_browser, + GtkVrmlBrowserEventFunc func, + gpointer user_data): + vrml_browser_(vrml_browser), + func_(func), + user_data_(user_data) + {} + + virtual ~event_func_listener() OPENVRML_NOTHROW + {} + + virtual void + do_browser_changed(const openvrml::browser_event & event) + { + assert(this->func_); + (this->func_)(&this->vrml_browser_, + GtkVrmlBrowserEvent(event.id()), + this->user_data_); + } + }; + class G_GNUC_INTERNAL GtkGLViewer : public openvrml::gl::viewer { ! friend class redraw_listener; ! friend void (::gtk_vrml_browser_load_url)(GtkVrmlBrowser * vrml_browser, const gchar ** url, const gchar ** parameter); + + friend gchar * + (::gtk_vrml_browser_get_world_url)(GtkVrmlBrowser * vrml_browser); + + friend gulong + (::gtk_vrml_browser_add_listener)(GtkVrmlBrowser *, + GtkVrmlBrowserEventFunc, + gpointer user_data); + friend gboolean + (::gtk_vrml_browser_remove_listener)(GtkVrmlBrowser *, + gulong listener_id); + friend void (::gtk_vrml_browser_set_world)(GtkVrmlBrowser * vrml_browser, *************** *** 156,160 **** ::resource_fetcher fetcher_; openvrml::browser browser_; ! ::browser_listener browser_listener_; bool browser_initialized_; openvrml::read_write_mutex browser_initialized_mutex_; --- 204,208 ---- ::resource_fetcher fetcher_; openvrml::browser browser_; ! ::redraw_listener redraw_listener_; bool browser_initialized_; openvrml::read_write_mutex browser_initialized_mutex_; *************** *** 162,170 **** guint timer; public: bool redrawNeeded; ! GtkGLViewer(GIOChannel & request_channel, ! GtkVrmlBrowser & vrml_browser); virtual ~GtkGLViewer() throw (); --- 210,222 ---- guint timer; + typedef boost::ptr_map<gulong, event_func_listener> + event_func_listener_map; + + event_func_listener_map event_func_listener_map_; + public: bool redrawNeeded; ! explicit GtkGLViewer(GtkVrmlBrowser & vrml_browser); virtual ~GtkGLViewer() throw (); *************** *** 182,192 **** } ! GtkWidget * gtk_vrml_browser_new(GIOChannel * const request_channel) { GtkVrmlBrowser * const vrml_browser = GTK_VRML_BROWSER(g_object_new(GTK_TYPE_VRML_BROWSER, 0)); try { ! vrml_browser->viewer = new GtkGLViewer(*request_channel, ! *vrml_browser); } catch (std::bad_alloc &) { g_return_val_if_reached(0); --- 234,243 ---- } ! GtkWidget * gtk_vrml_browser_new() { GtkVrmlBrowser * const vrml_browser = GTK_VRML_BROWSER(g_object_new(GTK_TYPE_VRML_BROWSER, 0)); try { ! vrml_browser->viewer = new GtkGLViewer(*vrml_browser); } catch (std::bad_alloc &) { g_return_val_if_reached(0); *************** *** 241,244 **** --- 292,343 ---- } + gchar * gtk_vrml_browser_get_world_url(GtkVrmlBrowser * const vrml_browser) + { + GtkGLViewer & viewer = *static_cast<GtkGLViewer *>(vrml_browser->viewer); + return g_strdup(viewer.browser_.world_url().c_str()); + } + + gulong gtk_vrml_browser_add_listener(GtkVrmlBrowser * vrml_browser, + GtkVrmlBrowserEventFunc func, + gpointer user_data) + { + g_return_val_if_fail(vrml_browser, 0); + g_return_val_if_fail(func, 0); + + GtkGLViewer & viewer = *static_cast<GtkGLViewer *>(vrml_browser->viewer); + std::auto_ptr<event_func_listener> + listener(new event_func_listener(*vrml_browser, func, user_data)); + const gulong listener_id = ptrdiff_t(listener.get()); + const std::pair<GtkGLViewer::event_func_listener_map::iterator, bool> + result = viewer.event_func_listener_map_.insert(listener_id, + listener); + if (!result.second) { return 0; } + + scope_guard listener_map_guard = + make_obj_guard(viewer.event_func_listener_map_, + static_cast<GtkGLViewer::event_func_listener_map::size_type (GtkGLViewer::event_func_listener_map::*)(const GtkGLViewer::event_func_listener_map::key_type &)>(&GtkGLViewer::event_func_listener_map::erase), + listener_id); + + const bool add_listener_succeeded = + viewer.browser_.add_listener(*result.first->second); + + if (!add_listener_succeeded) { return 0; } + + listener_map_guard.dismiss(); + + return result.first->first; + } + + gboolean gtk_vrml_browser_remove_listener(GtkVrmlBrowser * vrml_browser, + gulong listener_id) + { + g_return_val_if_fail(vrml_browser, false); + + GtkGLViewer & viewer = *static_cast<GtkGLViewer *>(vrml_browser->viewer); + const GtkGLViewer::event_func_listener_map::size_type num_erased = + viewer.event_func_listener_map_.erase(listener_id); + return num_erased > 0; + } + void gtk_vrml_browser_set_world(GtkVrmlBrowser * vrml_browser, openvrml::resource_istream & in) *************** *** 563,570 **** namespace { - resource_fetcher::resource_fetcher(GIOChannel & request_channel): - request_channel_(&request_channel) - {} - resource_fetcher::~resource_fetcher() OPENVRML_NOTHROW { --- 662,665 ---- *************** *** 606,613 **** gsize bytes_written; const bool write_succeeded = ! this->resource_fetcher_ ! .write_request_chars(request.str().data(), ! request.str().length(), ! &bytes_written); if (!write_succeeded) { this->setstate(ios_base::badbit); --- 701,708 ---- gsize bytes_written; const bool write_succeeded = ! openvrml_xembed::write_request_chars( ! request.str().data(), ! request.str().length(), ! &bytes_written); if (!write_succeeded) { this->setstate(ios_base::badbit); *************** *** 644,683 **** } ! bool resource_fetcher::write_request_chars(const gchar * const buf, ! const gssize count, ! gsize * const bytes_written) ! { ! boost::mutex::scoped_lock lock(this->request_channel_mutex_); ! ! using boost::ref; ! ! GError * error = 0; ! scope_guard error_guard = make_guard(g_error_free, ref(error)); ! boost::ignore_unused_variable_warning(error_guard); ! ! GIOStatus status = ! g_io_channel_write_chars(this->request_channel_, buf, count, ! bytes_written, &error); ! if (status != G_IO_STATUS_NORMAL) { ! g_warning(error->message); ! return false; ! } ! ! status = g_io_channel_flush(this->request_channel_, &error); ! if (status != G_IO_STATUS_NORMAL) { ! g_warning(error->message); ! return false; ! } ! ! error_guard.dismiss(); ! return true; ! } ! ! browser_listener::browser_listener(GtkGLViewer & viewer): viewer_(viewer) {} void ! browser_listener::do_browser_changed(const openvrml::browser_event & event) { if (event.id() == openvrml::browser_event::initialized) { --- 739,748 ---- } ! redraw_listener::redraw_listener(GtkGLViewer & viewer): viewer_(viewer) {} void ! redraw_listener::do_browser_changed(const openvrml::browser_event & event) { if (event.id() == openvrml::browser_event::initialized) { *************** *** 703,711 **** // all browser output to stderr. // ! GtkGLViewer::GtkGLViewer(GIOChannel & request_channel, ! GtkVrmlBrowser & vrml_browser): ! fetcher_(request_channel), browser_(this->fetcher_, std::cerr, std::cerr), ! browser_listener_(*this), browser_initialized_(true), vrml_browser_(vrml_browser), --- 768,774 ---- // all browser output to stderr. // ! GtkGLViewer::GtkGLViewer(GtkVrmlBrowser & vrml_browser): browser_(this->fetcher_, std::cerr, std::cerr), ! redraw_listener_(*this), browser_initialized_(true), vrml_browser_(vrml_browser), *************** *** 713,717 **** redrawNeeded(false) { ! this->browser_.add_listener(this->browser_listener_); this->browser_.viewer(this); } --- 776,780 ---- redrawNeeded(false) { ! this->browser_.add_listener(this->redraw_listener_); this->browser_.viewer(this); } *************** *** 720,724 **** { if (this->timer) { g_source_remove(timer); } ! this->browser_.remove_listener(this->browser_listener_); } --- 783,787 ---- { if (this->timer) { g_source_remove(timer); } ! this->browser_.remove_listener(this->redraw_listener_); } Index: gtkvrmlbrowser.h =================================================================== RCS file: /cvsroot/openvrml/openvrml/src/openvrml-xembed/gtkvrmlbrowser.h,v retrieving revision 1.2 retrieving revision 1.3 diff -C2 -d -r1.2 -r1.3 *** gtkvrmlbrowser.h 5 Feb 2007 05:36:12 -0000 1.2 --- gtkvrmlbrowser.h 2 Sep 2007 18:27:55 -0000 1.3 *************** *** 46,55 **** }; GType gtk_vrml_browser_get_type(void) G_GNUC_CONST; ! GtkWidget *gtk_vrml_browser_new(GIOChannel *request_channel); void gtk_vrml_browser_load_url(GtkVrmlBrowser *vrml_browser, const gchar **url, const gchar **parameter); G_END_DECLS --- 46,73 ---- }; + // + // This must correspond to openvrml::browser_event::type_id. + // + typedef enum { + GTK_VRML_BROWSER_INITIALIZED = 1, + GTK_VRML_BROWSER_SHUTDOWN = 2 + } GtkVrmlBrowserEvent; + + typedef void (*GtkVrmlBrowserEventFunc)(GtkVrmlBrowser *source, + GtkVrmlBrowserEvent event, + gpointer data); + GType gtk_vrml_browser_get_type(void) G_GNUC_CONST; ! GtkWidget *gtk_vrml_browser_new(); void gtk_vrml_browser_load_url(GtkVrmlBrowser *vrml_browser, const gchar **url, const gchar **parameter); + gchar *gtk_vrml_browser_get_world_url(GtkVrmlBrowser *vrml_browser); + gulong gtk_vrml_browser_add_listener(GtkVrmlBrowser *vrml_browser, + GtkVrmlBrowserEventFunc func, + gpointer user_data); + gboolean gtk_vrml_browser_remove_listener(GtkVrmlBrowser *vrml_browser, + gulong listener_id); G_END_DECLS |