1 /*
2 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 #include "config.h"
21 #include "PluginContainerQt.h"
22
23 #include "FocusController.h"
24 #include "Frame.h"
25 #include "FrameView.h"
26 #include "Page.h"
27 #include "PlatformKeyboardEvent.h"
28 #include "PlatformWheelEvent.h"
29 #include "PluginView.h"
30 #include <QApplication>
31 #include <QX11Info>
32
33 using namespace WebCore;
34
PluginClientWrapper(QWidget * parent,WId client)35 PluginClientWrapper::PluginClientWrapper(QWidget* parent, WId client)
36 : QWidget(0, Qt::Popup)
37 {
38 // create a QWidget that adopts the plugin window id, do not give it
39 // a parent so that we don't end up handling events supposed to be
40 // handled by the QX11EmbedContainer.
41
42 // without the parent this will be considered a toplevel widget,
43 // and thus make Qt not quit the event loop after the last window
44 // has been closed. In order to work around this, we set the window
45 // type to Qt::Popup.
46
47 create(client, false, true);
48 m_parent = parent;
49 }
50
~PluginClientWrapper()51 PluginClientWrapper::~PluginClientWrapper()
52 {
53 destroy(false, false);
54 }
55
x11Event(XEvent * event)56 bool PluginClientWrapper::x11Event(XEvent* event)
57 {
58 // modify the event window id and insert it into the Qt event system.
59 event->xany.window = m_parent->effectiveWinId();
60 static_cast<QApplication*>(QApplication::instance())->x11ProcessEvent(event);
61 return true;
62 }
63
PluginContainerQt(PluginView * view,QWidget * parent)64 PluginContainerQt::PluginContainerQt(PluginView* view, QWidget* parent)
65 : QX11EmbedContainer(parent)
66 , m_pluginView(view)
67 , m_clientWrapper(0)
68 {
69 connect(this, SIGNAL(clientClosed()), this, SLOT(on_clientClosed()));
70 connect(this, SIGNAL(clientIsEmbedded()), this, SLOT(on_clientIsEmbedded()));
71 }
72
~PluginContainerQt()73 PluginContainerQt::~PluginContainerQt()
74 {
75 delete m_clientWrapper;
76 m_pluginView->setPlatformPluginWidget(0);
77 }
78
on_clientClosed()79 void PluginContainerQt::on_clientClosed()
80 {
81 delete m_clientWrapper;
82 m_clientWrapper = 0;
83 }
84
on_clientIsEmbedded()85 void PluginContainerQt::on_clientIsEmbedded()
86 {
87 delete m_clientWrapper;
88 m_clientWrapper = 0;
89
90 // Only create a QWidget wrapper for the plugin in the case it isn't in the
91 // Qt window mapper, and thus receiving events from the Qt event system.
92 // This way the PluginClientWrapper receives the scroll events and passes
93 // them to the parent. NOTICE: Native Qt based plugins running in process,
94 // will already be in the window mapper, and thus creating a wrapper, stops
95 // them from getting events from Qt, as they are redirected to the wrapper.
96 if (!QWidget::find(clientWinId()))
97 m_clientWrapper = new PluginClientWrapper(this, clientWinId());
98 }
99
redirectWheelEventsToParent(bool enable)100 void PluginContainerQt::redirectWheelEventsToParent(bool enable)
101 {
102 // steal wheel events from the plugin as we want to handle it. When doing this
103 // all button 4, 5, 6, and 7, ButtonPress and ButtonRelease events are passed
104 // to the x11Event handler of the PluginClientWrapper, which then changes the
105 // window id of the event to the parent of PluginContainer and puts the event
106 // back into the Qt event loop, so that we will actually scroll the parent
107 // frame.
108 for (int buttonNo = 4; buttonNo < 8; buttonNo++) {
109 if (enable)
110 XGrabButton(x11Info().display(), buttonNo, AnyModifier, clientWinId(),
111 false, ButtonPressMask, GrabModeAsync, GrabModeAsync, 0L, 0L);
112 else
113 XUngrabButton(x11Info().display(), buttonNo, AnyModifier, clientWinId());
114 }
115 }
116
x11Event(XEvent * event)117 bool PluginContainerQt::x11Event(XEvent* event)
118 {
119 switch (event->type) {
120 case EnterNotify:
121 // if the plugin window doesn't have focus we do not want to send wheel
122 // events to it, but to the parent frame, so let's redirect here.
123 redirectWheelEventsToParent(!hasFocus());
124 break;
125 case LeaveNotify:
126 // it is always safe to ungrab wheel events when the mouse leaves the
127 // plugin window.
128 redirectWheelEventsToParent(false);
129 break;
130 }
131
132 return QX11EmbedContainer::x11Event(event);
133 }
134
focusInEvent(QFocusEvent * event)135 void PluginContainerQt::focusInEvent(QFocusEvent* event)
136 {
137 // we got focus, stop redirecting the wheel events
138 redirectWheelEventsToParent(false);
139
140 if (Page* page = m_pluginView->parentFrame()->page())
141 page->focusController()->setActive(true);
142
143 m_pluginView->focusPluginElement();
144 }
145
focusOutEvent(QFocusEvent *)146 void PluginContainerQt::focusOutEvent(QFocusEvent*)
147 {
148 if (Page* page = m_pluginView->parentFrame()->page())
149 page->focusController()->setActive(false);
150 }
151