Home | History | Annotate | Download | only in qt
      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