From 474b738f8b93aac0694b2f98251db8eaddaeb6b2 Mon Sep 17 00:00:00 2001 From: rdb Date: Thu, 9 Jul 2009 13:55:32 +0000 Subject: [PATCH] More Linux work - the plugin now really works on Linux. --- direct/src/plugin/Sources.pp | 10 +- direct/src/plugin/p3dInstance.cxx | 5 + direct/src/plugin/p3dInstanceManager.cxx | 3 +- direct/src/plugin/p3dPythonRun.cxx | 7 + direct/src/plugin/p3dWindowParams.cxx | 3 + direct/src/plugin/p3dX11SplashWindow.cxx | 301 ++++++++++++++++++++ direct/src/plugin/p3dX11SplashWindow.h | 82 ++++++ direct/src/plugin/p3d_plugin.h | 4 + direct/src/plugin/p3d_plugin_composite1.cxx | 1 + direct/src/plugin_npapi/Sources.pp | 6 + direct/src/plugin_npapi/ppInstance.cxx | 27 +- direct/src/plugin_npapi/startup.cxx | 12 +- 12 files changed, 457 insertions(+), 4 deletions(-) create mode 100755 direct/src/plugin/p3dX11SplashWindow.cxx create mode 100755 direct/src/plugin/p3dX11SplashWindow.h diff --git a/direct/src/plugin/Sources.pp b/direct/src/plugin/Sources.pp index c381b17c23..9d49ea4343 100644 --- a/direct/src/plugin/Sources.pp +++ b/direct/src/plugin/Sources.pp @@ -3,9 +3,15 @@ #define BUILD_DIRECTORY $[and $[HAVE_P3D_PLUGIN],$[HAVE_TINYXML],$[HAVE_OPENSSL],$[HAVE_ZLIB]] #begin lib_target - #define USE_PACKAGES tinyxml openssl zlib jpeg + #define USE_PACKAGES tinyxml openssl zlib jpeg x11 #define TARGET p3d_plugin #define LIB_PREFIX + + // We need this because we don't + // include dtool_config.h. + #if $[HAVE_X11] + #define EXTRA_CDEFS HAVE_X11 + #endif #define COMBINED_SOURCES \ $[TARGET]_composite1.cxx @@ -39,6 +45,7 @@ p3dStringObject.h \ p3dUndefinedObject.h \ p3dWinSplashWindow.h p3dWinSplashWindow.I \ + p3dX11SplashWindow.h \ p3dWindowParams.h p3dWindowParams.I #define INCLUDED_SOURCES \ @@ -62,6 +69,7 @@ p3dStringObject.cxx \ p3dUndefinedObject.cxx \ p3dWinSplashWindow.cxx \ + p3dX11SplashWindow.cxx \ p3dWindowParams.cxx #define INSTALL_HEADERS \ diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 3dd339c401..af5a48f326 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -19,6 +19,7 @@ #include "p3dPackage.h" #include "p3dSplashWindow.h" #include "p3dWinSplashWindow.h" +#include "p3dX11SplashWindow.h" #include "p3dObject.h" #include "p3dUndefinedObject.h" @@ -28,8 +29,12 @@ #ifdef _WIN32 typedef P3DWinSplashWindow SplashWindowType; #else +#ifdef HAVE_X11 +typedef P3DX11SplashWindow SplashWindowType; +#else typedef P3DSplashWindow SplashWindowType; #endif +#endif int P3DInstance::_next_instance_id = 0; diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 7449255ca7..9a105b3009 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -368,8 +368,9 @@ nt_thread_run() { for (ni = instances.begin(); ni != instances.end(); ++ni) { // TODO: a race condition here when instances are deleted. P3DInstance *inst = (*ni); - P3D_request_ready_func *func = inst->get_request_ready_func(); assert(inst != NULL); + P3D_request_ready_func *func = inst->get_request_ready_func(); + assert(func != NULL); (*func)(inst); } _notify_ready.acquire(); diff --git a/direct/src/plugin/p3dPythonRun.cxx b/direct/src/plugin/p3dPythonRun.cxx index d20da6e181..f0e48acf7f 100755 --- a/direct/src/plugin/p3dPythonRun.cxx +++ b/direct/src/plugin/p3dPythonRun.cxx @@ -851,6 +851,13 @@ setup_window(P3DCInstance *inst, TiXmlElement *xwparams) { parent_window_handle = (long)hwnd; } #endif +#ifdef HAVE_X11 + // Bad! Casting to int loses precision. + int xwindow; + if (xwparams->Attribute("parent_xwindow", &xwindow)) { + parent_window_handle = (unsigned long)xwindow; + } +#endif // TODO: direct this into the particular instance. This will // require a specialized ShowBase replacement. diff --git a/direct/src/plugin/p3dWindowParams.cxx b/direct/src/plugin/p3dWindowParams.cxx index f6eea62b32..962cc71e79 100644 --- a/direct/src/plugin/p3dWindowParams.cxx +++ b/direct/src/plugin/p3dWindowParams.cxx @@ -79,6 +79,9 @@ make_xml() { xwparams->SetAttribute("win_height", _win_height); #ifdef _WIN32 xwparams->SetAttribute("parent_hwnd", (int)_parent_window._hwnd); +#endif +#ifdef HAVE_X11 + xwparams->SetAttribute("parent_xwindow", (unsigned long)_parent_window._xwindow); #endif break; diff --git a/direct/src/plugin/p3dX11SplashWindow.cxx b/direct/src/plugin/p3dX11SplashWindow.cxx new file mode 100755 index 0000000000..96ec6a5948 --- /dev/null +++ b/direct/src/plugin/p3dX11SplashWindow.cxx @@ -0,0 +1,301 @@ +// Filename: p3dX11SplashWindow.cxx +// Created by: pro-rsoft (08Jul09) +// +//////////////////////////////////////////////////////////////////// +// +// 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 "p3dX11SplashWindow.h" + +#ifdef HAVE_X11 + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +P3DX11SplashWindow:: +P3DX11SplashWindow(P3DInstance *inst) : + P3DSplashWindow(inst) +{ + INIT_THREAD(_thread); + _display = None; + _window = None; + _screen = 0; + _graphics_context = None; + _thread_running = false; + _got_install = false; + _image_filename_changed = false; + _image_filename_temp = false; + _install_label_changed = false; + _install_progress = 0.0; + + INIT_LOCK(_install_lock); + + start_thread(); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +P3DX11SplashWindow:: +~P3DX11SplashWindow() { + stop_thread(); + + DESTROY_LOCK(_install_lock); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::set_image_filename +// Access: Public, Virtual +// displayed in the center of the splash window. If +// image_filename_temp is true, the file is immediately +// deleted after it has been read. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +set_image_filename(const string &image_filename, + bool image_filename_temp) { + ACQUIRE_LOCK(_install_lock); + if (_image_filename != image_filename) { + _image_filename = image_filename; + _image_filename_temp = image_filename_temp; + _image_filename_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: P3DX11SplashWindow::set_install_label +// Access: Public, Virtual +// Description: Specifies the text that is displayed above the +// install progress bar. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +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: P3DX11SplashWindow::set_install_progress +// Access: Public, Virtual +// Description: Moves the install progress bar from 0.0 to 1.0. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +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: P3DX11SplashWindow::start_thread +// Access: Private +// Description: Spawns the sub-thread. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +start_thread() { + _thread_continue = true; + INIT_THREAD(_thread); + SPAWN_THREAD(_thread, thread_run, this); + if (_thread != 0) { + _thread_running = true; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::stop_thread +// Access: Private +// Description: Terminates and joins the sub-thread. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +stop_thread() { + _thread_continue = false; + // Post a silly message to spin the message loop. + //PostThreadMessage(_thread_id, WM_USER, 0, 0); + + JOIN_THREAD(_thread); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::thread_run +// Access: Private +// Description: The sub-thread's main run method. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +thread_run() { + make_window(); + setup_gc(); + + XEvent event; + XSelectInput(_display, _window, ExposureMask); + + bool override = true, have_event = false; + string prev_label; + + while (_thread_continue) { + have_event = XCheckTypedWindowEvent(_display, _window, Expose, &event); + + ACQUIRE_LOCK(_install_lock); + double install_progress = _install_progress; + + if (have_event || _install_label != prev_label) { + redraw(_install_label, install_progress); + override = false; + } + prev_label = _install_label; + + RELEASE_LOCK(_install_lock); + } + + close_window(); + _thread_running = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::redraw +// Access: Private +// Description: Redraws the window. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +redraw(string label, double progress) { + if (_graphics_context == NULL) return; + + XClearWindow(_display, _window); + XDrawString(_display, _window, _graphics_context, 10, 20, label.c_str(), label.size()); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::make_window +// Access: Private +// Description: Creates the window for displaying progress. Runs +// within the sub-thread. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +make_window() { + int x = 0; + int y = 0; + 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(); + } + + Window parent = 0; + _display = (Display*) _wparams.get_parent_window()._xdisplay; + if (_display == 0) { + _display = XOpenDisplay(NULL); + } + _screen = DefaultScreen(_display); + + if (_wparams.get_window_type() == P3D_WT_embedded) { + // Create an embedded window. + parent = _wparams.get_parent_window()._xwindow; + } else { + // Create a toplevel window. + parent = XRootWindow(_display, _screen); + } + + assert(_display != NULL); + assert(parent != None); + _window = XCreateSimpleWindow(_display, parent, x, y, width, height, 0, 0, -1); + XMapWindow(_display, _window); +} + + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::setup_gc +// Access: Private +// Description: Sets up the graphics context for drawing the text. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +setup_gc() { + if (_graphics_context != NULL) { + return; + } + + ACQUIRE_LOCK(_install_lock); + string install_label = _install_label; + double install_progress = _install_progress; + _install_label_changed = false; + RELEASE_LOCK(_install_lock); + + + XFontStruct* fs = XLoadQueryFont(_display, "6x13"); + XGCValues gcval; + gcval.font = fs->fid; + gcval.function = GXcopy; + gcval.plane_mask = AllPlanes; + gcval.foreground = BlackPixel(_display, _screen); + gcval.background = WhitePixel(_display, _screen); + _graphics_context = XCreateGC(_display, _window, + GCFont | GCFunction | GCPlaneMask | GCForeground | GCBackground, &gcval); +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::close_window +// Access: Private +// Description: Closes the window created above. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +close_window() { + if (_window != None) { + XDestroyWindow(_display, _window); + _window = None; + } + + if (_display != None) { + XCloseDisplay(_display); + _display = None; + } +} + +#endif // HAVE_X11 diff --git a/direct/src/plugin/p3dX11SplashWindow.h b/direct/src/plugin/p3dX11SplashWindow.h new file mode 100755 index 0000000000..5d1f496003 --- /dev/null +++ b/direct/src/plugin/p3dX11SplashWindow.h @@ -0,0 +1,82 @@ +// Filename: p3dX11SplashWindow.h +// Created by: pro-rsoft (08Jul09) +// +//////////////////////////////////////////////////////////////////// +// +// 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 P3DX11SPLASHWINDOW_H +#define P3DX11SPLASHWINDOW_H + +#include "p3d_plugin_common.h" + +#ifdef HAVE_X11 + +#include "p3dSplashWindow.h" +#include "p3d_lock.h" + +#include +#include + +//////////////////////////////////////////////////////////////////// +// Class : P3DX11SplashWindow +// Description : This is the Windows implementation of the +// initial-download window. +//////////////////////////////////////////////////////////////////// +class P3DX11SplashWindow : public P3DSplashWindow { +public: + P3DX11SplashWindow(P3DInstance *inst); + virtual ~P3DX11SplashWindow(); + + virtual void set_image_filename(const string &image_filename, + bool image_filename_temp); + 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(); + THREAD_CALLBACK_DECLARATION(P3DX11SplashWindow, thread_run); + + void redraw(string label, double progress); + void make_window(); + void setup_gc(); + void close_window(); + +private: + bool _got_install; + bool _image_filename_changed; + string _image_filename; + bool _image_filename_temp; + bool _install_label_changed; + string _install_label; + double _install_progress; + LOCK _install_lock; + + string _label_text; + + bool _thread_continue; + bool _thread_running; + Display *_display; + int _screen; + GC _graphics_context; + + THREAD _thread; + Window _window; + int _bitmap_width, _bitmap_height; +}; + +#endif // HAVE_X11 + +#endif diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index 328c8ec72f..51d0bfb32a 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/direct/src/plugin/p3d_plugin.h @@ -131,6 +131,10 @@ typedef struct { #ifdef _WIN32 HWND _hwnd; #endif +#ifdef HAVE_X11 + unsigned long _xwindow; + void *_xdisplay; +#endif #ifdef __APPLE__ void *_nswindow; #endif diff --git a/direct/src/plugin/p3d_plugin_composite1.cxx b/direct/src/plugin/p3d_plugin_composite1.cxx index 17d70813af..e52eb158f1 100644 --- a/direct/src/plugin/p3d_plugin_composite1.cxx +++ b/direct/src/plugin/p3d_plugin_composite1.cxx @@ -18,4 +18,5 @@ #include "p3dStringObject.cxx" #include "p3dUndefinedObject.cxx" #include "p3dWinSplashWindow.cxx" +#include "p3dX11SplashWindow.cxx" #include "p3dWindowParams.cxx" diff --git a/direct/src/plugin_npapi/Sources.pp b/direct/src/plugin_npapi/Sources.pp index 0f96875163..645a7a09db 100644 --- a/direct/src/plugin_npapi/Sources.pp +++ b/direct/src/plugin_npapi/Sources.pp @@ -12,6 +12,12 @@ #define LOCAL_LIBS plugin_common + // We need this because we don't + // include dtool_config.h. + #if $[HAVE_X11] + #define EXTRA_CDEFS HAVE_X11 + #endif + #define COMBINED_SOURCES \ $[TARGET]_composite1.cxx diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 1f1ffd4f22..c759bfe02d 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -923,24 +923,49 @@ send_window() { 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. +#ifdef _WIN32 parent_window._hwnd = (HWND)(_window.window); +#endif +#ifdef HAVE_X11 + // We make it an 'unsigned long' instead of 'Window' + // to avoid nppanda3d.so getting a dependency on X11. + parent_window._xwindow = (unsigned long)(_window.window); +#endif x = 0; y = 0; } else { // We have a "windowless" plugin. Parent our window directly to // the browser window. +#ifdef _WIN32 parent_window._hwnd = 0; HWND hwnd; if (browser->getvalue(_npp_instance, NPNVnetscapeWindow, &hwnd) == NPERR_NO_ERROR) { parent_window._hwnd = hwnd; } +#endif +#ifdef HAVE_X11 + parent_window._xwindow = 0; + unsigned long win; + if (browser->getvalue(_npp_instance, NPNVnetscapeWindow, + &win) == NPERR_NO_ERROR) { + parent_window._xwindow = win; + } +#endif + } + +#ifdef HAVE_X11 + // In the case of X11, grab the display as well. + parent_window._xdisplay = 0; + void* disp; + if (browser->getvalue(_npp_instance, NPNVxDisplay, + &disp) == NPERR_NO_ERROR) { + parent_window._xdisplay = disp; } #endif diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx index 425e1946f3..bfa8aa8b3e 100644 --- a/direct/src/plugin_npapi/startup.cxx +++ b/direct/src/plugin_npapi/startup.cxx @@ -66,7 +66,13 @@ request_ready(P3D_instance *instance) { // it within HandleEvent(). TODO: enable a timer to ensure we get // HandleEvent callbacks in a timely manner? Or maybe we should // enable a one-shot timer in response to this asynchronous event? -#endif + +#ifndef __APPLE__ + // On Unix, HandleEvent isn't called, so we will do what it does + // right here. Not sure if this is right. + PPInstance::handle_request_loop(); +#endif // __APPLE__ +#endif // _WIN32 } //////////////////////////////////////////////////////////////////// @@ -98,7 +104,11 @@ NP_GetValue(void*, NPPVariable variable, void* value) { case NPPVpluginDescriptionString: *(const char **)value = "Runs 3-D games and interactive applets"; break; + case NPPVpluginNeedsXEmbed: + *((PRBool *)value) = PR_FALSE; + break; default: + logfile << "Ignoring GetValue request " << variable << "\n" << flush; return NPERR_INVALID_PARAM; }