fix windows crash; fix splash window drawing

This commit is contained in:
David Rose 2009-07-07 22:33:07 +00:00
parent 54732da355
commit bc0d953ab5
7 changed files with 173 additions and 72 deletions

View File

@ -17,6 +17,7 @@
#include "p3dSession.h"
#include "p3dPackage.h"
#include "p3d_plugin_config.h"
#include "p3dWinSplashWindow.h"
#include "find_root_dir.h"
#include "mkdir_complete.h"
@ -70,6 +71,10 @@ P3DInstanceManager::
assert(_instances.empty());
assert(_sessions.empty());
#ifdef _WIN32
P3DWinSplashWindow::unregister_window_class();
#endif
}
////////////////////////////////////////////////////////////////////

View File

@ -209,6 +209,7 @@ run_python() {
////////////////////////////////////////////////////////////////////
void P3DPythonRun::
handle_command(TiXmlDocument *doc) {
nout << "received: " << *doc << "\n" << flush;
TiXmlElement *xcommand = doc->FirstChildElement("command");
if (xcommand != NULL) {
bool needs_response = false;
@ -267,6 +268,7 @@ handle_command(TiXmlDocument *doc) {
xresponse->SetAttribute("response_id", want_response_id);
doc.LinkEndChild(decl);
doc.LinkEndChild(xresponse);
nout << "sent: " << doc << "\n" << flush;
_pipe_write << doc << flush;
}
}
@ -413,6 +415,7 @@ handle_pyobj_command(TiXmlElement *xcommand, bool needs_response,
}
if (needs_response) {
nout << "sent: " << doc << "\n" << flush;
_pipe_write << doc << flush;
}
}
@ -488,6 +491,7 @@ wait_script_response(int response_id) {
// This is the response we were waiting for.
_commands.erase(ci);
RELEASE_LOCK(_commands_lock);
nout << "received: " << *doc << "\n" << flush;
return doc;
}
}
@ -585,6 +589,7 @@ py_request_func(PyObject *args) {
}
xrequest->SetAttribute("message", message);
nout << "sent: " << doc << "\n" << flush;
_pipe_write << doc << flush;
} else if (strcmp(request_type, "script") == 0) {
@ -609,6 +614,7 @@ py_request_func(PyObject *args) {
TiXmlElement *xvalue = pyobj_to_xml(value);
xrequest->LinkEndChild(xvalue);
nout << "sent: " << doc << "\n" << flush;
_pipe_write << doc << flush;
} else {

View File

@ -85,6 +85,7 @@ P3DSession::
xcommand->SetAttribute("cmd", "exit");
doc.LinkEndChild(decl);
doc.LinkEndChild(xcommand);
nout << "sent: " << doc << "\n" << flush;
_pipe_write << doc << flush;
// Also close the pipe, to help underscore the point.
@ -214,6 +215,7 @@ void P3DSession::
send_command(TiXmlDocument *command) {
if (_p3dpython_running) {
// Python is running. Send the command.
nout << "sent: " << *command << "\n" << flush;
_pipe_write << *command << flush;
delete command;
} else {
@ -252,6 +254,7 @@ command_and_response(TiXmlDocument *command) {
assert(xcommand != NULL);
xcommand->SetAttribute("want_response_id", response_id);
nout << "sent: " << *command << "\n" << flush;
_pipe_write << *command << flush;
delete command;
@ -541,6 +544,7 @@ start_p3dpython() {
// may have queued up.
Commands::iterator ci;
for (ci = _commands.begin(); ci != _commands.end(); ++ci) {
nout << "sent: " << *(*ci) << "\n" << flush;
_pipe_write << *(*ci);
delete (*ci);
}

View File

@ -16,6 +16,8 @@
#ifdef _WIN32
bool P3DWinSplashWindow::_registered_window_class = false;
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::Constructor
// Access: Public
@ -132,7 +134,49 @@ set_install_progress(double install_progress) {
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::start_thraed
// Function: P3DWinSplashWindow::register_window_class
// Access: Public, Static
// Description: Registers the window class for this window, if
// needed.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
register_window_class() {
if (!_registered_window_class) {
HINSTANCE application = GetModuleHandle(NULL);
WNDCLASS wc;
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.lpfnWndProc = st_window_proc;
wc.hInstance = application;
wc.lpszClassName = "panda3d_splash";
if (!RegisterClass(&wc)) {
nout << "Could not register window class panda3d_splash\n";
}
_registered_window_class = true;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::unregister_window_class
// Access: Public, Static
// Description: Unregisters the window class for this window. It is
// necessary to do this before unloading the DLL.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
unregister_window_class() {
if (_registered_window_class) {
HINSTANCE application = GetModuleHandle(NULL);
if (!UnregisterClass("panda3d_splash", application)) {
nout << "Could not unregister window class panda3d_splash\n";
}
_registered_window_class = false;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::start_thread
// Access: Private
// Description: Spawns the sub-thread.
////////////////////////////////////////////////////////////////////
@ -146,7 +190,7 @@ start_thread() {
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::stop_thraed
// Function: P3DWinSplashWindow::stop_thread
// Access: Private
// Description: Terminates and joins the sub-thread.
////////////////////////////////////////////////////////////////////
@ -241,23 +285,8 @@ win_thread_run(LPVOID data) {
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
make_window() {
WNDCLASS wc;
register_window_class();
HINSTANCE application = GetModuleHandle(NULL);
static bool registered_class = false;
if (!registered_class) {
ZeroMemory(&wc, sizeof(WNDCLASS));
wc.lpfnWndProc = st_window_proc;
wc.hInstance = application;
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = "panda3d_splash";
if (!RegisterClass(&wc)) {
nout << "Could not register window class!\n";
}
registered_class = true;
}
int x = CW_USEDEFAULT;
int y = CW_USEDEFAULT;
@ -482,6 +511,69 @@ close_window() {
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::paint_window
// Access: Private
// Description: Paints the contents of the window into the indicated
// DC.
////////////////////////////////////////////////////////////////////
void P3DWinSplashWindow::
paint_window(HDC dc) {
RECT rect;
GetClientRect(_hwnd, &rect);
int win_width = rect.right - rect.left;
int win_height = rect.bottom - rect.top;
if (_bitmap != NULL) {
// Paint the background splash image.
HDC mem_dc = CreateCompatibleDC(dc);
SelectObject(mem_dc, _bitmap);
// Determine the relative size of bitmap and window.
int bm_width = _bitmap_width;
int bm_height = _bitmap_height;
int win_cx = win_width / 2;
int win_cy = win_height / 2;
if (bm_width <= win_width && bm_height <= win_height) {
// The bitmap fits within the window; center it.
// This is the top-left corner of the bitmap in window coordinates.
int p_x = win_cx - bm_width / 2;
int p_y = win_cy - bm_height / 2;
BitBlt(dc, p_x, p_y, bm_width, bm_height,
mem_dc, 0, 0, SRCCOPY);
// Now don't paint over this in the below FillRect().
ExcludeClipRect(dc, p_x, p_y, p_x + bm_width, p_y + bm_height);
} else {
// The bitmap is larger than the window; scale it down.
double x_scale = (double)win_width / (double)bm_width;
double y_scale = (double)win_height / (double)bm_height;
double scale = min(x_scale, y_scale);
int sc_width = (int)(bm_width * scale);
int sc_height = (int)(bm_height * scale);
int p_x = win_cx - sc_width / 2;
int p_y = win_cy - sc_height / 2;
StretchBlt(dc, p_x, p_y, sc_width, sc_height,
mem_dc, 0, 0, bm_width, bm_height, SRCCOPY);
// Now don't paint over this in the below FillRect().
ExcludeClipRect(dc, p_x, p_y, p_x + sc_width, p_y + sc_height);
}
SelectObject(mem_dc, NULL);
DeleteDC(mem_dc);
}
// Paint everything else the background color.
FillRect(dc, &rect, WHITE_BRUSH);
}
////////////////////////////////////////////////////////////////////
// Function: P3DWinSplashWindow::window_proc
// Access: Private
@ -495,59 +587,20 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
break;
case WM_SIZE:
InvalidateRect(hwnd, NULL, TRUE);
InvalidateRect(hwnd, NULL, FALSE);
break;
case WM_ERASEBKGND:
return true;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC dc = BeginPaint(hwnd, &ps);
if (_bitmap != NULL) {
// Paint the background splash image.
HDC mem_dc = CreateCompatibleDC(dc);
SelectObject(mem_dc, _bitmap);
// Determine the relative size of bitmap and window.
RECT rect;
GetClientRect(hwnd, &rect);
int win_width = rect.right - rect.left;
int win_height = rect.bottom - rect.top;
int bm_width = _bitmap_width;
int bm_height = _bitmap_height;
int win_cx = win_width / 2;
int win_cy = win_height / 2;
if (bm_width <= win_width && bm_height <= win_height) {
// The bitmap fits within the window; center it.
// This is the top-left corner of the bitmap in window coordinates.
int p_x = win_cx - bm_width / 2;
int p_y = win_cy - bm_height / 2;
BitBlt(dc, p_x, p_y, bm_width, bm_height,
mem_dc, 0, 0, SRCCOPY);
} else {
// The bitmap is larger than the window; scale it down.
double x_scale = (double)win_width / (double)bm_width;
double y_scale = (double)win_height / (double)bm_height;
double scale = min(x_scale, y_scale);
int sc_width = (int)(bm_width * scale);
int sc_height = (int)(bm_height * scale);
int p_x = win_cx - sc_width / 2;
int p_y = win_cy - sc_height / 2;
StretchBlt(dc, p_x, p_y, sc_width, sc_height,
mem_dc, 0, 0, bm_width, bm_height, SRCCOPY);
}
SelectObject(mem_dc, NULL);
DeleteDC(mem_dc);
}
paint_window(dc);
EndPaint(hwnd, &ps);
}
break;
return true;
case WM_DRAWITEM:
// Draw a text label placed within the window.

View File

@ -39,6 +39,9 @@ public:
virtual void set_install_label(const string &install_label);
virtual void set_install_progress(double install_progress);
static void register_window_class();
static void unregister_window_class();
private:
void start_thread();
void stop_thread();
@ -55,6 +58,7 @@ private:
bool image_filename_temp);
void close_window();
void paint_window(HDC dc);
LONG window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
static LONG WINAPI st_window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
@ -79,6 +83,8 @@ private:
int _bitmap_width, _bitmap_height;
HWND _progress_bar;
HWND _text_label;
static bool _registered_window_class;
};
#include "p3dWinSplashWindow.I"

View File

@ -419,6 +419,10 @@ handle_request(P3D_request *request) {
}
break;
case P3D_RT_script:
// We're allowed to ignore this.
break;
default:
// Some request types are not handled.
logfile << "Unhandled request: " << request->_request_type << "\n";
@ -762,24 +766,34 @@ void PPInstance::
send_window() {
assert(_p3d_inst != NULL);
int x = _window.x;
int y = _window.y;
P3D_window_handle parent_window;
#ifdef _WIN32
if (_window.type == NPWindowTypeWindow) {
// We have a "windowed" plugin. Parent our window to the one we
// were given. In this case, we should also reset the offset to
// (0, 0), since the window we were given is already placed in the
// right spot.
parent_window._hwnd = (HWND)(_window.window);
x = 0;
y = 0;
} else {
// Hmm, it's just a drawable; but we didn't ask for a windowless
// plugin.
// We have a "windowless" plugin. Parent our window directly to
// the browser window.
parent_window._hwnd = 0;
HWND hwnd;
if (browser->getvalue(_npp_instance, NPNVnetscapeWindow,
&hwnd) == NPERR_NO_ERROR) {
parent_window._hwnd = hwnd;
}
}
#endif
// Actually, we set up the window starting at (0, 0), instead of
// whatever Mozilla tells us, because the window handle we get is a
// specially created window that is already aligned to where we want
// our window to be.
P3D_instance_setup_window
(_p3d_inst, P3D_WT_embedded,
0, 0, _window.width, _window.height,
x, y, _window.width, _window.height,
parent_window);
}
@ -832,6 +846,13 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {
}
--recursion_protect;
switch (msg) {
case WM_ERASEBKGND:
// Eat the WM_ERASEBKGND message, so the browser's intervening
// window won't overdraw on top of our own window.
return true;
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
#endif // _WIN32

View File

@ -57,7 +57,7 @@ request_ready(P3D_instance *instance) {
PPInstance *inst = (PPInstance *)(instance->_user_data);
assert(inst != NULL);
const NPWindow *win = inst->get_window();
if (win != NULL) {
if (win != NULL && win->type == NPWindowTypeWindow) {
PostMessage((HWND)(win->window), WM_USER, 0, 0);
}
@ -161,6 +161,12 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16 mode,
instance->pdata = new PPInstance(pluginType, instance, mode,
argc, argn, argv, saved);
// To experiment with a "windowless" plugin, which really means we
// create our own window without an intervening window, try this.
// At the moment, there's a deadlock condition when we try it, but
// surely it can be solved.
// browser->setvalue(instance, NPPVpluginWindowBool, (void *)false);
return NPERR_NO_ERROR;
}
@ -307,7 +313,7 @@ NPP_Print(NPP instance, NPPrint *platformPrint) {
////////////////////////////////////////////////////////////////////
int16
NPP_HandleEvent(NPP instance, void *event) {
// logfile << "HandleEvent\n";
logfile << "HandleEvent\n" << flush;
// Here's a fine opportunity to check for new requests.
PPInstance::handle_request_loop();