| /* |
| * Copyright (C) 2010 Apple Inc. All rights reserved. |
| * Copyright (C) 2010 University of Szeged |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #if PLUGIN_ARCHITECTURE(X11) && ENABLE(NETSCAPE_PLUGIN_API) |
| |
| #include "NetscapePlugin.h" |
| |
| #include "PluginController.h" |
| #include "WebEvent.h" |
| #include <WebCore/GraphicsContext.h> |
| #include <WebCore/NotImplemented.h> |
| |
| #if PLATFORM(QT) |
| #include <WebCore/QtX11ImageConversion.h> |
| #elif PLATFORM(GTK) |
| #include <gtk/gtk.h> |
| #ifndef GTK_API_VERSION_2 |
| #include <gtk/gtkx.h> |
| #endif |
| #include <gdk/gdkx.h> |
| #include <WebCore/GtkVersioning.h> |
| #elif PLATFORM(EFL) && defined(HAVE_ECORE_X) |
| #include <Ecore_X.h> |
| #endif |
| |
| #if USE(CAIRO) && !PLATFORM(WIN_CAIRO) |
| #include "PlatformContextCairo.h" |
| #include "RefPtrCairo.h" |
| #include <cairo/cairo-xlib.h> |
| #endif |
| |
| using namespace WebCore; |
| |
| namespace WebKit { |
| |
| static Display* getPluginDisplay() |
| { |
| #if PLATFORM(QT) |
| // At the moment, we only support gdk based plugins (like Flash) that use a different X connection. |
| // The code below has the same effect as this one: |
| // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default()); |
| |
| QLibrary library(QLatin1String("libgdk-x11-2.0"), 0); |
| if (!library.load()) |
| return 0; |
| |
| typedef void *(*gdk_init_check_ptr)(void*, void*); |
| gdk_init_check_ptr gdk_init_check = (gdk_init_check_ptr)library.resolve("gdk_init_check"); |
| if (!gdk_init_check) |
| return 0; |
| |
| typedef void *(*gdk_display_get_default_ptr)(); |
| gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default"); |
| if (!gdk_display_get_default) |
| return 0; |
| |
| typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *); |
| gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay"); |
| if (!gdk_x11_display_get_xdisplay) |
| return 0; |
| |
| gdk_init_check(0, 0); |
| return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default()); |
| #elif PLATFORM(GTK) |
| // Since we're a gdk/gtk app, we'll (probably?) have the same X connection as any gdk-based |
| // plugins, so we can return that. We might want to add other implementations here later. |
| return GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); |
| #elif PLATFORM(EFL) && defined(HAVE_ECORE_X) |
| return static_cast<Display*>(ecore_x_display_get()); |
| #else |
| return 0; |
| #endif |
| } |
| |
| static inline int x11Screen() |
| { |
| #if PLATFORM(QT) |
| return XDefaultScreen(NetscapePlugin::x11HostDisplay()); |
| #elif PLATFORM(GTK) |
| return gdk_screen_get_number(gdk_screen_get_default()); |
| #elif PLATFORM(EFL) && defined(HAVE_ECORE_X) |
| return ecore_x_screen_index_get(ecore_x_default_screen_get()); |
| #else |
| return 0; |
| #endif |
| } |
| |
| static inline int displayDepth() |
| { |
| #if PLATFORM(QT) |
| return XDefaultDepth(NetscapePlugin::x11HostDisplay(), x11Screen()); |
| #elif PLATFORM(GTK) |
| return gdk_visual_get_depth(gdk_screen_get_system_visual(gdk_screen_get_default())); |
| #elif PLATFORM(EFL) && defined(HAVE_ECORE_X) |
| return ecore_x_default_depth_get(NetscapePlugin::x11HostDisplay(), ecore_x_default_screen_get()); |
| #else |
| return 0; |
| #endif |
| } |
| |
| static inline unsigned long rootWindowID() |
| { |
| #if PLATFORM(QT) |
| return XDefaultRootWindow(NetscapePlugin::x11HostDisplay()); |
| #elif PLATFORM(GTK) |
| return GDK_ROOT_WINDOW(); |
| #elif PLATFORM(EFL) && defined(HAVE_ECORE_X) |
| return ecore_x_window_root_first_get(); |
| #else |
| return 0; |
| #endif |
| } |
| |
| #if PLATFORM(GTK) |
| static bool moduleMixesGtkSymbols(Module* module) |
| { |
| #ifdef GTK_API_VERSION_2 |
| return module->functionPointer<gpointer>("gtk_application_get_type"); |
| #else |
| return module->functionPointer<gpointer>("gtk_object_get_type"); |
| #endif |
| } |
| #endif |
| |
| Display* NetscapePlugin::x11HostDisplay() |
| { |
| #if PLATFORM(QT) |
| static Display* dedicatedDisplay = 0; |
| if (!dedicatedDisplay) |
| dedicatedDisplay = XOpenDisplay(0); |
| |
| ASSERT(dedicatedDisplay); |
| return dedicatedDisplay; |
| #elif PLATFORM(GTK) |
| return GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); |
| #elif PLATFORM(EFL) && defined(HAVE_ECORE_X) |
| return static_cast<Display*>(ecore_x_display_get()); |
| #else |
| return 0; |
| #endif |
| } |
| |
| #if PLATFORM(GTK) |
| static gboolean socketPlugRemovedCallback(GtkSocket*) |
| { |
| // Default action is to destroy the GtkSocket, so we just return TRUE here |
| // to be able to reuse the socket. For some obscure reason, newer versions |
| // of flash plugin remove the plug from the socket, probably because the plug |
| // created by the plugin is re-parented. |
| return TRUE; |
| } |
| #endif |
| |
| bool NetscapePlugin::platformPostInitializeWindowed(bool needsXEmbed, uint64_t windowID) |
| { |
| m_npWindow.type = NPWindowTypeWindow; |
| if (!needsXEmbed) { |
| notImplemented(); |
| return false; |
| } |
| |
| Display* display = x11HostDisplay(); |
| |
| #if PLATFORM(GTK) |
| // It seems flash needs the socket to be in the same process, |
| // I guess it uses gdk_window_lookup(), so we create a new socket here |
| // containing a plug with the UI process socket embedded. |
| m_platformPluginWidget = gtk_plug_new(static_cast<Window>(windowID)); |
| GtkWidget* socket = gtk_socket_new(); |
| g_signal_connect(socket, "plug-removed", G_CALLBACK(socketPlugRemovedCallback), 0); |
| gtk_container_add(GTK_CONTAINER(m_platformPluginWidget), socket); |
| gtk_widget_show(socket); |
| gtk_widget_show(m_platformPluginWidget); |
| |
| m_npWindow.window = GINT_TO_POINTER(gtk_socket_get_id(GTK_SOCKET(socket))); |
| GdkWindow* window = gtk_widget_get_window(socket); |
| NPSetWindowCallbackStruct* callbackStruct = static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info); |
| callbackStruct->display = GDK_WINDOW_XDISPLAY(window); |
| callbackStruct->visual = GDK_VISUAL_XVISUAL(gdk_window_get_visual(window)); |
| callbackStruct->depth = gdk_visual_get_depth(gdk_window_get_visual(window)); |
| callbackStruct->colormap = XCreateColormap(display, GDK_ROOT_WINDOW(), callbackStruct->visual, AllocNone); |
| #else |
| UNUSED_PARAM(windowID); |
| #endif |
| |
| XFlush(display); |
| |
| callSetWindow(); |
| |
| return true; |
| } |
| |
| bool NetscapePlugin::platformPostInitializeWindowless() |
| { |
| Display* display = x11HostDisplay(); |
| m_npWindow.type = NPWindowTypeDrawable; |
| m_npWindow.window = 0; |
| |
| int depth = displayDepth(); |
| #if PLATFORM(QT) |
| ASSERT(depth == 16 || depth == 24 || depth == 32); |
| #endif |
| NPSetWindowCallbackStruct* callbackStruct = static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info); |
| callbackStruct->display = display; |
| callbackStruct->depth = depth; |
| |
| XVisualInfo visualTemplate; |
| visualTemplate.screen = x11Screen(); |
| visualTemplate.depth = depth; |
| visualTemplate.c_class = TrueColor; |
| int numMatching; |
| XVisualInfo* visualInfo = XGetVisualInfo(display, VisualScreenMask | VisualDepthMask | VisualClassMask, |
| &visualTemplate, &numMatching); |
| ASSERT(visualInfo); |
| Visual* visual = visualInfo[0].visual; |
| ASSERT(visual); |
| XFree(visualInfo); |
| |
| callbackStruct->visual = visual; |
| callbackStruct->colormap = XCreateColormap(display, rootWindowID(), visual, AllocNone); |
| |
| callSetWindow(); |
| |
| return true; |
| } |
| |
| bool NetscapePlugin::platformPostInitialize() |
| { |
| #if PLATFORM(GTK) |
| if (moduleMixesGtkSymbols(m_pluginModule->module())) |
| return false; |
| #endif |
| |
| uint64_t windowID = 0; |
| bool needsXEmbed = false; |
| if (m_isWindowed) { |
| NPP_GetValue(NPPVpluginNeedsXEmbed, &needsXEmbed); |
| if (needsXEmbed) { |
| windowID = controller()->createPluginContainer(); |
| if (!windowID) |
| return false; |
| } else { |
| notImplemented(); |
| return false; |
| } |
| } |
| |
| if (!(m_pluginDisplay = getPluginDisplay())) |
| return false; |
| |
| NPSetWindowCallbackStruct* callbackStruct = new NPSetWindowCallbackStruct; |
| callbackStruct->type = 0; |
| m_npWindow.ws_info = callbackStruct; |
| |
| if (m_isWindowed) |
| return platformPostInitializeWindowed(needsXEmbed, windowID); |
| |
| return platformPostInitializeWindowless(); |
| } |
| |
| void NetscapePlugin::platformDestroy() |
| { |
| NPSetWindowCallbackStruct* callbackStruct = static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info); |
| Display* hostDisplay = x11HostDisplay(); |
| XFreeColormap(hostDisplay, callbackStruct->colormap); |
| delete callbackStruct; |
| |
| if (m_drawable) { |
| XFreePixmap(hostDisplay, m_drawable); |
| m_drawable = 0; |
| } |
| } |
| |
| bool NetscapePlugin::platformInvalidate(const IntRect&) |
| { |
| notImplemented(); |
| return false; |
| } |
| |
| void NetscapePlugin::platformGeometryDidChange() |
| { |
| if (m_isWindowed) { |
| uint64_t windowID = 0; |
| #if PLATFORM(GTK) |
| windowID = static_cast<uint64_t>(GDK_WINDOW_XID(gtk_plug_get_socket_window(GTK_PLUG(m_platformPluginWidget)))); |
| #endif |
| IntRect clipRect(m_clipRect); |
| clipRect.move(-m_frameRectInWindowCoordinates.x(), -m_frameRectInWindowCoordinates.y()); |
| controller()->windowedPluginGeometryDidChange(m_frameRectInWindowCoordinates, clipRect, windowID); |
| return; |
| } |
| |
| Display* display = x11HostDisplay(); |
| if (m_drawable) |
| XFreePixmap(display, m_drawable); |
| |
| if (m_pluginSize.isEmpty()) { |
| m_drawable = 0; |
| return; |
| } |
| |
| m_drawable = XCreatePixmap(display, rootWindowID(), m_pluginSize.width(), m_pluginSize.height(), displayDepth()); |
| |
| XSync(display, false); // Make sure that the server knows about the Drawable. |
| } |
| |
| void NetscapePlugin::platformVisibilityDidChange() |
| { |
| notImplemented(); |
| } |
| |
| void NetscapePlugin::platformPaint(GraphicsContext* context, const IntRect& dirtyRect, bool /*isSnapshot*/) |
| { |
| if (m_isWindowed) |
| return; |
| |
| if (!m_isStarted) { |
| // FIXME: we should paint a missing plugin icon. |
| return; |
| } |
| |
| if (context->paintingDisabled() || !m_drawable) |
| return; |
| |
| XEvent xevent; |
| memset(&xevent, 0, sizeof(XEvent)); |
| XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose; |
| exposeEvent.type = GraphicsExpose; |
| exposeEvent.display = x11HostDisplay(); |
| exposeEvent.drawable = m_drawable; |
| |
| IntRect exposedRect(dirtyRect); |
| exposeEvent.x = exposedRect.x(); |
| exposeEvent.y = exposedRect.y(); |
| |
| // Note: in transparent mode Flash thinks width is the right and height is the bottom. |
| // We should take it into account if we want to support transparency. |
| exposeEvent.width = exposedRect.width(); |
| exposeEvent.height = exposedRect.height(); |
| |
| NPP_HandleEvent(&xevent); |
| |
| if (m_pluginDisplay != x11HostDisplay()) |
| XSync(m_pluginDisplay, false); |
| |
| #if PLATFORM(QT) |
| XImage* xImage = XGetImage(NetscapePlugin::x11HostDisplay(), m_drawable, exposedRect.x(), exposedRect.y(), |
| exposedRect.width(), exposedRect.height(), ULONG_MAX, ZPixmap); |
| QPainter* painter = context->platformContext(); |
| painter->drawImage(QPoint(exposedRect.x(), exposedRect.y()), qimageFromXImage(xImage), exposedRect); |
| |
| XDestroyImage(xImage); |
| #elif PLATFORM(GTK) || (PLATFORM(EFL) && USE(CAIRO)) |
| RefPtr<cairo_surface_t> drawableSurface = adoptRef(cairo_xlib_surface_create(m_pluginDisplay, |
| m_drawable, |
| static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info)->visual, |
| m_pluginSize.width(), |
| m_pluginSize.height())); |
| cairo_t* cr = context->platformContext()->cr(); |
| cairo_save(cr); |
| |
| cairo_set_source_surface(cr, drawableSurface.get(), 0, 0); |
| |
| cairo_rectangle(cr, exposedRect.x(), exposedRect.y(), exposedRect.width(), exposedRect.height()); |
| cairo_clip(cr); |
| cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); |
| cairo_paint(cr); |
| |
| cairo_restore(cr); |
| #else |
| notImplemented(); |
| #endif |
| } |
| |
| static inline void initializeXEvent(XEvent& event) |
| { |
| memset(&event, 0, sizeof(XEvent)); |
| event.xany.serial = 0; |
| event.xany.send_event = false; |
| event.xany.display = NetscapePlugin::x11HostDisplay(); |
| event.xany.window = 0; |
| } |
| |
| static inline uint64_t xTimeStamp(double timestampInSeconds) |
| { |
| return timestampInSeconds * 1000; |
| } |
| |
| static inline unsigned xKeyModifiers(const WebEvent& event) |
| { |
| unsigned xModifiers = 0; |
| if (event.controlKey()) |
| xModifiers |= ControlMask; |
| if (event.shiftKey()) |
| xModifiers |= ShiftMask; |
| if (event.altKey()) |
| xModifiers |= Mod1Mask; |
| if (event.metaKey()) |
| xModifiers |= Mod4Mask; |
| |
| return xModifiers; |
| } |
| |
| template <typename XEventType, typename WebEventType> |
| static inline void setCommonMouseEventFields(XEventType& xEvent, const WebEventType& webEvent, const WebCore::IntPoint& pluginLocation) |
| { |
| xEvent.root = rootWindowID(); |
| xEvent.subwindow = 0; |
| xEvent.time = xTimeStamp(webEvent.timestamp()); |
| xEvent.x = webEvent.position().x() - pluginLocation.x(); |
| xEvent.y = webEvent.position().y() - pluginLocation.y(); |
| xEvent.x_root = webEvent.globalPosition().x(); |
| xEvent.y_root = webEvent.globalPosition().y(); |
| xEvent.state = xKeyModifiers(webEvent); |
| xEvent.same_screen = true; |
| } |
| |
| static inline void setXMotionEventFields(XEvent& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation) |
| { |
| XMotionEvent& xMotion = xEvent.xmotion; |
| setCommonMouseEventFields(xMotion, webEvent, pluginLocation); |
| xMotion.type = MotionNotify; |
| } |
| |
| static inline void setXButtonEventFields(XEvent& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation) |
| { |
| XButtonEvent& xButton = xEvent.xbutton; |
| setCommonMouseEventFields(xButton, webEvent, pluginLocation); |
| |
| xButton.type = (webEvent.type() == WebEvent::MouseDown) ? ButtonPress : ButtonRelease; |
| switch (webEvent.button()) { |
| case WebMouseEvent::LeftButton: |
| xButton.button = Button1; |
| break; |
| case WebMouseEvent::MiddleButton: |
| xButton.button = Button2; |
| break; |
| case WebMouseEvent::RightButton: |
| xButton.button = Button3; |
| break; |
| default: |
| ASSERT_NOT_REACHED(); |
| break; |
| } |
| } |
| |
| static inline void setXButtonEventFieldsByWebWheelEvent(XEvent& xEvent, const WebWheelEvent& webEvent, const WebCore::IntPoint& pluginLocation) |
| { |
| XButtonEvent& xButton = xEvent.xbutton; |
| setCommonMouseEventFields(xButton, webEvent, pluginLocation); |
| |
| xButton.type = ButtonPress; |
| FloatSize ticks = webEvent.wheelTicks(); |
| if (ticks.height()) { |
| if (ticks.height() > 0) |
| xButton.button = 4; // up |
| else |
| xButton.button = 5; // down |
| } else { |
| if (ticks.width() > 0) |
| xButton.button = 6; // left |
| else |
| xButton.button = 7; // right |
| } |
| } |
| |
| static inline void setXCrossingEventFields(XEvent& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation, int type) |
| { |
| XCrossingEvent& xCrossing = xEvent.xcrossing; |
| setCommonMouseEventFields(xCrossing, webEvent, pluginLocation); |
| |
| xCrossing.type = type; |
| xCrossing.mode = NotifyNormal; |
| xCrossing.detail = NotifyDetailNone; |
| xCrossing.focus = false; |
| } |
| |
| bool NetscapePlugin::platformHandleMouseEvent(const WebMouseEvent& event) |
| { |
| if (m_isWindowed) |
| return false; |
| |
| if ((event.type() == WebEvent::MouseDown || event.type() == WebEvent::MouseUp) |
| && event.button() == WebMouseEvent::RightButton |
| && quirks().contains(PluginQuirks::IgnoreRightClickInWindowlessMode)) |
| return false; |
| |
| XEvent xEvent; |
| initializeXEvent(xEvent); |
| |
| switch (event.type()) { |
| case WebEvent::MouseDown: |
| case WebEvent::MouseUp: |
| setXButtonEventFields(xEvent, event, convertToRootView(IntPoint())); |
| break; |
| case WebEvent::MouseMove: |
| setXMotionEventFields(xEvent, event, convertToRootView(IntPoint())); |
| break; |
| case WebEvent::NoType: |
| case WebEvent::Wheel: |
| case WebEvent::KeyDown: |
| case WebEvent::KeyUp: |
| case WebEvent::RawKeyDown: |
| case WebEvent::Char: |
| #if ENABLE(GESTURE_EVENTS) |
| case WebEvent::GestureScrollBegin: |
| case WebEvent::GestureScrollEnd: |
| #endif |
| #if ENABLE(TOUCH_EVENTS) |
| case WebEvent::TouchStart: |
| case WebEvent::TouchMove: |
| case WebEvent::TouchEnd: |
| case WebEvent::TouchCancel: |
| #endif |
| return false; |
| } |
| |
| return !NPP_HandleEvent(&xEvent); |
| } |
| |
| // We undefine these constants in npruntime_internal.h to avoid collision |
| // with WebKit and platform headers. Values are defined in X.h. |
| const int kKeyPressType = 2; |
| const int kKeyReleaseType = 3; |
| const int kFocusInType = 9; |
| const int kFocusOutType = 10; |
| |
| bool NetscapePlugin::platformHandleWheelEvent(const WebWheelEvent& event) |
| { |
| if (m_isWindowed) |
| return false; |
| |
| XEvent xEvent; |
| initializeXEvent(xEvent); |
| setXButtonEventFieldsByWebWheelEvent(xEvent, event, convertToRootView(IntPoint())); |
| |
| return !NPP_HandleEvent(&xEvent); |
| } |
| |
| void NetscapePlugin::platformSetFocus(bool focusIn) |
| { |
| if (m_isWindowed) |
| return; |
| |
| XEvent xEvent; |
| initializeXEvent(xEvent); |
| XFocusChangeEvent& focusEvent = xEvent.xfocus; |
| focusEvent.type = focusIn ? kFocusInType : kFocusOutType; |
| focusEvent.mode = NotifyNormal; |
| focusEvent.detail = NotifyDetailNone; |
| |
| NPP_HandleEvent(&xEvent); |
| } |
| |
| bool NetscapePlugin::wantsPluginRelativeNPWindowCoordinates() |
| { |
| return true; |
| } |
| |
| bool NetscapePlugin::platformHandleMouseEnterEvent(const WebMouseEvent& event) |
| { |
| if (m_isWindowed) |
| return false; |
| |
| XEvent xEvent; |
| initializeXEvent(xEvent); |
| setXCrossingEventFields(xEvent, event, convertToRootView(IntPoint()), EnterNotify); |
| |
| return !NPP_HandleEvent(&xEvent); |
| } |
| |
| bool NetscapePlugin::platformHandleMouseLeaveEvent(const WebMouseEvent& event) |
| { |
| if (m_isWindowed) |
| return false; |
| |
| XEvent xEvent; |
| initializeXEvent(xEvent); |
| setXCrossingEventFields(xEvent, event, convertToRootView(IntPoint()), LeaveNotify); |
| |
| return !NPP_HandleEvent(&xEvent); |
| } |
| |
| static inline void setXKeyEventFields(XEvent& xEvent, const WebKeyboardEvent& webEvent) |
| { |
| xEvent.xany.type = (webEvent.type() == WebEvent::KeyDown) ? kKeyPressType : kKeyReleaseType; |
| XKeyEvent& xKey = xEvent.xkey; |
| xKey.root = rootWindowID(); |
| xKey.subwindow = 0; |
| xKey.time = xTimeStamp(webEvent.timestamp()); |
| xKey.state = xKeyModifiers(webEvent); |
| xKey.keycode = webEvent.nativeVirtualKeyCode(); |
| |
| xKey.same_screen = true; |
| |
| // Key events propagated to the plugin does not need to have position. |
| // source: https://developer.mozilla.org/en/NPEvent |
| xKey.x = 0; |
| xKey.y = 0; |
| xKey.x_root = 0; |
| xKey.y_root = 0; |
| } |
| |
| bool NetscapePlugin::platformHandleKeyboardEvent(const WebKeyboardEvent& event) |
| { |
| // We don't generate other types of keyboard events via WebEventFactory. |
| ASSERT(event.type() == WebEvent::KeyDown || event.type() == WebEvent::KeyUp); |
| |
| XEvent xEvent; |
| initializeXEvent(xEvent); |
| setXKeyEventFields(xEvent, event); |
| |
| return !NPP_HandleEvent(&xEvent); |
| } |
| |
| } // namespace WebKit |
| |
| #endif // PLUGIN_ARCHITECTURE(X11) && ENABLE(NETSCAPE_PLUGIN_API) |