mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
fix up X11 threading issues
This commit is contained in:
parent
429d3306a1
commit
a86a95b4ec
@ -140,7 +140,8 @@ wait(double timeout) {
|
|||||||
ts.tv_nsec += (int)((timeout - seconds) * 1000000.0);
|
ts.tv_nsec += (int)((timeout - seconds) * 1000000.0);
|
||||||
|
|
||||||
int result = pthread_cond_timedwait(&_cvar, &_lock, &ts);
|
int result = pthread_cond_timedwait(&_cvar, &_lock, &ts);
|
||||||
if (result != 0 && result != ETIMEDOUT && errno != ETIMEDOUT) {
|
if (result != 0 && result != ETIMEDOUT) {
|
||||||
|
errno = result;
|
||||||
perror("pthread_cond_timedwait");
|
perror("pthread_cond_timedwait");
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
|
@ -157,6 +157,7 @@ shutdown() {
|
|||||||
result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
result = waitpid(_p3dpython_pid, &status, WNOHANG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nout << "Python process has successfully stopped.\n";
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
nout << " exited normally, status = "
|
nout << " exited normally, status = "
|
||||||
<< WEXITSTATUS(status) << "\n";
|
<< WEXITSTATUS(status) << "\n";
|
||||||
|
@ -60,6 +60,7 @@ P3DWinSplashWindow::
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DWinSplashWindow::set_image_filename
|
// Function: P3DWinSplashWindow::set_image_filename
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
|
// Description: Specifies the name of a JPEG image file that is
|
||||||
// displayed in the center of the splash window. If
|
// displayed in the center of the splash window. If
|
||||||
// image_filename_temp is true, the file is immediately
|
// image_filename_temp is true, the file is immediately
|
||||||
// deleted after it has been read.
|
// deleted after it has been read.
|
||||||
|
@ -16,7 +16,12 @@
|
|||||||
|
|
||||||
#ifdef HAVE_X11
|
#ifdef HAVE_X11
|
||||||
|
|
||||||
|
#include "get_tinyxml.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
// Sleeps for a short time.
|
// Sleeps for a short time.
|
||||||
#define MILLISLEEP() \
|
#define MILLISLEEP() \
|
||||||
@ -36,7 +41,10 @@ P3DX11SplashWindow::
|
|||||||
P3DX11SplashWindow(P3DInstance *inst) :
|
P3DX11SplashWindow(P3DInstance *inst) :
|
||||||
P3DSplashWindow(inst)
|
P3DSplashWindow(inst)
|
||||||
{
|
{
|
||||||
INIT_THREAD(_thread);
|
// Init for parent process
|
||||||
|
_subprocess_pid = -1;
|
||||||
|
|
||||||
|
// Init for subprocess
|
||||||
_display = None;
|
_display = None;
|
||||||
_window = None;
|
_window = None;
|
||||||
_image = NULL;
|
_image = NULL;
|
||||||
@ -49,16 +57,13 @@ P3DX11SplashWindow(P3DInstance *inst) :
|
|||||||
_resized_width = 0;
|
_resized_width = 0;
|
||||||
_resized_height = 0;
|
_resized_height = 0;
|
||||||
_graphics_context = None;
|
_graphics_context = None;
|
||||||
_thread_running = false;
|
|
||||||
_got_install = false;
|
_got_install = false;
|
||||||
_image_filename_changed = false;
|
_image_filename_changed = false;
|
||||||
_image_filename_temp = false;
|
_image_filename_temp = false;
|
||||||
_install_label_changed = false;
|
_install_label_changed = false;
|
||||||
_install_progress = 0.0;
|
_install_progress = 0.0;
|
||||||
|
|
||||||
INIT_LOCK(_install_lock);
|
start_subprocess();
|
||||||
|
|
||||||
start_thread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -68,14 +73,13 @@ P3DX11SplashWindow(P3DInstance *inst) :
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
P3DX11SplashWindow::
|
P3DX11SplashWindow::
|
||||||
~P3DX11SplashWindow() {
|
~P3DX11SplashWindow() {
|
||||||
stop_thread();
|
stop_subprocess();
|
||||||
|
|
||||||
DESTROY_LOCK(_install_lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DX11SplashWindow::set_image_filename
|
// Function: P3DX11SplashWindow::set_image_filename
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
|
// Description: Specifies the name of a JPEG image file that is
|
||||||
// displayed in the center of the splash window. If
|
// displayed in the center of the splash window. If
|
||||||
// image_filename_temp is true, the file is immediately
|
// image_filename_temp is true, the file is immediately
|
||||||
// deleted after it has been read.
|
// deleted after it has been read.
|
||||||
@ -83,21 +87,21 @@ P3DX11SplashWindow::
|
|||||||
void P3DX11SplashWindow::
|
void P3DX11SplashWindow::
|
||||||
set_image_filename(const string &image_filename,
|
set_image_filename(const string &image_filename,
|
||||||
bool image_filename_temp) {
|
bool image_filename_temp) {
|
||||||
ACQUIRE_LOCK(_install_lock);
|
if (_subprocess_pid == -1) {
|
||||||
if (_image_filename != image_filename) {
|
return;
|
||||||
_image_filename = image_filename;
|
|
||||||
_image_filename_temp = image_filename_temp;
|
|
||||||
_image_filename_changed = true;
|
|
||||||
}
|
}
|
||||||
RELEASE_LOCK(_install_lock);
|
|
||||||
|
|
||||||
MILLISLEEP();
|
TiXmlDocument doc;
|
||||||
|
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
|
||||||
|
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||||
|
xcommand->SetAttribute("cmd", "set_image_filename");
|
||||||
|
xcommand->SetAttribute("image_filename", image_filename);
|
||||||
|
xcommand->SetAttribute("image_filename_temp", (int)image_filename_temp);
|
||||||
|
doc.LinkEndChild(decl);
|
||||||
|
doc.LinkEndChild(xcommand);
|
||||||
|
write_xml(_pipe_write, &doc, nout);
|
||||||
|
|
||||||
if (!_thread_running && _thread_continue) {
|
check_stopped();
|
||||||
// The user must have closed the window. Let's shut down the
|
|
||||||
// instance, too.
|
|
||||||
_inst->request_stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -108,20 +112,20 @@ set_image_filename(const string &image_filename,
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DX11SplashWindow::
|
void P3DX11SplashWindow::
|
||||||
set_install_label(const string &install_label) {
|
set_install_label(const string &install_label) {
|
||||||
ACQUIRE_LOCK(_install_lock);
|
if (_subprocess_pid == -1) {
|
||||||
if (_install_label != install_label) {
|
return;
|
||||||
_install_label = install_label;
|
|
||||||
_install_label_changed = true;
|
|
||||||
}
|
}
|
||||||
RELEASE_LOCK(_install_lock);
|
|
||||||
|
|
||||||
MILLISLEEP();
|
TiXmlDocument doc;
|
||||||
|
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
|
||||||
|
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||||
|
xcommand->SetAttribute("cmd", "set_install_label");
|
||||||
|
xcommand->SetAttribute("install_label", install_label);
|
||||||
|
doc.LinkEndChild(decl);
|
||||||
|
doc.LinkEndChild(xcommand);
|
||||||
|
write_xml(_pipe_write, &doc, nout);
|
||||||
|
|
||||||
if (!_thread_running && _thread_continue) {
|
check_stopped();
|
||||||
// The user must have closed the window. Let's shut down the
|
|
||||||
// instance, too.
|
|
||||||
_inst->request_stop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -131,56 +135,194 @@ set_install_label(const string &install_label) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DX11SplashWindow::
|
void P3DX11SplashWindow::
|
||||||
set_install_progress(double install_progress) {
|
set_install_progress(double install_progress) {
|
||||||
_got_install = true;
|
if (_subprocess_pid == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ACQUIRE_LOCK(_install_lock);
|
TiXmlDocument doc;
|
||||||
_install_progress = install_progress;
|
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
|
||||||
RELEASE_LOCK(_install_lock);
|
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||||
|
xcommand->SetAttribute("cmd", "set_install_progress");
|
||||||
|
xcommand->SetDoubleAttribute("install_progress", install_progress);
|
||||||
|
doc.LinkEndChild(decl);
|
||||||
|
doc.LinkEndChild(xcommand);
|
||||||
|
write_xml(_pipe_write, &doc, nout);
|
||||||
|
|
||||||
MILLISLEEP();
|
check_stopped();
|
||||||
|
}
|
||||||
|
|
||||||
if (!_thread_running && _thread_continue) {
|
////////////////////////////////////////////////////////////////////
|
||||||
// The user must have closed the window. Let's shut down the
|
// Function: P3DX11SplashWindow::start_subprocess
|
||||||
// instance, too.
|
// Access: Private
|
||||||
_inst->request_stop();
|
// Description: Spawns the subprocess that runs the window. We have
|
||||||
|
// to use a subprocess instead of just a sub-thread, to
|
||||||
|
// protect X11 against mutual access.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DX11SplashWindow::
|
||||||
|
start_subprocess() {
|
||||||
|
assert(_subprocess_pid == -1);
|
||||||
|
|
||||||
|
// Create a directional pipe to send messages to the sub-process.
|
||||||
|
// (We don't need a receive pipe.)
|
||||||
|
int to_fd[2];
|
||||||
|
if (pipe(to_fd) < 0) {
|
||||||
|
perror("failed to create pipe");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fork and exec.
|
||||||
|
pid_t child = fork();
|
||||||
|
if (child < 0) {
|
||||||
|
close(to_fd[0]);
|
||||||
|
close(to_fd[1]);
|
||||||
|
perror("fork");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child == 0) {
|
||||||
|
// Here we are in the child process.
|
||||||
|
|
||||||
|
// Open the read end of the pipe, and close the write end.
|
||||||
|
_pipe_read.open_read(to_fd[0]);
|
||||||
|
close(to_fd[1]);
|
||||||
|
|
||||||
|
subprocess_run();
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the parent process.
|
||||||
|
_subprocess_pid = child;
|
||||||
|
_pipe_write.open_write(to_fd[1]);
|
||||||
|
close(to_fd[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DX11SplashWindow::stop_subprocess
|
||||||
|
// Access: Private
|
||||||
|
// Description: Terminates the subprocess.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DX11SplashWindow::
|
||||||
|
stop_subprocess() {
|
||||||
|
if (_subprocess_pid == -1) {
|
||||||
|
// Already stopped.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ask the subprocess to stop.
|
||||||
|
TiXmlDocument doc;
|
||||||
|
TiXmlDeclaration *decl = new TiXmlDeclaration("1.0", "utf-8", "");
|
||||||
|
TiXmlElement *xcommand = new TiXmlElement("command");
|
||||||
|
xcommand->SetAttribute("cmd", "exit");
|
||||||
|
doc.LinkEndChild(decl);
|
||||||
|
doc.LinkEndChild(xcommand);
|
||||||
|
write_xml(_pipe_write, &doc, nout);
|
||||||
|
|
||||||
|
// Also close the pipe, to help underscore the point.
|
||||||
|
_pipe_write.close();
|
||||||
|
|
||||||
|
static const int max_wait_ms = 2000;
|
||||||
|
|
||||||
|
// Wait for a certain amount of time for the process to stop by
|
||||||
|
// itself.
|
||||||
|
struct timeval start;
|
||||||
|
gettimeofday(&start, NULL);
|
||||||
|
int start_ms = start.tv_sec * 1000 + start.tv_usec / 1000;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
pid_t result = waitpid(_subprocess_pid, &status, WNOHANG);
|
||||||
|
while (result != _subprocess_pid) {
|
||||||
|
if (result == -1) {
|
||||||
|
perror("waitpid");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct timeval now;
|
||||||
|
gettimeofday(&now, NULL);
|
||||||
|
int now_ms = now.tv_sec * 1000 + now.tv_usec / 1000;
|
||||||
|
int elapsed = now_ms - start_ms;
|
||||||
|
|
||||||
|
if (elapsed > max_wait_ms) {
|
||||||
|
// Tired of waiting. Kill the process.
|
||||||
|
nout << "Force-killing splash window process, pid " << _subprocess_pid
|
||||||
|
<< "\n" << flush;
|
||||||
|
kill(_subprocess_pid, SIGKILL);
|
||||||
|
start_ms = now_ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Yield the timeslice and wait some more.
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 1;
|
||||||
|
select(0, NULL, NULL, NULL, &tv);
|
||||||
|
result = waitpid(_subprocess_pid, &status, WNOHANG);
|
||||||
|
}
|
||||||
|
|
||||||
|
nout << "Splash window process has successfully stopped.\n";
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
nout << " exited normally, status = "
|
||||||
|
<< WEXITSTATUS(status) << "\n";
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
nout << " signalled by " << WTERMSIG(status) << ", core = "
|
||||||
|
<< WCOREDUMP(status) << "\n";
|
||||||
|
} else if (WIFSTOPPED(status)) {
|
||||||
|
nout << " stopped by " << WSTOPSIG(status) << "\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DX11SplashWindow::start_thread
|
// Function: P3DX11SplashWindow::check_stopped
|
||||||
// Access: Private
|
// Access: Private
|
||||||
// Description: Spawns the sub-thread.
|
// Description: Shuts down the instance if the window is closed
|
||||||
|
// prematurely (for instance, due to user action).
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DX11SplashWindow::
|
void P3DX11SplashWindow::
|
||||||
start_thread() {
|
check_stopped() {
|
||||||
_thread_continue = true;
|
if (_subprocess_pid == -1) {
|
||||||
INIT_THREAD(_thread);
|
// Already stopped.
|
||||||
SPAWN_THREAD(_thread, thread_run, this);
|
return;
|
||||||
if (_thread != 0) {
|
|
||||||
_thread_running = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int status;
|
||||||
|
int result = waitpid(_subprocess_pid, &status, WNOHANG);
|
||||||
|
if (result == 0) {
|
||||||
|
// Process is still running.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == -1) {
|
||||||
|
// Error in waitpid.
|
||||||
|
perror("waitpid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process has stopped.
|
||||||
|
assert(result == _subprocess_pid);
|
||||||
|
|
||||||
|
nout << "Splash window process has stopped unexpectedly.\n";
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
nout << " exited normally, status = "
|
||||||
|
<< WEXITSTATUS(status) << "\n";
|
||||||
|
} else if (WIFSIGNALED(status)) {
|
||||||
|
nout << " signalled by " << WTERMSIG(status) << ", core = "
|
||||||
|
<< WCOREDUMP(status) << "\n";
|
||||||
|
} else if (WIFSTOPPED(status)) {
|
||||||
|
nout << " stopped by " << WSTOPSIG(status) << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
_subprocess_pid = -1;
|
||||||
|
_inst->request_stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: P3DX11SplashWindow::stop_thread
|
// Function: P3DX11SplashWindow::subprocess_run
|
||||||
// Access: Private
|
// Access: Private
|
||||||
// Description: Terminates and joins the sub-thread.
|
// Description: The subprocess's main run method.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void P3DX11SplashWindow::
|
void P3DX11SplashWindow::
|
||||||
stop_thread() {
|
subprocess_run() {
|
||||||
_thread_continue = false;
|
// Since we're now isolated in a subprocess, we can safely make all
|
||||||
MILLISLEEP();
|
// the X calls we like, and run independently of the browser
|
||||||
|
// process.
|
||||||
|
|
||||||
JOIN_THREAD(_thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
// Function: P3DX11SplashWindow::thread_run
|
|
||||||
// Access: Private
|
|
||||||
// Description: The sub-thread's main run method.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
|
||||||
void P3DX11SplashWindow::
|
|
||||||
thread_run() {
|
|
||||||
make_window();
|
make_window();
|
||||||
setup_gc();
|
setup_gc();
|
||||||
|
|
||||||
@ -190,8 +332,10 @@ thread_run() {
|
|||||||
bool override = true, have_event = false;
|
bool override = true, have_event = false;
|
||||||
string prev_label;
|
string prev_label;
|
||||||
double prev_progress;
|
double prev_progress;
|
||||||
|
|
||||||
while (_thread_continue) {
|
_subprocess_continue = true;
|
||||||
|
while (_subprocess_continue) {
|
||||||
|
// First, scan for X events.
|
||||||
have_event = XCheckTypedWindowEvent(_display, _window, Expose, &event)
|
have_event = XCheckTypedWindowEvent(_display, _window, Expose, &event)
|
||||||
|| XCheckTypedWindowEvent(_display, _window, GraphicsExpose, &event);
|
|| XCheckTypedWindowEvent(_display, _window, GraphicsExpose, &event);
|
||||||
|
|
||||||
@ -205,7 +349,6 @@ thread_run() {
|
|||||||
_height = event.xconfigure.height;
|
_height = event.xconfigure.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
ACQUIRE_LOCK(_install_lock);
|
|
||||||
double install_progress = _install_progress;
|
double install_progress = _install_progress;
|
||||||
string install_label = _install_label;
|
string install_label = _install_label;
|
||||||
|
|
||||||
@ -214,8 +357,6 @@ thread_run() {
|
|||||||
}
|
}
|
||||||
_image_filename_changed = false;
|
_image_filename_changed = false;
|
||||||
|
|
||||||
RELEASE_LOCK(_install_lock);
|
|
||||||
|
|
||||||
if (override || have_event || install_label != prev_label) {
|
if (override || have_event || install_label != prev_label) {
|
||||||
redraw(install_label);
|
redraw(install_label);
|
||||||
override = false;
|
override = false;
|
||||||
@ -228,11 +369,82 @@ thread_run() {
|
|||||||
}
|
}
|
||||||
prev_label = install_label;
|
prev_label = install_label;
|
||||||
prev_progress = install_progress;
|
prev_progress = install_progress;
|
||||||
MILLISLEEP();
|
|
||||||
|
// Now check for input from the parent.
|
||||||
|
int read_fd = _pipe_read.get_handle();
|
||||||
|
fd_set fds;
|
||||||
|
FD_ZERO(&fds);
|
||||||
|
FD_SET(read_fd, &fds);
|
||||||
|
|
||||||
|
struct timeval tv;
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = 1; // Sleep a bit to yield the timeslice if there's
|
||||||
|
// nothing new.
|
||||||
|
|
||||||
|
int result = select(read_fd + 1, &fds, NULL, NULL, &tv);
|
||||||
|
if (result == 1) {
|
||||||
|
// There is some noise on the pipe, so read it.
|
||||||
|
receive_command();
|
||||||
|
} else if (result == -1) {
|
||||||
|
// Error in select.
|
||||||
|
perror("select");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close_window();
|
close_window();
|
||||||
_thread_running = false;
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: P3DX11SplashWindow::receive_command
|
||||||
|
// Access: Private
|
||||||
|
// Description: Receives a command from the parent.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void P3DX11SplashWindow::
|
||||||
|
receive_command() {
|
||||||
|
TiXmlDocument *doc = read_xml(_pipe_read, cerr);
|
||||||
|
if (doc == NULL) {
|
||||||
|
// Pipe closed or something.
|
||||||
|
_subprocess_continue = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TiXmlElement *xcommand = doc->FirstChildElement("command");
|
||||||
|
if (xcommand != NULL) {
|
||||||
|
const char *cmd = xcommand->Attribute("cmd");
|
||||||
|
if (cmd != NULL) {
|
||||||
|
if (strcmp(cmd, "exit") == 0) {
|
||||||
|
_subprocess_continue = false;
|
||||||
|
|
||||||
|
} else if (strcmp(cmd, "set_image_filename") == 0) {
|
||||||
|
const char *str = xcommand->Attribute("image_filename");
|
||||||
|
int image_filename_temp = 0;
|
||||||
|
xcommand->Attribute("image_filename_temp", &image_filename_temp);
|
||||||
|
if (str != NULL) {
|
||||||
|
if (_image_filename != string(str)) {
|
||||||
|
_image_filename = str;
|
||||||
|
_image_filename_temp = image_filename_temp;
|
||||||
|
_image_filename_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (strcmp(cmd, "set_install_label") == 0) {
|
||||||
|
const char *str = xcommand->Attribute("install_label");
|
||||||
|
if (str != NULL) {
|
||||||
|
if (_install_label != string(str)) {
|
||||||
|
_install_label = str;
|
||||||
|
_install_label_changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (strcmp(cmd, "set_install_progress") == 0) {
|
||||||
|
double install_progress = 0.0;
|
||||||
|
xcommand->Attribute("install_progress", &install_progress);
|
||||||
|
|
||||||
|
_got_install = true;
|
||||||
|
_install_progress = install_progress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -348,11 +560,9 @@ setup_gc() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ACQUIRE_LOCK(_install_lock);
|
|
||||||
string install_label = _install_label;
|
string install_label = _install_label;
|
||||||
double install_progress = _install_progress;
|
double install_progress = _install_progress;
|
||||||
_install_label_changed = false;
|
_install_label_changed = false;
|
||||||
RELEASE_LOCK(_install_lock);
|
|
||||||
|
|
||||||
XFontStruct* fs = XLoadQueryFont(_display, "6x13");
|
XFontStruct* fs = XLoadQueryFont(_display, "6x13");
|
||||||
XGCValues gcval;
|
XGCValues gcval;
|
||||||
@ -455,9 +665,6 @@ update_image_filename(const string &image_filename, bool image_filename_temp) {
|
|||||||
// Now load the image.
|
// Now load the image.
|
||||||
_image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen),
|
_image = XCreateImage(_display, CopyFromParent, DefaultDepth(_display, _screen),
|
||||||
ZPixmap, 0, (char *) new_data, _image_width, _image_height, 32, 0);
|
ZPixmap, 0, (char *) new_data, _image_width, _image_height, 32, 0);
|
||||||
|
|
||||||
nout << "Loaded splash file image: " << image_filename << "\n"
|
|
||||||
<< flush;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // HAVE_X11
|
#endif // HAVE_X11
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#ifdef HAVE_X11
|
#ifdef HAVE_X11
|
||||||
|
|
||||||
#include "p3dSplashWindow.h"
|
#include "p3dSplashWindow.h"
|
||||||
#include "p3d_lock.h"
|
#include "handleStream.h"
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
#include <X11/Xutil.h>
|
#include <X11/Xutil.h>
|
||||||
@ -41,13 +41,19 @@ public:
|
|||||||
virtual void set_install_progress(double install_progress);
|
virtual void set_install_progress(double install_progress);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void start_thread();
|
void start_subprocess();
|
||||||
void stop_thread();
|
void stop_subprocess();
|
||||||
|
void check_stopped();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// These methods run only within the window thread.
|
// Data members that are stored in the parent process.
|
||||||
void thread_run();
|
pid_t _subprocess_pid;
|
||||||
THREAD_CALLBACK_DECLARATION(P3DX11SplashWindow, thread_run);
|
HandleStream _pipe_write;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// These methods run only within the subprocess.
|
||||||
|
void subprocess_run();
|
||||||
|
void receive_command();
|
||||||
|
|
||||||
void redraw(string label);
|
void redraw(string label);
|
||||||
void make_window();
|
void make_window();
|
||||||
@ -57,6 +63,9 @@ private:
|
|||||||
void close_window();
|
void close_window();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Data members that are stored in the subprocess.
|
||||||
|
bool _subprocess_continue;
|
||||||
|
HandleStream _pipe_read;
|
||||||
int _width, _height;
|
int _width, _height;
|
||||||
|
|
||||||
bool _own_display;
|
bool _own_display;
|
||||||
@ -67,12 +76,9 @@ private:
|
|||||||
bool _install_label_changed;
|
bool _install_label_changed;
|
||||||
string _install_label;
|
string _install_label;
|
||||||
double _install_progress;
|
double _install_progress;
|
||||||
LOCK _install_lock;
|
|
||||||
|
|
||||||
string _label_text;
|
string _label_text;
|
||||||
|
|
||||||
bool _thread_continue;
|
|
||||||
bool _thread_running;
|
|
||||||
Display *_display;
|
Display *_display;
|
||||||
int _screen;
|
int _screen;
|
||||||
GC _graphics_context;
|
GC _graphics_context;
|
||||||
@ -81,7 +87,6 @@ private:
|
|||||||
int _image_width, _image_height;
|
int _image_width, _image_height;
|
||||||
int _resized_width, _resized_height;
|
int _resized_width, _resized_height;
|
||||||
|
|
||||||
THREAD _thread;
|
|
||||||
Window _window;
|
Window _window;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ public:
|
|||||||
// SPAWN_THREAD call. The wrapper will in turn call the method
|
// SPAWN_THREAD call. The wrapper will in turn call the method
|
||||||
// function you provide.
|
// function you provide.
|
||||||
#define THREAD_CALLBACK_DECLARATION(class, callback_function) \
|
#define THREAD_CALLBACK_DECLARATION(class, callback_function) \
|
||||||
static DWORD WINAPI class:: \
|
static DWORD WINAPI \
|
||||||
win_ ## callback_function(LPVOID data) { \
|
win_ ## callback_function(LPVOID data) { \
|
||||||
((class *)data)->callback_function(); \
|
((class *)data)->callback_function(); \
|
||||||
return 0; \
|
return 0; \
|
||||||
|
@ -469,12 +469,12 @@ handle_request(P3D_request *request) {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void PPInstance::
|
void PPInstance::
|
||||||
generic_browser_call() {
|
generic_browser_call() {
|
||||||
#ifndef HAS_PLUGIN_THREAD_ASYNC_CALL
|
//#ifndef HAS_PLUGIN_THREAD_ASYNC_CALL
|
||||||
// If we can't ask Mozilla to call us back using
|
// If we can't ask Mozilla to call us back using
|
||||||
// NPN_PluginThreadAsyncCall(), then we'll do it explicitly now,
|
// NPN_PluginThreadAsyncCall(), then we'll do it explicitly now,
|
||||||
// since we know we're in the main thread here.
|
// since we know we're in the main thread here.
|
||||||
handle_request_loop();
|
handle_request_loop();
|
||||||
#endif
|
//#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -1099,13 +1099,12 @@ handle_request_loop() {
|
|||||||
p3d_inst = P3D_check_request(false);
|
p3d_inst = P3D_check_request(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also check to see if we have any file datas that need streaming.
|
// Also check to see if we have any file_data objects that have
|
||||||
// Only stream up to the front four in the queue, so we don't
|
// finished and may be deleted.
|
||||||
// overwhelm the browser all at once.
|
size_t num_file_datas = _file_datas.size();
|
||||||
size_t num_file_datas = min(_file_datas.size(), (size_t)4);
|
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
while (i < num_file_datas) {
|
while (i < num_file_datas) {
|
||||||
if (_file_datas[i]->feed_data()) {
|
if (!_file_datas[i]->is_done()) {
|
||||||
// This one keeps going.
|
// This one keeps going.
|
||||||
++i;
|
++i;
|
||||||
} else {
|
} else {
|
||||||
@ -1184,6 +1183,13 @@ StreamingFileData(PPDownloadRequest *req, const string &filename,
|
|||||||
|
|
||||||
// Then return to the beginning to read the data.
|
// Then return to the beginning to read the data.
|
||||||
_file.seekg(0, ios::beg);
|
_file.seekg(0, ios::beg);
|
||||||
|
|
||||||
|
// Now start up the thread.
|
||||||
|
_thread_done = false;
|
||||||
|
_thread_continue = true;
|
||||||
|
INIT_THREAD(_thread);
|
||||||
|
|
||||||
|
SPAWN_THREAD(_thread, thread_run, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -1193,23 +1199,38 @@ StreamingFileData(PPDownloadRequest *req, const string &filename,
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PPInstance::StreamingFileData::
|
PPInstance::StreamingFileData::
|
||||||
~StreamingFileData() {
|
~StreamingFileData() {
|
||||||
|
// Time to stop.
|
||||||
|
_thread_continue = false;
|
||||||
|
|
||||||
|
JOIN_THREAD(_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: PPInstance::StreamingFileData::feed_data
|
// Function: PPInstance::StreamingFileData::is_done
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: Feeds the next batch of the file to the instance.
|
// Description: Returns true if the file has been fully read and this
|
||||||
// Returns true if there is more to come and this method
|
// object is ready to be deleted, or false if there is
|
||||||
// should be called again, false if we're done.
|
// more work to do.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool PPInstance::StreamingFileData::
|
bool PPInstance::StreamingFileData::
|
||||||
feed_data() {
|
is_done() const {
|
||||||
|
return _thread_done;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: PPInstance::StreamingFileData::thread_run
|
||||||
|
// Access: Private
|
||||||
|
// Description: The main function of the file thread. This reads the
|
||||||
|
// file contents and feeds it to the core API.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void PPInstance::StreamingFileData::
|
||||||
|
thread_run() {
|
||||||
static const size_t buffer_size = 81920;
|
static const size_t buffer_size = 81920;
|
||||||
char buffer[buffer_size];
|
char buffer[buffer_size];
|
||||||
|
|
||||||
_file.read(buffer, buffer_size);
|
_file.read(buffer, buffer_size);
|
||||||
size_t count = _file.gcount();
|
size_t count = _file.gcount();
|
||||||
if (count != 0) {
|
while (count != 0) {
|
||||||
_total_count += count;
|
_total_count += count;
|
||||||
bool download_ok = P3D_instance_feed_url_stream
|
bool download_ok = P3D_instance_feed_url_stream
|
||||||
(_p3d_inst, _user_id, P3D_RC_in_progress,
|
(_p3d_inst, _user_id, P3D_RC_in_progress,
|
||||||
@ -1217,11 +1238,20 @@ feed_data() {
|
|||||||
|
|
||||||
if (!download_ok) {
|
if (!download_ok) {
|
||||||
// Never mind.
|
// Never mind.
|
||||||
return false;
|
_thread_done = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// So far, so good.
|
if (!_thread_continue) {
|
||||||
return true;
|
// Interrupted by the main thread. Presumably we're being shut
|
||||||
|
// down.
|
||||||
|
_thread_done = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// So far, so good. Read some more.
|
||||||
|
_file.read(buffer, buffer_size);
|
||||||
|
count = _file.gcount();
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of file.
|
// End of file.
|
||||||
@ -1234,6 +1264,6 @@ feed_data() {
|
|||||||
P3D_instance_feed_url_stream
|
P3D_instance_feed_url_stream
|
||||||
(_p3d_inst, _user_id, result, 0, _total_count, NULL, 0);
|
(_p3d_inst, _user_id, result, 0, _total_count, NULL, 0);
|
||||||
|
|
||||||
// We're done.
|
// All done.
|
||||||
return false;
|
_thread_done = true;
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
#include "nppanda3d_common.h"
|
#include "nppanda3d_common.h"
|
||||||
#include "fileSpec.h"
|
#include "fileSpec.h"
|
||||||
#include "get_tinyxml.h"
|
#include "get_tinyxml.h"
|
||||||
|
#include "p3d_lock.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -107,15 +108,24 @@ private:
|
|||||||
P3D_instance *p3d_inst);
|
P3D_instance *p3d_inst);
|
||||||
~StreamingFileData();
|
~StreamingFileData();
|
||||||
|
|
||||||
bool feed_data();
|
bool is_done() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void thread_run();
|
||||||
|
THREAD_CALLBACK_DECLARATION(PPInstance::StreamingFileData, thread_run);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _thread_done;
|
||||||
|
bool _thread_continue;
|
||||||
|
|
||||||
P3D_instance *_p3d_inst;
|
P3D_instance *_p3d_inst;
|
||||||
int _user_id;
|
int _user_id;
|
||||||
string _filename;
|
string _filename;
|
||||||
ifstream _file;
|
ifstream _file;
|
||||||
size_t _file_size;
|
size_t _file_size;
|
||||||
size_t _total_count;
|
size_t _total_count;
|
||||||
|
|
||||||
|
THREAD _thread;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef vector<StreamingFileData *> FileDatas;
|
typedef vector<StreamingFileData *> FileDatas;
|
||||||
|
@ -286,6 +286,7 @@ NPP_WriteReady(NPP instance, NPStream *stream) {
|
|||||||
int32
|
int32
|
||||||
NPP_Write(NPP instance, NPStream *stream, int32 offset,
|
NPP_Write(NPP instance, NPStream *stream, int32 offset,
|
||||||
int32 len, void *buffer) {
|
int32 len, void *buffer) {
|
||||||
|
// logfile << "Write " << stream->url << ", " << len << "\n" << flush;
|
||||||
PPInstance::generic_browser_call();
|
PPInstance::generic_browser_call();
|
||||||
PPInstance *inst = (PPInstance *)(instance->pdata);
|
PPInstance *inst = (PPInstance *)(instance->pdata);
|
||||||
assert(inst != NULL);
|
assert(inst != NULL);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user