Răsfoiți Sursa

integrate pview with new task manager

David Rose 17 ani în urmă
părinte
comite
4beba6ca6f

+ 3 - 0
panda/src/event/Sources.pp

@@ -15,6 +15,7 @@
     config_event.h \
     buttonEvent.I buttonEvent.h \
     buttonEventList.I buttonEventList.h \
+    genericAsyncTask.h genericAsyncTask.I \
     pointerEvent.I pointerEvent.h \
     pointerEventList.I pointerEventList.h \
     pythonTask.h pythonTask.I \
@@ -30,6 +31,7 @@
     asyncTaskManager.cxx \
     buttonEvent.cxx \
     buttonEventList.cxx \
+    genericAsyncTask.cxx \
     pointerEvent.cxx \
     pointerEventList.cxx \
     pythonTask.cxx \
@@ -44,6 +46,7 @@
     asyncTaskManager.h asyncTaskManager.I \
     buttonEvent.I buttonEvent.h \
     buttonEventList.I buttonEventList.h \
+    genericAsyncTask.cxx \
     pointerEvent.I pointerEvent.h \
     pointerEventList.I pointerEventList.h \
     pythonTask.h pythonTask.I \

+ 27 - 0
panda/src/event/asyncTask.cxx

@@ -466,3 +466,30 @@ upon_death(bool clean_exit) {
     throw_event(event);
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: AsyncTask::release_lock
+//       Access: Protected
+//  Description: Releases the task lock.  This is intended to be
+//               used within callback functions, for instance
+//               upon_birth() or upon_death(), as needed to release
+//               the lock for processing.  Be sure to grab it again
+//               before returning.
+////////////////////////////////////////////////////////////////////
+void AsyncTask::
+release_lock() {
+  _manager->_lock.release();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AsyncTask::grab_lock
+//       Access: Protected
+//  Description: Releases the task lock.  This is intended to be
+//               used within callback functions, to grab the lock
+//               after a previous call to release_lock().
+////////////////////////////////////////////////////////////////////
+void AsyncTask::
+grab_lock() {
+  _manager->_lock.lock();
+}
+

+ 3 - 0
panda/src/event/asyncTask.h

@@ -117,6 +117,9 @@ protected:
   virtual void upon_birth();
   virtual void upon_death(bool clean_exit);
 
+  void release_lock();
+  void grab_lock();
+
 protected:
   AtomicAdjust::Integer _task_id;
   string _chain_name;

+ 0 - 1
panda/src/event/asyncTaskManager.h

@@ -156,7 +156,6 @@ private:
   friend class AsyncTaskChain;
   friend class AsyncTaskChain::AsyncTaskChainThread;
   friend class AsyncTask;
-  friend class PythonTask;
 };
 
 INLINE ostream &operator << (ostream &out, const AsyncTaskManager &manager) {

+ 2 - 0
panda/src/event/config_event.cxx

@@ -20,6 +20,7 @@
 #include "event.h"
 #include "eventHandler.h"
 #include "eventParameter.h"
+#include "genericAsyncTask.h"
 #include "pointerEventList.h"
 #include "pythonTask.h"
 
@@ -43,6 +44,7 @@ ConfigureFn(config_event) {
   EventStoreString::init_type("EventStoreString");
   EventStoreWstring::init_type("EventStoreWstring");
   EventStoreTypedRefCount::init_type();
+  GenericAsyncTask::init_type();
   PythonTask::init_type();
 
   ButtonEventList::register_with_read_factory();

+ 1 - 0
panda/src/event/event_composite1.cxx

@@ -4,6 +4,7 @@
 #include "asyncTaskManager.cxx"
 #include "buttonEvent.cxx"
 #include "buttonEventList.cxx"
+#include "genericAsyncTask.cxx"
 #include "pointerEvent.cxx"
 #include "pointerEventList.cxx"
 #include "pythonTask.cxx"

+ 103 - 0
panda/src/event/genericAsyncTask.I

@@ -0,0 +1,103 @@
+// Filename: genericAsyncTask.I
+// Created by:  drose (03Oct08)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::set_function
+//       Access: Published
+//  Description: Replaces the function that is called when the task
+//               runs.
+////////////////////////////////////////////////////////////////////
+INLINE void GenericAsyncTask::
+set_function(GenericAsyncTask::TaskFunc *function) {
+  _function = function;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::get_function
+//       Access: Published
+//  Description: Returns the function that is called when the task
+//               runs.
+////////////////////////////////////////////////////////////////////
+INLINE GenericAsyncTask::TaskFunc *GenericAsyncTask::
+get_function() const {
+  return _function;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::set_upon_birth
+//       Access: Published
+//  Description: Replaces the function that is called when the task
+//               begins.  This is an optional function.
+////////////////////////////////////////////////////////////////////
+INLINE void GenericAsyncTask::
+set_upon_birth(GenericAsyncTask::BirthFunc *upon_birth) {
+  _upon_birth = upon_birth;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::get_upon_birth
+//       Access: Published
+//  Description: Returns the function that is called when the task
+//               begins, or NULL if the function is not defined.
+////////////////////////////////////////////////////////////////////
+INLINE GenericAsyncTask::BirthFunc *GenericAsyncTask::
+get_upon_birth() const {
+  return _upon_birth;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::set_upon_death
+//       Access: Published
+//  Description: Replaces the function that is called when the task
+//               ends.  This is an optional function.
+////////////////////////////////////////////////////////////////////
+INLINE void GenericAsyncTask::
+set_upon_death(GenericAsyncTask::DeathFunc *upon_death) {
+  _upon_death = upon_death;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::get_upon_death
+//       Access: Published
+//  Description: Returns the function that is called when the task
+//               ends, or NULL if the function is not defined.
+////////////////////////////////////////////////////////////////////
+INLINE GenericAsyncTask::DeathFunc *GenericAsyncTask::
+get_upon_death() const {
+  return _upon_death;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::set_user_data
+//       Access: Published
+//  Description: Replaces the void pointer that is passed to the task
+//               function.  This is any arbitrary pointer; the task
+//               object does no processing on it.
+////////////////////////////////////////////////////////////////////
+INLINE void GenericAsyncTask::
+set_user_data(void *user_data) {
+  _user_data = user_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::get_user_data
+//       Access: Published
+//  Description: Returns the void pointer that is passed to the task
+//               function.
+////////////////////////////////////////////////////////////////////
+INLINE void *GenericAsyncTask::
+get_user_data() const {
+  return _user_data;
+}

+ 123 - 0
panda/src/event/genericAsyncTask.cxx

@@ -0,0 +1,123 @@
+// Filename: genericAsyncTask.cxx
+// Created by:  drose (03Oct08)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#include "genericAsyncTask.h"
+#include "pnotify.h"
+
+TypeHandle GenericAsyncTask::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+GenericAsyncTask::
+GenericAsyncTask(const string &name) :
+  AsyncTask(name)
+{
+  _function = NULL;
+  _upon_birth = NULL;
+  _upon_death = NULL;
+  _user_data = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+GenericAsyncTask::
+GenericAsyncTask(const string &name, GenericAsyncTask::TaskFunc *function, void *user_data) :
+  AsyncTask(name),
+  _function(function),
+  _user_data(user_data)
+{
+  _upon_birth = NULL;
+  _upon_death = NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::is_runnable
+//       Access: Protected, Virtual
+//  Description: Override this function to return true if the task can
+//               be successfully executed, false if it cannot.  Mainly
+//               intended as a sanity check when attempting to add the
+//               task to a task manager.
+//
+//               This function is called with the lock held.
+////////////////////////////////////////////////////////////////////
+bool GenericAsyncTask::
+is_runnable() {
+  return _function != NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::do_task
+//       Access: Protected, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+AsyncTask::DoneStatus GenericAsyncTask::
+do_task() {
+  nassertr(_function != NULL, DS_abort);
+  return (*_function)(this, _user_data);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::upon_birth
+//       Access: Protected, Virtual
+//  Description: Override this function to do something useful when the
+//               task has been added to the active queue.
+//
+//               This function is called with the lock held.  You may
+//               temporarily release if it necessary, but be sure to
+//               return with it held.
+////////////////////////////////////////////////////////////////////
+void GenericAsyncTask::
+upon_birth() {
+  AsyncTask::upon_birth();
+
+  if (_upon_birth != NULL) {
+    release_lock();
+    (*_upon_birth)(this, _user_data);
+    grab_lock();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GenericAsyncTask::upon_death
+//       Access: Protected, Virtual
+//  Description: Override this function to do something useful when the
+//               task has been removed from the active queue.  The
+//               parameter clean_exit is true if the task has been
+//               removed because it exited normally (returning
+//               DS_done), or false if it was removed for some other
+//               reason (e.g. AsyncTaskManager::remove()).
+//
+//               The normal behavior is to throw the done_event only
+//               if clean_exit is true.
+//
+//               This function is called with the lock held.  You may
+//               temporarily release if it necessary, but be sure to
+//               return with it held.
+////////////////////////////////////////////////////////////////////
+void GenericAsyncTask::
+upon_death(bool clean_exit) {
+  AsyncTask::upon_death(clean_exit);
+
+  if (_upon_death != NULL) {
+    release_lock();
+    (*_upon_death)(this, clean_exit, _user_data);
+    grab_lock();
+  }
+}

+ 83 - 0
panda/src/event/genericAsyncTask.h

@@ -0,0 +1,83 @@
+// Filename: genericAsyncTask.h
+// Created by:  drose (16Sep08)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) Carnegie Mellon University.  All rights reserved.
+//
+// All use of this software is subject to the terms of the revised BSD
+// license.  You should have received a copy of this license along
+// with this source code in a file named "LICENSE."
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GENERICASYNCTASK_H
+#define GENERICASYNCTASK_H
+
+#include "pandabase.h"
+
+#include "asyncTask.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : GenericAsyncTask
+// Description : Associates a generic C-style function pointer with an
+//               AsyncTask object.  You can use this when you want to
+//               create an AsyncTask without having to subclass.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA_PIPELINE GenericAsyncTask : public AsyncTask {
+public:
+  typedef DoneStatus TaskFunc(GenericAsyncTask *task, void *user_data);
+  typedef void BirthFunc(GenericAsyncTask *task, void *user_data);
+  typedef void DeathFunc(GenericAsyncTask *task, bool clean_exit, void *user_data);
+
+  GenericAsyncTask(const string &name = string());
+  GenericAsyncTask(const string &name, TaskFunc *function, void *user_data);
+  ALLOC_DELETED_CHAIN(GenericAsyncTask);
+
+  INLINE void set_function(TaskFunc *function);
+  INLINE TaskFunc *get_function() const;
+
+  INLINE void set_upon_birth(BirthFunc *function);
+  INLINE BirthFunc *get_upon_birth() const;
+
+  INLINE void set_upon_death(DeathFunc *function);
+  INLINE DeathFunc *get_upon_death() const;
+
+  INLINE void set_user_data(void *user_data);
+  INLINE void *get_user_data() const;
+
+protected:
+  virtual bool is_runnable();
+  virtual DoneStatus do_task();
+  virtual void upon_birth();
+  virtual void upon_death(bool clean_exit);
+
+private:
+  TaskFunc *_function;
+  BirthFunc *_upon_birth;
+  DeathFunc *_upon_death;
+  void *_user_data;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    AsyncTask::init_type();
+    register_type(_type_handle, "GenericAsyncTask",
+                  AsyncTask::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "genericAsyncTask.I"
+
+#endif
+

+ 4 - 4
panda/src/event/pythonTask.cxx

@@ -476,7 +476,7 @@ upon_birth() {
   AsyncTask::upon_birth();
 
   if (_owner != Py_None) {
-    _manager->_lock.release();
+    release_lock();
 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
     // Use PyGILState to protect this asynchronous call.
     PyGILState_STATE gstate;
@@ -488,7 +488,7 @@ upon_birth() {
 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
     PyGILState_Release(gstate);
 #endif
-    _manager->_lock.lock();
+    grab_lock();
   }
 }
 
@@ -514,7 +514,7 @@ upon_death(bool clean_exit) {
   AsyncTask::upon_death(clean_exit);
 
   if (_owner != Py_None && _upon_death != Py_None) {
-    _manager->_lock.release();
+    release_lock();
 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
     // Use PyGILState to protect this asynchronous call.
     PyGILState_STATE gstate;
@@ -527,7 +527,7 @@ upon_death(bool clean_exit) {
 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
     PyGILState_Release(gstate);
 #endif
-    _manager->_lock.lock();
+    grab_lock();
   }
 }
 

+ 15 - 1
panda/src/framework/pandaFramework.I

@@ -23,7 +23,10 @@
 INLINE GraphicsEngine *PandaFramework::
 get_graphics_engine() {
   if (_engine == (GraphicsEngine *)NULL) {
-    _engine = new GraphicsEngine;
+    _engine = GraphicsEngine::get_global_ptr();
+    PT(GenericAsyncTask) task = new GenericAsyncTask("igloop", task_igloop, this);
+    task->set_sort(50);
+    _task_mgr.add(task);
   }
   return _engine;
 }
@@ -52,6 +55,17 @@ get_event_handler() {
   return _event_handler;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaFramework::get_task_mgr
+//       Access: Public
+//  Description: Returns the Task Manager object that manages tasks in
+//               the framework.
+////////////////////////////////////////////////////////////////////
+INLINE AsyncTaskManager &PandaFramework::
+get_task_mgr() {
+  return _task_mgr;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaFramework::set_window_title
 //       Access: Public

+ 122 - 27
panda/src/framework/pandaFramework.cxx

@@ -37,7 +37,8 @@ LoaderOptions PandaFramework::_loader_options;
 ////////////////////////////////////////////////////////////////////
 PandaFramework::
 PandaFramework() :
-  _event_handler(*EventHandler::get_global_event_handler())
+  _event_handler(*EventHandler::get_global_event_handler()),
+  _task_mgr(*AsyncTaskManager::get_global_ptr())
 {
   _is_open = false;
   _made_default_pipe = false;
@@ -86,7 +87,18 @@ open_framework(int &argc, char **&argv) {
 
   reset_frame_rate();
 
+  {
+    PT(GenericAsyncTask) task = new GenericAsyncTask("event", task_event, this);
+    _task_mgr.add(task);
+  }
+
   _data_root = NodePath("data");
+  {
+    PT(GenericAsyncTask) task = new GenericAsyncTask("data_loop", task_data_loop, this);
+    task->set_sort(-50);
+    _task_mgr.add(task);
+  }
+
   _highlight_wireframe = NodePath("wireframe");
   _highlight_wireframe.set_render_mode_wireframe(1);
   _highlight_wireframe.set_texture_off(1);
@@ -98,12 +110,20 @@ open_framework(int &argc, char **&argv) {
     // playing.
     _recorder = new RecorderController;
     _recorder->begin_playback(Filename::from_os_specific(playback_session));
+
+    PT(GenericAsyncTask) task = new GenericAsyncTask("play_frame", task_play_frame, this);
+    task->set_sort(55);
+    _task_mgr.add(task);
     
   } else if (!record_session.empty()) {
     // If the config file so indicates, create a recorder and start it
     // recording.
     _recorder = new RecorderController;
     _recorder->begin_record(Filename::from_os_specific(record_session));
+
+    PT(GenericAsyncTask) task = new GenericAsyncTask("record_frame", task_record_frame, this);
+    task->set_sort(45);
+    _task_mgr.add(task);
   } 
 
   _event_handler.add_hook("window-event", event_window_event, this);
@@ -125,7 +145,7 @@ close_framework() {
   close_all_windows();
   // Also close down any other windows that might have been opened.
   if (_engine != (GraphicsEngine *)NULL) {
-    delete _engine;
+    _engine->remove_all_windows();
     _engine = NULL;
   }
 
@@ -766,30 +786,8 @@ enable_default_keys() {
 bool PandaFramework::
 do_frame(Thread *current_thread) {
   nassertr(_is_open, false);
-  DataGraphTraverser dg_trav(current_thread);
-  dg_trav.traverse(_data_root.node());
-
-  throw_event("NewFrame");
-  _event_handler.process_events();
-
-  if (!_screenshot_text.is_empty()) {
-    double now = ClockObject::get_global_clock()->get_frame_time();
-    if (now >= _screenshot_clear_time) {
-      _screenshot_text.remove_node();
-    }
-  }
 
-  if (_recorder != (RecorderController *)NULL) {
-    _recorder->record_frame();
-  }
-  
-  if (_engine != (GraphicsEngine *)NULL) {
-    _engine->render_frame();
-  }
-
-  if (_recorder != (RecorderController *)NULL) {
-    _recorder->play_frame();
-  }
+  _task_mgr.poll();
 
   return !_exit_flag;
 }
@@ -1338,8 +1336,11 @@ event_f9(const Event *event, void *data) {
     self->_screenshot_text.reparent_to(wf->get_aspect_2d());
     cout << "Screenshot saved: " + output_text + "\n";
 
-    double now = ClockObject::get_global_clock()->get_frame_time();
-    self->_screenshot_clear_time = now + 3.0;
+    // Set a do-later to remove the text in 3 seconds.
+    self->_task_mgr.remove(self->_task_mgr.find_tasks("clear_text"));
+    PT(GenericAsyncTask) task = new GenericAsyncTask("clear_text", task_clear_text, self);
+    task->set_delay(3.0);
+    self->_task_mgr.add(task);
   }
 }
 
@@ -1469,3 +1470,97 @@ event_window_event(const Event *event, void *data) {
     }
   }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaFramework::task_data_loop
+//       Access: Public, Static
+//  Description: Called once per frame to process the data graph (which
+//               handles user input via the mouse and keyboard, etc.)
+////////////////////////////////////////////////////////////////////
+AsyncTask::DoneStatus PandaFramework::
+task_data_loop(GenericAsyncTask *task, void *data) {
+  PandaFramework *self = (PandaFramework *)data;
+
+  DataGraphTraverser dg_trav;
+  dg_trav.traverse(self->_data_root.node());
+
+  return AsyncTask::DS_cont;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaFramework::task_event
+//       Access: Public, Static
+//  Description: Called once per frame to process the pending events.
+////////////////////////////////////////////////////////////////////
+AsyncTask::DoneStatus PandaFramework::
+task_event(GenericAsyncTask *task, void *data) {
+  PandaFramework *self = (PandaFramework *)data;
+
+  throw_event("NewFrame");
+  self->_event_handler.process_events();
+
+  return AsyncTask::DS_cont;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaFramework::task_igloop
+//       Access: Public, Static
+//  Description: Called once per frame to render the scene.
+////////////////////////////////////////////////////////////////////
+AsyncTask::DoneStatus PandaFramework::
+task_igloop(GenericAsyncTask *task, void *data) {
+  PandaFramework *self = (PandaFramework *)data;
+  
+  if (self->_engine != (GraphicsEngine *)NULL) {
+    self->_engine->render_frame();
+  }
+
+  return AsyncTask::DS_cont;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaFramework::task_record_frame
+//       Access: Public, Static
+//  Description: Called once per frame to ask the recorder to record
+//               the user input data, if enabled.
+////////////////////////////////////////////////////////////////////
+AsyncTask::DoneStatus PandaFramework::
+task_record_frame(GenericAsyncTask *task, void *data) {
+  PandaFramework *self = (PandaFramework *)data;
+
+  if (self->_recorder != (RecorderController *)NULL) {
+    self->_recorder->record_frame();
+  }
+
+  return AsyncTask::DS_cont;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaFramework::task_play_frame
+//       Access: Public, Static
+//  Description: Called once per frame to ask the recorder to play back
+//               the user input data, if enabled.
+////////////////////////////////////////////////////////////////////
+AsyncTask::DoneStatus PandaFramework::
+task_play_frame(GenericAsyncTask *task, void *data) {
+  PandaFramework *self = (PandaFramework *)data;
+
+  if (self->_recorder != (RecorderController *)NULL) {
+    self->_recorder->play_frame();
+  }
+
+  return AsyncTask::DS_cont;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaFramework::task_clear_text
+//       Access: Public, Static
+//  Description: Called once to remove the screenshot text from onscreen.
+////////////////////////////////////////////////////////////////////
+AsyncTask::DoneStatus PandaFramework::
+task_clear_text(GenericAsyncTask *task, void *data) {
+  PandaFramework *self = (PandaFramework *)data;
+
+  self->clear_text();
+  return AsyncTask::DS_cont;
+}

+ 14 - 2
panda/src/framework/pandaFramework.h

@@ -26,6 +26,8 @@
 #include "graphicsWindow.h"
 #include "recorderController.h"
 #include "pointerTo.h"
+#include "asyncTaskManager.h"
+#include "genericAsyncTask.h"
 
 #include "pvector.h"
 
@@ -47,6 +49,7 @@ public:
   INLINE GraphicsEngine *get_graphics_engine();
   INLINE const NodePath &get_data_root() const;
   INLINE EventHandler &get_event_handler();
+  INLINE AsyncTaskManager &get_task_mgr();
   NodePath get_mouse(GraphicsWindow *window);
   void remove_mouse(const GraphicsWindow *window);
 
@@ -148,6 +151,15 @@ public:
   static void event_window_event(const Event *, void *data);
 
 
+  static AsyncTask::DoneStatus task_data_loop(GenericAsyncTask *task, void *data);
+  static AsyncTask::DoneStatus task_event(GenericAsyncTask *task, void *data);
+  static AsyncTask::DoneStatus task_clear_screenshot_text(GenericAsyncTask *task, void *data);
+  static AsyncTask::DoneStatus task_igloop(GenericAsyncTask *task, void *data);
+  static AsyncTask::DoneStatus task_record_frame(GenericAsyncTask *task, void *data);
+  static AsyncTask::DoneStatus task_play_frame(GenericAsyncTask *task, void *data);
+
+  static AsyncTask::DoneStatus task_clear_text(GenericAsyncTask *task, void *data);
+
 private:
   bool _is_open;
   bool _made_default_pipe;
@@ -155,10 +167,11 @@ private:
   string _window_title;
 
   PT(GraphicsPipe) _default_pipe;
-  GraphicsEngine *_engine;
+  PT(GraphicsEngine) _engine;
 
   NodePath _data_root;
   EventHandler &_event_handler;
+  AsyncTaskManager &_task_mgr;
 
   typedef pvector< PT(WindowFramework) > Windows;
   Windows _windows;
@@ -196,7 +209,6 @@ private:
 
   NodePath _help_text;
   NodePath _screenshot_text;
-  double _screenshot_clear_time;
 
   PT(RecorderController) _recorder;
 

+ 5 - 4
panda/src/framework/windowFramework.cxx

@@ -1302,7 +1302,7 @@ create_anim_controls() {
   setup_shuttle_button("4", 2, st_play_button);
   setup_shuttle_button(":", 3, st_forward_button);
 
-  _panda_framework->get_event_handler().add_hook("NewFrame", st_update_anim_controls, (void *)this);
+  _panda_framework->get_task_mgr().add(new GenericAsyncTask("controls", st_update_anim_controls, (void *)this));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1442,12 +1442,13 @@ forward_button() {
 ////////////////////////////////////////////////////////////////////
 //     Function: WindowFramework::st_update_anim_controls
 //       Access: Private, Static
-//  Description: The static event handler function.
+//  Description: The static task function.
 ////////////////////////////////////////////////////////////////////
-void WindowFramework::
-st_update_anim_controls(const Event *, void *data) {
+AsyncTask::DoneStatus WindowFramework::
+st_update_anim_controls(GenericAsyncTask *, void *data) {
   WindowFramework *self = (WindowFramework *)data;
   self->update_anim_controls();
+  return AsyncTask::DS_cont;
 }
 
 

+ 2 - 1
panda/src/framework/windowFramework.h

@@ -32,6 +32,7 @@
 #include "pgSliderBar.h"
 #include "textNode.h"
 #include "eventHandler.h"
+#include "genericAsyncTask.h"
 
 class PandaFramework;
 class AmbientLight;
@@ -146,7 +147,7 @@ private:
   void play_button();
   void forward_button();
 
-  static void st_update_anim_controls(const Event *, void *data);
+  static AsyncTask::DoneStatus st_update_anim_controls(GenericAsyncTask *task, void *data);
 
   static void st_back_button(const Event *, void *data);
   static void st_pause_button(const Event *, void *data);