From 29a65d32a9964b34954486632badce85365117b2 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sat, 22 Aug 2009 21:26:25 +0000 Subject: [PATCH] osx toplevel splash windows --- direct/src/plugin/p3dInstance.cxx | 51 +++++-- direct/src/plugin/p3dInstance.h | 2 +- direct/src/plugin/p3dOsxSplashWindow.cxx | 182 +++++++++++++++++++---- direct/src/plugin/p3dOsxSplashWindow.h | 8 + direct/src/plugin/p3dPackage.cxx | 6 +- direct/src/plugin_npapi/ppInstance.cxx | 9 +- direct/src/plugin_standalone/Sources.pp | 2 +- direct/src/plugin_standalone/panda3d.cxx | 73 ++++++++- direct/src/plugin_standalone/panda3d.h | 5 + 9 files changed, 279 insertions(+), 59 deletions(-) diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 0bda98e824..7f6110c1b1 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -76,6 +76,7 @@ P3DInstance(P3D_request_ready_func *func, _panda3d = NULL; _splash_window = NULL; _instance_window_opened = false; + _stuff_to_download = false; INIT_LOCK(_request_lock); _requested_stop = false; @@ -179,10 +180,13 @@ P3DInstance:: //////////////////////////////////////////////////////////////////// void P3DInstance:: set_p3d_url(const string &p3d_url) { - nout << "set_p3d_url(" << p3d_url << ")\n"; // Make a temporary file to receive the instance data. assert(_temp_p3d_filename == NULL); _temp_p3d_filename = new P3DTemporaryFile(".p3d"); + _stuff_to_download = true; + + // Maybe it's time to open a splash window now. + make_splash_window(); // Mark the time we started downloading, so we'll know when to set // the install label. @@ -210,7 +214,6 @@ set_p3d_url(const string &p3d_url) { //////////////////////////////////////////////////////////////////// void P3DInstance:: set_p3d_filename(const string &p3d_filename) { - nout << "set_p3d_filename(" << p3d_filename << ")\n"; _got_fparams = true; _fparams.set_p3d_filename(p3d_filename); @@ -268,11 +271,10 @@ set_wparams(const P3DWindowParams &wparams) { if (_wparams.get_window_type() != P3D_WT_hidden) { // Update or create the splash window. - if (!_instance_window_opened) { - if (_splash_window == NULL) { - make_splash_window(); - } + if (_splash_window != NULL) { _splash_window->set_wparams(_wparams); + } else { + make_splash_window(); } #ifdef __APPLE__ @@ -281,7 +283,6 @@ set_wparams(const P3DWindowParams &wparams) { // to the browser. Set up this mechanism. int x_size = _wparams.get_win_width(); int y_size = _wparams.get_win_height(); - nout << "x_size, y_size = " << x_size << ", " << y_size << "\n"; if (x_size != 0 && y_size != 0) { if (_swbuffer == NULL || _swbuffer->get_x_size() != x_size || _swbuffer->get_y_size() != y_size) { @@ -1169,25 +1170,38 @@ handle_script_request(const string &operation, P3D_object *object, //////////////////////////////////////////////////////////////////// // Function: P3DInstance::make_splash_window // Access: Private -// Description: Creates the splash window to be displayed at startup. -// This method is called as soon as we have received -// both _fparams and _wparams. +// Description: Creates the splash window to be displayed at startup, +// if it's time. //////////////////////////////////////////////////////////////////// void P3DInstance:: make_splash_window() { - assert(_splash_window == NULL); + if (_splash_window != NULL || _instance_window_opened) { + // Already got one, or we're already showing the real instance. + return; + } + if (!_got_wparams) { + // Don't know where to put it yet. + return; + } + if (_wparams.get_window_type() == P3D_WT_toplevel && !_stuff_to_download) { + // If it's a toplevel window, then we don't want a splash window + // until we have stuff to download. + return; + } _splash_window = new SplashWindowType(this); + _splash_window->set_wparams(_wparams); _splash_window->set_install_label(_install_label); string splash_image_url = _fparams.lookup_token("splash_img"); if (!_fparams.has_token("splash_img")) { // No specific splash image is specified; get the default splash // image. - if (_panda3d != NULL) { - splash_image_url = _panda3d->get_host()->get_host_url_prefix(); - splash_image_url += "coreapi/splash.jpg"; + splash_image_url = PANDA_PACKAGE_HOST_URL; + if (!splash_image_url.empty() && splash_image_url[splash_image_url.size() - 1] != '/') { + splash_image_url += "/"; } + splash_image_url += "coreapi/splash.jpg"; } if (splash_image_url.empty()) { @@ -1236,6 +1250,13 @@ report_package_info_ready(P3DPackage *package) { << " packages, total " << _total_download_size << " bytes required.\n"; + if (_downloading_packages.size() > 0) { + _stuff_to_download = true; + + // Maybe it's time to open a splash window now. + make_splash_window(); + } + if (_splash_window != NULL) { _splash_window->set_install_progress(0.0); } @@ -1525,7 +1546,7 @@ paint_window() { // offscreen, the top left of the clipping rectangle will no longer // correspond to the top left of the original image. CGRect rect = CGContextGetClipBoundingBox(context); - cerr << "rect: " << rect.origin.x << " " << rect.origin.y + nout << "rect: " << rect.origin.x << " " << rect.origin.y << " " << rect.size.width << " " << rect.size.height << "\n"; rect.size.width = x_size; rect.size.height = y_size; diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 93a5ad0fea..ad00a8d5f6 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -162,7 +162,6 @@ private: bool _full_disk_access; bool _hidden; - // Not ref-counted: session is the parent. P3DSession *_session; #ifdef __APPLE__ @@ -182,6 +181,7 @@ private: P3DSplashWindow *_splash_window; string _install_label; bool _instance_window_opened; + bool _stuff_to_download; // Members for deciding whether and when to display the progress bar // for downloading the initial instance data. diff --git a/direct/src/plugin/p3dOsxSplashWindow.cxx b/direct/src/plugin/p3dOsxSplashWindow.cxx index d14f0797b8..60f4145f8c 100644 --- a/direct/src/plugin/p3dOsxSplashWindow.cxx +++ b/direct/src/plugin/p3dOsxSplashWindow.cxx @@ -31,6 +31,7 @@ P3DOsxSplashWindow(P3DInstance *inst) : _image_data = NULL; _install_progress = 0; _got_wparams = false; + _toplevel_window = NULL; } //////////////////////////////////////////////////////////////////// @@ -40,6 +41,13 @@ P3DOsxSplashWindow(P3DInstance *inst) : //////////////////////////////////////////////////////////////////// P3DOsxSplashWindow:: ~P3DOsxSplashWindow() { + if (_toplevel_window != NULL) { + SetWRefCon(_toplevel_window, 0); + HideWindow(_toplevel_window); + DisposeWindow(_toplevel_window); + _toplevel_window = NULL; + } + if (_image != NULL) { DisposeGWorld(_image); } @@ -61,6 +69,43 @@ void P3DOsxSplashWindow:: set_wparams(const P3DWindowParams &wparams) { P3DSplashWindow::set_wparams(wparams); _got_wparams = true; + + if (_wparams.get_window_type() == P3D_WT_toplevel || + _wparams.get_window_type() == P3D_WT_fullscreen) { + // Creating a toplevel splash window. + if (_toplevel_window == NULL) { + Rect r; + r.top = _wparams.get_win_y(); + r.left = _wparams.get_win_x(); + if (r.top == 0 && r.left == 0) { + r.top = 250; + r.left = 210; + } + + r.right = r.left + _wparams.get_win_width(); + r.bottom = r.top + _wparams.get_win_height(); + WindowAttributes attrib = + kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute; + CreateNewWindow(kDocumentWindowClass, attrib, &r, &_toplevel_window); + + EventHandlerRef application_event_ref_ref1; + EventTypeSpec list1[] = { + { kEventClassWindow, kEventWindowDrawContent }, + //{ kEventClassWindow, kEventWindowUpdate }, + }; + + EventHandlerUPP gEvtHandler = NewEventHandlerUPP(st_event_callback); + InstallWindowEventHandler(_toplevel_window, gEvtHandler, + GetEventTypeCount(list1), list1, this, &application_event_ref_ref1); + + ProcessSerialNumber psn = { 0, kCurrentProcess }; + TransformProcessType(&psn, kProcessTransformToForegroundApplication); + SetFrontProcess(&psn); + + ShowWindow(_toplevel_window); + } + } + } //////////////////////////////////////////////////////////////////// @@ -130,7 +175,7 @@ set_image_filename(const string &image_filename, return; } - _inst->request_refresh(); + refresh(); } //////////////////////////////////////////////////////////////////// @@ -142,7 +187,7 @@ set_image_filename(const string &image_filename, void P3DOsxSplashWindow:: set_install_label(const string &install_label) { _install_label = install_label; - _inst->request_refresh(); + refresh(); } //////////////////////////////////////////////////////////////////// @@ -154,7 +199,7 @@ void P3DOsxSplashWindow:: set_install_progress(double install_progress) { if ((int)(install_progress * 500.0) != (int)(_install_progress * 500.0)) { // Only request a refresh if we're changing substantially. - _inst->request_refresh(); + refresh(); } _install_progress = install_progress; } @@ -175,6 +220,25 @@ handle_event(P3D_event_data event) { return false; } +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::refresh +// Access: Private +// Description: Requests that the window will be repainted. +//////////////////////////////////////////////////////////////////// +void P3DOsxSplashWindow:: +refresh() { + if (_toplevel_window != NULL) { + int win_width = _wparams.get_win_width(); + int win_height = _wparams.get_win_height(); + + Rect r = { 0, 0, win_height, win_width }; + InvalWindowRect(_toplevel_window, &r); + + } else { + _inst->request_refresh(); + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DOsxSplashWindow::paint_window // Access: Private @@ -186,16 +250,28 @@ paint_window() { return; } - GrafPtr out_port = _wparams.get_parent_window()._port; + GrafPtr out_port = NULL; GrafPtr portSave = NULL; - Boolean portChanged = QDSwapPort(out_port, &portSave); + Boolean portChanged = false; + + if (_toplevel_window != NULL) { + /* + GetPort(&portSave); + SetPortWindowPort(_toplevel_window); + BeginUpdate(_toplevel_window); + */ + GetPort(&out_port); + + } else { + out_port = _wparams.get_parent_window()._port; + portChanged = QDSwapPort(out_port, &portSave); + } int win_width = _wparams.get_win_width(); int win_height = _wparams.get_win_height(); Rect r = { 0, 0, win_height, win_width }; ClipRect(&r); - EraseRect(&r); if (_image != NULL) { @@ -246,8 +322,8 @@ paint_window() { get_bar_placement(win_width, win_height, bar_x, bar_y, bar_width, bar_height); - int progress_width = (int)((bar_width - 2) * _install_progress); - if (progress_width > 0) { + if (_install_progress != 0.0) { + int progress_width = (int)((bar_width - 2) * _install_progress); int progress = bar_x + 1 + progress_width; Rect rbar = { bar_y, bar_x, bar_y + bar_height, bar_x + bar_width }; @@ -262,37 +338,77 @@ paint_window() { RGBColor black = { 0, 0, 0 }; RGBForeColor(&black); - } - if (!_install_label.empty()) { - // Now draw the install_label right above it. - TextFont(0); - TextFace(bold); - TextMode(srcOr); - TextSize(0); + if (!_install_label.empty()) { + // Now draw the install_label right above it. + TextFont(0); + TextFace(bold); + TextMode(srcOr); + TextSize(0); + + Point numer = { 1, 1 }; + Point denom = { 1, 1 }; + FontInfo font_info; + StdTxMeas(_install_label.size(), _install_label.data(), &numer, &denom, &font_info); + int ascent = font_info.ascent * numer.v / denom.v; + int descent = font_info.descent * numer.v / denom.v; + + int text_width = TextWidth(_install_label.data(), 0, _install_label.size()); + int text_x = (win_width - text_width) / 2; + int text_y = bar_y - descent - 8; + + Rect rtext = { text_y - ascent - 2, text_x - 2, + text_y + descent + 2, text_x + text_width + 2 }; + EraseRect(&rtext); + + MoveTo(text_x, text_y); + DrawText(_install_label.data(), 0, _install_label.size()); + } + } - Point numer = { 1, 1 }; - Point denom = { 1, 1 }; - FontInfo font_info; - StdTxMeas(_install_label.size(), _install_label.data(), &numer, &denom, &font_info); - int ascent = font_info.ascent * numer.v / denom.v; - int descent = font_info.descent * numer.v / denom.v; + if (_toplevel_window == NULL) { + if (portChanged) { + QDSwapPort(portSave, NULL); + } + } +} - int text_width = TextWidth(_install_label.data(), 0, _install_label.size()); - int text_x = (win_width - text_width) / 2; - int text_y = bar_y - descent - 8; - - Rect rtext = { text_y - ascent - 2, text_x - 2, - text_y + descent + 2, text_x + text_width + 2 }; - EraseRect(&rtext); +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::st_event_callback +// Access: Private, Static +// Description: The event callback on the toplevel window. +//////////////////////////////////////////////////////////////////// +pascal OSStatus P3DOsxSplashWindow:: +st_event_callback(EventHandlerCallRef my_handler, EventRef event, + void *user_data) { + return ((P3DOsxSplashWindow *)user_data)->event_callback(my_handler, event); +} - MoveTo(text_x, text_y); - DrawText(_install_label.data(), 0, _install_label.size()); +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::event_callback +// Access: Private +// Description: The event callback on the toplevel window. +//////////////////////////////////////////////////////////////////// +OSStatus P3DOsxSplashWindow:: +event_callback(EventHandlerCallRef my_handler, EventRef event) { + OSStatus result = eventNotHandledErr; + + WindowRef window = NULL; + UInt32 the_class = GetEventClass(event); + UInt32 kind = GetEventKind(event); + + GetEventParameter(event, kEventParamWindowRef, typeWindowRef, NULL, + sizeof(WindowRef), NULL, (void*) &window); + switch (the_class) { + case kEventClassWindow: + switch (kind) { + case kEventWindowDrawContent: + paint_window(); + result = noErr; + } } - if (portChanged) { - QDSwapPort(portSave, NULL); - } + return result; } diff --git a/direct/src/plugin/p3dOsxSplashWindow.h b/direct/src/plugin/p3dOsxSplashWindow.h index 33220ed916..abef11daa8 100644 --- a/direct/src/plugin/p3dOsxSplashWindow.h +++ b/direct/src/plugin/p3dOsxSplashWindow.h @@ -42,8 +42,14 @@ public: virtual bool handle_event(P3D_event_data event); private: + void refresh(); void paint_window(); + static pascal OSStatus + st_event_callback(EventHandlerCallRef my_handler, EventRef event, + void *user_data); + OSStatus event_callback(EventHandlerCallRef my_handler, EventRef event); + private: bool _got_wparams; GWorldPtr _image; @@ -52,6 +58,8 @@ private: string _install_label; double _install_progress; + + WindowRef _toplevel_window; }; #include "p3dOsxSplashWindow.I" diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index 8a87178f17..0b29765ad4 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/direct/src/plugin/p3dPackage.cxx @@ -81,7 +81,11 @@ P3DPackage:: _active_download = NULL; } - assert(_temp_contents_file == NULL); + if (_temp_contents_file != NULL) { + delete _temp_contents_file; + _temp_contents_file = NULL; + } + assert(_instances.empty()); } diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 19883e3aa5..5afcca17e4 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -255,9 +255,12 @@ write_stream(NPStream *stream, int offset, int len, void *buffer) { return len; case PPDownloadRequest::RT_instance_data: - // Here's a stream we don't really want. - browser->destroystream(_npp_instance, stream, NPRES_USER_BREAK); - return 0; + // Here's a stream we don't really want. But stopping it early + // seems to freak out Safari. (And stopping it before it starts + // freaks out Firefox.) + + // Whatever. We'll just quietly ignore the data. + return len; default: nout << "Unexpected write_stream on " << stream->url << "\n"; diff --git a/direct/src/plugin_standalone/Sources.pp b/direct/src/plugin_standalone/Sources.pp index 8aa3fb0190..aa18233d22 100644 --- a/direct/src/plugin_standalone/Sources.pp +++ b/direct/src/plugin_standalone/Sources.pp @@ -14,7 +14,7 @@ express:c downloader:c pandaexpress:m \ pystub - #define OSX_SYS_FRAMEWORKS Foundation AppKit + #define OSX_SYS_FRAMEWORKS Foundation AppKit Carbon #define SOURCES \ panda3d.cxx panda3d.h panda3d.I diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index 3d9735c774..72126d168e 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/direct/src/plugin_standalone/panda3d.cxx @@ -265,7 +265,6 @@ run(int argc, char *argv[]) { retval = GetMessage(&msg, NULL, 0, 0); } - cerr << "WM_QUIT\n"; // WM_QUIT has been received. Terminate all instances, and fall // through. while (!_instances.empty()) { @@ -287,8 +286,27 @@ run(int argc, char *argv[]) { run_getters(); } } + +#elif defined(__APPLE__) + // OSX really prefers to own the main loop, so we install a timer to + // call out to our instances and getters, rather than polling within + // the event loop as we do in the Windows case, above. + EventLoopRef main_loop = GetMainEventLoop(); + EventLoopTimerUPP timer_upp = NewEventLoopTimerUPP(st_timer_callback); + EventLoopTimerRef timer; + EventTimerInterval interval = 200 * kEventDurationMillisecond; + InstallEventLoopTimer(main_loop, interval, interval, + timer_upp, this, &timer); + RunApplicationEventLoop(); + RemoveEventLoopTimer(timer); + + // Terminate all instances, and fall through. + while (!_instances.empty()) { + P3D_instance *inst = *(_instances.begin()); + delete_instance(inst); + } -#endif +#else // _WIN32, __APPLE__ // Now wait while we process pending requests. while (!_instances.empty()) { @@ -302,6 +320,8 @@ run(int argc, char *argv[]) { run_getters(); } +#endif // _WIN32, __APPLE__ + // All instances have finished; we can exit. unload_plugin(); return 0; @@ -642,17 +662,17 @@ create_instance(const string &p3d, P3D_window_type window_type, // Build up the token list. pvector tokens; + P3D_token token; + string log_basename; if (!_log_dirname.empty()) { // Generate output to a logfile. log_basename = p3d_filename.get_basename_wo_extension(); - P3D_token token; token._keyword = "log_basename"; token._value = log_basename.c_str(); tokens.push_back(token); } else { // Send output to the console. - P3D_token token; token._keyword = "console_output"; token._value = "1"; tokens.push_back(token); @@ -801,7 +821,7 @@ report_downloading_package(P3D_instance *instance) { P3D_object *display_name = P3D_object_get_property(obj, "downloadPackageDisplayName"); if (display_name == NULL) { - cerr << "no name: " << obj << "\n"; + cerr << "Downloading package.\n"; return; } @@ -828,6 +848,48 @@ report_download_complete(P3D_instance *instance) { } } +#ifdef __APPLE__ +//////////////////////////////////////////////////////////////////// +// Function: Panda3D::st_timer_callback +// Access: Private, Static +// Description: Installed as a timer on the event loop, so we can +// process local events, in the Apple implementation. +//////////////////////////////////////////////////////////////////// +pascal void Panda3D:: +st_timer_callback(EventLoopTimerRef timer, void *user_data) { + ((Panda3D *)user_data)->timer_callback(timer); +} +#endif // __APPLE__ + +#ifdef __APPLE__ +//////////////////////////////////////////////////////////////////// +// Function: Panda3D::timer_callback +// Access: Private +// Description: Installed as a timer on the event loop, so we can +// process local events, in the Apple implementation. +//////////////////////////////////////////////////////////////////// +void Panda3D:: +timer_callback(EventLoopTimerRef timer) { + // Check for new requests from the Panda3D plugin. + P3D_instance *inst = P3D_check_request(false); + while (inst != (P3D_instance *)NULL) { + P3D_request *request = P3D_instance_get_request(inst); + if (request != (P3D_request *)NULL) { + handle_request(request); + } + inst = P3D_check_request(false); + } + + // Check the download tasks. + run_getters(); + + // If we're out of instances, exit the application. + if (_instances.empty()) { + QuitApplicationEventLoop(); + } +} +#endif // __APPLE__ + //////////////////////////////////////////////////////////////////// // Function: Panda3D::URLGetter::Constructor // Access: Public @@ -844,6 +906,7 @@ URLGetter(P3D_instance *instance, int unique_id, HTTPClient *http = HTTPClient::get_global_ptr(); _channel = http->make_channel(false); + // _channel->set_download_throttle(true); if (_post_data.empty()) { _channel->begin_get_document(_url); } else { diff --git a/direct/src/plugin_standalone/panda3d.h b/direct/src/plugin_standalone/panda3d.h index 52a36a1b63..30e6e26349 100755 --- a/direct/src/plugin_standalone/panda3d.h +++ b/direct/src/plugin_standalone/panda3d.h @@ -68,6 +68,11 @@ private: void report_downloading_package(P3D_instance *instance); void report_download_complete(P3D_instance *instance); +#ifdef __APPLE__ + static pascal void st_timer_callback(EventLoopTimerRef timer, void *user_data); + void timer_callback(EventLoopTimerRef timer); +#endif + private: string _root_dir; string _log_dirname;