From: Braden M. <br...@us...> - 2006-09-27 06:35:28
|
Update of /cvsroot/openvrml/openvrml/src/openvrml-gtkplug In directory sc8-pr-cvs3.sourceforge.net:/tmp/cvs-serv18608/src/openvrml-gtkplug Added Files: Tag: OpenVRML-GtkPlug-BRANCH .cvsignore Makefile.am bounded_buffer.h command_istream.cpp command_istream.h flag.cpp flag.h gtkvrmlbrowser.cpp gtkvrmlbrowser.h main.cpp plugin_streambuf.cpp plugin_streambuf.h Log Message: Moved openvrml-player to openvrml-gtkplug. --- NEW FILE: .cvsignore --- Makefile Makefile.in openvrml-player --- NEW FILE: main.cpp --- // -*- 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 // 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 // # include <iostream> # include <sstream> # include <boost/lexical_cast.hpp> # include <boost/thread/thread.hpp> # include <unistd.h> // Must include before X11 headers. # include <boost/numeric/conversion/converter.hpp> # include <gtk/gtk.h> # include <openvrml/browser.h> # include "gtkvrmlbrowser.h" # include "command_istream.h" # include "plugin_streambuf.h" # include "flag.h" using namespace openvrml_player; namespace { const char application_name[] = "OpenVRML GtkPlug"; // // We don't already know what the URI of the initial stream is until we // start getting that data from the browser. This is a placeholder that // is used to identify the plugin_streambuf that will be used to receive // the initial stream data. // const char initial_stream_uri[] = "x-openvrml-initial:"; // // Used to signal the various threads that we're done. "quit" is // initiated when the command_istream gets EOF. At that point, the // command_istream_reader thread sets quit_flag to true. This flag is // checked by the command_channel_loop thread and the main (rendering) // thread, signaling them to terminate. // flag quit_flag; } namespace openvrml_player { struct command_istream_reader { explicit command_istream_reader(command_istream & in): in_(&in) {} void operator()() const throw () { using std::string; string command_line; while (getline(*this->in_, command_line)) { using std::istringstream; istringstream command_line_stream(command_line); string command; command_line_stream >> command; if (command == "get-url-result") { using boost::shared_ptr; std::string url; int result; command_line_stream >> url >> result; shared_ptr<plugin_streambuf> streambuf = uninitialized_plugin_streambuf_map_.find(url); assert(streambuf); streambuf->set_get_url_result(result); } else if (command == "new-stream") { using boost::shared_ptr; size_t stream_id; std::string type, url; command_line_stream >> stream_id >> type >> url; shared_ptr<plugin_streambuf> streambuf = uninitialized_plugin_streambuf_map_.find(url); static bool got_initial_stream = false; if (!streambuf) { if (!got_initial_stream) { g_assert(uninitialized_plugin_streambuf_map_.size() == 1); streambuf = uninitialized_plugin_streambuf_map_.front(); got_initial_stream = true; } else { g_warning("Attempt to create an unrequested " "stream."); continue; } } streambuf->init(stream_id, url, type); } else if (command == "destroy-stream") { size_t stream_id; command_line_stream >> stream_id; plugin_streambuf_map_t::iterator pos = plugin_streambuf_map.find(stream_id); if (pos == plugin_streambuf_map.end()) { g_warning("Attempt to destroy a nonexistent stream."); continue; } pos->second->buf_.set_eof(); plugin_streambuf_map.erase(pos); } else if (command == "write") { size_t stream_id, offset, length; command_line_stream >> stream_id >> offset >> length; plugin_streambuf_map_t::const_iterator pos = plugin_streambuf_map.find(stream_id); if (pos == plugin_streambuf_map.end()) { g_warning("Attempt to write to a nonexistent stream."); continue; } for (size_t i = 0; i < length; ++i) { pos->second->buf_.put(this->in_->get()); } } } // // Got EOF from the command stream. Time to shut down. // ::quit_flag.value(true); // // We can safely shut down the Gtk main loop from here. // // (However, trying to shut down the command_main loop results in // it deadlocking in g_main_context_check's call to poll. So we // still use the annoying quit_flag condition variable (see above) // to end that thread). // gtk_main_quit(); } private: command_istream * in_; }; } extern "C" gboolean openvrml_player_command_channel_loop_quit_event(gpointer data); namespace { gchar ** args; GOptionEntry options[] = { { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_STRING_ARRAY, &args, "a GtkSocket id", "GTK-SOCKET-ID" }, { 0, '\0', 0, G_OPTION_ARG_NONE, 0, 0, 0 } }; struct initial_stream_reader { initial_stream_reader( const boost::shared_ptr<plugin_streambuf> & streambuf, GtkVrmlBrowser & vrml_browser): streambuf_(streambuf), vrml_browser_(&vrml_browser) {} void operator()() const throw () { class plugin_istream : public openvrml::resource_istream { boost::shared_ptr<plugin_streambuf> streambuf_; public: explicit plugin_istream( const boost::shared_ptr<plugin_streambuf> & streambuf): openvrml::resource_istream(streambuf.get()), streambuf_(streambuf) {} virtual ~plugin_istream() throw () {} private: virtual const std::string do_url() const throw (std::bad_alloc) { return this->streambuf_->url(); } virtual const std::string do_type() const throw (std::bad_alloc) { return this->streambuf_->type(); } virtual bool do_data_available() const throw () { return this->streambuf_->data_available(); } } in(this->streambuf_); gtk_vrml_browser_set_world(this->vrml_browser_, in); } private: boost::shared_ptr<plugin_streambuf> streambuf_; GtkVrmlBrowser * vrml_browser_; }; GIOChannel * request_channel; struct command_channel_loop { explicit command_channel_loop(GMainLoop & main_loop): main_loop_(&main_loop) {} void operator()() const throw () { GSource * const quit = g_idle_source_new(); const GDestroyNotify notify = 0; g_source_set_callback( quit, ::openvrml_player_command_channel_loop_quit_event, this->main_loop_, notify); guint source_id = g_source_attach(quit, g_main_loop_get_context(this->main_loop_)); g_return_if_fail(source_id != 0); g_main_loop_run(this->main_loop_); } private: GMainLoop * main_loop_; }; } int main(int argc, char * argv[]) { using std::cerr; using std::endl; using std::vector; using boost::function0; using boost::shared_ptr; using boost::thread; using boost::thread_group; using namespace openvrml_player; g_set_application_name(application_name); gtk_init(&argc, &argv); gtk_gl_init(&argc, &argv); GError * error = 0; GOptionContext * const context = g_option_context_new("- render VRML worlds"); const gchar * const translation_domain = 0; g_option_context_add_main_entries(context, options, translation_domain); g_option_context_add_group(context, gtk_get_option_group(true)); gboolean succeeded = g_option_context_parse(context, &argc, &argv, &error); if (!succeeded) { if (error) { g_critical(error->message); g_error_free(error); } return EXIT_FAILURE; } if (!args) { cerr << argv[0] << ": missing required GTK-SOCKET-ID argument" << endl; return EXIT_FAILURE; } GdkNativeWindow socket_id; try { socket_id = boost::lexical_cast<GdkNativeWindow>(args[0]); } catch (const boost::bad_lexical_cast & ex) { cerr << argv[0] << ": expected integer value for GTK-SOCKET-ID " "argument" << endl; return EXIT_FAILURE; } command_istream command_in; ::request_channel = g_io_channel_unix_new(1); // stdout GtkWidget * const window = gtk_plug_new(socket_id); GtkWidget * const vrml_browser = gtk_vrml_browser_new(::request_channel); gtk_container_add(GTK_CONTAINER(window), vrml_browser); gtk_widget_show_all(window); thread_group threads; GMainContext * command_main_context = 0; GMainLoop * command_main = 0; GIOChannel * command_channel = 0; GSource * command_watch = 0; command_main_context = g_main_context_new(); command_main = g_main_loop_new(command_main_context, false); command_channel = g_io_channel_unix_new(0); // stdin error = 0; GIOStatus status = g_io_channel_set_encoding(command_channel, 0, // binary (no encoding) &error); if (status != G_IO_STATUS_NORMAL) { if (error) { g_critical(error->message); g_error_free(error); } return EXIT_FAILURE; } command_watch = g_io_create_watch(command_channel, GIOCondition(G_IO_IN | G_IO_HUP)); const GDestroyNotify notify = 0; g_source_set_callback( command_watch, reinterpret_cast<GSourceFunc>(::command_data_available), static_cast<command_streambuf *>(command_in.rdbuf()), notify); guint source_id = g_source_attach(command_watch, command_main_context); g_return_val_if_fail(source_id != 0, EXIT_FAILURE); function0<void> command_channel_loop_func = command_channel_loop(*command_main); threads.create_thread(command_channel_loop_func); shared_ptr<plugin_streambuf> initial_stream( new plugin_streambuf(initial_stream_uri)); uninitialized_plugin_streambuf_map_.insert(initial_stream_uri, initial_stream); function0<void> initial_stream_reader_func = initial_stream_reader(initial_stream, *GTK_VRML_BROWSER(vrml_browser)); threads.create_thread(initial_stream_reader_func); function0<void> read_commands = command_istream_reader(command_in); threads.create_thread(read_commands); gtk_main(); threads.join_all(); g_source_unref(command_watch); status = g_io_channel_shutdown(command_channel, true, &error); if (status != G_IO_STATUS_NORMAL) { if (error) { g_critical(error->message); g_error_free(error); } } g_io_channel_unref(command_channel); g_main_loop_unref(command_main); g_main_context_unref(command_main_context); if (::request_channel) { GError * error = 0; const gboolean flush = false; GIOStatus status = g_io_channel_shutdown(::request_channel, flush, &error); if (status != G_IO_STATUS_NORMAL) { if (error) { g_critical(error->message); g_error_free(error); } } } g_io_channel_unref(::request_channel); } gboolean openvrml_player_command_channel_loop_quit_event(const gpointer data) { GMainLoop * const main_loop = static_cast<GMainLoop *>(data); if (::quit_flag.value()) { g_main_loop_quit(main_loop); return false; } return true; } --- NEW FILE: gtkvrmlbrowser.cpp --- // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; -*- // // OpenVRML Mozilla plug-in // Copyright 2004, 2005, 2006 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 // # include <iostream> # include <sstream> // Must include before X11 headers. # include <boost/numeric/conversion/converter.hpp> # include <X11/keysym.h> # include <gdk/gdkx.h> # include <openvrml/browser.h> # include <openvrml/gl/viewer.h> # include "gtkvrmlbrowser.h" # include "plugin_streambuf.h" extern "C" { void gtk_vrml_browser_class_init(GtkVrmlBrowserClass * klass); void gtk_vrml_browser_init(GtkVrmlBrowser * vrml_browser); G_GNUC_INTERNAL gboolean gtk_vrml_browser_destroy(GtkWidget * widget, GdkEvent * event, gpointer data); G_GNUC_INTERNAL gboolean gtk_vrml_browser_realize(GtkWidget * widget, GdkEvent * event, gpointer data); G_GNUC_INTERNAL gboolean gtk_vrml_browser_expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer data); G_GNUC_INTERNAL gboolean gtk_vrml_browser_configure_event(GtkWidget * widget, GdkEventConfigure * event, gpointer data); G_GNUC_INTERNAL gboolean gtk_vrml_browser_key_press_event(GtkWidget * widget, GdkEventKey * event, gpointer data); G_GNUC_INTERNAL gboolean gtk_vrml_browser_button_press_event(GtkWidget * widget, GdkEventButton * event, gpointer data); G_GNUC_INTERNAL gboolean gtk_vrml_browser_button_release_event(GtkWidget * widget, GdkEventButton * event, gpointer data); G_GNUC_INTERNAL gboolean gtk_vrml_browser_motion_notify_event(GtkWidget * widget, GdkEventMotion * event, gpointer data); G_GNUC_INTERNAL gint gtk_vrml_browser_timeout_callback(gpointer ptr); } GType gtk_vrml_browser_get_type() { static GType type = 0; if (!type) { static const GTypeInfo info = { sizeof (GtkVrmlBrowserClass), 0, // base_init 0, // base_finalize reinterpret_cast<GClassInitFunc>(gtk_vrml_browser_class_init), 0, // class_finalize 0, // class_data sizeof (GtkVrmlBrowser), 0, // n_preallocs reinterpret_cast<GInstanceInitFunc>(gtk_vrml_browser_init), 0 // value_table }; type = g_type_register_static(GTK_TYPE_DRAWING_AREA, "GtkVrmlBrowser", &info, GTypeFlags(0)); } return type; } namespace { G_GNUC_INTERNAL GdkGLConfig * gl_config; class G_GNUC_INTERNAL browser : public openvrml::browser { GIOChannel * request_channel_; public: explicit browser(GIOChannel & request_channel); private: virtual std::auto_ptr<openvrml::resource_istream> do_get_resource(const std::string & uri); }; class G_GNUC_INTERNAL GtkGLViewer : public openvrml::gl::viewer { 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, openvrml::resource_istream & in); friend gint (::gtk_vrml_browser_timeout_callback)(gpointer ptr); friend gboolean (::gtk_vrml_browser_expose_event)(GtkWidget *, GdkEventExpose *, gpointer); ::browser browser_; GtkVrmlBrowser & vrml_browser_; guint timer; public: bool redrawNeeded; GtkGLViewer(GIOChannel & request_channel, GtkVrmlBrowser & vrml_browser); virtual ~GtkGLViewer() throw (); void timer_update(); protected: // // Implement pure virtual methods from openvrml::gl::viewer. // virtual void post_redraw(); virtual void set_cursor(openvrml::gl::viewer::cursor_style); virtual void swap_buffers(); virtual void set_timer(double); }; } 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); } static_cast<GtkGLViewer *>(vrml_browser->viewer) ->resize(GTK_WIDGET(vrml_browser)->allocation.width, GTK_WIDGET(vrml_browser)->allocation.height); return GTK_WIDGET(vrml_browser); } void gtk_vrml_browser_load_url(GtkVrmlBrowser * const vrml_browser, const gchar ** url, const gchar ** parameter) { using std::string; using std::vector; GtkGLViewer & viewer = *static_cast<GtkGLViewer *>(vrml_browser->viewer); vector<string> url_vec, param_vec; while (url && *url) { url_vec.push_back(*(url++)); } while (parameter && *parameter) { param_vec.push_back(*(parameter++)); } viewer.browser_.load_url(url_vec, param_vec); } void gtk_vrml_browser_set_world(GtkVrmlBrowser * vrml_browser, openvrml::resource_istream & in) { GtkGLViewer & viewer = *static_cast<GtkGLViewer *>(vrml_browser->viewer); viewer.browser_.set_world(in); } void gtk_vrml_browser_class_init(GtkVrmlBrowserClass *) {} void gtk_vrml_browser_init(GtkVrmlBrowser * const vrml_browser) { vrml_browser->viewer = 0; if (!::gl_config) { static const int attrib_list[] = { // GDK_GL_ALPHA_SIZE, 1, GDK_GL_DOUBLEBUFFER, GDK_GL_DEPTH_SIZE, 1, GDK_GL_RGBA, GDK_GL_RED_SIZE, 1, GDK_GL_ATTRIB_LIST_NONE }; ::gl_config = gdk_gl_config_new(attrib_list); } static GdkGLContext * const share_list = 0; static const gboolean direct = false; static const int render_type = GDK_GL_RGBA_TYPE; gtk_widget_set_gl_capability(GTK_WIDGET(vrml_browser), ::gl_config, share_list, direct, render_type); gtk_widget_add_events(GTK_WIDGET(vrml_browser), GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_POINTER_MOTION_MASK); g_signal_connect(G_OBJECT(vrml_browser), "destroy_event", G_CALLBACK(gtk_vrml_browser_destroy), 0); g_signal_connect(G_OBJECT(vrml_browser), "expose_event", G_CALLBACK(gtk_vrml_browser_expose_event), 0); g_signal_connect(G_OBJECT(vrml_browser), "configure_event", G_CALLBACK(gtk_vrml_browser_configure_event), 0); g_signal_connect(G_OBJECT(vrml_browser), "key_press_event", G_CALLBACK(gtk_vrml_browser_key_press_event), 0); g_signal_connect(G_OBJECT(vrml_browser), "button_press_event", G_CALLBACK(gtk_vrml_browser_button_press_event), 0); g_signal_connect(G_OBJECT(vrml_browser), "button_release_event", G_CALLBACK(gtk_vrml_browser_button_release_event), 0); g_signal_connect(G_OBJECT(vrml_browser), "motion_notify_event", G_CALLBACK(gtk_vrml_browser_motion_notify_event), 0); } gboolean gtk_vrml_browser_destroy(GtkWidget * const widget, GdkEvent *, gpointer) { delete static_cast<GtkGLViewer *>(GTK_VRML_BROWSER(widget)->viewer); return true; } gboolean gtk_vrml_browser_realize(GtkWidget *, GdkEvent *, gpointer) { return true; } gboolean gtk_vrml_browser_expose_event(GtkWidget * const widget, GdkEventExpose * const event, gpointer) { GdkGLDrawable * const gl_drawable = gtk_widget_get_gl_drawable(widget); g_assert(gl_drawable); GdkGLContext * const gl_context = gtk_widget_get_gl_context(widget); g_assert(gl_context); GtkGLViewer & viewer = *static_cast<GtkGLViewer *>(GTK_VRML_BROWSER(widget)->viewer); if (event->count == 0 && gdk_gl_drawable_make_current(gl_drawable, gl_context)) { viewer.redraw(); } viewer.redrawNeeded = false; if (viewer.timer == 0) { viewer.timer_update(); } return true; } gboolean gtk_vrml_browser_configure_event(GtkWidget * const widget, GdkEventConfigure *, gpointer) { GdkGLDrawable * const gl_drawable = gtk_widget_get_gl_drawable(widget); g_assert(gl_drawable); GdkGLContext * const gl_context = gtk_widget_get_gl_context(widget); g_assert(gl_context); if (GTK_VRML_BROWSER(widget)->viewer && gdk_gl_drawable_make_current(gl_drawable, gl_context)) { GtkGLViewer & viewer = *static_cast<GtkGLViewer *>(GTK_VRML_BROWSER(widget)->viewer); viewer.resize(widget->allocation.width, widget->allocation.height); } return true; } gboolean gtk_vrml_browser_key_press_event(GtkWidget * const widget, GdkEventKey * const event, gpointer) { using openvrml::gl::viewer; viewer::event_info info; info.event = viewer::event_key_down; switch (event->keyval) { case XK_Home: info.what = viewer::key_home; break; case XK_Left: info.what = viewer::key_left; break; case XK_Up: info.what = viewer::key_up; break; case XK_Right: info.what = viewer::key_right; break; case XK_Down: info.what = viewer::key_down; break; case XK_Page_Up: info.what = viewer::key_page_up; break; case XK_Page_Down: info.what = viewer::key_page_down; break; default: if (event->length <= 0) { return true; } info.what = event->string[0]; } GdkGLDrawable * const gl_drawable = gtk_widget_get_gl_drawable(widget); g_assert(gl_drawable); GdkGLContext * const gl_context = gtk_widget_get_gl_context(widget); g_assert(gl_context); if (gdk_gl_drawable_make_current(gl_drawable, gl_context)) { GtkGLViewer * const viewer = static_cast<GtkGLViewer *>(GTK_VRML_BROWSER(widget)->viewer); g_assert(viewer); viewer->input(&info); } return true; } gboolean gtk_vrml_browser_button_press_event(GtkWidget * const widget, GdkEventButton * const event, gpointer) { using openvrml::gl::viewer; viewer::event_info info; info.event = viewer::event_mouse_click; switch (event->button) { case Button1: info.what = 0; break; case Button2: info.what = 1; break; case Button3: info.what = 2; break; } info.x = int(event->x); info.y = int(event->y); GdkGLDrawable * const gl_drawable = gtk_widget_get_gl_drawable(widget); g_assert(gl_drawable); GdkGLContext * const gl_context = gtk_widget_get_gl_context(widget); g_assert(gl_context); if (gdk_gl_drawable_make_current(gl_drawable, gl_context)) { GtkGLViewer * const viewer = static_cast<GtkGLViewer *>(GTK_VRML_BROWSER(widget)->viewer); g_assert(viewer); viewer->input(&info); } return true; } gboolean gtk_vrml_browser_button_release_event(GtkWidget * const widget, GdkEventButton * const event, gpointer) { using openvrml::gl::viewer; viewer::event_info info; info.event = viewer::event_mouse_release; switch (event->button) { case Button1: info.what = 0; break; case Button2: info.what = 1; break; case Button3: info.what = 2; break; } info.x = int(event->x); info.y = int(event->y); GdkGLDrawable * const gl_drawable = gtk_widget_get_gl_drawable(widget); g_assert(gl_drawable); GdkGLContext * const gl_context = gtk_widget_get_gl_context(widget); g_assert(gl_context); if (gdk_gl_drawable_make_current(gl_drawable, gl_context)) { GtkGLViewer * const viewer = static_cast<GtkGLViewer *>(GTK_VRML_BROWSER(widget)->viewer); g_assert(viewer); viewer->input(&info); } return true; } gboolean gtk_vrml_browser_motion_notify_event(GtkWidget * const widget, GdkEventMotion * const event, gpointer) { using openvrml::gl::viewer; viewer::event_info info; info.event = viewer::event_mouse_drag; info.what = 0; if (event->state & Button1Mask) { info.what = 0; } else if (event->state & Button2Mask) { info.what = 1; } else if (event->state & Button3Mask) { info.what = 2; } else { info.event = viewer::event_mouse_move; } info.x = int(event->x); info.y = int(event->y); GdkGLDrawable * const gl_drawable = gtk_widget_get_gl_drawable(widget); g_assert(gl_drawable); GdkGLContext * const gl_context = gtk_widget_get_gl_context(widget); g_assert(gl_context); if (gdk_gl_drawable_make_current(gl_drawable, gl_context)) { GtkGLViewer * const viewer = static_cast<GtkGLViewer *>(GTK_VRML_BROWSER(widget)->viewer); g_assert(viewer); viewer->input(&info); } return true; } gint gtk_vrml_browser_timeout_callback(const gpointer ptr) { assert(ptr); GtkGLViewer & viewer = *static_cast<GtkGLViewer *>(ptr); viewer.timer_update(); return false; } namespace { browser::browser(GIOChannel & request_channel): openvrml::browser(std::cout, std::cerr), request_channel_(&request_channel) {} std::auto_ptr<openvrml::resource_istream> browser::do_get_resource(const std::string & uri) { using openvrml_player::plugin_streambuf; class plugin_resource_istream : public openvrml::resource_istream { boost::shared_ptr<plugin_streambuf> streambuf_; GIOChannel * request_channel_; public: plugin_resource_istream(const std::string & uri, GIOChannel * const request_channel): openvrml::resource_istream(0), streambuf_(new plugin_streambuf(uri)), request_channel_(request_channel) { using std::ostringstream; using openvrml_player::uninitialized_plugin_streambuf_map_; this->rdbuf(this->streambuf_.get()); uninitialized_plugin_streambuf_map_.insert(uri, this->streambuf_); ostringstream request; request << "get-url " << uri << '\n'; gsize bytes_written; g_io_channel_write_chars(this->request_channel_, request.str().data(), request.str().length(), &bytes_written, 0); g_io_channel_flush(this->request_channel_, 0); // // This blocks until we know the result of NPN_GetURL. // const int get_url_result = this->streambuf_->get_url_result(); if (get_url_result != 0) { this->setstate(std::ios_base::failbit); } } private: virtual const std::string do_url() const throw () { return this->streambuf_->url(); } virtual const std::string do_type() const throw () { return this->streambuf_->type(); } virtual bool do_data_available() const throw () { return this->streambuf_->data_available(); } }; return std::auto_ptr<openvrml::resource_istream>( new plugin_resource_istream(uri, this->request_channel_)); } GtkGLViewer::GtkGLViewer(GIOChannel & request_channel, GtkVrmlBrowser & vrml_browser): browser_(request_channel), vrml_browser_(vrml_browser), timer(0), redrawNeeded(false) { this->browser_.viewer(this); } GtkGLViewer::~GtkGLViewer() throw () { if (this->timer) { g_source_remove(timer); } } void GtkGLViewer::post_redraw() { if (!this->redrawNeeded) { this->redrawNeeded = true; gtk_widget_queue_draw(GTK_WIDGET(&this->vrml_browser_)); } } void GtkGLViewer::set_cursor(cursor_style style) { GdkCursor * cursor(0); switch(style) { case cursor_inherit: XDefineCursor(GDK_WINDOW_XDISPLAY( GTK_WIDGET(&this->vrml_browser_)->window), GDK_WINDOW_XWINDOW( GTK_WIDGET(&this->vrml_browser_)->window), None); return; case cursor_info: cursor = gdk_cursor_new(GDK_HAND1); break; case cursor_cycle: cursor = gdk_cursor_new(GDK_EXCHANGE); break; case cursor_up_down: cursor = gdk_cursor_new(GDK_SB_V_DOUBLE_ARROW); break; case cursor_crosshair: cursor = gdk_cursor_new(GDK_CROSSHAIR); break; default: cursor = gdk_cursor_new(GDK_ARROW); } gdk_window_set_cursor(GTK_WIDGET(&this->vrml_browser_)->window, cursor); gdk_cursor_destroy(cursor); } void GtkGLViewer::swap_buffers() { GdkGLDrawable * const gl_drawable = gtk_widget_get_gl_drawable(GTK_WIDGET(&this->vrml_browser_)); gdk_gl_drawable_swap_buffers(gl_drawable); } void GtkGLViewer::set_timer(const double t) { if (!this->timer) { this->timer = g_timeout_add(guint(10.0 * (t + 1)), GtkFunction(gtk_vrml_browser_timeout_callback), this); } } void GtkGLViewer::timer_update() { this->timer = 0; this->viewer::update(); } } --- NEW FILE: plugin_streambuf.h --- // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; -*- // // OpenVRML Mozilla plug-in // Copyright 2004, 2005, 2006 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_PLAYER_PLUGIN_STREAMBUF_H # define OPENVRML_PLAYER_PLUGIN_STREAMBUF_H # include <map> # include <set> # include <streambuf> # include <boost/shared_ptr.hpp> # include <boost/enable_shared_from_this.hpp> # include "bounded_buffer.h" namespace openvrml_player { class command_istream_reader; class plugin_streambuf : public boost::enable_shared_from_this<plugin_streambuf>, public std::streambuf { friend class command_istream_reader; mutable boost::mutex mutex_; int get_url_result_; mutable boost::condition received_get_url_result_; bool initialized_; mutable boost::condition streambuf_initialized_; std::string url_; std::string type_; bounded_buffer<char_type, 16384> buf_; int_type i_; char_type c_; protected: virtual int_type underflow(); public: explicit plugin_streambuf(const std::string & requested_url); void set_get_url_result(int result); int get_url_result() const; void init(size_t stream_id, const std::string & received_url, const std::string & type); const std::string & url() const; const std::string & type() const; bool data_available() const; }; extern class uninitialized_plugin_streambuf_map { mutable boost::mutex mutex_; typedef std::multimap<std::string, boost::shared_ptr<plugin_streambuf> > map_t; map_t map_; public: const boost::shared_ptr<plugin_streambuf> find(const std::string & url) const; void insert(const std::string & url, const boost::shared_ptr<plugin_streambuf> & streambuf); bool erase(const std::string & url); size_t size() const; const boost::shared_ptr<plugin_streambuf> front() const; } uninitialized_plugin_streambuf_map_; typedef std::map<size_t, boost::shared_ptr<plugin_streambuf> > plugin_streambuf_map_t; extern plugin_streambuf_map_t plugin_streambuf_map; } # endif // ifndef OPENVRML_PLAYER_PLUGIN_STREAMBUF_H --- NEW FILE: flag.h --- // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 78 -*- // // OpenVRML Mozilla plug-in // Copyright 2006 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_PLAYER_FLAG_H # define OPENVRML_PLAYER_FLAG_H # include <boost/thread/mutex.hpp> namespace openvrml_player { class flag : boost::noncopyable { mutable boost::mutex mutex_; bool value_; public: flag(bool init = false); bool value() const; void value(bool val); }; } # endif // ifndef OPENVRML_PLAYER_FLAG_H --- NEW FILE: command_istream.h --- // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; -*- // // OpenVRML Mozilla plug-in // Copyright 2004, 2005, 2006 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_PLAYER_COMMAND_ISTREAM_H # define OPENVRML_PLAYER_COMMAND_ISTREAM_H # include <streambuf> # include <glib.h> # include "bounded_buffer.h" extern "C" gboolean command_data_available(GIOChannel * source, GIOCondition condition, gpointer data); namespace openvrml_player { class command_streambuf : boost::noncopyable, public std::streambuf { friend gboolean (::command_data_available)(GIOChannel * source, GIOCondition condition, gpointer data); bounded_buffer<char_type, 16384> source_buffer_; char_type c_; protected: virtual int_type underflow(); public: command_streambuf(); }; class command_istream : boost::noncopyable, public std::istream { command_streambuf buf_; public: command_istream(); }; } # endif // ifndef OPENVRML_PLAYER_COMMAND_ISTREAM_H --- NEW FILE: gtkvrmlbrowser.h --- /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; -*- * * OpenVRML Mozilla plug-in * Copyright 2004, 2005, 2006 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 GTK_VRML_BROWSER_H # define GTK_VRML_BROWSER_H # include <gtk/gtkdrawingarea.h> # include <gtk/gtkgl.h> G_BEGIN_DECLS # define GTK_TYPE_VRML_BROWSER (gtk_vrml_browser_get_type ()) # define GTK_VRML_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_VRML_BROWSER, GtkVrmlBrowser)) # define GTK_VRML_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_VRML_BROWSER, GtkVrmlBrowserClass)) # define GTK_IS_VRML_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_VRML_BROWSER)) # define GTK_IS_VRML_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_VRML_BROWSER)) # define GTK_VRML_BROWSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_VRML_BROWSER, GtkVrmlBrowserClass)) typedef struct GtkVrmlBrowser_ GtkVrmlBrowser; typedef struct GtkVrmlBrowserClass_ GtkVrmlBrowserClass; struct GtkVrmlBrowser_ { GtkDrawingArea drawing_area; void *viewer; }; struct GtkVrmlBrowserClass_ { GtkDrawingAreaClass parent_class; }; 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 char **parameter); G_END_DECLS # ifdef __cplusplus namespace openvrml { class resource_istream; } // // Since OpenVRML has a C++ interface, exposing this to C is Hard. // void gtk_vrml_browser_set_world(GtkVrmlBrowser * vrml_browser, openvrml::resource_istream & in); # endif # endif /* ifndef GTK_VRML_BROWSER_H */ --- NEW FILE: Makefile.am --- AM_CPPFLAGS = \ -I$(top_srcdir)/lib/gtkglext \ -I$(top_builddir)/lib/gtkglext \ -I$(top_builddir)/lib/gtkglext/gdk \ -I$(top_builddir)/src/libopenvrml \ -I$(top_srcdir)/src/libopenvrml \ -I$(top_builddir)/src/libopenvrml-gl \ -I$(top_srcdir)/src/libopenvrml-gl \ -I$(mozincludedir) \ -DGTK_DISABLE_DEPRECATED AM_CXXFLAGS = @PTHREAD_CFLAGS@ @GTK_CFLAGS@ @GL_CFLAGS@ if ENABLE_GTKPLUG libexec_PROGRAMS = openvrml-gtkplug endif noinst_HEADERS = \ bounded_buffer.h \ command_istream.h \ plugin_streambuf.h \ gtkvrmlbrowser.h \ flag.h openvrml_gtkplug_SOURCES = \ main.cpp \ command_istream.cpp \ plugin_streambuf.cpp \ gtkvrmlbrowser.cpp \ flag.cpp openvrml_gtkplug_LDADD = \ $(top_builddir)/src/libopenvrml-gl/libopenvrml-gl.la \ $(top_builddir)/src/libopenvrml/libopenvrml.la \ $(top_builddir)/lib/gtkglext/gtk/libgtkglext-x11-1.0.la \ $(top_builddir)/lib/gtkglext/gdk/libgdkglext-x11-1.0.la openvrml_gtkplug_LDFLAGS = \ @GTK_LIBS@ \ @GL_LIBS@ \ -lXmu -lXt @X_PRE_LIBS@ @X_LIBS@ @X_EXTRA_LIBS@ \ -lboost_thread \ @PTHREAD_LIBS@ EXTRA_DIST = $(openvrml_gtkplug_SOURCES) --- NEW FILE: command_istream.cpp --- // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; -*- // // OpenVRML Mozilla plug-in // Copyright 2004, 2005, 2006 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 // # include <cassert> # include <cerrno> # include "command_istream.h" openvrml_player::command_streambuf::command_streambuf(): c_('\0') { this->setg(&this->c_, &this->c_, &this->c_); } openvrml_player::command_streambuf::int_type openvrml_player::command_streambuf::underflow() { const int_type i = this->source_buffer_.get(); if (traits_type::eq_int_type(i, traits_type::eof())) { return traits_type::eof(); } this->c_ = traits_type::to_char_type(i); this->setg(&this->c_, &this->c_, &this->c_ + 1); return i; } openvrml_player::command_istream::command_istream(): std::istream(&this->buf_) {} gboolean command_data_available(GIOChannel * source, GIOCondition, gpointer data) { using namespace openvrml_player; typedef command_istream::traits_type traits_type; command_streambuf & streambuf = *static_cast<command_streambuf *>(data); do { gchar c; gsize bytes_read; GError * error = 0; const GIOStatus status = g_io_channel_read_chars(source, &c, 1, &bytes_read, &error); if (status == G_IO_STATUS_ERROR) { if (error) { g_warning(error->message); g_error_free(error); } return false; } if (status == G_IO_STATUS_EOF) { streambuf.source_buffer_.set_eof(); return false; } if (status == G_IO_STATUS_AGAIN) { continue; } g_return_val_if_fail(status == G_IO_STATUS_NORMAL, false); g_assert(bytes_read == 1); streambuf.source_buffer_.put(c); } while (g_io_channel_get_buffer_condition(source) & G_IO_IN); return true; } --- NEW FILE: flag.cpp --- // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 78 -*- // // OpenVRML Mozilla plug-in // Copyright 2006 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 // # include "flag.h" openvrml_player::flag::flag(const bool init): value_(init) {} bool openvrml_player::flag::value() const { boost::mutex::scoped_lock lock(this->mutex_); return this->value_; } void openvrml_player::flag::value(const bool val) { boost::mutex::scoped_lock lock(this->mutex_); this->value_ = val; } --- NEW FILE: plugin_streambuf.cpp --- // -*- 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 // 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 // # include <glib.h> # include "plugin_streambuf.h" openvrml_player::plugin_streambuf:: plugin_streambuf(const std::string & requested_url): get_url_result_(-1), initialized_(false), url_(requested_url), i_(0), c_('\0') { // // This is really just here to emphasize that c_ must not be EOF. // this->i_ = traits_type::not_eof(this->i_); this->c_ = traits_type::to_char_type( traits_type::not_eof(traits_type::to_int_type(this->c_))); this->setg(&this->c_, &this->c_, &this->c_); } void openvrml_player::plugin_streambuf::set_get_url_result(const int result) { boost::mutex::scoped_lock lock(this->mutex_); assert(this->get_url_result_ == -1); this->get_url_result_ = result; this->received_get_url_result_.notify_all(); } int openvrml_player::plugin_streambuf::get_url_result() const { boost::mutex::scoped_lock lock(this->mutex_); while (this->get_url_result_ == -1) { this->received_get_url_result_.wait(lock); } return this->get_url_result_; } void openvrml_player::plugin_streambuf::init(const size_t stream_id, const std::string & received_url, const std::string & type) { boost::mutex::scoped_lock lock(this->mutex_); bool succeeded = uninitialized_plugin_streambuf_map_.erase(this->url_); g_assert(succeeded); this->url_ = received_url; this->type_ = type; this->initialized_ = true; const boost::shared_ptr<plugin_streambuf> this_ = shared_from_this(); succeeded = plugin_streambuf_map.insert(make_pair(stream_id, this_)) .second; g_assert(succeeded); this->streambuf_initialized_.notify_all(); } const std::string & openvrml_player::plugin_streambuf::url() const { boost::mutex::scoped_lock lock(this->mutex_); while (!this->initialized_) { this->streambuf_initialized_.wait(lock); } return this->url_; } const std::string & openvrml_player::plugin_streambuf::type() const { boost::mutex::scoped_lock lock(this->mutex_); while (!this->initialized_) { this->streambuf_initialized_.wait(lock); } return this->type_; } bool openvrml_player::plugin_streambuf::data_available() const { // // It may seem a bit counterintuitive to return true here if the stream // has been destroyed; however, if we don't return true in this case, // clients may never get EOF from the stream. // return this->buf_.buffered() > 0 || this->buf_.eof(); } openvrml_player::plugin_streambuf::int_type openvrml_player::plugin_streambuf::underflow() { boost::mutex::scoped_lock lock(this->mutex_); while (!this->initialized_) { this->streambuf_initialized_.wait(lock); } if (traits_type::eq_int_type(this->i_, traits_type::eof())) { return traits_type::eof(); } this->i_ = this->buf_.get(); this->c_ = traits_type::to_char_type(this->i_); if (traits_type::eq_int_type(this->i_, traits_type::eof())) { return traits_type::eof(); } this->setg(&this->c_, &this->c_, &this->c_ + 1); return traits_type::to_int_type(*this->gptr()); } openvrml_player::uninitialized_plugin_streambuf_map openvrml_player::uninitialized_plugin_streambuf_map_; const boost::shared_ptr<openvrml_player::plugin_streambuf> openvrml_player::uninitialized_plugin_streambuf_map:: find(const std::string & url) const { boost::mutex::scoped_lock lock(this->mutex_); map_t::const_iterator pos = this->map_.find(url); return pos == this->map_.end() ? boost::shared_ptr<plugin_streambuf>() : pos->second; } void openvrml_player::uninitialized_plugin_streambuf_map:: insert(const std::string & url, const boost::shared_ptr<plugin_streambuf> & streambuf) { boost::mutex::scoped_lock lock(this->mutex_); this->map_.insert(make_pair(url, streambuf)); } /** * @brief Erase the first entry corresponding to @p url. * * The map may have multiple entries corresponding to @p url if the same * resource has been requested multiple times. A single call to @c erase will * only remove one of them. * * @return @c true if an entry was removed; @c false otherwise. */ bool openvrml_player::uninitialized_plugin_streambuf_map:: erase(const std::string & url) { boost::mutex::scoped_lock lock(this->mutex_); const map_t::iterator pos = this->map_.find(url); if (pos == this->map_.end()) { return false; } this->map_.erase(pos); return true; } size_t openvrml_player::uninitialized_plugin_streambuf_map::size() const { boost::mutex::scoped_lock lock(this->mutex_); return this->map_.size(); } const boost::shared_ptr<openvrml_player::plugin_streambuf> openvrml_player::uninitialized_plugin_streambuf_map::front() const { boost::mutex::scoped_lock lock(this->mutex_); g_assert(!this->map_.empty()); return this->map_.begin()->second; } openvrml_player::plugin_streambuf_map_t openvrml_player::plugin_streambuf_map; --- NEW FILE: bounded_buffer.h --- // -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4; -*- // // OpenVRML Mozilla plug-in // Copyright 2004, 2005, 2006 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_PLAYER_BOUNDED_BUFFER_H # define OPENVRML_PLAYER_BOUNDED_BUFFER_H # include <string> # include <boost/thread/mutex.hpp> # include <boost/thread/condition.hpp> namespace openvrml_player { template <typename CharT, size_t BufferSize> class bounded_buffer { mutable boost::mutex mutex_; boost::condition buffer_not_full_, buffer_not_empty_or_eof_; CharT buf_[BufferSize]; size_t begin_, end_, buffered_; bool eof_; public: typedef CharT char_type; typedef typename std::char_traits<char_type> traits_type; typedef typename traits_type::int_type int_type; bounded_buffer(); void put(const char_type & c); int_type get(); size_t buffered() const; void set_eof(); bool eof() const; }; template <typename CharT, size_t BufferSize> bounded_buffer<CharT, BufferSize>::bounded_buffer(): begin_(0), end_(0), buffered_(0), eof_(false) {} template <typename CharT, size_t BufferSize> void bounded_buffer<CharT, BufferSize>::put(const char_type & c) { boost::mutex::scoped_lock lock(this->mutex_); while (this->buffered_ == BufferSize) { this->buffer_not_full_.wait(lock); } this->buf_[this->end_] = c; this->end_ = (this->end_ + 1) % BufferSize; ++this->buffered_; this->buffer_not_empty_or_eof_.notify_one(); } template <typename CharT, size_t BufferSize> typename bounded_buffer<CharT, BufferSize>::int_type bounded_buffer<CharT, BufferSize>::get() { boost::mutex::scoped_lock lock(this->mutex_); while (this->buffered_ == 0 && !this->eof_) { this->buffer_not_empty_or_eof_.wait(lock); } if (this->buffered_ == 0 && this->eof_) { return traits_type::eof(); } const int_type c = traits_type::to_int_type(this->buf_[this->begin_]); this->begin_ = (this->begin_ + 1) % BufferSize; --this->buffered_; this->buffer_not_full_.notify_one(); assert(!traits_type::eq_int_type(c, traits_type::eof())); return c; } template <typename CharT, size_t BufferSize> size_t bounded_buffer<CharT, BufferSize>::buffered() const { boost::mutex::scoped_lock lock(this->mutex_); return this->buffered_; } template <typename CharT, size_t BufferSize> void bounded_buffer<CharT, BufferSize>::set_eof() { boost::mutex::scoped_lock lock(this->mutex_); this->eof_ = true; this->buffer_not_empty_or_eof_.notify_one(); } template <typename CharT, size_t BufferSize> bool bounded_buffer<CharT, BufferSize>::eof() const { boost::mutex::scoped_lock lock(this->mutex_); return this->eof_; } } # endif // ifndef OPENVRML_PLAYER_BOUNDED_BUFFER_H |