1 /*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 University of Szeged
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24 * THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #if PLUGIN_ARCHITECTURE(X11)
29
30 #include "NetscapePlugin.h"
31
32 #include "WebEvent.h"
33 #include <WebCore/GraphicsContext.h>
34 #include <WebCore/NotImplemented.h>
35
36 #if PLATFORM(QT)
37 #include <QApplication>
38 #include <QDesktopWidget>
39 #include <QPixmap>
40 #include <QX11Info>
41 #elif PLATFORM(GTK)
42 #include <gdk/gdkx.h>
43 #include <WebCore/GtkVersioning.h>
44 #endif
45
46 using namespace WebCore;
47
48 namespace WebKit {
49
getPluginDisplay()50 static Display *getPluginDisplay()
51 {
52 #if PLATFORM(QT)
53 // At the moment, we only support gdk based plugins (like Flash) that use a different X connection.
54 // The code below has the same effect as this one:
55 // Display *gdkDisplay = gdk_x11_display_get_xdisplay(gdk_display_get_default());
56
57 QLibrary library(QLatin1String("libgdk-x11-2.0"), 0);
58 if (!library.load())
59 return 0;
60
61 typedef void *(*gdk_display_get_default_ptr)();
62 gdk_display_get_default_ptr gdk_display_get_default = (gdk_display_get_default_ptr)library.resolve("gdk_display_get_default");
63 if (!gdk_display_get_default)
64 return 0;
65
66 typedef void *(*gdk_x11_display_get_xdisplay_ptr)(void *);
67 gdk_x11_display_get_xdisplay_ptr gdk_x11_display_get_xdisplay = (gdk_x11_display_get_xdisplay_ptr)library.resolve("gdk_x11_display_get_xdisplay");
68 if (!gdk_x11_display_get_xdisplay)
69 return 0;
70
71 return (Display*)gdk_x11_display_get_xdisplay(gdk_display_get_default());
72 #elif PLATFORM(GTK)
73 // Since we're a gdk/gtk app, we'll (probably?) have the same X connection as any gdk-based
74 // plugins, so we can return that. We might want to add other implementations here later.
75 return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
76 #else
77 return 0;
78 #endif
79 }
80
x11Display()81 static inline Display* x11Display()
82 {
83 #if PLATFORM(QT)
84 return QX11Info::display();
85 #elif PLATFORM(GTK)
86 return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
87 #else
88 return 0;
89 #endif
90 }
91
displayDepth()92 static inline int displayDepth()
93 {
94 #if PLATFORM(QT)
95 return QApplication::desktop()->x11Info().depth();
96 #elif PLATFORM(GTK)
97 return gdk_visual_get_depth(gdk_screen_get_system_visual(gdk_screen_get_default()));
98 #else
99 return 0;
100 #endif
101 }
102
rootWindowID()103 static inline unsigned long rootWindowID()
104 {
105 #if PLATFORM(QT)
106 return QX11Info::appRootWindow();
107 #elif PLATFORM(GTK)
108 return GDK_ROOT_WINDOW();
109 #else
110 return 0;
111 #endif
112 }
113
x11Screen()114 static inline int x11Screen()
115 {
116 #if PLATFORM(QT)
117 return QX11Info::appScreen();
118 #elif PLATFORM(GTK)
119 return gdk_screen_get_number(gdk_screen_get_default());
120 #else
121 return 0;
122 #endif
123 }
124
platformPostInitialize()125 bool NetscapePlugin::platformPostInitialize()
126 {
127 if (m_isWindowed)
128 return false;
129
130 if (!(m_pluginDisplay = getPluginDisplay()))
131 return false;
132
133 NPSetWindowCallbackStruct* callbackStruct = new NPSetWindowCallbackStruct;
134 callbackStruct->type = 0;
135 Display* display = x11Display();
136 int depth = displayDepth();
137 callbackStruct->display = display;
138 callbackStruct->depth = depth;
139
140 XVisualInfo visualTemplate;
141 visualTemplate.screen = x11Screen();
142 visualTemplate.depth = depth;
143 visualTemplate.c_class = TrueColor;
144 int numMatching;
145 XVisualInfo* visualInfo = XGetVisualInfo(display, VisualScreenMask | VisualDepthMask | VisualClassMask,
146 &visualTemplate, &numMatching);
147 ASSERT(visualInfo);
148 Visual* visual = visualInfo[0].visual;
149 ASSERT(visual);
150 XFree(visualInfo);
151
152 callbackStruct->visual = visual;
153 callbackStruct->colormap = XCreateColormap(display, rootWindowID(), visual, AllocNone);
154
155 m_npWindow.type = NPWindowTypeDrawable;
156 m_npWindow.window = 0;
157 m_npWindow.ws_info = callbackStruct;
158
159 callSetWindow();
160
161 return true;
162 }
163
platformDestroy()164 void NetscapePlugin::platformDestroy()
165 {
166 delete static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info);
167
168 if (m_drawable) {
169 XFreePixmap(x11Display(), m_drawable);
170 m_drawable = 0;
171 }
172 }
173
platformInvalidate(const IntRect &)174 bool NetscapePlugin::platformInvalidate(const IntRect&)
175 {
176 notImplemented();
177 return false;
178 }
179
platformGeometryDidChange()180 void NetscapePlugin::platformGeometryDidChange()
181 {
182 if (m_isWindowed) {
183 notImplemented();
184 return;
185 }
186
187 Display* display = x11Display();
188 if (m_drawable)
189 XFreePixmap(display, m_drawable);
190
191 m_drawable = XCreatePixmap(display, rootWindowID(), m_frameRect.width(), m_frameRect.height(), displayDepth());
192
193 XSync(display, false); // Make sure that the server knows about the Drawable.
194 }
195
platformPaint(GraphicsContext * context,const IntRect & dirtyRect,bool)196 void NetscapePlugin::platformPaint(GraphicsContext* context, const IntRect& dirtyRect, bool /*isSnapshot*/)
197 {
198 if (m_isWindowed) {
199 notImplemented();
200 return;
201 }
202
203 if (!m_isStarted) {
204 // FIXME: we should paint a missing plugin icon.
205 return;
206 }
207
208 if (context->paintingDisabled())
209 return;
210
211 ASSERT(m_drawable);
212
213 #if PLATFORM(QT)
214 QPainter* painter = context->platformContext();
215 painter->translate(m_frameRect.x(), m_frameRect.y());
216 #else
217 notImplemented();
218 return;
219 #endif
220
221 XEvent xevent;
222 memset(&xevent, 0, sizeof(XEvent));
223 XGraphicsExposeEvent& exposeEvent = xevent.xgraphicsexpose;
224 exposeEvent.type = GraphicsExpose;
225 exposeEvent.display = x11Display();
226 exposeEvent.drawable = m_drawable;
227
228 IntRect exposedRect(dirtyRect);
229 exposedRect.intersect(m_frameRect);
230 exposedRect.move(-m_frameRect.x(), -m_frameRect.y());
231 exposeEvent.x = exposedRect.x();
232 exposeEvent.y = exposedRect.y();
233
234 // Note: in transparent mode Flash thinks width is the right and height is the bottom.
235 // We should take it into account if we want to support transparency.
236 exposeEvent.width = exposedRect.width();
237 exposeEvent.height = exposedRect.height();
238
239 NPP_HandleEvent(&xevent);
240
241 if (m_pluginDisplay != x11Display())
242 XSync(m_pluginDisplay, false);
243
244 #if PLATFORM(QT)
245 QPixmap qtDrawable = QPixmap::fromX11Pixmap(m_drawable, QPixmap::ExplicitlyShared);
246 ASSERT(qtDrawable.depth() == static_cast<NPSetWindowCallbackStruct*>(m_npWindow.ws_info)->depth);
247 painter->drawPixmap(QPoint(exposedRect.x(), exposedRect.y()), qtDrawable, exposedRect);
248
249 painter->translate(-m_frameRect.x(), -m_frameRect.y());
250 #endif
251 }
252
initializeXEvent(XEvent & event)253 static inline void initializeXEvent(XEvent& event)
254 {
255 memset(&event, 0, sizeof(XEvent));
256 event.xany.serial = 0;
257 event.xany.send_event = false;
258 event.xany.display = x11Display();
259 event.xany.window = 0;
260 }
261
xTimeStamp(double timestampInSeconds)262 static inline uint64_t xTimeStamp(double timestampInSeconds)
263 {
264 return timestampInSeconds * 1000;
265 }
266
xKeyModifiers(const WebEvent & event)267 static inline unsigned xKeyModifiers(const WebEvent& event)
268 {
269 unsigned xModifiers = 0;
270 if (event.controlKey())
271 xModifiers |= ControlMask;
272 if (event.shiftKey())
273 xModifiers |= ShiftMask;
274 if (event.altKey())
275 xModifiers |= Mod1Mask;
276 if (event.metaKey())
277 xModifiers |= Mod4Mask;
278
279 return xModifiers;
280 }
281
282 template <typename XEventType>
setCommonMouseEventFields(XEventType & xEvent,const WebMouseEvent & webEvent,const WebCore::IntPoint & pluginLocation)283 static inline void setCommonMouseEventFields(XEventType& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation)
284 {
285 xEvent.root = rootWindowID();
286 xEvent.subwindow = 0;
287 xEvent.time = xTimeStamp(webEvent.timestamp());
288 xEvent.x = webEvent.position().x() - pluginLocation.x();
289 xEvent.y = webEvent.position().y() - pluginLocation.y();
290 xEvent.x_root = webEvent.globalPosition().x();
291 xEvent.y_root = webEvent.globalPosition().y();
292 xEvent.state = xKeyModifiers(webEvent);
293 xEvent.same_screen = true;
294 }
295
setXMotionEventFields(XEvent & xEvent,const WebMouseEvent & webEvent,const WebCore::IntPoint & pluginLocation)296 static inline void setXMotionEventFields(XEvent& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation)
297 {
298 XMotionEvent& xMotion = xEvent.xmotion;
299 setCommonMouseEventFields(xMotion, webEvent, pluginLocation);
300 xMotion.type = MotionNotify;
301 }
302
setXButtonEventFields(XEvent & xEvent,const WebMouseEvent & webEvent,const WebCore::IntPoint & pluginLocation)303 static inline void setXButtonEventFields(XEvent& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation)
304 {
305 XButtonEvent& xButton = xEvent.xbutton;
306 setCommonMouseEventFields(xButton, webEvent, pluginLocation);
307
308 xButton.type = (webEvent.type() == WebEvent::MouseDown) ? ButtonPress : ButtonRelease;
309 switch (webEvent.button()) {
310 case WebMouseEvent::LeftButton:
311 xButton.button = Button1;
312 break;
313 case WebMouseEvent::MiddleButton:
314 xButton.button = Button2;
315 break;
316 case WebMouseEvent::RightButton:
317 xButton.button = Button3;
318 break;
319 }
320 }
321
setXCrossingEventFields(XEvent & xEvent,const WebMouseEvent & webEvent,const WebCore::IntPoint & pluginLocation,int type)322 static inline void setXCrossingEventFields(XEvent& xEvent, const WebMouseEvent& webEvent, const WebCore::IntPoint& pluginLocation, int type)
323 {
324 XCrossingEvent& xCrossing = xEvent.xcrossing;
325 setCommonMouseEventFields(xCrossing, webEvent, pluginLocation);
326
327 xCrossing.type = type;
328 xCrossing.mode = NotifyNormal;
329 xCrossing.detail = NotifyDetailNone;
330 xCrossing.focus = false;
331 }
332
platformHandleMouseEvent(const WebMouseEvent & event)333 bool NetscapePlugin::platformHandleMouseEvent(const WebMouseEvent& event)
334 {
335 if (m_isWindowed)
336 return false;
337
338 XEvent xEvent;
339 initializeXEvent(xEvent);
340
341 switch (event.type()) {
342 case WebEvent::MouseDown:
343 case WebEvent::MouseUp:
344 setXButtonEventFields(xEvent, event, m_frameRect.location());
345 break;
346 case WebEvent::MouseMove:
347 setXMotionEventFields(xEvent, event, m_frameRect.location());
348 break;
349 }
350
351 return NPP_HandleEvent(&xEvent);
352 }
353
354 // We undefine these constants in npruntime_internal.h to avoid collision
355 // with WebKit and platform headers. Values are defined in X.h.
356 const int kKeyPressType = 2;
357 const int kKeyReleaseType = 3;
358 const int kFocusInType = 9;
359 const int kFocusOutType = 10;
360
platformHandleWheelEvent(const WebWheelEvent &)361 bool NetscapePlugin::platformHandleWheelEvent(const WebWheelEvent&)
362 {
363 notImplemented();
364 return false;
365 }
366
platformSetFocus(bool)367 void NetscapePlugin::platformSetFocus(bool)
368 {
369 notImplemented();
370 }
371
platformHandleMouseEnterEvent(const WebMouseEvent & event)372 bool NetscapePlugin::platformHandleMouseEnterEvent(const WebMouseEvent& event)
373 {
374 if (m_isWindowed)
375 return false;
376
377 XEvent xEvent;
378 initializeXEvent(xEvent);
379 setXCrossingEventFields(xEvent, event, m_frameRect.location(), EnterNotify);
380
381 return NPP_HandleEvent(&xEvent);
382 }
383
platformHandleMouseLeaveEvent(const WebMouseEvent & event)384 bool NetscapePlugin::platformHandleMouseLeaveEvent(const WebMouseEvent& event)
385 {
386 if (m_isWindowed)
387 return false;
388
389 XEvent xEvent;
390 initializeXEvent(xEvent);
391 setXCrossingEventFields(xEvent, event, m_frameRect.location(), LeaveNotify);
392
393 return NPP_HandleEvent(&xEvent);
394 }
395
setXKeyEventFields(XEvent & xEvent,const WebKeyboardEvent & webEvent)396 static inline void setXKeyEventFields(XEvent& xEvent, const WebKeyboardEvent& webEvent)
397 {
398 xEvent.xany.type = (webEvent.type() == WebEvent::KeyDown) ? kKeyPressType : kKeyReleaseType;
399 XKeyEvent& xKey = xEvent.xkey;
400 xKey.root = rootWindowID();
401 xKey.subwindow = 0;
402 xKey.time = xTimeStamp(webEvent.timestamp());
403 xKey.state = xKeyModifiers(webEvent);
404 xKey.keycode = webEvent.nativeVirtualKeyCode();
405
406 xKey.same_screen = true;
407
408 // Key events propagated to the plugin does not need to have position.
409 // source: https://developer.mozilla.org/en/NPEvent
410 xKey.x = 0;
411 xKey.y = 0;
412 xKey.x_root = 0;
413 xKey.y_root = 0;
414 }
415
platformHandleKeyboardEvent(const WebKeyboardEvent & event)416 bool NetscapePlugin::platformHandleKeyboardEvent(const WebKeyboardEvent& event)
417 {
418 // We don't generate other types of keyboard events via WebEventFactory.
419 ASSERT(event.type() == WebEvent::KeyDown || event.type() == WebEvent::KeyUp);
420
421 XEvent xEvent;
422 initializeXEvent(xEvent);
423 setXKeyEventFields(xEvent, event);
424
425 return NPP_HandleEvent(&xEvent);
426 }
427
428 } // namespace WebKit
429
430 #endif // PLUGIN_ARCHITECTURE(X11)
431