• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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