소스 검색

twirling icon for mac too

David Rose 14 년 전
부모
커밋
262a23e09f
2개의 변경된 파일299개의 추가작업 그리고 11개의 파일을 삭제
  1. 273 11
      direct/src/plugin_npapi/ppInstance.cxx
  2. 26 0
      direct/src/plugin_npapi/ppInstance.h

+ 273 - 11
direct/src/plugin_npapi/ppInstance.cxx

@@ -34,7 +34,8 @@
 
 
 #ifndef _WIN32
 #ifndef _WIN32
 #include <sys/select.h>
 #include <sys/select.h>
-#endif
+#include <sys/time.h>
+#endif  // _WIN32
 
 
 PPInstance::FileDatas PPInstance::_file_datas;
 PPInstance::FileDatas PPInstance::_file_datas;
 
 
@@ -101,6 +102,13 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode,
   _hwnd = 0;
   _hwnd = 0;
 #endif // _WIN32
 #endif // _WIN32
 
 
+#ifndef _WIN32
+  // Save the startup time to improve precision of gettimeofday().
+  struct timeval tv;
+  gettimeofday(&tv, (struct timezone *)NULL);
+  _init_sec = tv.tv_sec;
+#endif  // !_WIN32
+
 #ifdef __APPLE__
 #ifdef __APPLE__
   // Get the run loop in the browser thread.  (CFRunLoopGetMain() is
   // Get the run loop in the browser thread.  (CFRunLoopGetMain() is
   // only 10.5 or higher.  Plus, the browser thread is not necessarily
   // only 10.5 or higher.  Plus, the browser thread is not necessarily
@@ -109,7 +117,20 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode,
   CFRetain(_run_loop_main);
   CFRetain(_run_loop_main);
   _request_timer = NULL;
   _request_timer = NULL;
   INIT_LOCK(_timer_lock);
   INIT_LOCK(_timer_lock);
+
+  // Also set up a timer to twirl the icon until the instance loads.
+  _twirl_timer = NULL;
+  CFRunLoopTimerContext timer_context;
+  memset(&timer_context, 0, sizeof(timer_context));
+  timer_context.info = this;
+  _twirl_timer = CFRunLoopTimerCreate
+    (NULL, 0, 0.1, 0, 0, st_twirl_timer_callback, &timer_context);
+  CFRunLoopAddTimer(_run_loop_main, _twirl_timer, kCFRunLoopCommonModes);
 #endif  // __APPLE__
 #endif  // __APPLE__
+
+#ifdef MACOSX_HAS_EVENT_MODELS
+  _got_twirl_images = false;
+#endif  // MACOSX_HAS_EVENT_MODELS
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -122,6 +143,11 @@ PPInstance::
   cleanup_window();
   cleanup_window();
 
 
 #ifdef __APPLE__
 #ifdef __APPLE__
+  if (_twirl_timer != NULL) {
+    CFRunLoopTimerInvalidate(_twirl_timer);
+    CFRelease(_twirl_timer);
+    _twirl_timer = NULL;
+  }
   if (_request_timer != NULL) {
   if (_request_timer != NULL) {
     CFRunLoopTimerInvalidate(_request_timer);
     CFRunLoopTimerInvalidate(_request_timer);
     CFRelease(_request_timer);
     CFRelease(_request_timer);
@@ -132,6 +158,10 @@ PPInstance::
   DESTROY_LOCK(_timer_lock);
   DESTROY_LOCK(_timer_lock);
 #endif  // __APPLE__
 #endif  // __APPLE__
 
 
+#ifdef MACOSX_HAS_EVENT_MODELS
+  osx_release_twirl_images();
+#endif  // MACOSX_HAS_EVENT_MODELS
+
   if (_p3d_inst != NULL) {
   if (_p3d_inst != NULL) {
     P3D_instance_finish_ptr(_p3d_inst);
     P3D_instance_finish_ptr(_p3d_inst);
     _p3d_inst = NULL;
     _p3d_inst = NULL;
@@ -251,8 +281,8 @@ set_window(NPWindow *window) {
     assert(_window.window == window->window);
     assert(_window.window == window->window);
   }
   }
 
 
-#ifdef _WIN32
   if (!_got_window) {
   if (!_got_window) {
+#ifdef _WIN32
     _orig_window_proc = NULL;
     _orig_window_proc = NULL;
     if (window->type == NPWindowTypeWindow) {
     if (window->type == NPWindowTypeWindow) {
       // Save the window handle.
       // Save the window handle.
@@ -275,8 +305,11 @@ set_window(NPWindow *window) {
       // slips through.
       // slips through.
       SetTimer(_hwnd, 1, 100, NULL);
       SetTimer(_hwnd, 1, 100, NULL);
     }
     }
-  }
 #endif  // _WIN32
 #endif  // _WIN32
+#ifdef MACOSX_HAS_EVENT_MODELS
+    osx_get_twirl_images();
+#endif  // MACOSX_HAS_EVENT_MODELS
+  }
 
 
   _window = *window;
   _window = *window;
   _got_window = true;
   _got_window = true;
@@ -810,11 +843,6 @@ bool PPInstance::
 handle_event(void *event) {
 handle_event(void *event) {
   bool retval = false;
   bool retval = false;
 
 
-  if (_p3d_inst == NULL) {
-    // Ignore events that come in before we've launched the instance.
-    return retval;
-  }
-
   P3D_event_data edata;
   P3D_event_data edata;
   memset(&edata, 0, sizeof(edata));
   memset(&edata, 0, sizeof(edata));
   edata._event_type = _event_type;
   edata._event_type = _event_type;
@@ -831,12 +859,16 @@ handle_event(void *event) {
     NPCocoaEvent *np_event = (NPCocoaEvent *)event;
     NPCocoaEvent *np_event = (NPCocoaEvent *)event;
     P3DCocoaEvent *p3d_event = &edata._event._osx_cocoa._event;
     P3DCocoaEvent *p3d_event = &edata._event._osx_cocoa._event;
     copy_cocoa_event(p3d_event, np_event, aux_data);
     copy_cocoa_event(p3d_event, np_event, aux_data);
+    if (_got_window) {
+      handle_cocoa_event(p3d_event);
+    }
 #endif  // MACOSX_HAS_EVENT_MODELS
 #endif  // MACOSX_HAS_EVENT_MODELS
-
   }
   }
 
 
-  if (P3D_instance_handle_event_ptr(_p3d_inst, &edata)) {
-    retval = true;
+  if (_p3d_inst != NULL) {
+    if (P3D_instance_handle_event_ptr(_p3d_inst, &edata)) {
+      retval = true;
+    }
   }
   }
 
 
   return retval;
   return retval;
@@ -1650,6 +1682,15 @@ create_instance() {
     return;
     return;
   }
   }
 
 
+#ifdef __APPLE__
+  // We no longer need to twirl the icon.  Stop the timer.
+  if (_twirl_timer != NULL) {
+    CFRunLoopTimerInvalidate(_twirl_timer);
+    CFRelease(_twirl_timer);
+    _twirl_timer = NULL;
+  }
+#endif  // __APPLE__
+
   P3D_token *tokens = NULL;
   P3D_token *tokens = NULL;
   if (!_tokens.empty()) {
   if (!_tokens.empty()) {
     tokens = &_tokens[0];
     tokens = &_tokens[0];
@@ -2369,6 +2410,197 @@ make_ansi_string(wstring &result, NPNSString *ns_string) {
 }
 }
 #endif  // MACOSX_HAS_EVENT_MODELS
 #endif  // MACOSX_HAS_EVENT_MODELS
 
 
+#ifdef MACOSX_HAS_EVENT_MODELS
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::handle_cocoa_event
+//       Access: Private
+//  Description: Locally processes a Cocoa event for the window before
+//               sending it down to the Core API.  This is used for
+//               drawing a twirling icon in the window while the Core
+//               API is downloading.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+handle_cocoa_event(const P3DCocoaEvent *p3d_event) {
+  switch (p3d_event->type) {
+  case P3DCocoaEventDrawRect:
+    if (!_started) {
+      CGContextRef context = p3d_event->data.draw.context;
+      paint_twirl_osx_cgcontext(context);
+    }
+    break;
+    
+  default:
+    break;
+  }
+}
+#endif  // MACOSX_HAS_EVENT_MODELS
+
+#ifdef MACOSX_HAS_EVENT_MODELS
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::osx_get_twirl_images
+//       Access: Private
+//  Description: Fills _twirl_images with an array of images for
+//               drawing the twirling icon while we're waiting for the
+//               instance to load.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+osx_get_twirl_images() {
+  if (_got_twirl_images) {
+    return;
+  }
+  _got_twirl_images = true;
+
+  static const size_t twirl_size = twirl_width * twirl_height;
+  unsigned char twirl_data[twirl_size];
+
+  for (int step = 0; step < twirl_num_steps; ++step) {
+    get_twirl_data(twirl_data, twirl_size, step);
+
+    unsigned char *new_data = new unsigned char[twirl_size * 4];
+
+    // Replicate out the grayscale channels into RGBA.  Flip
+    // upside-down too.
+    for (int yi = 0; yi < twirl_height; ++yi) {
+      const unsigned char *sp = twirl_data + (twirl_height - 1 - yi) * twirl_width;
+      unsigned char *dp = new_data + yi * twirl_width * 4;
+      for (int xi = 0; xi < twirl_width; ++xi) {
+        dp[0] = sp[0];
+        dp[1] = sp[0];
+        dp[2] = sp[0];
+        dp[3] = (unsigned char)0xff;
+        sp += 1;
+        dp += 4;
+      }
+    }
+
+    OsxImageData &image = _twirl_images[step];
+    image._raw_data = new_data;
+
+    image._data =
+      CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)image._raw_data, 
+                                  twirl_size * 4, kCFAllocatorNull);
+    image._provider = CGDataProviderCreateWithCFData(image._data);
+    image._color_space = CGColorSpaceCreateDeviceRGB();
+    
+    image._image =
+      CGImageCreate(twirl_width, twirl_height, 8, 32, 
+                    twirl_width * 4, image._color_space,
+                    kCGImageAlphaFirst | kCGBitmapByteOrder32Little, 
+                    image._provider, NULL, false, kCGRenderingIntentDefault);
+  }
+}
+#endif  // MACOSX_HAS_EVENT_MODELS
+
+#ifdef MACOSX_HAS_EVENT_MODELS
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::osx_release_twirl_images
+//       Access: Private
+//  Description: Frees the twirl_images array.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+osx_release_twirl_images() {
+  if (!_got_twirl_images) {
+    return;
+  }
+  _got_twirl_images = false;
+
+  for (int step = 0; step < twirl_num_steps; ++step) {
+    OsxImageData &image = _twirl_images[step];
+
+    if (image._image != NULL) {
+      CGImageRelease(image._image);
+      image._image = NULL;
+    }
+    if (image._color_space != NULL) {
+      CGColorSpaceRelease(image._color_space);
+      image._color_space = NULL;
+    }
+    if (image._provider != NULL) {
+      CGDataProviderRelease(image._provider);
+      image._provider = NULL;
+    }
+    if (image._data != NULL) {
+      CFRelease(image._data);
+      image._data = NULL;
+    }
+    if (image._raw_data != NULL) {
+      delete[] image._raw_data;
+      image._raw_data = NULL;
+    }
+  }
+}
+#endif  // MACOSX_HAS_EVENT_MODELS
+
+#ifdef MACOSX_HAS_EVENT_MODELS
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::paint_twirl_osx_cgcontext
+//       Access: Private
+//  Description: Actually paints the twirling icon in the OSX window,
+//               using Core Graphics.  (We don't bother painting it in
+//               the older Cocoa interface.)
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+paint_twirl_osx_cgcontext(CGContextRef context) {
+  // Clear the whole region to white before beginning.
+  CGFloat bg_components[] = { 1, 1, 1, 1 };
+  CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB();
+  CGColorRef bg = CGColorCreate(rgb_space, bg_components);
+
+  CGRect region = { { 0, 0 }, { _window.width, _window.height } };
+  CGContextBeginPath(context);
+  CGContextSetFillColorWithColor(context, bg);
+  CGContextAddRect(context, region);
+  CGContextFillPath(context);
+
+  CGColorRelease(bg);
+  CGColorSpaceRelease(rgb_space);
+
+  struct timeval tv;
+  gettimeofday(&tv, (struct timezone *)NULL);
+  double now = (double)(tv.tv_sec - _init_sec) + (double)tv.tv_usec / 1000000.0;
+  int step = ((int)(now * 10.0)) % twirl_num_steps;
+
+  osx_paint_image(context, _twirl_images[step]);
+}
+#endif  // MACOSX_HAS_EVENT_MODELS
+
+#ifdef MACOSX_HAS_EVENT_MODELS
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::osx_paint_image
+//       Access: Private
+//  Description: Draws the indicated image, centered within the
+//               window.  Returns true on success, false if the image
+//               is not defined.
+////////////////////////////////////////////////////////////////////
+bool PPInstance::
+osx_paint_image(CGContextRef context, const OsxImageData &image) {
+  if (image._image == NULL) {
+    return false;
+  }
+    
+  // Determine the relative size of image and window.
+  int win_cx = _window.width / 2;
+  int win_cy = _window.height / 2;
+
+  CGRect rect = { { 0, 0 }, { 0, 0 } };
+    
+  // The bitmap fits within the window; center it.
+      
+  // This is the top-left corner of the bitmap in window coordinates.
+  int p_x = win_cx - twirl_width / 2;
+  int p_y = win_cy - twirl_height / 2;
+  
+  rect.origin.x += p_x;
+  rect.origin.y += p_y;
+  rect.size.width = twirl_width;
+  rect.size.height = twirl_height;
+
+  CGContextDrawImage(context, rect, image._image);
+  
+  return true;
+}
+#endif  // MACOSX_HAS_EVENT_MODELS
+
 #ifdef __APPLE__
 #ifdef __APPLE__
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::timer_callback
 //     Function: PPInstance::timer_callback
@@ -2392,6 +2624,36 @@ timer_callback(CFRunLoopTimerRef timer, void *info) {
 }
 }
 #endif  // __APPLE__
 #endif  // __APPLE__
 
 
+#ifdef __APPLE__
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::st_twirl_timer_callback
+//       Access: Private, Static
+//  Description: OSX only: this callback is used to twirl the icon
+//               before the instance loads.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+st_twirl_timer_callback(CFRunLoopTimerRef timer, void *info) {
+  PPInstance *self = (PPInstance *)info;
+  self->twirl_timer_callback();
+}
+#endif  // __APPLE__
+
+#ifdef __APPLE__
+////////////////////////////////////////////////////////////////////
+//     Function: PPInstance::twirl_timer_callback
+//       Access: Private
+//  Description: OSX only: this callback is used to twirl the icon
+//               before the instance loads.
+////////////////////////////////////////////////////////////////////
+void PPInstance::
+twirl_timer_callback() {
+  if (_got_window) {
+    NPRect rect = { 0, 0, (unsigned short)_window.height, (unsigned short)_window.width };
+    browser->invalidaterect(_npp_instance, &rect);
+  }
+}
+#endif  // __APPLE__
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PPInstance::StreamingFileData::Constructor
 //     Function: PPInstance::StreamingFileData::Constructor
 //       Access: Public
 //       Access: Public

+ 26 - 0
direct/src/plugin_npapi/ppInstance.h

@@ -123,10 +123,18 @@ private:
                                NPCocoaEvent *np_event,
                                NPCocoaEvent *np_event,
                                EventAuxData &aux_data);
                                EventAuxData &aux_data);
   static const wchar_t *make_ansi_string(wstring &result, NPNSString *ns_string);
   static const wchar_t *make_ansi_string(wstring &result, NPNSString *ns_string);
+  void handle_cocoa_event(const P3DCocoaEvent *p3d_event);
+  void osx_get_twirl_images();
+  void osx_release_twirl_images();
+  void paint_twirl_osx_cgcontext(CGContextRef context);
+  class OsxImageData;
+  bool osx_paint_image(CGContextRef context, const OsxImageData &image);
 #endif  // MACOSX_HAS_EVENT_MODELS
 #endif  // MACOSX_HAS_EVENT_MODELS
 
 
 #ifdef __APPLE__
 #ifdef __APPLE__
   static void timer_callback(CFRunLoopTimerRef timer, void *info);
   static void timer_callback(CFRunLoopTimerRef timer, void *info);
+  static void st_twirl_timer_callback(CFRunLoopTimerRef timer, void *info);
+  void twirl_timer_callback();
 #endif  // __APPLE__
 #endif  // __APPLE__
 
 
 private:
 private:
@@ -213,8 +221,26 @@ private:
   CFRunLoopRef _run_loop_main;
   CFRunLoopRef _run_loop_main;
   CFRunLoopTimerRef _request_timer;
   CFRunLoopTimerRef _request_timer;
   LOCK _timer_lock;
   LOCK _timer_lock;
+  CFRunLoopTimerRef _twirl_timer;
 #endif  // __APPLE__
 #endif  // __APPLE__
 
 
+#ifdef MACOSX_HAS_EVENT_MODELS
+  class OsxImageData {
+  public:
+    unsigned char *_raw_data;
+    CFDataRef _data;
+    CGDataProviderRef _provider;
+    CGColorSpaceRef _color_space;
+    CGImageRef _image;
+  };
+  OsxImageData _twirl_images[twirl_num_steps];
+  bool _got_twirl_images;
+#endif  // MACOSX_HAS_EVENT_MODELS
+
+#ifndef _WIN32
+  long _init_sec;
+#endif  // _WIN32
+
   bool _python_window_open;
   bool _python_window_open;
 
 
   PPToplevelObject *_script_object;
   PPToplevelObject *_script_object;