progress bars are back

This commit is contained in:
David Rose 2009-06-24 22:02:13 +00:00
parent aaa1924b60
commit 01ced75007
21 changed files with 474 additions and 698 deletions

View File

@ -23,11 +23,9 @@
p3dInstanceManager.h p3dInstanceManager.I \
p3dMultifileReader.h p3dMultifileReader.I \
p3dPackage.h p3dPackage.I \
p3dProgressWindow.h p3dProgressWindow.I \
p3dSession.h p3dSession.I \
p3dSplashWindow.h p3dSplashWindow.I \
p3dWindowParams.h p3dWindowParams.I \
p3dWinProgressWindow.h p3dWinProgressWindow.I \
p3dWinSplashWindow.h p3dWinSplashWindow.I
#define INCLUDED_SOURCES \
@ -39,11 +37,9 @@
p3dInstanceManager.cxx \
p3dMultifileReader.cxx \
p3dPackage.cxx \
p3dProgressWindow.cxx \
p3dSplashWindow.cxx \
p3dSession.cxx \
p3dWindowParams.cxx \
p3dWinProgressWindow.cxx \
p3dWinSplashWindow.cxx
#define INSTALL_HEADERS \

View File

@ -76,7 +76,7 @@ P3DInstance::
_packages.clear();
if (_splash_window != NULL) {
_splash_window->close_window();
nout << "Deleting splash window in destructor\n" << flush;
delete _splash_window;
_splash_window = NULL;
}
@ -98,9 +98,11 @@ set_fparams(const P3DFileParams &fparams) {
_got_fparams = true;
_fparams = fparams;
// Update the splash window.
if (_splash_window != NULL) {
_splash_window->set_fparams(_fparams);
// Maybe create the splash window.
if (!_instance_window_opened && _got_wparams) {
if (_splash_window == NULL) {
_splash_window = new SplashWindowType(this);
}
}
// This also sets up some internal data based on the contents of the
@ -128,10 +130,9 @@ set_wparams(const P3DWindowParams &wparams) {
_wparams = wparams;
// Update or create the splash window.
if (!_instance_window_opened) {
if (!_instance_window_opened && _got_fparams) {
if (_splash_window == NULL) {
_splash_window = new SplashWindowType(this);
_splash_window->open_window();
} else {
_splash_window->set_wparams(_wparams);
}
@ -238,7 +239,7 @@ get_request() {
nout << "Instance " << this << " got window_opened\n" << flush;
_instance_window_opened = true;
if (_splash_window != NULL) {
_splash_window->close_window();
nout << "Deleting splash window\n" << flush;
delete _splash_window;
_splash_window = NULL;
}
@ -257,6 +258,8 @@ get_request() {
////////////////////////////////////////////////////////////////////
void P3DInstance::
add_request(P3D_request *request) {
nout << "Instance " << this << " add_request(" << request->_request_type
<< ")\n" << flush;
request->_instance = this;
ACQUIRE_LOCK(_request_lock);
@ -414,3 +417,16 @@ make_xml() {
return xinstance;
}
////////////////////////////////////////////////////////////////////
// Function: P3DInstance::install_progress
// Access: Private
// Description: Notified as the _panda3d package is downloaded.
////////////////////////////////////////////////////////////////////
void P3DInstance::
install_progress(P3DPackage *package, double progress) {
if (_splash_window != NULL) {
_splash_window->set_install_label("Installing Panda3D");
_splash_window->set_install_progress(progress);
}
}

View File

@ -71,11 +71,11 @@ public:
inline bool is_started() const;
void request_stop();
void async_notify(const string &message);
TiXmlElement *make_xml();
private:
void install_progress(P3DPackage *package, double progress);
P3D_request_ready_func *_func;
bool _got_fparams;

View File

@ -1,14 +0,0 @@
// Filename: p3dProgressWindow.I
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////

View File

@ -1,54 +0,0 @@
// Filename: p3dProgressWindow.cxx
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 "p3dProgressWindow.h"
////////////////////////////////////////////////////////////////////
// Function: P3DProgressWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DProgressWindow::
P3DProgressWindow(P3DPackage *package, P3DSession *session,
P3DInstance *inst) :
_package(package),
_session(session),
_inst(inst)
{
}
////////////////////////////////////////////////////////////////////
// Function: P3DProgressWindow::package_ready
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void P3DProgressWindow::
package_ready(P3DPackage *package, bool success) {
if (this == _session->_panda3d_callback) {
_session->_panda3d_callback = NULL;
if (package == _session->_panda3d) {
if (success) {
_session->start_p3dpython();
} else {
nout << "Failed to install " << package->get_package_name()
<< "_" << package->get_package_version() << "\n";
}
} else {
nout << "Unexpected panda3d package: " << package << "\n";
}
} else {
nout << "Unexpected callback for P3DSession\n";
}
}

View File

@ -1,52 +0,0 @@
// Filename: p3dProgressWindow.h
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 P3DPROGRESSWINDOW_H
#define P3DPROGRESSWINDOW_H
#include "p3d_plugin_common.h"
#include "p3dPackage.h"
#include "p3dWindowParams.h"
class P3DInstance;
////////////////////////////////////////////////////////////////////
// Class : P3DProgressWindow
// Description : This window is displayed temporarily, in place of an
// instance's actual window, during the initial download
// of the Panda3D code. When the download is finished,
// it notifies the session.
//
// This is the base implementation; it contains no
// specific code to open a window.
////////////////////////////////////////////////////////////////////
class P3DProgressWindow : public P3DPackage::Callback {
public:
P3DProgressWindow(P3DPackage *package, P3DSession *session,
P3DInstance *inst);
virtual void package_ready(P3DPackage *package, bool success);
protected:
P3DPackage *_package;
P3DSession *_session;
P3DInstance *_inst;
P3DWindowParams _wparams;
};
#include "p3dProgressWindow.I"
#endif

View File

@ -299,6 +299,7 @@ py_request_func(PyObject *args) {
xrequest->SetAttribute("message", message);
doc.LinkEndChild(decl);
doc.LinkEndChild(xrequest);
nout << "sending " << doc << "\n" << flush;
_pipe_write << doc << flush;
} else {

View File

@ -15,20 +15,12 @@
#include "p3dSession.h"
#include "p3dInstance.h"
#include "p3dInstanceManager.h"
#include "p3dProgressWindow.h"
#include "p3dWinProgressWindow.h"
#include "p3d_plugin_config.h"
#ifndef _WIN32
#include <fcntl.h>
#endif
#ifdef _WIN32
typedef P3DWinProgressWindow ProgressWindowType;
#else
typedef P3DProgressWindow ProgressWindowType;
#endif
////////////////////////////////////////////////////////////////////
// Function: P3DSession::Constructor
// Access: Public
@ -161,23 +153,7 @@ start_instance(P3DInstance *inst) {
} else {
// Otherwise, set a callback, so we'll know when it is ready.
if (_panda3d_callback == NULL) {
_panda3d_callback = new P3DProgressWindow(_panda3d, this, inst);
/*
// The callback object will be a ProgressWindow, to show
// visual progress to the user while we're downloading.
if (inst->get_window_type() == P3D_WT_hidden) {
// For a hidden window, just create an instance of the base
// class, which manifests no actual window.
_panda3d_callback = new P3DProgressWindow(_panda3d, this, inst);
} else {
// For a non-hidden window, create an instance of
// ProgressWindowType, which is typedeffed above to be the kind
// of class that actually does manifest a window.
_panda3d_callback = new ProgressWindowType(_panda3d, this, inst);
}
*/
_panda3d_callback = new PackageCallback(this);
_panda3d->set_callback(_panda3d_callback);
}
}
@ -234,6 +210,20 @@ send_command(TiXmlDocument *command) {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::install_progress
// Access: Private
// Description: Notified as the _panda3d package is downloaded.
////////////////////////////////////////////////////////////////////
void P3DSession::
install_progress(P3DPackage *package, double progress) {
Instances::iterator ii;
for (ii = _instances.begin(); ii != _instances.end(); ++ii) {
P3DInstance *inst = (*ii).second;
inst->install_progress(package, progress);
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::start_p3dpython
// Access: Private
@ -712,3 +702,51 @@ posix_create_process(const string &program, const string &start_dir,
}
#endif // _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DSession::PackageCallback::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DSession::PackageCallback::
PackageCallback(P3DSession *session) :
_session(session)
{
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::PackageCallback::package_ready
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void P3DSession::PackageCallback::
package_ready(P3DPackage *package, bool success) {
if (this == _session->_panda3d_callback) {
_session->_panda3d_callback = NULL;
if (package == _session->_panda3d) {
if (success) {
_session->start_p3dpython();
} else {
nout << "Failed to install " << package->get_package_name()
<< "_" << package->get_package_version() << "\n";
}
} else {
nout << "Unexpected panda3d package: " << package << "\n";
}
} else {
nout << "Unexpected callback for P3DSession\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DSession::PackageCallback::install_progress
// Access: Public, Virtual
// Description: This callback is received during the download process
// to inform us how much has been installed so far.
////////////////////////////////////////////////////////////////////
void P3DSession::PackageCallback::
install_progress(P3DPackage *package, double progress) {
if (this == _session->_panda3d_callback) {
_session->install_progress(package, progress);
}
}

View File

@ -49,6 +49,7 @@ public:
void send_command(TiXmlDocument *command);
private:
void install_progress(P3DPackage *package, double progress);
void start_p3dpython();
void spawn_read_thread();
@ -79,6 +80,17 @@ private:
HandleStream &pipe_read, HandleStream &pipe_write);
#endif
class PackageCallback : public P3DPackage::Callback {
public:
PackageCallback(P3DSession *session);
virtual void install_progress(P3DPackage *package, double progress);
virtual void package_ready(P3DPackage *package, bool success);
protected:
P3DSession *_session;
};
private:
string _session_key;
string _python_version;
@ -97,7 +109,7 @@ private:
Commands _commands;
P3DPackage *_panda3d;
P3DProgressWindow *_panda3d_callback;
PackageCallback *_panda3d_callback;
// Members for communicating with the p3dpython child process.
#ifdef _WIN32
@ -119,7 +131,7 @@ private:
pthread_t _read_thread;
#endif
friend class P3DProgressWindow;
friend class PackageCallback;
};
#include "p3dSession.I"

View File

@ -17,7 +17,9 @@
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::Constructor
// Access: Public
// Description:
// Description: By the time the SplashWindow is created, the instance
// has received both its fparams and its wparams. Copy
// them both into this class for reference.
////////////////////////////////////////////////////////////////////
P3DSplashWindow::
P3DSplashWindow(P3DInstance *inst) :
@ -36,16 +38,6 @@ P3DSplashWindow::
~P3DSplashWindow() {
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_fparams
// Access: Public, Virtual
// Description: Sets up the file parameters for the window.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
set_fparams(const P3DFileParams &fparams) {
_fparams = fparams;
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::set_wparams
// Access: Public, Virtual
@ -59,21 +51,21 @@ set_wparams(const P3DWindowParams &wparams) {
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::open_window
// Function: P3DSplashWindow::set_install_label
// Access: Public, Virtual
// Description: Creates the splash window.
// Description: Specifies the text that is displayed above the
// install progress bar.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
open_window() {
nout << "P3DSplashWindow::open_window()\n" << flush;
set_install_label(const string &install_label) {
}
////////////////////////////////////////////////////////////////////
// Function: P3DSplashWindow::close_window
// Function: P3DSplashWindow::set_install_progress
// Access: Public, Virtual
// Description: Closes the window created above.
// Description: Moves the install progress bar from 0.0 to 1.0.
////////////////////////////////////////////////////////////////////
void P3DSplashWindow::
close_window() {
nout << "P3DSplashWindow::close_window()\n" << flush;
set_install_progress(double install_progress) {
}

View File

@ -37,14 +37,13 @@ public:
P3DSplashWindow(P3DInstance *inst);
virtual ~P3DSplashWindow();
virtual void set_fparams(const P3DFileParams &fparams);
inline const P3DFileParams &get_fparams() const;
virtual void set_wparams(const P3DWindowParams &wparams);
inline const P3DWindowParams &get_wparams() const;
virtual void open_window();
virtual void close_window();
virtual void set_install_label(const string &install_label);
virtual void set_install_progress(double install_progress);
protected:
P3DInstance *_inst;

View File

@ -1,14 +0,0 @@
// Filename: p3dWinProgressWindow.I
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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."
//
////////////////////////////////////////////////////////////////////

View File

@ -1,354 +0,0 @@
// Filename: p3dWinProgressWindow.cxx
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 "p3dWinProgressWindow.h"
#ifdef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DWinProgressWindow::
P3DWinProgressWindow(P3DPackage *package, P3DSession *session,
P3DInstance *inst) :
P3DProgressWindow(package, session, inst)
{
_thread = NULL;
_hwnd = NULL;
_progress_bar = NULL;
_thread_running = false;
INIT_LOCK(_progress_lock);
assert(_wparams.get_window_type() != P3D_WT_hidden);
start_thread();
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
P3DWinProgressWindow::
~P3DWinProgressWindow() {
stop_thread();
DESTROY_LOCK(_progress_lock);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::install_progress
// Access: Public, Virtual
// Description: This callback is received during the download process
// to inform us how much has been installed so far.
////////////////////////////////////////////////////////////////////
void P3DWinProgressWindow::
install_progress(P3DPackage *package, double progress) {
P3DProgressWindow::install_progress(package, progress);
ACQUIRE_LOCK(_progress_lock);
_progress = progress;
RELEASE_LOCK(_progress_lock);
// Post a silly message to spin the message loop.
PostThreadMessage(_thread_id, WM_USER, 0, 0);
if (!_thread_running) {
_inst->request_stop();
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::start_thraed
// Access: Private
// Description: Spawns the sub-thread.
////////////////////////////////////////////////////////////////////
void P3DWinProgressWindow::
start_thread() {
_thread_continue = true;
_thread = CreateThread(NULL, 0, &win_thread_run, this, 0, &_thread_id);
if (_thread != NULL) {
_thread_running = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::stop_thraed
// Access: Private
// Description: Terminates and joins the sub-thread.
////////////////////////////////////////////////////////////////////
void P3DWinProgressWindow::
stop_thread() {
_thread_continue = false;
// Post a silly message to spin the message loop.
PostThreadMessage(_thread_id, WM_USER, 0, 0);
WaitForSingleObject(_thread, INFINITE);
CloseHandle(_thread);
_thread = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::thread_run
// Access: Private
// Description: The sub-thread's main run method.
////////////////////////////////////////////////////////////////////
void P3DWinProgressWindow::
thread_run() {
make_window();
double last_progress = -1.0;
_loop_started = GetTickCount();
MSG msg;
int retval;
retval = GetMessage(&msg, NULL, 0, 0);
while (retval != 0 && _thread_continue) {
if (retval == -1) {
nout << "Error processing message queue.\n";
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
{
ACQUIRE_LOCK(_progress_lock);
double new_progress = _progress;
RELEASE_LOCK(_progress_lock);
if (new_progress != last_progress) {
if (_progress_bar == NULL) {
// Is it time to create the progress bar?
int now = GetTickCount();
if (now - _loop_started > 2000) {
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)(new_progress * 100.0), 0);
last_progress = new_progress;
}
}
}
retval = GetMessage(&msg, NULL, 0, 0);
}
close_window();
_thread_running = false;
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::win_thread_run
// Access: Private, Static
// Description: The OS-specific thread callback function.
////////////////////////////////////////////////////////////////////
DWORD P3DWinProgressWindow::
win_thread_run(LPVOID data) {
((P3DWinProgressWindow *)data)->thread_run();
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::make_window
// Access: Private
// Description: Creates the window for displaying progress. Runs
// within the sub-thread.
////////////////////////////////////////////////////////////////////
void P3DWinProgressWindow::
make_window() {
WNDCLASS wc;
HINSTANCE application = GetModuleHandle(NULL);
static bool registered_class = false;
if (!registered_class) {
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.lpfnWndProc = window_proc;
wc.hInstance = application;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = "panda3d_progress";
if (!RegisterClass(&wc)) {
nout << "Could not register window class!\n";
}
registered_class = true;
}
int x = CW_USEDEFAULT;
int y = CW_USEDEFAULT;
if (_wparams.get_win_x() != 0 && _wparams.get_win_y() != 0) {
x = _wparams.get_win_x();
y = _wparams.get_win_y();
}
int width = 320;
int height = 240;
if (_wparams.get_win_width() != 0 && _wparams.get_win_height() != 0) {
width = _wparams.get_win_width();
height = _wparams.get_win_height();
}
if (_wparams.get_window_type() == P3D_WT_embedded) {
// Create an embedded window.
DWORD window_style =
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
HWND parent_hwnd = _wparams.get_parent_window()._hwnd;
_hwnd =
CreateWindow("panda3d_progress", "Panda3D", window_style,
x, y, width, height,
parent_hwnd, NULL, application, 0);
if (!_hwnd) {
nout << "Could not create embedded window!\n";
return;
}
} else {
// Create a toplevel window.
DWORD window_style =
WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS |
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX |
WS_SIZEBOX | WS_MAXIMIZEBOX;
_hwnd =
CreateWindow("panda3d_progress", "Panda3D", window_style,
x, y, width, height,
NULL, NULL, application, 0);
if (!_hwnd) {
nout << "Could not create toplevel window!\n";
return;
}
// We don't initially show the toplevel window. We'll show it
// when we create the actual progress bar, a few seconds later;
// otherwise, it might be distracting if the window pops up and
// then immediately disappears.
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::make_progress_bar
// Access: Private
// Description: Creates the progress bar and label. Runs
// within the sub-thread. This is done a few seconds
// after the main window is created, to give us a chance
// to launch quickly without bothering the user.
////////////////////////////////////////////////////////////////////
void P3DWinProgressWindow::
make_progress_bar() {
if (_progress_bar != NULL) {
return;
}
HINSTANCE application = GetModuleHandle(NULL);
DWORD window_style =
WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
RECT rect;
GetClientRect(_hwnd, &rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
int bar_width = min((int)(width * 0.6), 400);
int bar_height = min((int)(height * 0.1), 24);
int bar_x = (width - bar_width) / 2;
int bar_y = (height - bar_height) / 2;
_progress_bar =
CreateWindowEx(0, PROGRESS_CLASS, "", window_style,
bar_x, bar_y, bar_width, bar_height,
_hwnd, NULL, application, 0);
// Create a static text label. What a major pain *this* is.
string text_string = "Installing " + _package->get_package_display_name();
const char *text = text_string.c_str();
HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT);
HDC dc = GetDC(_hwnd);
SelectObject(dc, font);
SIZE text_size;
GetTextExtentPoint32(dc, text, strlen(text), &text_size);
ReleaseDC(_hwnd, dc);
int text_width = text_size.cx;
int text_height = text_size.cy;
int text_x = (width - text_width) / 2;
int text_y = bar_y - text_height - 2;
CreateWindowEx(0, "STATIC", text, SS_OWNERDRAW | window_style,
text_x, text_y, text_width, text_height,
_hwnd, NULL, application, 0);
// Ensure the main window is visible now.
ShowWindow(_hwnd, SW_SHOWNORMAL);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::close_window
// Access: Private
// Description: Closes the window created above.
////////////////////////////////////////////////////////////////////
void P3DWinProgressWindow::
close_window() {
if (_hwnd) {
ShowWindow(_hwnd, SW_HIDE);
CloseWindow(_hwnd);
_hwnd = NULL;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinProgressWindow::window_proc
// Access: Private, Static
// Description: The windows event-processing handler.
////////////////////////////////////////////////////////////////////
LONG P3DWinProgressWindow::
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_DRAWITEM:
{
DRAWITEMSTRUCT *dis = (DRAWITEMSTRUCT *)lparam;
FillRect(dis->hDC, &(dis->rcItem), WHITE_BRUSH);
static const int text_buffer_size = 512;
char text_buffer[text_buffer_size];
GetWindowText(dis->hwndItem, text_buffer, text_buffer_size);
HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT);
SelectObject(dis->hDC, font);
SetBkColor(dis->hDC, 0x00ffffff);
DrawText(dis->hDC, text_buffer, -1, &(dis->rcItem),
DT_BOTTOM | DT_CENTER | DT_SINGLELINE);
}
};
return DefWindowProc(hwnd, msg, wparam, lparam);
}
#endif // _WIN32

View File

@ -1,72 +0,0 @@
// Filename: p3dWinProgressWindow.h
// Created by: drose (17Jun09)
//
////////////////////////////////////////////////////////////////////
//
// 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 P3DWINPROGRESSWINDOW_H
#define P3DWINPROGRESSWINDOW_H
#include "p3d_plugin_common.h"
#ifdef _WIN32
#include "p3dProgressWindow.h"
#include "p3d_lock.h"
#include <windows.h>
////////////////////////////////////////////////////////////////////
// Class : P3DWinProgressWindow
// Description : This is the Windows implementation of the
// initial-download window.
////////////////////////////////////////////////////////////////////
class P3DWinProgressWindow : public P3DProgressWindow {
public:
P3DWinProgressWindow(P3DPackage *package, P3DSession *session, P3DInstance *inst);
virtual ~P3DWinProgressWindow();
protected:
virtual void install_progress(P3DPackage *package, double progress);
private:
void start_thread();
void stop_thread();
private:
// These methods run only within the window thread.
void thread_run();
static DWORD WINAPI win_thread_run(LPVOID data);
void make_window();
void make_progress_bar();
void close_window();
static LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
private:
double _progress;
LOCK _progress_lock;
int _loop_started;
bool _thread_continue;
bool _thread_running;
HANDLE _thread;
DWORD _thread_id;
HWND _hwnd;
HWND _progress_bar;
};
#include "p3dWinProgressWindow.I"
#endif // _WIN32
#endif

View File

@ -25,7 +25,19 @@ P3DWinSplashWindow::
P3DWinSplashWindow(P3DInstance *inst) :
P3DSplashWindow(inst)
{
_thread = NULL;
_thread_id = 0;
_hwnd = NULL;
_progress_bar = NULL;
_text_label = NULL;
_thread_running = false;
_got_install = false;
_install_progress = 0.0;
_install_label_changed = false;
INIT_LOCK(_install_lock);
start_thread();
}
////////////////////////////////////////////////////////////////////
@ -35,17 +47,165 @@ P3DWinSplashWindow(P3DInstance *inst) :
////////////////////////////////////////////////////////////////////
P3DWinSplashWindow::
~P3DWinSplashWindow() {
close_window();
stop_thread();
DESTROY_LOCK(_install_lock);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::open_window
// Function: P3DWinSplashWindow::set_install_label
// Access: Public, Virtual
// Description: Creates the splash window.
// Description: Specifies the text that is displayed above the
// install progress bar.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
open_window() {
P3DSplashWindow::open_window();
set_install_label(const string &install_label) {
ACQUIRE_LOCK(_install_lock);
if (_install_label != install_label) {
_install_label = install_label;
_install_label_changed = true;
}
RELEASE_LOCK(_install_lock);
// Post a silly message to spin the message loop.
PostThreadMessage(_thread_id, WM_USER, 0, 0);
if (!_thread_running && _thread_continue) {
// The user must have closed the window. Let's shut down the
// instance, too.
_inst->request_stop();
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::set_install_progress
// Access: Public, Virtual
// Description: Moves the install progress bar from 0.0 to 1.0.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
set_install_progress(double install_progress) {
_got_install = true;
ACQUIRE_LOCK(_install_lock);
_install_progress = install_progress;
RELEASE_LOCK(_install_lock);
// Post a silly message to spin the message loop.
PostThreadMessage(_thread_id, WM_USER, 0, 0);
if (!_thread_running && _thread_continue) {
// The user must have closed the window. Let's shut down the
// instance, too.
_inst->request_stop();
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::start_thraed
// Access: Private
// Description: Spawns the sub-thread.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
start_thread() {
_thread_continue = true;
_thread = CreateThread(NULL, 0, &win_thread_run, this, 0, &_thread_id);
if (_thread != NULL) {
_thread_running = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::stop_thraed
// Access: Private
// Description: Terminates and joins the sub-thread.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
stop_thread() {
_thread_continue = false;
// Post a silly message to spin the message loop.
PostThreadMessage(_thread_id, WM_USER, 0, 0);
WaitForSingleObject(_thread, INFINITE);
CloseHandle(_thread);
_thread = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::thread_run
// Access: Private
// Description: The sub-thread's main run method.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
thread_run() {
make_window();
double last_progress = -1.0;
_loop_started = GetTickCount();
MSG msg;
int retval;
retval = GetMessage(&msg, NULL, 0, 0);
while (retval != 0 && _thread_continue) {
if (retval == -1) {
nout << "Error processing message queue.\n";
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
if (_got_install) {
ACQUIRE_LOCK(_install_lock);
double install_progress = _install_progress;
if (_install_label_changed && _progress_bar != NULL) {
update_install_label(_install_label);
}
_install_label_changed = false;
RELEASE_LOCK(_install_lock);
if (install_progress != last_progress) {
if (_progress_bar == NULL) {
// Is it time to create the progress bar?
int now = GetTickCount();
if (now - _loop_started > 2000) {
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);
last_progress = install_progress;
}
}
}
retval = GetMessage(&msg, NULL, 0, 0);
}
close_window();
_thread_running = false;
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::win_thread_run
// Access: Private, Static
// Description: The OS-specific thread callback function.
////////////////////////////////////////////////////////////////////
DWORD P3DWinSplashWindow::
win_thread_run(LPVOID data) {
((P3DWinSplashWindow *)data)->thread_run();
return 0;
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::make_window
// Access: Private
// Description: Creates the window for displaying progress. Runs
// within the sub-thread.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
make_window() {
WNDCLASS wc;
HINSTANCE application = GetModuleHandle(NULL);
@ -55,7 +215,7 @@ open_window() {
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.lpfnWndProc = window_proc;
wc.hInstance = application;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = "panda3d_splash";
if (!RegisterClass(&wc)) {
@ -110,21 +270,117 @@ open_window() {
nout << "Could not create toplevel window!\n";
return;
}
ShowWindow(_hwnd, SW_SHOWNORMAL);
}
}
// Ensure the main window is visible now.
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::make_progress_bar
// Access: Private
// Description: Creates the progress bar and label. Runs
// within the sub-thread. This is done a few seconds
// after the main window is created, to give us a chance
// to launch quickly without bothering the user.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
make_progress_bar() {
if (_progress_bar != NULL) {
return;
}
ACQUIRE_LOCK(_install_lock);
string install_label = _install_label;
double install_progress = _install_progress;
_install_label_changed = false;
RELEASE_LOCK(_install_lock);
HINSTANCE application = GetModuleHandle(NULL);
DWORD window_style =
WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
RECT rect;
GetClientRect(_hwnd, &rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
int bar_width = min((int)(width * 0.6), 400);
int bar_height = min((int)(height * 0.1), 24);
int bar_x = (width - bar_width) / 2;
int bar_y = (height - bar_height) / 2;
_progress_bar =
CreateWindowEx(0, PROGRESS_CLASS, "", window_style,
bar_x, bar_y, bar_width, bar_height,
_hwnd, NULL, application, 0);
SendMessage(_progress_bar, PBM_SETPOS, (int)(install_progress * 100.0), 0);
ShowWindow(_progress_bar, SW_SHOWNORMAL);
update_install_label(install_label);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::update_install_label
// Access: Private
// Description: Changes the text on the install label. Runs within
// the sub-thread.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
update_install_label(const string &install_label) {
assert(_progress_bar != NULL);
if (_text_label != NULL) {
DestroyWindow(_text_label);
_text_label = NULL;
}
if (install_label.empty()) {
// Trivial case.
return;
}
// Create a static text label. What a major pain *this* is.
const char *text = install_label.c_str();
HFONT font = (HFONT)GetStockObject(ANSI_VAR_FONT);
HDC dc = GetDC(_hwnd);
SelectObject(dc, font);
SIZE text_size;
GetTextExtentPoint32(dc, text, strlen(text), &text_size);
ReleaseDC(_hwnd, dc);
HINSTANCE application = GetModuleHandle(NULL);
DWORD window_style =
SS_OWNERDRAW | WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
RECT rect;
GetClientRect(_hwnd, &rect);
int width = rect.right - rect.left;
int height = rect.bottom - rect.top;
int bar_height = min((int)(height * 0.1), 24);
int bar_y = (height - bar_height) / 2;
int text_width = text_size.cx;
int text_height = text_size.cy;
int text_x = (width - text_width) / 2;
int text_y = bar_y - text_height - 2;
_text_label = CreateWindowEx(0, "STATIC", text, window_style,
text_x, text_y, text_width, text_height,
_hwnd, NULL, application, 0);
ShowWindow(_text_label, SW_SHOWNORMAL);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::close_window
// Access: Public, Virtual
// Access: Private
// Description: Closes the window created above.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
close_window() {
P3DSplashWindow::close_window();
if (_hwnd) {
ShowWindow(_hwnd, SW_HIDE);
CloseWindow(_hwnd);

View File

@ -34,14 +34,41 @@ public:
P3DWinSplashWindow(P3DInstance *inst);
virtual ~P3DWinSplashWindow();
virtual void open_window();
virtual void close_window();
virtual void set_install_label(const string &install_label);
virtual void set_install_progress(double install_progress);
private:
void start_thread();
void stop_thread();
private:
// These methods run only within the window thread.
void thread_run();
static DWORD WINAPI win_thread_run(LPVOID data);
void make_window();
void make_progress_bar();
void update_install_label(const string &install_label);
void close_window();
static LONG WINAPI window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
private:
bool _got_install;
bool _install_label_changed;
string _install_label;
double _install_progress;
LOCK _install_lock;
int _loop_started;
bool _thread_continue;
bool _thread_running;
HANDLE _thread;
DWORD _thread_id;
HWND _hwnd;
HWND _progress_bar;
HWND _text_label;
};
#include "p3dWinSplashWindow.I"

View File

@ -6,9 +6,7 @@
#include "p3dInstanceManager.cxx"
#include "p3dMultifileReader.cxx"
#include "p3dPackage.cxx"
#include "p3dProgressWindow.cxx"
#include "p3dSplashWindow.cxx"
#include "p3dSession.cxx"
#include "p3dWindowParams.cxx"
#include "p3dWinProgressWindow.cxx"
#include "p3dWinSplashWindow.cxx"

View File

@ -334,8 +334,9 @@ stream_as_file(NPStream *stream, const char *fname) {
////////////////////////////////////////////////////////////////////
void PPInstance::
handle_request(P3D_request *request) {
logfile << "handle_request: " << request << ", " << request->_instance
<< " within " << this << ", " << _p3d_inst << "\n" << flush;
logfile
<< "handle_request: " << request << ", " << request->_request_type
<< " within " << this << "\n" << flush;
assert(request->_instance == _p3d_inst);
bool handled = false;
@ -428,7 +429,13 @@ send_window() {
P3D_window_handle parent_window;
#ifdef _WIN32
parent_window._hwnd = (HWND)(_window.window);
if (_window.type == NPWindowTypeWindow) {
parent_window._hwnd = (HWND)(_window.window);
} else {
// Hmm, it's just a drawable; but we didn't ask for a windowless
// plugin.
parent_window._hwnd = 0;
}
#endif
// Actually, we set up the window starting at (0, 0), instead of

View File

@ -34,9 +34,9 @@ open_logfile() {
}
#ifdef _WIN32
UINT _timer = 0;
DWORD main_thread_id = 0;
#endif
LOCK _timer_lock;
////////////////////////////////////////////////////////////////////
// Function: handle_request_loop
@ -45,44 +45,45 @@ LOCK _timer_lock;
////////////////////////////////////////////////////////////////////
static void
handle_request_loop() {
assert(is_plugin_loaded());
if (!is_plugin_loaded()) {
return;
}
logfile << "about to call P3D_check_request()\n" << flush;
P3D_instance *p3d_inst = P3D_check_request(false);
logfile << "P3D_check_request() returns " << p3d_inst << "\n" << flush;
while (p3d_inst != (P3D_instance *)NULL) {
P3D_request *request = P3D_instance_get_request(p3d_inst);
logfile << "got request " << request << "\n";
if (request != (P3D_request *)NULL) {
PPInstance *inst = (PPInstance *)(p3d_inst->_user_data);
assert(inst != NULL);
inst->handle_request(request);
}
p3d_inst = P3D_check_request(false);
logfile << "P3D_check_request() returns " << p3d_inst << "\n" << flush;
}
}
////////////////////////////////////////////////////////////////////
// Function: win_timer_func
// Description: The Windows flavor of the timer callback function.
////////////////////////////////////////////////////////////////////
#ifdef _WIN32
static VOID CALLBACK
win_timer_func(HWND hwnd, UINT msg, UINT_PTR event, DWORD time) {
ACQUIRE_LOCK(_timer_lock);
logfile
<< "win_timer_func " << hwnd << ", " << msg << ", " << event
<< ", " << time << "\n"
<< "timer thread = " << GetCurrentThreadId() << "\n"
<< flush;
KillTimer(NULL, _timer);
_timer = 0;
RELEASE_LOCK(_timer_lock);
////////////////////////////////////////////////////////////////////
// Function: window_proc
// Description: We bind this function to the parent windows we are
// given in NPP_New(), so we can spin the request_loop
// when needed.
////////////////////////////////////////////////////////////////////
static LONG
window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
// If this is a toplevel window event, but not something caused as a
// result of something done by handle_request_loop(), then call
// handle_request_loop() to see if there are any new requests to be
// forwarded to the main thread.
static int recursion_protect = 0;
++recursion_protect;
if (recursion_protect == 1) {
handle_request_loop();
}
--recursion_protect;
handle_request_loop();
return DefWindowProc(hwnd, msg, wparam, lparam);
}
#endif // _WIN32
#endif // _WIN32
////////////////////////////////////////////////////////////////////
// Function: request_ready
@ -94,20 +95,15 @@ win_timer_func(HWND hwnd, UINT msg, UINT_PTR event, DWORD time) {
void
request_ready(P3D_instance *instance) {
logfile
<< "request_ready"
// << " thread = " << GetCurrentThreadId()
<< "request_ready in " << instance
<< " thread = " << GetCurrentThreadId()
<< "\n" << flush;
// Since we might be in a sub-thread at this point, use a timer to
// forward this event to the main thread.
// Since we might be in a sub-thread at this point, use a Windows
// message to forward this event to the main thread.
#ifdef _WIN32
ACQUIRE_LOCK(_timer_lock);
if (_timer == 0) {
_timer = SetTimer(NULL, 0, 0, win_timer_func);
logfile << "_timer = " << _timer << "\n" << flush;
}
RELEASE_LOCK(_timer_lock);
PostThreadMessage(main_thread_id, WM_USER, 0, 0);
#else
// TODO: send the message to the main thread properly.
handle_request_loop();
@ -139,12 +135,16 @@ NP_Initialize(NPNetscapeFuncs *browserFuncs,
open_logfile();
logfile << "initializing\n" << flush;
// logfile << "main thread = " << GetCurrentThreadId() << "\n";
#ifdef _WIN32
// Save the calling thread ID (i.e. the main thread) so we can post
// messages back to this thread when needed.
main_thread_id = GetCurrentThreadId();
logfile << "main thread = " << main_thread_id << "\n";
#endif
logfile << "browserFuncs = " << browserFuncs << "\n" << flush;
INIT_LOCK(_timer_lock);
/*
#ifdef _WIN32
string plugin_location = "c:/cygwin/home/drose/player/direct/built/lib/p3d_plugin.dll";
@ -202,23 +202,8 @@ NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) {
NPError OSCALL
NP_Shutdown(void) {
logfile << "shutdown\n" << flush;
ACQUIRE_LOCK(_timer_lock);
#ifdef _WIN32
if (_timer != 0) {
KillTimer(NULL, _timer);
_timer = 0;
}
#endif
RELEASE_LOCK(_timer_lock);
DESTROY_LOCK(_timer_lock);
logfile << "unloading plugin\n" << flush;
unload_plugin();
logfile << "done shutdown\n" << flush;
// Not clear whether there's a return value or not. Some versions
// of the API have different opinions on this.
return NPERR_NO_ERROR;
@ -270,6 +255,14 @@ NPP_SetWindow(NPP instance, NPWindow *window) {
<< ", " << window->width << ", " << window->height
<< "\n" << flush;
if (window->type == NPWindowTypeWindow) {
// Subclass the window to make it call our own window_proc instead
// of whatever window_proc it has already. This is just a dopey
// trick to allow us to poll events in the main thread.
HWND hwnd = (HWND)window->window;
LONG_PTR orig = SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR)window_proc);
}
PPInstance *inst = (PPInstance *)(instance->pdata);
assert(inst != NULL);
inst->set_window(window);
@ -426,3 +419,4 @@ NPP_SetValue(NPP instance, NPNVariable variable, void *value) {
logfile << "SetValue " << variable << "\n";
return NPERR_GENERIC_ERROR;
}

View File

@ -248,10 +248,11 @@ P3D_instance *
create_instance(const string &arg, P3D_window_type window_type,
int win_x, int win_y, int win_width, int win_height,
P3D_window_handle parent_window,
const string &output_filename) {
const Filename &output_filename) {
string os_output_filename = output_filename.to_os_specific();
P3D_token tokens[] = {
{ "output_filename", output_filename.c_str() },
{ "output_filename", os_output_filename.c_str() },
{ "src", arg.c_str() },
};
int num_tokens = sizeof(tokens) / sizeof(P3D_token);
@ -343,8 +344,8 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
extern int optind;
const char *optstr = "p:l:t:s:o:h";
string p3d_plugin_filename;
string output_filename;
Filename p3d_plugin_filename;
Filename output_filename;
P3D_window_type window_type = P3D_WT_toplevel;
int win_x = 0, win_y = 0;
int win_width = 0, win_height = 0;
@ -354,11 +355,11 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
while (flag != EOF) {
switch (flag) {
case 'p':
p3d_plugin_filename = optarg;
p3d_plugin_filename = Filename::from_os_specific(optarg);
break;
case 'l':
output_filename = optarg;
output_filename = Filename::from_os_specific(optarg);
break;
case 't':
@ -407,7 +408,7 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
return 1;
}
if (!load_plugin(p3d_plugin_filename)) {
if (!load_plugin(p3d_plugin_filename.to_os_specific())) {
cerr << "Unable to load Panda3D plugin.\n";
return 1;
}

View File

@ -133,7 +133,6 @@ class AppRunner(DirectObject):
# One day we will have support for multiple instances within a
# Python session. Against that day, we save the instance ID
# for this instance.
print "setP3DFilename(%s, %s, %s)" % (p3dFilename, tokens, instanceId)
self.instanceId = instanceId
tokenDict = dict(tokens)