Bug 121065

Summary: DIV with scroll bar can't be scrolled with the mouse wheel
Product: [Applications] konqueror Reporter: Iñaki Baz Castillo <ibc>
Component: khtmlAssignee: Konqueror Developers <konq-bugs>
Status: RESOLVED FIXED    
Severity: normal CC: fh, ismail, paulpach
Priority: NOR    
Version: unspecified   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:

Description Iñaki Baz Castillo 2006-01-30 21:55:19 UTC
Version:           3.5.1 (using KDE 3.5.1, Debian Package 4:3.5.1-1 (testing/unstable))
Compiler:          Target: i486-linux-gnu
OS:                Linux (i686) release 2.6.14

The mouse wheel can't work in DIV's with scroll bar.

For example, go to his page: http://www.musicalibre.es

The left and right columns are not frames, they are DIV's. So, put the mouse over each one and try to scroll down the content of the div with the mouse wheel. It's impossible. The only way is to use the mouse wheel just over the scroll bar, that is not very usable.

In Firefox this doesn't occur, and it's not necessary to focus the div for scrolling it.
Comment 1 Thiago Macieira 2006-02-02 20:30:24 UTC
Confirmed. Annoying behaviour.

r500000
Comment 2 Iñaki Baz Castillo 2006-04-27 17:31:03 UTC
Note the the page I set as example (http://www.musicalibre.es) has changed so now there are not these DIV's with scroll bar. I'll try to find another web example.
Comment 3 Paul Pacheco 2006-05-19 15:19:23 UTC
I found some examples of this behaviour which is annoying me too to the point where I have to switch browser because our company uses this.

http://www.cssplay.co.uk/layouts/bodyfix.html
http://www.cssplay.co.uk/layouts/body2.html
http://www.cssplay.co.uk/layouts/body4.html
http://www.cssplay.co.uk/layouts/body5.html

Note firefox and IE work fine with these pages
Comment 4 Allan Sandfeld 2006-05-19 16:03:34 UTC
*** Bug 126897 has been marked as a duplicate of this bug. ***
Comment 5 Germain Garand 2007-01-24 15:57:06 UTC
SVN commit 626756 by ggarand:

implement scrolling of CSS containers with the mousewheel

BUG: 121065



 M  +53 -0     rendering/render_box.cpp  
 M  +2 -0      rendering/render_box.h  
 M  +2 -0      rendering/render_object.h  
 M  +5 -1      xml/dom_nodeimpl.cpp  


--- trunk/KDE/kdelibs/khtml/rendering/render_box.cpp #626755:626756
@@ -6,6 +6,7 @@
  *           (C) 2002-2003 Apple Computer, Inc.
  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
  *           (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
+ *           (C) 2007 Germain Garand (germain@ebooksfrance.org)
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -31,6 +32,7 @@
 #include <qpainter.h>
 
 #include "misc/loader.h"
+#include "rendering/render_form.h"
 #include "rendering/render_replaced.h"
 #include "rendering/render_canvas.h"
 #include "rendering/render_table.h"
@@ -41,8 +43,10 @@
 #include "misc/htmlhashes.h"
 #include "xml/dom_nodeimpl.h"
 #include "xml/dom_docimpl.h"
+#include "xml/dom2_eventsimpl.h"
 #include "html/html_elementimpl.h"
 
+#include <QWheelEvent>
 #include <khtmlview.h>
 #include <kdebug.h>
 #include <kglobal.h>
@@ -2204,6 +2208,55 @@
         return false;
 }
 
+bool RenderBox::handleEvent(const DOM::EventImpl& e) 
+{
+    if ( e.id() == EventImpl::KHTML_MOUSEWHEEL_EVENT && scrollsOverflow()) {
+
+        const MouseEventImpl& me = static_cast<const MouseEventImpl&>(e);
+        Qt::MouseButtons buttons = Qt::NoButton;
+        Qt::KeyboardModifiers state = 0;
+        Qt::Orientation orient = Qt::Vertical;
+
+        switch (me.button()) {
+        case 0:
+            buttons = Qt::LeftButton;
+            break;
+        case 1:
+            buttons = Qt::MidButton;
+            break;
+        case 2:
+            buttons = Qt::RightButton;
+            break;
+        default:
+            break;
+        }
+
+        if (me.orientation() == MouseEventImpl::OHorizontal)
+            orient = Qt::Horizontal;
+
+        int absx = 0;
+        int absy = 0;
+        absolutePosition(absx, absy);
+        absx += borderLeft()+paddingLeft();
+        absy += borderTop()+paddingTop();
+        QPoint p(me.clientX() - absx + canvas()->view()->contentsX(),
+                 me.clientY() - absy + canvas()->view()->contentsY());
+
+        QWheelEvent we(p, -me.detail()*40, buttons, state, orient);
+        KHTMLAssert(layer());
+        if (orient == Qt::Vertical) {
+            if (QWidget* w = dynamic_cast<QWidget*>( layer()->verticalScrollbar() ))
+                QApplication::sendEvent( w, &we);
+        } else {
+            if (QWidget* w = dynamic_cast<QWidget*>( layer()->horizontalScrollbar() ))
+                QApplication::sendEvent( w, &we);
+        }
+        if (we.isAccepted())
+            return true;
+    }
+    return RenderContainer::handleEvent(e);
+}
+
 void RenderBox::caretPos(int /*offset*/, int flags, int &_x, int &_y, int &width, int &height)
 {
 #if 0
--- trunk/KDE/kdelibs/khtml/rendering/render_box.h #626755:626756
@@ -120,6 +120,8 @@
 
     virtual int pageTopAfter(int y) const;
     virtual int crossesPageBreak(int t, int b) const;
+    
+    virtual bool handleEvent(const DOM::EventImpl& ev);
 
     int calcBoxWidth(int w) const;
     int calcBoxHeight(int h) const;
--- trunk/KDE/kdelibs/khtml/rendering/render_object.h #626755:626756
@@ -317,6 +317,8 @@
     DOM::DocumentImpl* document() const;
     DOM::NodeImpl* element() const { return isAnonymous() ? 0L : m_node; }
     DOM::NodeImpl* node() const { return m_node; }
+    
+    virtual bool handleEvent(const DOM::EventImpl&) { return false; };
 
    /**
      * returns the object containing this one. can be different from parent for
--- trunk/KDE/kdelibs/khtml/xml/dom_nodeimpl.cpp #626755:626756
@@ -623,8 +623,12 @@
     }
 }
 
-void NodeImpl::defaultEventHandler(EventImpl *)
+void NodeImpl::defaultEventHandler(EventImpl *e)
 {
+    if (e->isMouseEvent() && e->id() == EventImpl::KHTML_MOUSEWHEEL_EVENT && e->target() == this)
+        if (m_render && m_render->scrollsOverflow())
+            if (m_render->handleEvent(*e))
+                e->setDefaultHandled();
 }
 
 unsigned long NodeImpl::childNodeCount()
Comment 6 Germain Garand 2007-01-24 16:23:25 UTC
*** Bug 86224 has been marked as a duplicate of this bug. ***
Comment 7 Leo Savernik 2007-01-24 19:48:44 UTC
Note that this only fixes half the bug. You still can't scroll using the 
keyboard.
Comment 8 Germain Garand 2007-01-25 00:25:00 UTC
mmh, right but then this would only make sense if scrollable layers are made focusable, wouldn't it? 

I can't seem to find this in any spec, but OTOH as scrollbars are controls, it makes a lot of sense... I'll have a look.
Comment 9 Germain Garand 2007-01-25 15:26:02 UTC
SVN commit 627032 by ggarand:

elaborate on scrollable containers event handling: 
make them focusable and add keyboard events handling 
so as to make keyboard-only navigation possible.

CCBUG: 121065



 M  +50 -4     rendering/render_box.cpp  
 M  +22 -0     xml/dom_elementimpl.cpp  
 M  +2 -0      xml/dom_elementimpl.h  
 M  +0 -4      xml/dom_nodeimpl.cpp  


--- trunk/KDE/kdelibs/khtml/rendering/render_box.cpp #627031:627032
@@ -2210,8 +2210,12 @@
 
 bool RenderBox::handleEvent(const DOM::EventImpl& e) 
 {
-    if ( e.id() == EventImpl::KHTML_MOUSEWHEEL_EVENT && scrollsOverflow()) {
+    KHTMLAssert( scrollsOverflow() );
+    bool accepted = false;
 
+    switch ( e.id() ) {
+      case EventImpl::KHTML_MOUSEWHEEL_EVENT: {
+
         const MouseEventImpl& me = static_cast<const MouseEventImpl&>(e);
         Qt::MouseButtons buttons = Qt::NoButton;
         Qt::KeyboardModifiers state = 0;
@@ -2239,21 +2243,63 @@
         absolutePosition(absx, absy);
         absx += borderLeft()+paddingLeft();
         absy += borderTop()+paddingTop();
+
         QPoint p(me.clientX() - absx + canvas()->view()->contentsX(),
                  me.clientY() - absy + canvas()->view()->contentsY());
 
         QWheelEvent we(p, -me.detail()*40, buttons, state, orient);
         KHTMLAssert(layer());
         if (orient == Qt::Vertical) {
-            if (QWidget* w = dynamic_cast<QWidget*>( layer()->verticalScrollbar() ))
+            if (QWidget* w = layer()->verticalScrollbar())
                 QApplication::sendEvent( w, &we);
         } else {
-            if (QWidget* w = dynamic_cast<QWidget*>( layer()->horizontalScrollbar() ))
+            if (QWidget* w = layer()->horizontalScrollbar())
                 QApplication::sendEvent( w, &we);
         }
         if (we.isAccepted())
-            return true;
+            accepted = true;
+        break;
+      }
+      case EventImpl::KEYDOWN_EVENT:
+      case EventImpl::KEYUP_EVENT: 
+        break;
+      case EventImpl::KEYPRESS_EVENT:
+      {
+        if (!e.isKeyRelatedEvent()) break;
+        const KeyEventBaseImpl& domKeyEv = static_cast<const KeyEventBaseImpl &>(e);
+
+        QKeyEvent* const ke = domKeyEv.qKeyEvent();
+        QScrollBar* vbar = layer()->verticalScrollbar();
+        QScrollBar* hbar = layer()->horizontalScrollbar();
+        switch (ke->key()) {
+          case Qt::Key_PageUp:
+            if(vbar) vbar->triggerAction(QScrollBar::SliderPageStepSub);
+            break;
+          case Qt::Key_PageDown:
+            if(vbar) vbar->triggerAction(QScrollBar::SliderPageStepAdd);
+            break;
+          case Qt::Key_Up:
+            if(vbar) vbar->triggerAction(QScrollBar::SliderSingleStepSub);
+            break;
+          case Qt::Key_Down:
+            if(vbar) vbar->triggerAction(QScrollBar::SliderSingleStepAdd);
+            break;
+          case Qt::Key_Left:
+            if (hbar) hbar->triggerAction(QScrollBar::SliderSingleStepSub);
+            break;
+          case Qt::Key_Right:
+            if (hbar) hbar->triggerAction(QScrollBar::SliderSingleStepAdd);
+            break;
+          default:
+            break;
+        }
+        break;
+      }
+      default: 
+        break;
     }
+    if (accepted)
+        return true;
     return RenderContainer::handleEvent(e);
 }
 
--- trunk/KDE/kdelibs/khtml/xml/dom_elementimpl.cpp #627031:627032
@@ -626,6 +626,25 @@
         m_prefix->ref();
 }
 
+void ElementImpl::defaultEventHandler(EventImpl *e)
+{
+    if (m_render && m_render->scrollsOverflow()) {
+        switch( e->id() ) {
+          case EventImpl::KEYDOWN_EVENT:
+          case EventImpl::KEYUP_EVENT:
+          case EventImpl::KEYPRESS_EVENT:
+            if (!focused() || e->target() != this)
+              break;
+          // fall through
+          case EventImpl::KHTML_MOUSEWHEEL_EVENT:
+            if (m_render->handleEvent(*e))
+                e->setDefaultHandled();
+          default:
+            break;
+        }
+    }
+}
+
 void ElementImpl::createAttributeMap() const
 {
     namedAttrMap = new NamedAttrMapImpl(const_cast<ElementImpl*>(this));
@@ -789,6 +808,9 @@
 
 bool ElementImpl::isFocusable() const
 {
+    if (m_render && m_render->scrollsOverflow())
+        return true;
+
     // Only make editable elements selectable if its parent element
     // is not editable. FIXME: this is not 100% right as non-editable elements
     // within editable elements are focusable too.
--- trunk/KDE/kdelibs/khtml/xml/dom_elementimpl.h #627031:627032
@@ -209,6 +209,8 @@
     virtual void structureChanged();
     virtual void backwardsStructureChanged();
     virtual void attributeChanged(NodeImpl::Id attrId);
+    
+    virtual void defaultEventHandler(EventImpl *evt);
 
     virtual khtml::RenderStyle *styleForRenderer(khtml::RenderObject *parent);
     virtual khtml::RenderObject *createRenderer(khtml::RenderArena *, khtml::RenderStyle *);
--- trunk/KDE/kdelibs/khtml/xml/dom_nodeimpl.cpp #627031:627032
@@ -625,10 +625,6 @@
 
 void NodeImpl::defaultEventHandler(EventImpl *e)
 {
-    if (e->isMouseEvent() && e->id() == EventImpl::KHTML_MOUSEWHEEL_EVENT && e->target() == this)
-        if (m_render && m_render->scrollsOverflow())
-            if (m_render->handleEvent(*e))
-                e->setDefaultHandled();
 }
 
 unsigned long NodeImpl::childNodeCount()
Comment 10 David Lee 2007-08-11 11:29:49 UTC
Has this been committed into the most recent version (3.5.7)?
It's not working for me.
Comment 11 Bram Schoenmakers 2007-08-11 12:51:05 UTC
It should be in KDE 3.5.7, indeed.

So reopening because of comment #10.
Comment 12 Tommi Tervo 2007-08-13 08:56:27 UTC
Hmm, Germain didn't backport this fix to 3.5-branch, so it's fixed only in KDE4.