diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index 831ab53c4e..2e85127091 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -33,6 +33,20 @@ #ifdef __APPLE__ #include #include + +// Lifted from NSEvent.h (which is Objective-C). +enum { + NSAlphaShiftKeyMask = 1 << 16, + NSShiftKeyMask = 1 << 17, + NSControlKeyMask = 1 << 18, + NSAlternateKeyMask = 1 << 19, + NSCommandKeyMask = 1 << 20, + NSNumericPadKeyMask = 1 << 21, + NSHelpKeyMask = 1 << 22, + NSFunctionKeyMask = 1 << 23, + NSDeviceIndependentModifierFlagsMask = 0xffff0000U +}; + #endif // __APPLE__ #ifdef _WIN32 @@ -63,6 +77,15 @@ const char *P3DInstance::_image_type_names[P3DInstance::IT_num_image_types] = { "none", // Not really used. }; +static void +write_str(ostream &out, const wchar_t *str) { + const wchar_t *p = str; + while (*p != 0) { + out << (int)*p << ' '; + ++p; + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::Constructor // Access: Public @@ -137,6 +160,7 @@ P3DInstance(P3D_request_ready_func *func, // We have to start with _mouse_active true; firefox doesn't send // activate events. _mouse_active = true; + _modifiers = 0; _frame_timer = NULL; #endif // __APPLE__ @@ -833,88 +857,15 @@ handle_event(const P3D_event_data &event) { } #if defined(__APPLE__) - assert(event._event_type == P3D_ET_osx_event_record); - EventRecord *er = event._event._osx_event_record._event; - - // Need to ensure we have the correct port set, in order to - // convert the mouse coordinates successfully via - // GlobalToLocal(). - const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_osx_port); - GrafPtr out_port = handle._handle._osx_port._port; - GrafPtr port_save = NULL; - Boolean port_changed = QDSwapPort(out_port, &port_save); - - Point pt = er->where; - GlobalToLocal(&pt); - - if (port_changed) { - QDSwapPort(port_save, NULL); + if (event._event_type == P3D_ET_osx_event_record) { + retval = handle_event_osx_event_record(event); + } else if (event._event_type == P3D_ET_osx_cocoa) { + retval = handle_event_osx_cocoa(event); + } else { + assert(false); } +#endif // __APPLE__ - SubprocessWindowBuffer::Event swb_event; - swb_event._source = SubprocessWindowBuffer::ES_none; - swb_event._type = SubprocessWindowBuffer::ET_none; - swb_event._code = 0; - swb_event._flags = 0; - add_modifier_flags(swb_event._flags, er->modifiers); - - switch (er->what) { - case mouseDown: - case mouseUp: - { - P3D_window_handle window = _wparams.get_parent_window(); - swb_event._source = SubprocessWindowBuffer::ES_mouse; - if (er->what == mouseUp) { - swb_event._type = SubprocessWindowBuffer::ET_button_up; - } else { - swb_event._type = SubprocessWindowBuffer::ET_button_down; - } - retval = true; - } - break; - - case keyDown: - case keyUp: - case autoKey: - if (_swbuffer != NULL) { - swb_event._source = SubprocessWindowBuffer::ES_keyboard; - swb_event._code = er->message; - if (er->what == keyUp) { - swb_event._type = SubprocessWindowBuffer::ET_button_up; - } else if (er->what == keyDown) { - swb_event._type = SubprocessWindowBuffer::ET_button_down; - } else { - swb_event._type = SubprocessWindowBuffer::ET_button_again; - } - retval = true; - } - break; - - case updateEvt: - paint_window(); - retval = true; - break; - - case activateEvt: - _mouse_active = ((er->modifiers & 1) != 0); - break; - - default: - break; - } - - if (_mouse_active) { - swb_event._x = pt.h; - swb_event._y = pt.v; - swb_event._flags |= SubprocessWindowBuffer::EF_mouse_position | SubprocessWindowBuffer::EF_has_mouse; - } - - if (_swbuffer != NULL) { - _swbuffer->add_event(swb_event); - } - -#endif return retval; } @@ -3018,28 +2969,47 @@ set_install_label(const string &install_label) { // Function: P3DInstance::paint_window // Access: Private // Description: Actually paints the rendered image to the browser -// window. This is only implemented (and needed) for -// OSX, where the child process isn't allowed to do it -// directly. +// window. This is only needed for OSX, where the child +// process isn't allowed to do it directly. //////////////////////////////////////////////////////////////////// void P3DInstance:: paint_window() { + const P3D_window_handle &handle = _wparams.get_parent_window(); + if (handle._window_handle_type == P3D_WHT_osx_port) { + paint_window_osx_port(); + + } else if (handle._window_handle_type == P3D_WHT_osx_cgcontext) { + const P3D_window_handle &handle = _wparams.get_parent_window(); + assert(handle._window_handle_type == P3D_WHT_osx_cgcontext); + CGContextRef context = handle._handle._osx_cgcontext._context; + + paint_window_osx_cgcontext(context); + } +} + #ifdef __APPLE__ +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::get_framebuffer +// Access: Private +// Description: Fills _reversed_buffer with the pixels from the +// current frame. Returns true on success, or false if +// there is no Panda3D window visible. Only needed on +// OSX. +//////////////////////////////////////////////////////////////////// +bool P3DInstance:: +get_framebuffer() { if (_swbuffer == NULL || !_instance_window_opened) { // We don't have a Panda3D window yet. - return; + return false; } if (_splash_window != NULL && _splash_window->get_visible()) { // If the splash window is up, don't draw the Panda3D window. - return; + return false; } - QDErr err; - // blit rendered framebuffer into window backing store int x_size = min(_wparams.get_win_width(), _swbuffer->get_x_size()); int y_size = min(_wparams.get_win_height(), _swbuffer->get_y_size()); - size_t rowsize = _swbuffer->get_row_size(); if (_swbuffer->ready_for_read()) { @@ -3089,61 +3059,34 @@ paint_window() { // time. } - /* - // This is an attempt to paint the frame using the less-deprecated - // Quartz interfaces. Sure does seem like a lot of layers to go - // through just to paint a bitmap. - CFDataRef data = - CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)_reversed_buffer, - y_size * rowsize, kCFAllocatorNull); + return true; +} +#endif // __APPLE__ - CGDataProviderRef provider = CGDataProviderCreateWithCFData(data); - CGColorSpaceRef color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); - - CGImageRef image = - CGImageCreate(x_size, y_size, 8, 32, rowsize, color_space, - kCGImageAlphaFirst | kCGBitmapByteOrder32Little, provider, - NULL, false, kCGRenderingIntentDefault); - - CGrafPtr port = _wparams.get_parent_window()._port; - CGContextRef context; - err = QDBeginCGContext(port, &context); - if (err != noErr) { - nout << "Error: QDBeginCGContext\n"; +#ifdef __APPLE__ +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::paint_window_osx_port +// Access: Private +// Description: Actually paints the rendered image to the browser +// window, using the OSX deprecated QuickDraw +// interfaces. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +paint_window_osx_port() { + if (!get_framebuffer()) { + // No Panda3D window is showing. return; } - // CGContextTranslateCTM(context, 0.0, win_height); - // CGContextScaleCTM(context, 1.0, -1.0); + int x_size = min(_wparams.get_win_width(), _swbuffer->get_x_size()); + int y_size = min(_wparams.get_win_height(), _swbuffer->get_y_size()); + size_t rowsize = _swbuffer->get_row_size(); - // We have to rely on the clipping rectangle having been set up - // correctly in order to get the proper location to draw the image. - // This isn't completely right, because if the image is slightly - // offscreen, the top left of the clipping rectangle will no longer - // correspond to the top left of the original image. - CGRect rect = CGContextGetClipBoundingBox(context); - 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; - - CGContextDrawImage(context, rect, image); - - //CGContextSynchronize(context); - CGContextFlush(context); - QDEndCGContext(port, &context); - - CGImageRelease(image); - CGColorSpaceRelease(color_space); - CGDataProviderRelease(provider); - - CFRelease(data); - */ - - // Painting the frame using the deprecated QuickDraw interfaces. Rect src_rect = {0, 0, y_size, x_size}; Rect ddrc_rect = {0, 0, y_size, x_size}; + QDErr err; + GWorldPtr pGWorld; err = NewGWorldFromPtr(&pGWorld, k32BGRAPixelFormat, &src_rect, 0, 0, 0, _reversed_buffer, rowsize); @@ -3172,18 +3115,269 @@ paint_window() { } DisposeGWorld(pGWorld); +} #endif // __APPLE__ + +#ifdef __APPLE__ +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::paint_window_osx_cgcontext +// Access: Private +// Description: Actually paints the rendered image to the browser +// window. This is the newer CoreGraphics +// implementation on OSX. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +paint_window_osx_cgcontext(CGContextRef context) { + if (!get_framebuffer()) { + // No Panda3D window is showing. + return; + } + + int x_size = min(_wparams.get_win_width(), _swbuffer->get_x_size()); + int y_size = min(_wparams.get_win_height(), _swbuffer->get_y_size()); + size_t rowsize = _swbuffer->get_row_size(); + + CGContextTranslateCTM(context, 0, y_size); + CGContextScaleCTM(context, 1.0, -1.0); + + CFDataRef data = + CFDataCreateWithBytesNoCopy(NULL, (const UInt8 *)_reversed_buffer, + y_size * rowsize, kCFAllocatorNull); + + CGDataProviderRef provider = CGDataProviderCreateWithCFData(data); + //CGColorSpaceRef color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB); + CGColorSpaceRef color_space = CGColorSpaceCreateDeviceRGB(); + + CGImageRef image = + CGImageCreate(x_size, y_size, 8, 32, rowsize, color_space, + kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little, + provider, NULL, false, kCGRenderingIntentDefault); + + CGRect region = { { 0, 0 }, { x_size, y_size } }; + CGContextDrawImage(context, region, image); + + CGImageRelease(image); + CGColorSpaceRelease(color_space); + CGDataProviderRelease(provider); + + CFRelease(data); +} +#endif // __APPLE__ + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::handle_event_osx_event_record +// Access: Private +// Description: Responds to the deprecated Carbon event types in Mac +// OSX. +//////////////////////////////////////////////////////////////////// +bool P3DInstance:: +handle_event_osx_event_record(const P3D_event_data &event) { + bool retval = false; + +#ifdef __APPLE__ + assert(event._event_type == P3D_ET_osx_event_record); + EventRecord *er = event._event._osx_event_record._event; + + Point pt = er->where; + + // Need to ensure we have the correct port set, in order to + // convert the mouse coordinates successfully via + // GlobalToLocal(). + const P3D_window_handle &handle = _wparams.get_parent_window(); + if (handle._window_handle_type == P3D_WHT_osx_port) { + GrafPtr out_port = handle._handle._osx_port._port; + GrafPtr port_save = NULL; + Boolean port_changed = QDSwapPort(out_port, &port_save); + + GlobalToLocal(&pt); + + if (port_changed) { + QDSwapPort(port_save, NULL); + } + } else { + // First, convert the coordinates from screen coordinates to + // browser window coordinates. + WindowRef window = handle._handle._osx_cgcontext._window; + CGPoint cgpt = { pt.h, pt.v }; + HIPointConvert(&cgpt, kHICoordSpaceScreenPixel, NULL, + kHICoordSpaceWindow, window); + + // Then convert to plugin coordinates. + pt.h = cgpt.x - _wparams.get_win_x(); + pt.v = cgpt.y - _wparams.get_win_y(); + } + + SubprocessWindowBuffer::Event swb_event; + swb_event._source = SubprocessWindowBuffer::ES_none; + swb_event._type = SubprocessWindowBuffer::ET_none; + swb_event._code = 0; + swb_event._flags = 0; + add_carbon_modifier_flags(swb_event._flags, er->modifiers); + + switch (er->what) { + case mouseDown: + swb_event._source = SubprocessWindowBuffer::ES_mouse; + swb_event._type = SubprocessWindowBuffer::ET_button_down; + retval = true; + break; + + case mouseUp: + swb_event._source = SubprocessWindowBuffer::ES_mouse; + swb_event._type = SubprocessWindowBuffer::ET_button_up; + retval = true; + break; + + case keyDown: + case keyUp: + case autoKey: + if (_swbuffer != NULL) { + swb_event._source = SubprocessWindowBuffer::ES_keyboard; + swb_event._code = er->message; + if (er->what == keyUp) { + swb_event._type = SubprocessWindowBuffer::ET_button_up; + } else if (er->what == keyDown) { + swb_event._type = SubprocessWindowBuffer::ET_button_down; + } else { + swb_event._type = SubprocessWindowBuffer::ET_button_again; + } + retval = true; + } + break; + + case updateEvt: + paint_window(); + retval = true; + break; + + case activateEvt: + _mouse_active = ((er->modifiers & 1) != 0); + break; + + default: + break; + } + + if (_mouse_active) { + swb_event._x = pt.h; + swb_event._y = pt.v; + swb_event._flags |= SubprocessWindowBuffer::EF_mouse_position | SubprocessWindowBuffer::EF_has_mouse; + } + + if (_swbuffer != NULL) { + _swbuffer->add_event(swb_event); + } +#endif // __APPLE__ + + return retval; } //////////////////////////////////////////////////////////////////// -// Function: P3DInstance::add_modifier_flags +// Function: P3DInstance::handle_event_osx_cocoa +// Access: Private +// Description: Responds to the new Cocoa event types in Mac +// OSX. +//////////////////////////////////////////////////////////////////// +bool P3DInstance:: +handle_event_osx_cocoa(const P3D_event_data &event) { + bool retval = false; + +#ifdef __APPLE__ + assert(event._event_type == P3D_ET_osx_cocoa); + const P3DCocoaEvent &ce = event._event._osx_cocoa._event; + + SubprocessWindowBuffer::Event swb_event; + swb_event._source = SubprocessWindowBuffer::ES_none; + swb_event._type = SubprocessWindowBuffer::ET_none; + swb_event._code = 0; + swb_event._flags = 0; + + switch (ce.type) { + case P3DCocoaEventDrawRect: + { + CGContextRef context = ce.data.draw.context; + paint_window_osx_cgcontext(context); + retval = true; + } + break; + + case P3DCocoaEventMouseDown: + swb_event._source = SubprocessWindowBuffer::ES_mouse; + swb_event._type = SubprocessWindowBuffer::ET_button_down; + retval = true; + break; + + case P3DCocoaEventMouseUp: + swb_event._source = SubprocessWindowBuffer::ES_mouse; + swb_event._type = SubprocessWindowBuffer::ET_button_up; + retval = true; + break; + + case P3DCocoaEventKeyDown: + swb_event._source = SubprocessWindowBuffer::ES_keyboard; + swb_event._code = ce.data.key.keyCode << 8; + if (ce.data.key.isARepeat) { + swb_event._type = SubprocessWindowBuffer::ET_button_again; + } else { + swb_event._type = SubprocessWindowBuffer::ET_button_down; + if (ce.data.key.characters[0] > 0 & ce.data.key.characters[0] < 0x100) { + swb_event._code |= ce.data.key.characters[0]; + } + } + _modifiers = ce.data.key.modifierFlags; + retval = true; + break; + + case P3DCocoaEventKeyUp: + swb_event._source = SubprocessWindowBuffer::ES_keyboard; + swb_event._type = SubprocessWindowBuffer::ET_button_up; + swb_event._code = ce.data.key.keyCode << 8; + _modifiers = ce.data.key.modifierFlags; + retval = true; + break; + + case P3DCocoaEventFlagsChanged: + _modifiers = ce.data.key.modifierFlags; + retval = true; + break; + + case P3DCocoaEventFocusChanged: + _mouse_active = (ce.data.focus.hasFocus != 0); + retval = true; + break; + } + + add_cocoa_modifier_flags(swb_event._flags, _modifiers); + + switch (ce.type) { + case P3DCocoaEventMouseDown: + case P3DCocoaEventMouseMoved: + case P3DCocoaEventMouseDragged: + swb_event._x = ce.data.mouse.pluginX; + swb_event._y = ce.data.mouse.pluginY; + swb_event._flags |= SubprocessWindowBuffer::EF_mouse_position; + } + + if (_mouse_active) { + swb_event._flags |= SubprocessWindowBuffer::EF_has_mouse; + } + + if (_swbuffer != NULL) { + _swbuffer->add_event(swb_event); + } +#endif // __APPLE__ + + return retval; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::add_carbon_modifier_flags // Access: Private // Description: OSX only: adds the appropriate bits to the Event flag // bitmask to correspond to the modifier buttons held in // the MacOS-style EventRecord::modifiers mask. //////////////////////////////////////////////////////////////////// void P3DInstance:: -add_modifier_flags(unsigned int &swb_flags, int modifiers) { +add_carbon_modifier_flags(unsigned int &swb_flags, int modifiers) { #ifdef __APPLE__ if (modifiers & cmdKey) { swb_flags |= SubprocessWindowBuffer::EF_meta_held; @@ -3200,6 +3394,31 @@ add_modifier_flags(unsigned int &swb_flags, int modifiers) { #endif // __APPLE__ } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::add_cocoa_modifier_flags +// Access: Private +// Description: OSX only: adds the appropriate bits to the Event flag +// bitmask to correspond to the modifier buttons held in +// the P3DCocoaEvent modifierFlags mask. +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +add_cocoa_modifier_flags(unsigned int &swb_flags, int modifiers) { +#ifdef __APPLE__ + if (modifiers & NSCommandKeyMask) { + swb_flags |= SubprocessWindowBuffer::EF_meta_held; + } + if (modifiers & NSShiftKeyMask) { + swb_flags |= SubprocessWindowBuffer::EF_shift_held; + } + if (modifiers & NSAlternateKeyMask) { + swb_flags |= SubprocessWindowBuffer::EF_alt_held; + } + if (modifiers & NSControlKeyMask) { + swb_flags |= SubprocessWindowBuffer::EF_control_held; + } +#endif // __APPLE__ +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstance::send_notify // Access: Private @@ -3284,7 +3503,7 @@ parse_hexdigit(int &result, char digit) { #ifdef __APPLE__ //////////////////////////////////////////////////////////////////// // Function: P3DInstance::timer_callback -// Access: Private +// Access: Private, Static // Description: OSX only: this callback is associated with a // CFRunLoopTimer, to be called periodically for // updating the frame. @@ -3293,7 +3512,6 @@ void P3DInstance:: timer_callback(CFRunLoopTimerRef timer, void *info) { P3DInstance *self = (P3DInstance *)info; self->request_refresh(); - //self->paint_window(); } #endif // __APPLE__ diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 9536a03861..d6b30ec411 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -200,7 +200,17 @@ private: void set_install_label(const string &install_label); void paint_window(); - void add_modifier_flags(unsigned int &swb_flags, int modifiers); + +#ifdef __APPLE__ + bool get_framebuffer(); + void paint_window_osx_port(); + void paint_window_osx_cgcontext(CGContextRef context); +#endif // __APPLE__ + + bool handle_event_osx_event_record(const P3D_event_data &event); + bool handle_event_osx_cocoa(const P3D_event_data &event); + void add_carbon_modifier_flags(unsigned int &swb_flags, int modifiers); + void add_cocoa_modifier_flags(unsigned int &swb_flags, int modifiers); void send_notify(const string &message); @@ -286,6 +296,7 @@ private: SubprocessWindowBuffer *_swbuffer; char *_reversed_buffer; bool _mouse_active; + unsigned int _modifiers; CFRunLoopTimerRef _frame_timer; #endif // __APPLE__ diff --git a/direct/src/plugin/p3dOsxSplashWindow.cxx b/direct/src/plugin/p3dOsxSplashWindow.cxx index b98a3ba9ee..4774fa6eee 100644 --- a/direct/src/plugin/p3dOsxSplashWindow.cxx +++ b/direct/src/plugin/p3dOsxSplashWindow.cxx @@ -220,51 +220,17 @@ set_install_progress(double install_progress, //////////////////////////////////////////////////////////////////// bool P3DOsxSplashWindow:: handle_event(const P3D_event_data &event) { - assert(event._event_type == P3D_ET_osx_event_record); - EventRecord *er = event._event._osx_event_record._event; + bool retval = false; - // Need to ensure we have the correct port set, in order to - // convert the mouse coordinates successfully via - // GlobalToLocal(). - const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_osx_port); - GrafPtr out_port = handle._handle._osx_port._port; - GrafPtr port_save = NULL; - Boolean port_changed = QDSwapPort(out_port, &port_save); - - Point pt = er->where; - GlobalToLocal(&pt); - - if (port_changed) { - QDSwapPort(port_save, NULL); - } - - switch (er->what) { - case updateEvt: - paint_window(); - break; - - case mouseDown: - set_mouse_data(_mouse_x, _mouse_y, true); - break; - - case mouseUp: - set_mouse_data(_mouse_x, _mouse_y, false); - break; - - case activateEvt: - _mouse_active = ((er->modifiers & 1) != 0); - break; - - default: - break; + if (event._event_type == P3D_ET_osx_event_record) { + retval = handle_event_osx_event_record(event); + } else if (event._event_type == P3D_ET_osx_cocoa) { + retval = handle_event_osx_cocoa(event); + } else { + assert(false); } - if (_mouse_active) { - set_mouse_data(pt.h, pt.v, _mouse_down); - } - - return false; + return retval; } //////////////////////////////////////////////////////////////////// @@ -297,34 +263,65 @@ paint_window() { return; } - GrafPtr out_port = NULL; - if (_toplevel_window != NULL) { - GetPort(&out_port); + if (_toplevel_window != NULL || + _wparams.get_parent_window()._window_handle_type == P3D_WHT_osx_port) { + // The old QuickDraw-style window handle. We use + // CreateCGContextForPort() to map this to the new + // CoreGraphics-style. + GrafPtr out_port = NULL; + if (_toplevel_window != NULL) { + GetPort(&out_port); + + } else { + const P3D_window_handle &handle = _wparams.get_parent_window(); + assert(handle._window_handle_type == P3D_WHT_osx_port); + out_port = handle._handle._osx_port._port; + } + + CGContextRef context; + OSStatus err = CreateCGContextForPort(out_port, &context); + if (err != noErr) { + nout << "Couldn't create CG context\n"; + return; + } + + // Adjust for any SetOrigin calls on out_port + SyncCGContextOriginWithPort(context, out_port); + + // Move the CG origin to the upper left of the port + Rect port_rect; + GetPortBounds(out_port, &port_rect); + CGContextTranslateCTM(context, 0, (float)(port_rect.bottom - port_rect.top)); + + // Flip the y axis so that positive Y points down + CGContextScaleCTM(context, 1.0, -1.0); + + paint_window_osx_cgcontext(context); + + // CGContextSynchronize(context); + CGContextRelease(context); + } else { + // The new CoreGraphics-style window handle. We can draw to this + // directly. + const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_osx_port); - out_port = handle._handle._osx_port._port; + assert(handle._window_handle_type == P3D_WHT_osx_cgcontext); + CGContextRef context = handle._handle._osx_cgcontext._context; + + paint_window_osx_cgcontext(context); } +} - CGContextRef context; - OSStatus err = CreateCGContextForPort(out_port, &context); - if (err != noErr) { - nout << "Couldn't create CG context\n"; - return; - } - - // Adjust for any SetOrigin calls on out_port - SyncCGContextOriginWithPort(context, out_port); - - // Move the CG origin to the upper left of the port - Rect port_rect; - GetPortBounds(out_port, &port_rect); - CGContextTranslateCTM(context, 0, (float)(port_rect.bottom - port_rect.top)); - - // Flip the y axis so that positive Y points down - CGContextScaleCTM(context, 1.0, -1.0); - +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::paint_window_osx_cgcontext +// Access: Private +// Description: Redraws the current splash window, using the new +// CoreGraphics interface. +//////////////////////////////////////////////////////////////////// +void P3DOsxSplashWindow:: +paint_window_osx_cgcontext(CGContextRef context) { // Clear the whole region to the background color before beginning. CGFloat bg_components[] = { _bgcolor_r / 255.0f, _bgcolor_g / 255.0f, _bgcolor_b / 255.0f, 1 }; CGColorSpaceRef rgb_space = CGColorSpaceCreateDeviceRGB(); @@ -364,9 +361,122 @@ paint_window() { if (!_progress_known || _install_progress != 0.0) { paint_progress_bar(context); } +} - CGContextSynchronize(context); - CGContextRelease(context); +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::handle_event_osx_event_record +// Access: Private +// Description: Responds to the deprecated Carbon event types in Mac +// OSX. +//////////////////////////////////////////////////////////////////// +bool P3DOsxSplashWindow:: +handle_event_osx_event_record(const P3D_event_data &event) { + assert(event._event_type == P3D_ET_osx_event_record); + EventRecord *er = event._event._osx_event_record._event; + + Point pt = er->where; + + // Need to ensure we have the correct port set, in order to + // convert the mouse coordinates successfully via + // GlobalToLocal(). + const P3D_window_handle &handle = _wparams.get_parent_window(); + if (handle._window_handle_type == P3D_WHT_osx_port) { + GrafPtr out_port = handle._handle._osx_port._port; + GrafPtr port_save = NULL; + Boolean port_changed = QDSwapPort(out_port, &port_save); + + GlobalToLocal(&pt); + + if (port_changed) { + QDSwapPort(port_save, NULL); + } + + } else if (handle._window_handle_type == P3D_WHT_osx_cgcontext) { + // First, convert the coordinates from screen coordinates to + // browser window coordinates. + WindowRef window = handle._handle._osx_cgcontext._window; + CGPoint cgpt = { pt.h, pt.v }; + HIPointConvert(&cgpt, kHICoordSpaceScreenPixel, NULL, + kHICoordSpaceWindow, window); + + // Then convert to plugin coordinates. + pt.h = cgpt.x - _wparams.get_win_x(); + pt.v = cgpt.y - _wparams.get_win_y(); + } + + switch (er->what) { + case updateEvt: + paint_window(); + break; + + case mouseDown: + set_mouse_data(_mouse_x, _mouse_y, true); + break; + + case mouseUp: + set_mouse_data(_mouse_x, _mouse_y, false); + break; + + case activateEvt: + _mouse_active = ((er->modifiers & 1) != 0); + break; + + default: + break; + } + + if (_mouse_active) { + set_mouse_data(pt.h, pt.v, _mouse_down); + } + + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DOsxSplashWindow::handle_event_osx_cocoa +// Access: Private +// Description: Responds to the new Cocoa event types in Mac +// OSX. +//////////////////////////////////////////////////////////////////// +bool P3DOsxSplashWindow:: +handle_event_osx_cocoa(const P3D_event_data &event) { + bool retval = false; + + assert(event._event_type == P3D_ET_osx_cocoa); + const P3DCocoaEvent &ce = event._event._osx_cocoa._event; + + switch (ce.type) { + case P3DCocoaEventDrawRect: + if (_visible) { + CGContextRef context = ce.data.draw.context; + paint_window_osx_cgcontext(context); + retval = true; + } + break; + + case P3DCocoaEventMouseDown: + set_mouse_data(ce.data.mouse.pluginX, ce.data.mouse.pluginY, true); + retval = true; + break; + + case P3DCocoaEventMouseUp: + set_mouse_data(ce.data.mouse.pluginX, ce.data.mouse.pluginY, false); + retval = true; + break; + + case P3DCocoaEventMouseMoved: + case P3DCocoaEventMouseDragged: + set_mouse_data(ce.data.mouse.pluginX, ce.data.mouse.pluginY, _mouse_down); + retval = true; + break; + + case P3DCocoaEventFocusChanged: + _mouse_active = (ce.data.focus.hasFocus != 0); + retval = true; + break; + } + + return retval; } //////////////////////////////////////////////////////////////////// @@ -681,13 +791,8 @@ event_callback(EventHandlerCallRef my_handler, EventRef event) { sizeof(Point), NULL, (void *)&point); GrafPtr port; - if (_toplevel_window != NULL) { - port = GetWindowPort(_toplevel_window); - } else { - const P3D_window_handle &handle = _wparams.get_parent_window(); - assert(handle._window_handle_type == P3D_WHT_osx_port); - port = handle._handle._osx_port._port; - } + assert(_toplevel_window != NULL); + port = GetWindowPort(_toplevel_window); GrafPtr port_save = NULL; Boolean port_changed = QDSwapPort(port, &port_save); GlobalToLocal(&point); diff --git a/direct/src/plugin/p3dOsxSplashWindow.h b/direct/src/plugin/p3dOsxSplashWindow.h index 6523798dc9..95cec44587 100644 --- a/direct/src/plugin/p3dOsxSplashWindow.h +++ b/direct/src/plugin/p3dOsxSplashWindow.h @@ -48,6 +48,9 @@ protected: private: void paint_window(); + void paint_window_osx_cgcontext(CGContextRef context); + bool handle_event_osx_event_record(const P3D_event_data &event); + bool handle_event_osx_cocoa(const P3D_event_data &event); class OsxImageData; void load_image(OsxImageData &image, const string &image_filename); diff --git a/direct/src/plugin/p3d_plugin.h b/direct/src/plugin/p3d_plugin.h index 450af1e950..37e84f307f 100644 --- a/direct/src/plugin/p3d_plugin.h +++ b/direct/src/plugin/p3d_plugin.h @@ -204,6 +204,7 @@ typedef enum { P3D_WHT_win_hwnd, P3D_WHT_osx_port, P3D_WHT_x11_window, + P3D_WHT_osx_cgcontext, } P3D_window_handle_type; typedef struct { @@ -220,6 +221,15 @@ typedef struct { #endif } P3D_window_handle_osx_port; + /* A CoreGraphics handle, as used by NPAPI with + NPDrawingModelCoreGraphics in effect. */ +typedef struct { +#if defined(__APPLE__) + CGContextRef _context; + WindowRef _window; +#endif +} P3D_window_handle_osx_cgcontext; + typedef struct { #if defined(HAVE_X11) unsigned long _xwindow; @@ -233,6 +243,7 @@ typedef struct { P3D_window_handle_win_hwnd _win_hwnd; P3D_window_handle_osx_port _osx_port; P3D_window_handle_x11_window _x11_window; + P3D_window_handle_osx_cgcontext _osx_cgcontext; } _handle; } P3D_window_handle; @@ -913,6 +924,7 @@ P3D_instance_feed_url_stream_func(P3D_instance *instance, int unique_id, typedef enum { P3D_ET_none = 0, P3D_ET_osx_event_record, + P3D_ET_osx_cocoa, } P3D_event_type; typedef struct { @@ -921,10 +933,72 @@ typedef struct { #endif } P3D_event_osx_event_record; +// This enum reimplements NPCocoaEventTyped, used below. +typedef enum { + P3DCocoaEventDrawRect = 1, + P3DCocoaEventMouseDown, + P3DCocoaEventMouseUp, + P3DCocoaEventMouseMoved, + P3DCocoaEventMouseEntered, + P3DCocoaEventMouseExited, + P3DCocoaEventMouseDragged, + P3DCocoaEventKeyDown, + P3DCocoaEventKeyUp, + P3DCocoaEventFlagsChanged, + P3DCocoaEventFocusChanged, + P3DCocoaEventWindowFocusChanged, + P3DCocoaEventScrollWheel, + P3DCocoaEventTextInput +} P3DCocoaEventType; + +// This structure reimplements NPCocoaEvent, to pass the complex +// cocoa event structures as generated by NPAPI. +typedef struct { + P3DCocoaEventType type; + unsigned int version; + union { + struct { + unsigned int modifierFlags; + double pluginX; + double pluginY; + int buttonNumber; + int clickCount; + double deltaX; + double deltaY; + double deltaZ; + } mouse; + struct { + unsigned int modifierFlags; + const wchar_t *characters; + const wchar_t *charactersIgnoringModifiers; + bool isARepeat; + unsigned short keyCode; + } key; + struct { + CGContextRef context; + double x; + double y; + double width; + double height; + } draw; + struct { + bool hasFocus; + } focus; + struct { + const wchar_t *text; + } text; + } data; +} P3DCocoaEvent; + +typedef struct { + P3DCocoaEvent _event; +} P3D_event_osx_cocoa; + typedef struct { P3D_event_type _event_type; union { P3D_event_osx_event_record _osx_event_record; + P3D_event_osx_cocoa _osx_cocoa; } _event; } P3D_event_data; diff --git a/direct/src/plugin_npapi/nppanda3d_common.h b/direct/src/plugin_npapi/nppanda3d_common.h index 65bc3bb2cb..4affdc3884 100644 --- a/direct/src/plugin_npapi/nppanda3d_common.h +++ b/direct/src/plugin_npapi/nppanda3d_common.h @@ -107,6 +107,18 @@ struct UC_NPString { #define HAS_PLUGIN_THREAD_ASYNC_CALL 1 #endif +// We also need to know whether we have Apple's new Cocoa-based +// drawing and event callbacks. +#if defined(NPVERS_MACOSX_HAS_EVENT_MODELS) && NP_VERSION_MINOR >= NPVERS_MACOSX_HAS_EVENT_MODELS +#define MACOSX_HAS_EVENT_MODELS 1 +#endif + +// No one defined a symbol for the introduction of the Cocoa drawing, +// but it appears to have been version 19. +#if NP_VERSION_MINOR >= 19 +#define MACOSX_HAS_COREGRAPHICS_DRAWING_MODEL 1 +#endif + // Appears in startup.cxx. extern NPNetscapeFuncs *browser; diff --git a/direct/src/plugin_npapi/ppInstance.cxx b/direct/src/plugin_npapi/ppInstance.cxx index 5e5522ff2a..58ccee4c8f 100644 --- a/direct/src/plugin_npapi/ppInstance.cxx +++ b/direct/src/plugin_npapi/ppInstance.cxx @@ -48,11 +48,15 @@ PPInstance::FileDatas PPInstance::_file_datas; //////////////////////////////////////////////////////////////////// PPInstance:: PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode, - int16_t argc, char *argn[], char *argv[], NPSavedData *saved) { + int16_t argc, char *argn[], char *argv[], NPSavedData *saved, + P3D_window_handle_type window_handle_type, + P3D_event_type event_type) { _p3d_inst = NULL; _npp_instance = instance; _npp_mode = mode; + _window_handle_type = window_handle_type; + _event_type = event_type; _script_object = NULL; _failed = false; _started = false; @@ -79,6 +83,10 @@ PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode, _got_instance_url = false; _got_window = false; _python_window_open = false; + +#ifdef __APPLE__ + _request_timer = NULL; +#endif // __APPLE__ } //////////////////////////////////////////////////////////////////// @@ -90,6 +98,14 @@ PPInstance:: ~PPInstance() { cleanup_window(); +#ifdef __APPLE__ + if (_request_timer != NULL) { + CFRunLoopTimerInvalidate(_request_timer); + CFRelease(_request_timer); + _request_timer = NULL; + } +#endif // __APPLE__ + if (_p3d_inst != NULL) { P3D_instance_finish(_p3d_inst); _p3d_inst = NULL; @@ -124,7 +140,8 @@ PPInstance:: void PPInstance:: begin() { // On Windows and Linux, we must insist on having this call. OSX - // doesn't necessarily require it. + // doesn't necessarily require it (which is lucky, since it appears + // that Safari doesn't necessarily provide it!) #ifndef __APPLE__ if (!has_plugin_thread_async_call) { nout << "Browser version insufficient: we require at least NPAPI version 0.19.\n"; @@ -677,17 +694,30 @@ handle_event(void *event) { return retval; } -#ifdef __APPLE__ P3D_event_data edata; memset(&edata, 0, sizeof(edata)); - edata._event_type = P3D_ET_osx_event_record; - edata._event._osx_event_record._event = (EventRecord *)event; + edata._event_type = _event_type; + EventAuxData aux_data; + if (_event_type == P3D_ET_osx_event_record) { +#ifdef __APPLE__ + edata._event._osx_event_record._event = (EventRecord *)event; +#endif // __APPLE__ + +#ifdef MACOSX_HAS_EVENT_MODELS + } else if (_event_type == P3D_ET_osx_cocoa) { + // Copy the NPCocoaEvent structure componentwise into a + // P3DCocoaEvent structure. + NPCocoaEvent *np_event = (NPCocoaEvent *)event; + P3DCocoaEvent *p3d_event = &edata._event._osx_cocoa._event; + copy_cocoa_event(p3d_event, np_event, aux_data); +#endif // MACOSX_HAS_EVENT_MODELS + + } + if (P3D_instance_handle_event(_p3d_inst, &edata)) { retval = true; } -#endif // __APPLE__ - return retval; } @@ -962,14 +992,18 @@ request_ready(P3D_instance *instance) { PPInstance *inst = (PPInstance *)(instance->_user_data); assert(inst != NULL); + { + static int n = 0; + nout << "request_ready " << ++n << "\n"; + } + if (has_plugin_thread_async_call) { #ifdef HAS_PLUGIN_THREAD_ASYNC_CALL // Since we are running at least Gecko 1.9, and we have this very // useful function, let's use it to ask the browser to call us back // in the main thread. - if ((void *)browser->pluginthreadasynccall != (void *)NULL) { - browser->pluginthreadasynccall(inst->_npp_instance, browser_sync_callback, NULL); - } + assert((void *)browser->pluginthreadasynccall != (void *)NULL); + browser->pluginthreadasynccall(inst->_npp_instance, browser_sync_callback, NULL); #endif // HAS_PLUGIN_THREAD_ASYNC_CALL } else { @@ -986,8 +1020,28 @@ request_ready(P3D_instance *instance) { PostMessage((HWND)(win->window), WM_USER, 0, 0); } #endif // _WIN32 - // On Mac and Linux, we ignore this asynchronous event, and rely on - // detecting it within HandleEvent() and similar callbacks. + +#ifdef __APPLE__ + // Use an OSX timer to forward this event to the main thread. + + // Stop any previously-started timer--we don't need more than one. + if (inst->_request_timer != NULL) { + CFRunLoopTimerInvalidate(inst->_request_timer); + CFRelease(inst->_request_timer); + inst->_request_timer = NULL; + } + + // And start a new one. + CFRunLoopTimerContext timer_context; + memset(&timer_context, 0, sizeof(timer_context)); + timer_context.info = inst; + inst->_request_timer = CFRunLoopTimerCreate + (NULL, 0, 0, 0, 0, timer_callback, &timer_context); + CFRunLoopRef run_loop = CFRunLoopGetMain(); + CFRunLoopAddTimer(run_loop, inst->_request_timer, kCFRunLoopCommonModes); +#endif // __APPLE__ + + // Doesn't appear to be a reliable way to simulate this in Linux. } } @@ -1380,14 +1434,17 @@ send_window() { y = 0; #elif defined(__APPLE__) - NP_Port *port = (NP_Port *)_window.window; - parent_window._window_handle_type = P3D_WHT_osx_port; - parent_window._handle._osx_port._port = port->port; - /* - NP_CGContext *context = (NP_CGContext *)_window.window; - parent_window._context = context->context; - parent_window._window = (WindowRef)context->window; - */ + parent_window._window_handle_type = _window_handle_type; + if (_window_handle_type == P3D_WHT_osx_port) { + NP_Port *port = (NP_Port *)_window.window; + parent_window._handle._osx_port._port = port->port; + } else if (_window_handle_type == P3D_WHT_osx_cgcontext) { + NP_CGContext *context = (NP_CGContext *)_window.window; + if (context != NULL) { + parent_window._handle._osx_cgcontext._context = context->context; + parent_window._handle._osx_cgcontext._window = (WindowRef)context->window; + } + } #elif defined(HAVE_X11) // We make it an 'unsigned long' instead of 'Window' @@ -1410,14 +1467,17 @@ send_window() { } #elif defined(__APPLE__) - NP_Port *port = (NP_Port *)_window.window; - parent_window._window_handle_type = P3D_WHT_osx_port; - parent_window._handle._osx_port._port = port->port; - /* - NP_CGContext *context = (NP_CGContext *)_window.window; - parent_window._context = context->context; - parent_window._window = (WindowRef)context->window; - */ + parent_window._window_handle_type = _window_handle_type; + if (_window_handle_type == P3D_WHT_osx_port) { + NP_Port *port = (NP_Port *)_window.window; + parent_window._handle._osx_port._port = port->port; + } else if (_window_handle_type == P3D_WHT_osx_cgcontext) { + NP_CGContext *context = (NP_CGContext *)_window.window; + if (context != NULL) { + parent_window._handle._osx_cgcontext._context = context->context; + parent_window._handle._osx_cgcontext._window = (WindowRef)context->window; + } + } #elif defined(HAVE_X11) unsigned long win; @@ -1440,7 +1500,7 @@ send_window() { #endif P3D_window_type window_type = P3D_WT_embedded; - if (_window.window == NULL) { + if (_window.window == NULL && _event_type != P3D_ET_osx_cocoa) { // No parent window: it must be a hidden window. window_type = P3D_WT_hidden; } else if (_window.width == 0 || _window.height == 0) { @@ -1654,6 +1714,156 @@ window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { } #endif // _WIN32 +#ifdef MACOSX_HAS_EVENT_MODELS +//////////////////////////////////////////////////////////////////// +// Function: PPInstance::copy_cocoa_event +// Access: Private, Static +// Description: Copies the NPCocoaEvent structure componentwise into +// a P3DCocoaEvent structure, for passing into the core +// API. +// +// The aux_data object is used to manage temporary +// storage on the strings created for the event. +//////////////////////////////////////////////////////////////////// +void PPInstance:: +copy_cocoa_event(P3DCocoaEvent *p3d_event, NPCocoaEvent *np_event, + EventAuxData &aux_data) { + p3d_event->version = np_event->version; + + switch (np_event->type) { + case NPCocoaEventDrawRect: + p3d_event->type = P3DCocoaEventDrawRect; + break; + case NPCocoaEventMouseDown: + p3d_event->type = P3DCocoaEventMouseDown; + break; + case NPCocoaEventMouseUp: + p3d_event->type = P3DCocoaEventMouseUp; + break; + case NPCocoaEventMouseMoved: + p3d_event->type = P3DCocoaEventMouseMoved; + break; + case NPCocoaEventMouseEntered: + p3d_event->type = P3DCocoaEventMouseEntered; + break; + case NPCocoaEventMouseExited: + p3d_event->type = P3DCocoaEventMouseExited; + break; + case NPCocoaEventMouseDragged: + p3d_event->type = P3DCocoaEventMouseDragged; + break; + case NPCocoaEventKeyDown: + p3d_event->type = P3DCocoaEventKeyDown; + break; + case NPCocoaEventKeyUp: + p3d_event->type = P3DCocoaEventKeyUp; + break; + case NPCocoaEventFlagsChanged: + p3d_event->type = P3DCocoaEventFlagsChanged; + break; + case NPCocoaEventFocusChanged: + p3d_event->type = P3DCocoaEventFocusChanged; + break; + case NPCocoaEventWindowFocusChanged: + p3d_event->type = P3DCocoaEventWindowFocusChanged; + break; + case NPCocoaEventScrollWheel: + p3d_event->type = P3DCocoaEventScrollWheel; + break; + case NPCocoaEventTextInput: + p3d_event->type = P3DCocoaEventTextInput; + break; + } + + switch (np_event->type) { + case NPCocoaEventDrawRect: + p3d_event->data.draw.context = np_event->data.draw.context; + p3d_event->data.draw.x = np_event->data.draw.x; + p3d_event->data.draw.y = np_event->data.draw.y; + p3d_event->data.draw.width = np_event->data.draw.width; + p3d_event->data.draw.height = np_event->data.draw.height; + break; + + case NPCocoaEventMouseDown: + case NPCocoaEventMouseUp: + case NPCocoaEventMouseMoved: + case NPCocoaEventMouseEntered: + case NPCocoaEventMouseExited: + case NPCocoaEventMouseDragged: + case NPCocoaEventScrollWheel: + p3d_event->data.mouse.modifierFlags = np_event->data.mouse.modifierFlags; + p3d_event->data.mouse.pluginX = np_event->data.mouse.pluginX; + p3d_event->data.mouse.pluginY = np_event->data.mouse.pluginY; + p3d_event->data.mouse.buttonNumber = np_event->data.mouse.buttonNumber; + p3d_event->data.mouse.clickCount = np_event->data.mouse.clickCount; + p3d_event->data.mouse.deltaX = np_event->data.mouse.deltaX; + p3d_event->data.mouse.deltaY = np_event->data.mouse.deltaY; + p3d_event->data.mouse.deltaZ = np_event->data.mouse.deltaZ; + break; + + case NPCocoaEventKeyDown: + case NPCocoaEventKeyUp: + case NPCocoaEventFlagsChanged: + p3d_event->data.key.modifierFlags = np_event->data.key.modifierFlags; + p3d_event->data.key.characters = + make_ansi_string(aux_data._characters, np_event->data.key.characters); + p3d_event->data.key.charactersIgnoringModifiers = + make_ansi_string(aux_data._characters_im, np_event->data.key.charactersIgnoringModifiers); + p3d_event->data.key.isARepeat = np_event->data.key.isARepeat; + p3d_event->data.key.keyCode = np_event->data.key.keyCode; + break; + + case NPCocoaEventFocusChanged: + case NPCocoaEventWindowFocusChanged: + p3d_event->data.focus.hasFocus = np_event->data.focus.hasFocus; + break; + + case NPCocoaEventTextInput: + p3d_event->data.text.text = + make_ansi_string(aux_data._text, np_event->data.text.text); + break; + } +} +#endif // MACOSX_HAS_EVENT_MODELS + +#ifdef MACOSX_HAS_EVENT_MODELS +//////////////////////////////////////////////////////////////////// +// Function: PPInstance::make_ansi_string +// Access: Private, Static +// Description: OSX only: Fills result with the unicode characters in +// the NPNSString. Also returns result.c_str(). +//////////////////////////////////////////////////////////////////// +const wchar_t *PPInstance:: +make_ansi_string(wstring &result, NPNSString *ns_string) { + // An NPNSString is really just an NSString, which is itself just a + // CFString. + CFStringRef cfstr = (CFStringRef)ns_string; + CFIndex length = CFStringGetLength(cfstr); + + result.clear(); + for (CFIndex i = 0; i < length; ++i) { + result += (wchar_t)CFStringGetCharacterAtIndex(cfstr, i); + } + + return result.c_str(); +} +#endif // MACOSX_HAS_EVENT_MODELS + +#ifdef __APPLE__ +//////////////////////////////////////////////////////////////////// +// Function: PPInstance::timer_callback +// Access: Private, Static +// Description: OSX only: this callback is associated with a +// CFRunLoopTimer; it's used to forward request messages +// to the main thread. +//////////////////////////////////////////////////////////////////// +void PPInstance:: +timer_callback(CFRunLoopTimerRef timer, void *info) { + PPInstance *self = (PPInstance *)info; + self->handle_request_loop(); +} +#endif // __APPLE__ + //////////////////////////////////////////////////////////////////// // Function: PPInstance::StreamingFileData::Constructor // Access: Public diff --git a/direct/src/plugin_npapi/ppInstance.h b/direct/src/plugin_npapi/ppInstance.h index 4582b0d15b..69c08e852f 100644 --- a/direct/src/plugin_npapi/ppInstance.h +++ b/direct/src/plugin_npapi/ppInstance.h @@ -35,7 +35,9 @@ class PPDownloadRequest; class PPInstance { public: PPInstance(NPMIMEType pluginType, NPP instance, uint16_t mode, - int16_t argc, char *argn[], char *argv[], NPSavedData *saved); + int16_t argc, char *argn[], char *argv[], NPSavedData *saved, + P3D_window_handle_type window_handle_type, + P3D_event_type event_type); ~PPInstance(); void begin(); @@ -99,9 +101,28 @@ private: window_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam); #endif // _WIN32 + class EventAuxData { + public: + wstring _characters; + wstring _characters_im; + wstring _text; + }; +#ifdef MACOSX_HAS_EVENT_MODELS + static void copy_cocoa_event(P3DCocoaEvent *p3d_event, + NPCocoaEvent *np_event, + EventAuxData &aux_data); + static const wchar_t *make_ansi_string(wstring &result, NPNSString *ns_string); +#endif // MACOSX_HAS_EVENT_MODELS + +#ifdef __APPLE__ + static void timer_callback(CFRunLoopTimerRef timer, void *info); +#endif // __APPLE__ + private: NPP _npp_instance; unsigned int _npp_mode; + P3D_window_handle_type _window_handle_type; + P3D_event_type _event_type; typedef vector Tokens; Tokens _tokens; @@ -165,6 +186,10 @@ private: LONG_PTR _orig_window_proc; #endif // _WIN32 +#ifdef __APPLE__ + CFRunLoopTimerRef _request_timer; +#endif // __APPLE__ + bool _python_window_open; PPToplevelObject *_script_object; diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx index d61762d249..18f4dca2c9 100644 --- a/direct/src/plugin_npapi/startup.cxx +++ b/direct/src/plugin_npapi/startup.cxx @@ -194,7 +194,12 @@ NP_Initialize(NPNetscapeFuncs *browserFuncs, #ifdef HAS_PLUGIN_THREAD_ASYNC_CALL // Check if the browser offers this very useful call. if (browser_major > 0 || browser_minor >= NPVERS_HAS_PLUGIN_THREAD_ASYNC_CALL) { - has_plugin_thread_async_call = true; + if ((void *)browser->pluginthreadasynccall == (void *)NULL) { + nout << "Browser should have PLUGIN_THREAD_ASYNC_CALL, but the pointer is NULL.\n"; + has_plugin_thread_async_call = false; + } else { + has_plugin_thread_async_call = true; + } } #endif @@ -287,30 +292,65 @@ NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char *argn[], char *argv[], NPSavedData *saved) { nout << "new instance " << instance << "\n"; - /* + P3D_window_handle_type window_handle_type = P3D_WHT_none; + P3D_event_type event_type = P3D_ET_none; + #ifdef __APPLE__ - // We have to request the "core graphics" drawing model to be + // The default drawing model for Apple is via the deprecated + // QuickDraw GrafPtr, and the default event model is via the + // deprecated Carbon EventRecord. + window_handle_type = P3D_WHT_osx_port; + event_type = P3D_ET_osx_event_record; + + // But we have to request the CoreGraphics drawing model to be // compatible with Snow Leopard. - NPBool supportsCoreGraphics = false; + NPBool supports_core_graphics = false; +#ifdef MACOSX_HAS_COREGRAPHICS_DRAWING_MODEL NPError err = browser->getvalue(instance, NPNVsupportsCoreGraphicsBool, - &supportsCoreGraphics); - if (err != NPERR_NO_ERROR || !supportsCoreGraphics) { - return NPERR_INCOMPATIBLE_VERSION_ERROR; - } - - // Set the drawing model - err = browser->setvalue(instance, - (NPPVariable)NPNVpluginDrawingModel, - (void *)NPDrawingModelCoreGraphics); + &supports_core_graphics); if (err != NPERR_NO_ERROR) { - return NPERR_INCOMPATIBLE_VERSION_ERROR; + supports_core_graphics = false; } -#endif - */ + + if (supports_core_graphics) { + // Set the drawing model + err = browser->setvalue(instance, + (NPPVariable)NPNVpluginDrawingModel, + (void *)NPDrawingModelCoreGraphics); + if (err == NPERR_NO_ERROR) { + window_handle_type = P3D_WHT_osx_cgcontext; + } + } +#endif // MACOSX_HAS_COREGRAPHICS_DRAWING_MODEL + nout << "supports_core_graphics = " << (bool)supports_core_graphics + << " window_handle_type = " << window_handle_type << "\n"; + + // And Snow Leopard also wants the new Cocoa event model. + NPBool supports_cocoa = false; +#ifdef MACOSX_HAS_EVENT_MODELS + err = browser->getvalue(instance, NPNVsupportsCocoaBool, &supports_cocoa); + if (err != NPERR_NO_ERROR) { + supports_cocoa = false; + } + + if (supports_cocoa) { + // Set the event model + err = browser->setvalue(instance, + (NPPVariable)NPPVpluginEventModel, + (void *)NPEventModelCocoa); + if (err == NPERR_NO_ERROR) { + event_type = P3D_ET_osx_cocoa; + } + } +#endif // MACOSX_HAS_EVENT_MODELS + nout << "supports_cocoa = " << (bool)supports_cocoa + << " event_type = " << event_type << "\n"; +#endif // __APPLE__ PPInstance *inst = new PPInstance(pluginType, instance, mode, - argc, argn, argv, saved); + argc, argn, argv, saved, + window_handle_type, event_type); instance->pdata = inst; nout << "new instance->pdata = " << inst << "\n";