This commit is contained in:
David Rose 2009-08-16 17:36:44 +00:00
parent e7daad7dce
commit 8f96fa71f5
14 changed files with 241 additions and 77 deletions

View File

@ -84,6 +84,7 @@ P3DInstance(P3D_request_ready_func *func,
#endif // __APPLE__
// Set some initial properties.
_panda_script_object->set_float_property("instanceDownloadProgress", 0.0);
_panda_script_object->set_float_property("downloadProgress", 0.0);
_panda_script_object->set_string_property("downloadPackageName", "");
_panda_script_object->set_string_property("downloadPackageDisplayName", "");
@ -147,6 +148,44 @@ P3DInstance::
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::set_p3d_url
// Access: Public
// Description: Specifies a URL that should be contacted to download
// the instance data. Normally this, or
// set_p3d_filename(), is only called once.
//
// The instance data at the other end of this URL is
// key. We can't start the instance until we have
// downloaded the instance file and examined the
// p3d_info.xml, and we know what Python version we need
// and so forth.
////////////////////////////////////////////////////////////////////
void P3DInstance::
set_p3d_url(const string &p3d_url) {
// Make a temporary file to receive the instance data.
char *name = tempnam(NULL, "p3d_");
string filename = name;
free(name);
// Mark the time we started downloading, so we'll know when to set
// the install label.
#ifdef _WIN32
_start_dl_instance_tick = GetTickCount();
#else
gettimeofday(&_start_dl_instance_timeval, NULL);
#endif
_show_dl_instance_progress = false;
// Start downloading the data.
InstanceDownload *download = new InstanceDownload(this);
download->set_url(p3d_url);
download->set_filename(filename);
_panda_script_object->set_string_property("status", "downloading_instance");
start_download(download);
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::set_p3d_filename
// Access: Public
@ -158,6 +197,8 @@ set_p3d_filename(const string &p3d_filename) {
_got_fparams = true;
_fparams.set_p3d_filename(p3d_filename);
_panda_script_object->set_float_property("instanceDownloadProgress", 1.0);
// This also sets up some internal data based on the contents of the
// above file and the associated tokens.
@ -184,6 +225,9 @@ set_p3d_filename(const string &p3d_filename) {
// plugin has read its parameters and is ready to be queried (even
// if Python has not yet started).
send_notify("onpluginload");
// Now we're ready to start.
inst_mgr->start_instance(this);
}
////////////////////////////////////////////////////////////////////
@ -1082,6 +1126,7 @@ make_splash_window() {
assert(_splash_window == NULL);
_splash_window = new SplashWindowType(this);
_splash_window->set_install_label(_install_label);
string splash_image_url = _fparams.lookup_token("splash_img");
if (!_fparams.has_token("splash_img")) {
@ -1139,6 +1184,9 @@ report_package_info_ready(P3DPackage *package) {
<< " packages, total " << _total_download_size
<< " bytes required.\n";
if (_splash_window != NULL) {
_splash_window->set_install_progress(0.0);
}
_panda_script_object->set_string_property("status", "downloading");
send_notify("ondownloadbegin");
@ -1170,9 +1218,7 @@ start_next_download() {
}
_panda_script_object->set_string_property("downloadPackageName", package->get_package_name());
_panda_script_object->set_string_property("downloadPackageDisplayName", name);
if (_splash_window != NULL) {
_splash_window->set_install_label("Installing " + name);
}
set_install_label("Installing " + name);
nout << "Downloading " << package->get_package_name()
<< ", package " << _download_package_index + 1
@ -1204,10 +1250,48 @@ start_next_download() {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::report_instance_progress
// Access: Private
// Description: Notified as the instance file is downloaded.
////////////////////////////////////////////////////////////////////
void P3DInstance::
report_instance_progress(double progress) {
if (!_show_dl_instance_progress) {
// If we haven't yet set the download label, set it after a full
// second has elapsed. We don't want to set it too soon, because
// we're not really sure how long it will take to download (the
// instance file might be already in the browser cache).
#ifdef _WIN32
int now = GetTickCount();
double elapsed = (double)(now - _start_dl_instance_tick) * 0.001;
#else
struct timeval now;
gettimeofday(&now, NULL);
double elapsed = (double)(now.tv_sec - _start_dl_instance_timeval.tv_sec) +
(double)(now.tv_usec - _start_dl_instance_timeval.tv_usec) / 1000000.0;
#endif
// Put up the progress bar after 2 seconds have elapsed, if we've
// still got some distance to go; or after 5 seconds have elapsed
// regardless.
if ((elapsed > 2.0 && progress < 0.7) ||
(elapsed > 5.0)) {
_show_dl_instance_progress = true;
}
}
if (_splash_window != NULL && _show_dl_instance_progress) {
_splash_window->set_install_progress(progress);
}
_panda_script_object->set_float_property("instanceDownloadProgress", progress);
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::report_package_progress
// Access: Private
// Description: Notified as a required package is downloaded.
// Description: Notified as the packages required by the instance
// file are downloaded.
////////////////////////////////////////////////////////////////////
void P3DInstance::
report_package_progress(P3DPackage *package, double progress) {
@ -1246,6 +1330,20 @@ report_package_done(P3DPackage *package, bool success) {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::set_install_label
// Access: Private
// Description: Sets the install label that will be displayed on the
// splash window, if it is present.
////////////////////////////////////////////////////////////////////
void P3DInstance::
set_install_label(const string &install_label) {
_install_label = install_label;
if (_splash_window != NULL) {
_splash_window->set_install_label(_install_label);
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::send_notify
// Access: Private
@ -1490,3 +1588,42 @@ download_finished(bool success) {
}
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::InstanceDownload::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DInstance::InstanceDownload::
InstanceDownload(P3DInstance *inst) :
_inst(inst)
{
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::InstanceDownload::download_progress
// Access: Protected, Virtual
// Description: Intended to be overloaded to generate an occasional
// callback as new data comes in.
////////////////////////////////////////////////////////////////////
void P3DInstance::InstanceDownload::
download_progress() {
_inst->report_instance_progress(get_download_progress());
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::InstanceDownload::download_finished
// Access: Protected, Virtual
// Description: Intended to be overloaded to generate a callback
// when the download finishes, either successfully or
// otherwise. The bool parameter is true if the
// download was successful.
////////////////////////////////////////////////////////////////////
void P3DInstance::InstanceDownload::
download_finished(bool success) {
P3DFileDownload::download_finished(success);
if (success) {
// We've successfully downloaded the instance data.
_inst->set_p3d_filename(get_filename());
}
}

View File

@ -27,6 +27,10 @@
#include <CoreFoundation/CoreFoundation.h>
#endif
#ifndef _WIN32
#include <sys/time.h>
#endif
#include <deque>
#include <map>
@ -48,6 +52,7 @@ public:
const P3D_token tokens[], size_t num_tokens, void *user_data);
~P3DInstance();
void set_p3d_url(const string &p3d_url);
void set_p3d_filename(const string &p3d_filename);
inline const P3DFileParams &get_fparams() const;
@ -95,10 +100,17 @@ private:
class SplashDownload : public P3DFileDownload {
public:
SplashDownload(P3DInstance *inst);
protected:
virtual void download_finished(bool success);
private:
P3DInstance *_inst;
};
class InstanceDownload : public P3DFileDownload {
public:
InstanceDownload(P3DInstance *inst);
protected:
virtual void download_progress();
virtual void download_finished(bool success);
private:
P3DInstance *_inst;
};
@ -114,8 +126,10 @@ private:
void make_splash_window();
void report_package_info_ready(P3DPackage *package);
void start_next_download();
void report_instance_progress(double progress);
void report_package_progress(P3DPackage *package, double progress);
void report_package_done(P3DPackage *package, bool progress);
void set_install_label(const string &install_label);
void paint_window();
void add_modifier_flags(unsigned int &swb_flags, int modifiers);
@ -158,8 +172,18 @@ private:
#endif // __APPLE__
P3DSplashWindow *_splash_window;
string _install_label;
bool _instance_window_opened;
// Members for deciding whether and when to display the progress bar
// for downloading the initial instance data.
#ifdef _WIN32
int _start_dl_instance_tick;
#else
struct timeval _start_dl_instance_timeval;
#endif
bool _show_dl_instance_progress;
typedef vector<P3DPackage *> Packages;
Packages _packages;
Packages _downloading_packages;

View File

@ -216,21 +216,35 @@ create_instance(P3D_request_ready_func *func,
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::start_instance
// Function: P3DInstanceManager::set_p3d_filename
// Access: Public
// Description: Actually starts the instance running. Before this
// call, the instance is in an indeterminate state. It
// is an error to call this more than once for a
// particular instance.
// Description: Sets the p3d_filename (or p3d_url) on a particular
// instance.
////////////////////////////////////////////////////////////////////
bool P3DInstanceManager::
start_instance(P3DInstance *inst, const string &p3d_filename) {
set_p3d_filename(P3DInstance *inst, bool is_local,
const string &p3d_filename) {
if (inst->is_started()) {
nout << "Instance started twice: " << inst << "\n";
return false;
}
inst->set_p3d_filename(p3d_filename);
if (is_local) {
inst->set_p3d_filename(p3d_filename);
} else {
inst->set_p3d_url(p3d_filename);
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstanceManager::start_instance
// Access: Public
// Description: Actually starts the instance running on a particular
// session. This is called by the P3DInstance when it
// successfully loads its instance file.
////////////////////////////////////////////////////////////////////
bool P3DInstanceManager::
start_instance(P3DInstance *inst) {
P3DSession *session;
Sessions::iterator si = _sessions.find(inst->get_session_key());
if (si == _sessions.end()) {

View File

@ -57,7 +57,9 @@ public:
const P3D_token tokens[], size_t num_tokens,
void *user_data);
bool start_instance(P3DInstance *inst, const string &p3d_filename);
bool set_p3d_filename(P3DInstance *inst, bool is_local,
const string &p3d_filename);
bool start_instance(P3DInstance *inst);
void finish_instance(P3DInstance *inst);
P3DInstance *validate_instance(P3D_instance *instance);

View File

@ -240,15 +240,16 @@ paint_window() {
&src_rect, &dest_rect, srcCopy, 0);
}
if (!_install_label.empty()) {
// Draw the progress bar. We don't draw this bar unless the
// install_label has been set nonempty.
int bar_width = min((int)(win_width * 0.6), 400);
int bar_height = min((int)(win_height * 0.1), 24);
int bar_x = (win_width - bar_width) / 2;
int bar_y = (win_height - bar_height * 2);
int progress = bar_x + 1 + (int)((bar_width - 2) * _install_progress);
// Draw the progress bar. We don't draw this bar at all unless we
// have nonzero progress.
int bar_width = min((int)(win_width * 0.6), 400);
int bar_height = min((int)(win_height * 0.1), 24);
int bar_x = (win_width - bar_width) / 2;
int bar_y = (win_height - bar_height * 2);
int progress_width = (int)((bar_width - 2) * _install_progress);
if (progress_width > 0) {
int progress = bar_x + 1 + progress_width;
Rect rbar = { bar_y, bar_x, bar_y + bar_height, bar_x + bar_width };
Rect rneed = { bar_y + 1, progress, bar_y + bar_height - 1, bar_x + bar_width - 1 };
@ -262,7 +263,9 @@ paint_window() {
RGBColor black = { 0, 0, 0 };
RGBForeColor(&black);
}
if (!_install_label.empty()) {
// Now draw the install_label right above it.
TextFont(0);
TextFace(bold);

View File

@ -34,7 +34,6 @@ P3DWinSplashWindow(P3DInstance *inst) :
_progress_bar = NULL;
_text_label = NULL;
_thread_running = false;
_got_install = false;
_image_filename_changed = false;
_image_filename_temp = false;
_install_label_changed = false;
@ -137,8 +136,6 @@ set_install_label(const string &install_label) {
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
set_install_progress(double install_progress) {
_got_install = true;
ACQUIRE_LOCK(_install_lock);
_install_progress = install_progress;
RELEASE_LOCK(_install_lock);
@ -265,7 +262,6 @@ thread_run() {
DispatchMessage(&msg);
ACQUIRE_LOCK(_install_lock);
bool got_install = _got_install;
double install_progress = _install_progress;
if (_image_filename_changed) {
update_image_filename(_image_filename, _image_filename_temp);
@ -277,17 +273,18 @@ thread_run() {
_install_label_changed = false;
RELEASE_LOCK(_install_lock);
if (got_install && install_progress != last_progress) {
if (install_progress != last_progress) {
int progress = (int)(install_progress * 100.0);
if (_progress_bar == NULL) {
// Is it time to create the progress bar?
if (!_install_label.empty()) {
if (progress != 0) {
make_progress_bar();
}
} else {
// Update the progress bar. We do this only within the
// thread, to ensure we don't get a race condition when
// starting or closing the thread.
SendMessage(_progress_bar, PBM_SETPOS, (int)(install_progress * 100.0), 0);
SendMessage(_progress_bar, PBM_SETPOS, progress, 0);
last_progress = install_progress;
}

View File

@ -57,7 +57,6 @@ P3DX11SplashWindow(P3DInstance *inst) :
_resized_width = 0;
_resized_height = 0;
_graphics_context = None;
_got_install = false;
_image_filename_changed = false;
_image_filename_temp = false;
_install_label_changed = false;
@ -366,19 +365,17 @@ subprocess_run() {
_image_filename_changed = false;
if (override || have_event || install_label != prev_label) {
redraw(install_label);
override = false;
// Don't draw the progress bar unless we have some text in
// install_label.
if (!install_label.empty()) {
if (install_progress != 0.0) {
redraw(install_label);
XFillRectangle(_display, _window, _graphics_context, 12, _height - 18,
(unsigned int)(install_progress * (_width - 24)), 7);
}
XFlush(_display);
} else if (install_progress != prev_progress) {
if (!install_label.empty()) {
if (install_progress != 0.0) {
XFillRectangle(_display, _window, _graphics_context, 12, _height - 18,
(unsigned int)(install_progress * (_width - 24)), 7);
}
@ -457,7 +454,6 @@ receive_command() {
double install_progress = 0.0;
xcommand->Attribute("install_progress", &install_progress);
_got_install = true;
_install_progress = install_progress;
}
}
@ -513,7 +509,7 @@ redraw(string label) {
XClearArea(_display, _window, 10, _height - 20, _width - 20, 10, false);
}
if (!label.empty()) {
if (_install_progress != 0.0) {
// Draw the rest - the label and the progress bar outline.
int text_width = label.size() * 6;
int text_height = 10;
@ -587,8 +583,6 @@ setup_gc() {
return;
}
string install_label = _install_label;
double install_progress = _install_progress;
_install_label_changed = false;
XFontStruct* fs = XLoadQueryFont(_display, "6x13");

View File

@ -70,7 +70,6 @@ private:
int _width, _height;
bool _own_display;
bool _got_install;
bool _image_filename_changed;
string _image_filename;
bool _image_filename_temp;

View File

@ -116,7 +116,8 @@ P3D_new_instance(P3D_request_ready_func *func,
}
bool
P3D_instance_start(P3D_instance *instance, const char *p3d_filename) {
P3D_instance_start(P3D_instance *instance, bool is_local,
const char *p3d_filename) {
nout << "instance_start\n";
assert(P3DInstanceManager::get_global_ptr()->is_initialized());
if (p3d_filename == NULL) {
@ -127,7 +128,10 @@ P3D_instance_start(P3D_instance *instance, const char *p3d_filename) {
P3DInstance *inst = inst_mgr->validate_instance(instance);
bool result = false;
if (inst != NULL) {
result = inst_mgr->start_instance(inst, p3d_filename);
// We don't actually start it immediately; the instance will have
// to download the p3d url and read it, reading the python
// version, before it can start.
result = inst_mgr->set_p3d_filename(inst, is_local, p3d_filename);
}
RELEASE_LOCK(_api_lock);
return result;

View File

@ -79,7 +79,7 @@ extern "C" {
(below). This number will be incremented whenever there are changes
to any of the interface specifications defined in this header
file. */
#define P3D_API_VERSION 6
#define P3D_API_VERSION 7
/************************ GLOBAL FUNCTIONS **************************/
@ -240,14 +240,14 @@ P3D_new_instance_func(P3D_request_ready_func *func,
P3D_new_instance(); it actually starts the instance running.
Before this call, the instance will be in an indeterminate state.
For p3d_filename pass the name of a file on disk that contains the
contents of the p3d file that should be launched within the
instance. If this is empty or NULL, the "src" token (below) will
be downloaded instead.
If is_local is true, then p3d_filename contains the name of a local
p3d file on disk. If false, then p3d_filename contains a URL that
should be downloaded to retrieve the p3d file.
The return value is true on success, false on failure. */
typedef bool
P3D_instance_start_func(P3D_instance *instance, const char *p3d_filename);
P3D_instance_start_func(P3D_instance *instance, bool is_local,
const char *p3d_filename);
/* Call this function to interrupt a particular instance and stop it

View File

@ -28,7 +28,6 @@ public:
enum RequestType {
RT_contents_file,
RT_core_dll,
RT_instance_data,
RT_user
};

View File

@ -61,8 +61,7 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16 mode,
_root_dir = find_root_dir();
_started_instance_data = false;
_got_instance_data = false;
_got_instance_url = false;
_got_window = false;
_python_window_open = false;
}
@ -180,15 +179,18 @@ new_stream(NPMIMEType type, NPStream *stream, bool seekable, uint16 *stype) {
// This is an unsolicited stream. Assume the first unsolicited
// stream we receive is the instance data; any other unsolicited
// stream is an error.
if (!_started_instance_data) {
stream->notifyData = new PPDownloadRequest(PPDownloadRequest::RT_instance_data);
*stype = NP_ASFILEONLY;
_started_instance_data = true;
return NPERR_NO_ERROR;
// We don't let Mozilla finish downloading the instance data, but
// we do extract its URL to pass to the instance.
if (!_got_instance_url && stream->url != NULL) {
_got_instance_url = true;
_instance_url = stream->url;
if (_p3d_inst != NULL) {
P3D_instance_start(_p3d_inst, false, _instance_url.c_str());
}
}
// This is an unexpected unsolicited stream. (Firefox seems to
// give us the instance data twice for some reason.)
// Don't finish downloading the unsolicited stream.
return NPERR_GENERIC_ERROR;
}
@ -793,17 +795,6 @@ downloaded_file(PPDownloadRequest *req, const string &filename) {
downloaded_plugin(filename);
break;
case PPDownloadRequest::RT_instance_data:
// This is the instance data, e.g. the p3d filename. Now we can
// launch the instance.
_got_instance_data = true;
_p3d_filename = filename;
if (_p3d_inst != NULL) {
P3D_instance_start(_p3d_inst, _p3d_filename.c_str());
}
break;
case PPDownloadRequest::RT_user:
// Normally, RT_user requests won't come here, unless we
// short-circuited the browser by "downloading" a file:// url. In
@ -987,8 +978,8 @@ create_instance() {
_script_object->set_p3d_object(obj);
}
if (_got_instance_data) {
P3D_instance_start(_p3d_inst, _p3d_filename.c_str());
if (_got_instance_url) {
P3D_instance_start(_p3d_inst, false, _instance_url.c_str());
}
if (_got_window) {
@ -1314,6 +1305,7 @@ is_done() const {
void PPInstance::StreamingFileData::
thread_run() {
static const size_t buffer_size = 81920;
//static const size_t buffer_size = 512;
char buffer[buffer_size];
_file.read(buffer, buffer_size);

View File

@ -98,9 +98,8 @@ private:
string _root_dir;
FileSpec _core_api_dll;
bool _started_instance_data;
bool _got_instance_data;
string _p3d_filename;
bool _got_instance_url;
string _instance_url;
// This class is used for feeding local files (accessed via a
// "file://" url) into the core API.

View File

@ -632,7 +632,7 @@ create_instance(const string &arg, P3D_window_type window_type,
if (inst != NULL) {
P3D_instance_setup_window
(inst, window_type, win_x, win_y, win_width, win_height, parent_window);
P3D_instance_start(inst, os_p3d_filename.c_str());
P3D_instance_start(inst, true, os_p3d_filename.c_str());
}
return inst;