Index: webkit/glue/plugins/webplugin_delegate_impl_gtk.cc |
=================================================================== |
--- webkit/glue/plugins/webplugin_delegate_impl_gtk.cc (revision 16673) |
+++ webkit/glue/plugins/webplugin_delegate_impl_gtk.cc (working copy) |
@@ -2,17 +2,6 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-// HACK: we need this #define in place before npapi.h is included for |
-// plugins to work. However, all sorts of headers include npapi.h, so |
-// the only way to be certain the define is in place is to put it |
-// here. You might ask, "Why not set it in npapi.h directly, or in |
-// this directory's SConscript, then?" but it turns out this define |
-// makes npapi.h include Xlib.h, which in turn defines a ton of symbols |
-// like None and Status, causing conflicts with the aforementioned |
-// many headers that include npapi.h. Ugh. |
-// See also plugin_host.cc. |
-#define MOZ_X11 1 |
- |
#include "webkit/glue/plugins/webplugin_delegate_impl.h" |
#include <string> |
@@ -27,6 +16,7 @@ |
#include "base/process_util.h" |
#include "base/stats_counters.h" |
#include "base/string_util.h" |
+#include "webkit/api/public/WebInputEvent.h" |
// #include "webkit/default_plugin/plugin_impl.h" |
#include "webkit/glue/glue_util.h" |
#include "webkit/glue/webplugin.h" |
@@ -36,7 +26,14 @@ |
#include "webkit/glue/plugins/plugin_list.h" |
#include "webkit/glue/plugins/plugin_stream_url.h" |
#include "webkit/glue/webkit_glue.h" |
+#if defined(OS_LINUX) |
+#include "third_party/npapi/bindings/npapi_x11.h" |
+#endif |
+using WebKit::WebKeyboardEvent; |
+using WebKit::WebInputEvent; |
+using WebKit::WebMouseEvent; |
+ |
WebPluginDelegate* WebPluginDelegate::Create( |
const FilePath& filename, |
const std::string& mime_type, |
@@ -63,13 +60,13 @@ |
windowed_did_set_window_(false), |
windowless_(false), |
plugin_(NULL), |
+ windowless_needs_set_window_(true), |
instance_(instance), |
pixmap_(NULL), |
+ first_event_time_(-1.0), |
parent_(containing_view), |
- quirks_(0) |
- { |
+ quirks_(0) { |
memset(&window_, 0, sizeof(window_)); |
- |
} |
WebPluginDelegateImpl::~WebPluginDelegateImpl() { |
@@ -120,7 +117,7 @@ |
// a valid window handle causes subtle bugs with plugins which retreive |
// the window handle and validate the same. The window handle can be |
// retreived via NPN_GetValue of NPNVnetscapeWindow. |
- // instance_->set_window_handle(parent_); |
+ instance_->set_window_handle(parent_); |
// CreateDummyWindowForActivation(); |
// handle_event_pump_messages_event_ = CreateEvent(NULL, TRUE, FALSE, NULL); |
} else { |
@@ -393,7 +390,7 @@ |
return; |
} |
- // XXX instance()->set_window_handle(windowed_handle_); |
+ instance()->set_window_handle(windowed_handle_); |
DCHECK(!instance()->windowless()); |
@@ -545,7 +542,8 @@ |
cairo_destroy(cairo); |
// Construct the paint message, targeting the pixmap. |
- XGraphicsExposeEvent event = {0}; |
+ NPEvent np_event = {0}; |
+ XGraphicsExposeEvent &event = np_event.xgraphicsexpose; |
event.type = GraphicsExpose; |
event.display = GDK_DISPLAY(); |
event.drawable = GDK_PIXMAP_XID(pixmap_); |
@@ -557,7 +555,7 @@ |
// Tell the plugin to paint into the pixmap. |
static StatsRate plugin_paint("Plugin.Paint"); |
StatsScope<StatsRate> scope(plugin_paint); |
- NPError err = instance()->NPP_HandleEvent(reinterpret_cast<XEvent*>(&event)); |
+ NPError err = instance()->NPP_HandleEvent(&np_event); |
DCHECK_EQ(err, NPERR_NO_ERROR); |
// Now copy the rendered image pixmap back into the drawing buffer. |
@@ -621,19 +619,202 @@ |
void WebPluginDelegateImpl::SetFocus() { |
DCHECK(instance()->windowless()); |
- NOTIMPLEMENTED(); |
- /* NPEvent focus_event; |
- focus_event.event = WM_SETFOCUS; |
- focus_event.wParam = 0; |
- focus_event.lParam = 0; |
+ NPEvent np_event = {0}; |
+ XFocusChangeEvent &event = np_event.xfocus; |
+ event.type = FocusIn; |
+ event.display = GDK_DISPLAY(); |
+ // Same values as Firefox. .serial and .window stay 0. |
+ event.mode = -1; |
+ event.detail = NotifyDetailNone; |
+ instance()->NPP_HandleEvent(&np_event); |
+} |
- instance()->NPP_HandleEvent(&focus_event);*/ |
+// Converts a WebInputEvent::Modifiers bitfield into a |
+// corresponding X modifier state. |
+static int GetXModifierState(int modifiers) { |
+ int x_state = 0; |
+ if (modifiers & WebInputEvent::ControlKey) |
+ x_state |= ControlMask; |
+ if (modifiers & WebInputEvent::ShiftKey) |
+ x_state |= ShiftMask; |
+ if (modifiers & WebInputEvent::AltKey) |
+ x_state |= Mod1Mask; |
+ if (modifiers & WebInputEvent::MetaKey) |
+ x_state |= Mod2Mask; |
+ if (modifiers & WebInputEvent::LeftButtonDown) |
+ x_state |= Button1Mask; |
+ if (modifiers & WebInputEvent::MiddleButtonDown) |
+ x_state |= Button2Mask; |
+ if (modifiers & WebInputEvent::RightButtonDown) |
+ x_state |= Button3Mask; |
+ // TODO(piman@google.com): There are other modifiers, e.g. Num Lock, that |
+ // should be set (and Firefox does), but we didn't keep the information in |
+ // the WebKit event. |
+ return x_state; |
} |
-bool WebPluginDelegateImpl::HandleEvent(NPEvent* event, |
- WebCursor* cursor) { |
- bool ret = instance()->NPP_HandleEvent(event) != 0; |
+static bool NPEventFromWebMouseEvent(const WebMouseEvent& event, |
+ Time timestamp, |
+ NPEvent *np_event) { |
+ np_event->xany.display = GDK_DISPLAY(); |
+ // NOTE: Firefox keeps xany.serial and xany.window as 0. |
+ int modifier_state = GetXModifierState(event.modifiers); |
+ |
+ Window root = GDK_ROOT_WINDOW(); |
+ switch (event.type) { |
+ case WebInputEvent::MouseMove: { |
+ np_event->type = MotionNotify; |
+ XMotionEvent &motion_event = np_event->xmotion; |
+ motion_event.root = root; |
+ motion_event.time = timestamp; |
+ motion_event.x = event.x; |
+ motion_event.y = event.y; |
+ motion_event.x_root = event.globalX; |
+ motion_event.y_root = event.globalY; |
+ motion_event.state = modifier_state; |
+ motion_event.is_hint = NotifyNormal; |
+ motion_event.same_screen = True; |
+ break; |
+ } |
+ case WebInputEvent::MouseLeave: |
+ case WebInputEvent::MouseEnter: { |
+ if (event.type == WebInputEvent::MouseEnter) { |
+ np_event->type = EnterNotify; |
+ } else { |
+ np_event->type = LeaveNotify; |
+ } |
+ XCrossingEvent &crossing_event = np_event->xcrossing; |
+ crossing_event.root = root; |
+ crossing_event.time = timestamp; |
+ crossing_event.x = event.x; |
+ crossing_event.y = event.y; |
+ crossing_event.x_root = event.globalX; |
+ crossing_event.y_root = event.globalY; |
+ crossing_event.mode = -1; // This is what Firefox sets it to. |
+ crossing_event.detail = NotifyDetailNone; |
+ crossing_event.same_screen = True; |
+ // TODO(piman@google.com): set this to the correct value. Firefox does. I |
+ // don't know where to get the information though, we get focus |
+ // notifications, but no unfocus. |
+ crossing_event.focus = 0; |
+ crossing_event.state = modifier_state; |
+ break; |
+ } |
+ case WebInputEvent::MouseUp: |
+ case WebInputEvent::MouseDown: { |
+ if (event.type == WebInputEvent::MouseDown) { |
+ np_event->type = ButtonPress; |
+ } else { |
+ np_event->type = ButtonRelease; |
+ } |
+ XButtonEvent &button_event = np_event->xbutton; |
+ button_event.root = root; |
+ button_event.time = timestamp; |
+ button_event.x = event.x; |
+ button_event.y = event.y; |
+ button_event.x_root = event.globalX; |
+ button_event.y_root = event.globalY; |
+ button_event.state = modifier_state; |
+ switch (event.button) { |
+ case WebMouseEvent::ButtonLeft: |
+ button_event.button = Button1; |
+ break; |
+ case WebMouseEvent::ButtonMiddle: |
+ button_event.button = Button2; |
+ break; |
+ case WebMouseEvent::ButtonRight: |
+ button_event.button = Button3; |
+ break; |
+ } |
+ button_event.same_screen = True; |
+ break; |
+ } |
+ default: |
+ NOTREACHED(); |
+ return false; |
+ } |
+ return true; |
+} |
+ |
+static bool NPEventFromWebKeyboardEvent(const WebKeyboardEvent& event, |
+ Time timestamp, |
+ NPEvent *np_event) { |
+ np_event->xany.display = GDK_DISPLAY(); |
+ // NOTE: Firefox keeps xany.serial and xany.window as 0. |
+ |
+ switch (event.type) { |
+ case WebKeyboardEvent::KeyDown: |
+ np_event->type = KeyPress; |
+ break; |
+ case WebKeyboardEvent::KeyUp: |
+ np_event->type = KeyRelease; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ return false; |
+ } |
+ XKeyEvent &key_event = np_event->xkey; |
+ key_event.send_event = False; |
+ key_event.display = GDK_DISPLAY(); |
+ // NOTE: Firefox keeps xany.serial and xany.window as 0. |
+ // TODO(piman@google.com): is this right for multiple screens ? |
+ key_event.root = DefaultRootWindow(key_event.display); |
+ key_event.time = timestamp; |
+ // NOTE: We don't have the correct information for x/y/x_root/y_root. Firefox |
+ // doesn't have it either, so we pass the same values. |
+ key_event.x = 0; |
+ key_event.y = 0; |
+ key_event.x_root = -1; |
+ key_event.y_root = -1; |
+ key_event.state = GetXModifierState(event.modifiers); |
+ key_event.keycode = event.nativeKeyCode; |
+ key_event.same_screen = True; |
+ return true; |
+} |
+ |
+static bool NPEventFromWebInputEvent(const WebInputEvent& event, |
+ Time timestamp, |
+ NPEvent* np_event) { |
+ switch (event.type) { |
+ case WebInputEvent::MouseMove: |
+ case WebInputEvent::MouseLeave: |
+ case WebInputEvent::MouseEnter: |
+ case WebInputEvent::MouseDown: |
+ case WebInputEvent::MouseUp: |
+ if (event.size < sizeof(WebMouseEvent)) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ return NPEventFromWebMouseEvent( |
+ *static_cast<const WebMouseEvent*>(&event), timestamp, np_event); |
+ case WebInputEvent::KeyDown: |
+ case WebInputEvent::KeyUp: |
+ if (event.size < sizeof(WebKeyboardEvent)) { |
+ NOTREACHED(); |
+ return false; |
+ } |
+ return NPEventFromWebKeyboardEvent( |
+ *static_cast<const WebKeyboardEvent*>(&event), timestamp, np_event); |
+ default: |
+ return false; |
+ } |
+} |
+ |
+bool WebPluginDelegateImpl::HandleInputEvent(const WebInputEvent& event, |
+ WebCursor* cursor) { |
+ DCHECK(windowless_) << "events should only be received in windowless mode"; |
+ |
+ if (first_event_time_ < 0.0) |
+ first_event_time_ = event.timeStampSeconds; |
+ Time timestamp = static_cast<Time>( |
+ (event.timeStampSeconds - first_event_time_) * 1.0e3); |
+ NPEvent np_event = {0}; |
+ if (!NPEventFromWebInputEvent(event, timestamp, &np_event)) { |
+ return false; |
+ } |
+ bool ret = instance()->NPP_HandleEvent(&np_event) != 0; |
+ |
#if 0 |
if (event->event == WM_MOUSEMOVE) { |
// Snag a reference to the current cursor ASAP in case the plugin modified |