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 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 51 PluginClientWrapper::~PluginClientWrapper() 52 { 53 destroy(false, false); 54 } 55 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 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 73 PluginContainerQt::~PluginContainerQt() 74 { 75 delete m_clientWrapper; 76 m_pluginView->setPlatformPluginWidget(0); 77 } 78 79 void PluginContainerQt::on_clientClosed() 80 { 81 delete m_clientWrapper; 82 m_clientWrapper = 0; 83 } 84 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 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 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 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 146 void PluginContainerQt::focusOutEvent(QFocusEvent*) 147 { 148 if (Page* page = m_pluginView->parentFrame()->page()) 149 page->focusController()->setActive(false); 150 } 151