Browse Source

osx toplevel splash windows

David Rose 16 years ago
parent
commit
29a65d32a9

+ 36 - 15
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;

+ 1 - 1
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.

+ 150 - 34
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);
-    
-    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;
+    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());
+    }
+  }
     
-    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());
+  if (_toplevel_window == NULL) {
+    if (portChanged) {
+      QDSwapPort(portSave, NULL);
+    }
   }
+}
+
+////////////////////////////////////////////////////////////////////
+//     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);
+}
+
+////////////////////////////////////////////////////////////////////
+//     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;
 
-  if (portChanged) {
-    QDSwapPort(portSave, NULL);
+  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;
+    }
   }
+
+  return result;
 }
 
 

+ 8 - 0
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"

+ 5 - 1
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());
 }
 

+ 6 - 3
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";

+ 1 - 1
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

+ 68 - 5
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<P3D_token> 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 {

+ 5 - 0
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;