a7dadb0a73f4f41f022c9e8af01ec6f4c719dcd1
[WebKit-https.git] / WebCore / khtml / khtmlview.cpp
1 /* This file is part of the KDE project
2  *
3  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
4  *                     1999 Lars Knoll <knoll@kde.org>
5  *                     1999 Antti Koivisto <koivisto@kde.org>
6  *                     2000 Dirk Mueller <mueller@kde.org>
7  * Copyright (C) 2004 Apple Computer, Inc.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24 #include "khtmlview.moc"
25
26 #include "khtmlview.h"
27
28 #include "khtml_part.h"
29 #include "khtml_events.h"
30
31 #include "html/html_documentimpl.h"
32 #include "html/html_inlineimpl.h"
33 #include "html/html_formimpl.h"
34 #include "rendering/render_arena.h"
35 #include "rendering/render_object.h"
36 #include "rendering/render_canvas.h"
37 #include "rendering/render_style.h"
38 #include "rendering/render_replaced.h"
39 #include "rendering/render_line.h"
40 #include "rendering/render_text.h"
41 #include "xml/dom_nodeimpl.h"
42 #include "xml/dom2_eventsimpl.h"
43 #include "css/cssstyleselector.h"
44 #include "misc/htmlhashes.h"
45 #include "misc/helper.h"
46 #include "khtml_settings.h"
47 #include "khtml_printsettings.h"
48 #include "khtmlpart_p.h"
49
50 #include <kcursor.h>
51 #include <ksimpleconfig.h>
52 #include <kstandarddirs.h>
53 #include <kprinter.h>
54
55 #include <qtooltip.h>
56 #include <qpainter.h>
57 #include <qpaintdevicemetrics.h>
58 #include <kapplication.h>
59
60 #include <kimageio.h>
61 #include <assert.h>
62 #include <kdebug.h>
63 #include <kurldrag.h>
64 #include <qobjectlist.h>
65
66 #if APPLE_CHANGES
67 #include "KWQAccObjectCache.h"
68 #endif
69
70 #define PAINT_BUFFER_HEIGHT 128
71
72 // #define INSTRUMENT_LAYOUT_SCHEDULING 1
73
74 using namespace DOM;
75 using namespace khtml;
76 class KHTMLToolTip;
77
78 #ifndef QT_NO_TOOLTIP
79
80 class KHTMLToolTip : public QToolTip
81 {
82 public:
83     KHTMLToolTip(KHTMLView *view,  KHTMLViewPrivate* vp) : QToolTip(view->viewport())
84     {
85         m_view = view;
86         m_viewprivate = vp;
87     };
88
89 protected:
90     virtual void maybeTip(const QPoint &);
91
92 private:
93
94     KHTMLView *m_view;
95     KHTMLViewPrivate* m_viewprivate;
96 };
97
98 #endif
99
100 class KHTMLViewPrivate {
101     friend class KHTMLToolTip;
102 public:
103     KHTMLViewPrivate()
104     {
105         repaintRects = 0;
106         underMouse = 0;
107         clickNode = 0;
108         reset();
109 #if !APPLE_CHANGES
110         tp=0;
111         paintBuffer=0;
112         formCompletions=0;
113 #endif
114         layoutTimerId = 0;
115         delayedLayout = false;
116         mousePressed = false;
117 #ifndef QT_NO_TOOLTIP
118         tooltip = 0;
119 #endif
120         doFullRepaint = true;
121         isTransparent = false;
122 #if APPLE_CHANGES
123         vmode = hmode = QScrollView::Auto;
124         firstLayout = true;
125         needToInitScrollBars = true;
126 #else
127         prevScrollbarVisible = true;
128 #endif
129     }
130     ~KHTMLViewPrivate()
131     {
132 #if !APPLE_CHANGES
133         delete formCompletions;
134         delete tp; tp = 0;
135         delete paintBuffer; paintBuffer =0;
136 #endif
137         
138         if (underMouse)
139             underMouse->deref();
140         if (clickNode)
141             clickNode->deref();
142 #ifndef QT_NO_TOOLTIP
143         delete tooltip;
144 #endif
145         delete repaintRects;
146     }
147     void reset()
148     {
149         if (underMouse)
150             underMouse->deref();
151         underMouse = 0;
152         linkPressed = false;
153         useSlowRepaints = false;
154         dragTarget = 0;
155         borderTouched = false;
156 #if !APPLE_CHANGES
157 #ifndef KHTML_NO_SCROLLBARS
158         vmode = QScrollView::Auto;
159         hmode = QScrollView::Auto;
160 #else
161         vmode = QScrollView::AlwaysOff;
162         hmode = QScrollView::AlwaysOff;
163 #endif
164 #endif
165         scrollBarMoved = false;
166         ignoreWheelEvents = false;
167         borderX = 30;
168         borderY = 30;
169 #if !APPLE_CHANGES
170         clickX = -1;
171         clickY = -1;
172 #endif
173         prevMouseX = -1;
174         prevMouseY = -1;
175         clickCount = 0;
176         if (clickNode)
177             clickNode->deref();
178         clickNode = 0;
179         isDoubleClick = false;
180         scrollingSelf = false;
181         layoutTimerId = 0;
182         delayedLayout = false;
183         mousePressed = false;
184         doFullRepaint = true;
185         layoutSchedulingEnabled = true;
186         layoutSuppressed = false;
187         layoutCount = 0;
188 #if APPLE_CHANGES
189         firstLayout = true;
190 #endif
191         if (repaintRects)
192             repaintRects->clear();
193     }
194
195 #if !APPLE_CHANGES
196     QPainter *tp;
197     QPixmap  *paintBuffer;
198 #endif
199     NodeImpl *underMouse;
200
201     bool borderTouched:1;
202     bool borderStart:1;
203     bool scrollBarMoved:1;
204     bool doFullRepaint:1;
205     
206     QScrollView::ScrollBarMode vmode;
207     QScrollView::ScrollBarMode hmode;
208 #if !APPLE_CHANGES
209     bool prevScrollbarVisible;
210 #endif
211     bool linkPressed;
212     bool useSlowRepaints;
213     bool ignoreWheelEvents;
214
215     int borderX, borderY;
216 #if !APPLE_CHANGES
217     KSimpleConfig *formCompletions;
218
219     int clickX, clickY;
220 #endif
221     int clickCount;
222     NodeImpl *clickNode;
223     bool isDoubleClick;
224
225     int prevMouseX, prevMouseY;
226     bool scrollingSelf;
227     int layoutTimerId;
228     bool delayedLayout;
229     
230     bool layoutSchedulingEnabled;
231     bool layoutSuppressed;
232     int layoutCount;
233
234 #if APPLE_CHANGES
235     bool firstLayout;
236     bool needToInitScrollBars;
237 #endif
238     bool mousePressed;
239     bool isTransparent;
240 #ifndef QT_NO_TOOLTIP
241     KHTMLToolTip *tooltip;
242 #endif
243     
244     // Used by objects during layout to communicate repaints that need to take place only
245     // after all layout has been completed.
246     QPtrList<RenderObject::RepaintInfo>* repaintRects;
247     
248     Node dragTarget;
249 };
250
251 #ifndef QT_NO_TOOLTIP
252
253 void KHTMLToolTip::maybeTip(const QPoint& /*p*/)
254 {
255     DOM::NodeImpl *node = m_viewprivate->underMouse;
256     while ( node ) {
257         if ( node->isElementNode() ) {
258             AtomicString s = static_cast<DOM::ElementImpl*>( node )->getAttribute(ATTR_TITLE);
259             if (!s.isEmpty()) {
260                 QRect r( m_view->contentsToViewport( node->getRect().topLeft() ), node->getRect().size() );
261                 tip( r,  s.string() );
262             }
263             break;
264         }
265         node = node->parentNode();
266     }
267 }
268 #endif
269
270 KHTMLView::KHTMLView( KHTMLPart *part, QWidget *parent, const char *name)
271     : QScrollView( parent, name, WResizeNoErase | WRepaintNoErase | WPaintUnclipped ),
272       _refCount(1)
273 {
274     m_medium = "screen";
275
276     m_part = part;
277 #if APPLE_CHANGES
278     m_part->ref();
279 #endif
280     d = new KHTMLViewPrivate;
281
282 #if !APPLE_CHANGES
283     QScrollView::setVScrollBarMode(d->vmode);
284     QScrollView::setHScrollBarMode(d->hmode);
285 #endif
286     
287     connect(kapp, SIGNAL(kdisplayPaletteChanged()), this, SLOT(slotPaletteChanged()));
288     connect(this, SIGNAL(contentsMoving(int, int)), this, SLOT(slotScrollBarMoved()));
289
290     // initialize QScrollview
291     enableClipper(true);
292     viewport()->setMouseTracking(true);
293     viewport()->setBackgroundMode(NoBackground);
294
295     KImageIO::registerFormats();
296
297 #ifndef QT_NO_TOOLTIP
298     d->tooltip = new KHTMLToolTip( this, d );
299 #endif
300
301     init();
302
303     viewport()->show();
304 }
305
306 KHTMLView::~KHTMLView()
307 {
308 #if APPLE_CHANGES
309     resetScrollBars();
310 #endif
311
312     assert(_refCount == 0);
313
314     if (m_part)
315     {
316         //WABA: Is this Ok? Do I need to deref it as well?
317         //Does this need to be done somewhere else?
318         DOM::DocumentImpl *doc = m_part->xmlDocImpl();
319         if (doc)
320             doc->detach();
321
322 #if APPLE_CHANGES
323         m_part->deref();
324 #endif
325     }
326
327     delete d; d = 0;
328 }
329
330 void KHTMLView::clearPart()
331 {
332     if (m_part){
333         m_part->deref();
334         m_part = 0;
335     }
336 }
337
338 #if APPLE_CHANGES
339 void KHTMLView::resetScrollBars()
340 {
341     // Reset the document's scrollbars back to our defaults before we yield the floor.
342     d->firstLayout = true;
343     suppressScrollBars(true);
344     QScrollView::setVScrollBarMode(d->vmode);
345     QScrollView::setHScrollBarMode(d->hmode);
346     suppressScrollBars(false);
347 }
348 #endif
349
350 void KHTMLView::init()
351 {
352 #if !APPLE_CHANGES
353     if(!d->paintBuffer) d->paintBuffer = new QPixmap(PAINT_BUFFER_HEIGHT, PAINT_BUFFER_HEIGHT);
354     if(!d->tp) d->tp = new QPainter();
355 #endif
356
357     setFocusPolicy(QWidget::StrongFocus);
358     viewport()->setFocusPolicy( QWidget::WheelFocus );
359     viewport()->setFocusProxy(this);
360
361     _marginWidth = -1; // undefined
362     _marginHeight = -1;
363     _width = 0;
364     _height = 0;
365
366     setAcceptDrops(true);
367     
368 #if !APPLE_CHANGES
369     resizeContents(visibleWidth(), visibleHeight());
370 #endif
371 }
372
373 void KHTMLView::clear()
374 {
375 //    viewport()->erase();
376
377     setStaticBackground(false);
378     
379     m_part->clearSelection();
380
381     d->reset();
382
383 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
384     if (d->layoutTimerId && m_part->xmlDocImpl() && !m_part->xmlDocImpl()->ownerElement())
385         printf("Killing the layout timer from a clear at %d\n", m_part->xmlDocImpl()->elapsedTime());
386 #endif
387     
388     killTimers();
389     emit cleared();
390
391 #if APPLE_CHANGES
392     suppressScrollBars(true);
393 #else
394     QScrollView::setHScrollBarMode(d->hmode);
395     if (d->vmode==Auto)
396         QScrollView::setVScrollBarMode(d->prevScrollbarVisible?AlwaysOn:Auto);
397     else
398         QScrollView::setVScrollBarMode(d->vmode);
399     resizeContents(visibleWidth(), visibleHeight());
400 #endif
401 }
402
403 void KHTMLView::hideEvent(QHideEvent* e)
404 {
405 //    viewport()->setBackgroundMode(PaletteBase);
406     QScrollView::hideEvent(e);
407 }
408
409 void KHTMLView::showEvent(QShowEvent* e)
410 {
411 //    viewport()->setBackgroundMode(NoBackground);
412     QScrollView::showEvent(e);
413 }
414
415 void KHTMLView::resizeEvent (QResizeEvent* e)
416 {
417     QScrollView::resizeEvent(e);
418
419 #if !APPLE_CHANGES
420     int w = visibleWidth();
421     int h = visibleHeight();
422
423     layout();
424
425     //  this is to make sure we get the right width even if the scrolbar has dissappeared
426     // due to the size change.
427     if(visibleHeight() != h || visibleWidth() != w)
428         layout();
429 #endif
430     if ( m_part && m_part->xmlDocImpl() )
431         m_part->xmlDocImpl()->dispatchWindowEvent( EventImpl::RESIZE_EVENT, false, false );
432
433     KApplication::sendPostedEvents(viewport(), QEvent::Paint);
434 }
435
436 #if APPLE_CHANGES
437 void KHTMLView::initScrollBars()
438 {
439     if (!d->needToInitScrollBars)
440         return;
441     d->needToInitScrollBars = false;
442     setScrollBarsMode(hScrollBarMode());
443 }
444 #endif
445
446 #if !APPLE_CHANGES
447
448 // this is to get rid of a compiler virtual overload mismatch warning. do not remove
449 void KHTMLView::drawContents( QPainter*)
450 {
451 }
452
453 void KHTMLView::drawContents( QPainter *p, int ex, int ey, int ew, int eh )
454 {
455     //kdDebug( 6000 ) << "drawContents x=" << ex << ",y=" << ey << ",w=" << ew << ",h=" << eh << endl;
456     if(!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->renderer()) {
457         p->fillRect(ex, ey, ew, eh, palette().normal().brush(QColorGroup::Base));
458         return;
459     }
460     if ( d->paintBuffer->width() < visibleWidth() )
461         d->paintBuffer->resize(visibleWidth(),PAINT_BUFFER_HEIGHT);
462
463     int py=0;
464     while (py < eh) {
465         int ph = eh-py < PAINT_BUFFER_HEIGHT ? eh-py : PAINT_BUFFER_HEIGHT;
466         d->tp->begin(d->paintBuffer);
467         d->tp->translate(-ex, -ey-py);
468         d->tp->fillRect(ex, ey+py, ew, ph, palette().normal().brush(QColorGroup::Base));
469         m_part->xmlDocImpl()->renderer()->print(d->tp, ex, ey+py, ew, ph, 0, 0);
470 #ifdef BOX_DEBUG
471         if (m_part->xmlDocImpl()->focusNode())
472         {
473             d->tp->setBrush(Qt::NoBrush);
474             d->tp->drawRect(m_part->xmlDocImpl()->focusNode()->getRect());
475         }
476 #endif
477         d->tp->end();
478
479         p->drawPixmap(ex, ey+py, *d->paintBuffer, 0, 0, ew, ph);
480         py += PAINT_BUFFER_HEIGHT;
481     }
482
483     // EDIT FIXME: KDE needs to draw the caret here.
484
485     khtml::DrawContentsEvent event( p, ex, ey, ew, eh );
486     QApplication::sendEvent( m_part, &event );
487
488 }
489
490 #endif // !APPLE_CHANGES
491
492 void KHTMLView::setMarginWidth(int w)
493 {
494     // make it update the rendering area when set
495     _marginWidth = w;
496 }
497
498 void KHTMLView::setMarginHeight(int h)
499 {
500     // make it update the rendering area when set
501     _marginHeight = h;
502 }
503
504
505 void KHTMLView::adjustViewSize()
506 {
507     if( m_part->xmlDocImpl() ) {
508         DOM::DocumentImpl *document = m_part->xmlDocImpl();
509
510         khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas *>(document->renderer());
511         if ( !root )
512             return;
513         
514         int docw = root->docWidth();
515         int doch = root->docHeight();
516     
517         resizeContents(docw, doch);
518     }
519 }
520
521 void KHTMLView::applyBodyScrollQuirk(khtml::RenderObject* o, ScrollBarMode& hMode, ScrollBarMode& vMode)
522 {
523     // Handle the overflow:hidden/scroll quirk for the body elements.  WinIE treats
524     // overflow:hidden and overflow:scroll on <body> as applying to the document's
525     // scrollbars.  The CSS2.1 draft has even added a sentence, "HTML UAs may apply overflow
526     // specified on the body or HTML elements to the viewport."  Since WinIE and Mozilla both
527     // do it, we will do it too for <body> elements.
528     switch(o->style()->overflow()) {
529         case OHIDDEN:
530             hMode = vMode = AlwaysOff;
531             break;
532         case OSCROLL:
533             hMode = vMode = AlwaysOn;
534             break;
535         case OAUTO:
536             hMode = vMode = Auto;
537             break;
538         default:
539             // Don't set it at all.
540             ;
541     }
542 }
543
544 bool KHTMLView::inLayout() const
545 {
546     return d->layoutSuppressed;
547 }
548
549 int KHTMLView::layoutCount() const
550 {
551     return d->layoutCount;
552 }
553
554 bool KHTMLView::needsFullRepaint() const
555 {
556     return d->doFullRepaint;
557 }
558
559 void KHTMLView::addRepaintInfo(RenderObject* o, const QRect& r)
560 {
561     if (!d->repaintRects) {
562         d->repaintRects = new QPtrList<RenderObject::RepaintInfo>;
563         d->repaintRects->setAutoDelete(true);
564     }
565     
566     d->repaintRects->append(new RenderObject::RepaintInfo(o, r));
567 }
568
569 void KHTMLView::layout()
570 {
571     if (d->layoutSuppressed)
572         return;
573     
574     d->layoutSchedulingEnabled=false;
575     killTimer(d->layoutTimerId);
576     d->layoutTimerId = 0;
577     d->delayedLayout = false;
578
579     if (!m_part) {
580         // FIXME: Do we need to set _width here?
581         // FIXME: Should we set _height here too?
582         _width = visibleWidth();
583         return;
584     }
585
586     DOM::DocumentImpl* document = m_part->xmlDocImpl();
587     if (!document) {
588         // FIXME: Should we set _height here too?
589         _width = visibleWidth();
590         return;
591     }
592
593     // Always ensure our style info is up-to-date.  This can happen in situations where
594     // the layout beats any sort of style recalc update that needs to occur.
595     if (document->hasChangedChild())
596         document->recalcStyle();
597
598     khtml::RenderCanvas* root = static_cast<khtml::RenderCanvas*>(document->renderer());
599     if (!root) {
600         // FIXME: Do we need to set _width or _height here?
601         return;
602     }
603
604     ScrollBarMode hMode = d->hmode;
605     ScrollBarMode vMode = d->vmode;
606     
607     if (document->isHTMLDocument()) {
608         NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
609         if (body && body->renderer()) {
610             if (body->id() == ID_FRAMESET) {
611                 body->renderer()->setNeedsLayout(true);
612                 vMode = AlwaysOff;
613                 hMode = AlwaysOff;
614             }
615             else if (body->id() == ID_BODY)
616                 applyBodyScrollQuirk(body->renderer(), hMode, vMode); // Only applies to HTML UAs, not to XML/XHTML UAs
617         }
618     }
619
620 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
621     if (d->firstLayout && !document->ownerElement())
622         printf("Elapsed time before first layout: %d\n", document->elapsedTime());
623 #endif
624
625     d->doFullRepaint = d->firstLayout || root->printingMode();
626     if (d->repaintRects)
627         d->repaintRects->clear();
628
629 #if APPLE_CHANGES
630     // Now set our scrollbar state for the layout.
631     ScrollBarMode currentHMode = hScrollBarMode();
632     ScrollBarMode currentVMode = vScrollBarMode();
633
634     bool didFirstLayout = false;
635     if (d->firstLayout || (hMode != currentHMode || vMode != currentVMode)) {
636         suppressScrollBars(true);
637         if (d->firstLayout) {
638             d->firstLayout = false;
639             didFirstLayout = true;
640             
641             // Set the initial vMode to AlwaysOn if we're auto.
642             if (vMode == Auto)
643                 QScrollView::setVScrollBarMode(AlwaysOn); // This causes a vertical scrollbar to appear.
644             // Set the initial hMode to AlwaysOff if we're auto.
645             if (hMode == Auto)
646                 QScrollView::setHScrollBarMode(AlwaysOff); // This causes a horizontal scrollbar to disappear.
647         }
648         
649         if (hMode == vMode)
650             QScrollView::setScrollBarsMode(hMode);
651         else {
652             QScrollView::setHScrollBarMode(hMode);
653             QScrollView::setVScrollBarMode(vMode);
654         }
655
656         suppressScrollBars(false, true);
657     }
658 #else
659     QScrollView::setHScrollBarMode(hMode);
660     QScrollView::setVScrollBarMode(vMode);
661 #endif
662
663     int oldHeight = _height;
664     int oldWidth = _width;
665     
666     _height = visibleHeight();
667     _width = visibleWidth();
668
669     if (oldHeight != _height || oldWidth != _width)
670         d->doFullRepaint = true;
671     
672     RenderLayer* layer = root->layer();
673      
674     if (!d->doFullRepaint) {
675         layer->computeRepaintRects();
676         root->repaintObjectsBeforeLayout();
677     }
678
679     root->layout();
680
681     m_part->invalidateSelection();
682         
683     //kdDebug( 6000 ) << "TIME: layout() dt=" << qt.elapsed() << endl;
684    
685     d->layoutSchedulingEnabled=true;
686     d->layoutSuppressed = false;
687
688     if (!root->printingMode())
689         resizeContents(layer->width(), layer->height());
690
691     // Now update the positions of all layers.
692     layer->updateLayerPositions(d->doFullRepaint);
693
694 #if APPLE_CHANGES
695     // We update our widget positions right after doing a layout.
696     root->updateWidgetPositions();
697 #endif
698     
699     if (d->repaintRects && !d->repaintRects->isEmpty()) {
700         // FIXME: Could optimize this and have objects removed from this list
701         // if they ever do full repaints.
702         RenderObject::RepaintInfo* r;
703         QPtrListIterator<RenderObject::RepaintInfo> it(*d->repaintRects);
704         for ( ; (r = it.current()); ++it)
705             r->m_object->repaintRectangle(r->m_repaintRect);
706         d->repaintRects->clear();
707     }
708     
709     d->layoutCount++;
710 #if APPLE_CHANGES
711     if (KWQAccObjectCache::accessibilityEnabled())
712         root->document()->getAccObjectCache()->postNotification(root, "AXLayoutComplete");
713 #endif
714
715 #if APPLE_CHANGES
716     updateDashboardRegions();
717 #endif
718
719     if (root->needsLayout()) {
720         //qDebug("needs layout, delaying repaint");
721         scheduleRelayout();
722         return;
723     }
724     setStaticBackground(d->useSlowRepaints);
725
726 #if APPLE_CHANGES
727     if (didFirstLayout) {
728         m_part->didFirstLayout();
729     }
730 #endif
731 }
732
733 #if APPLE_CHANGES
734 void KHTMLView::updateDashboardRegions()
735 {
736     DOM::DocumentImpl* document = m_part->xmlDocImpl();
737     if (document->hasDashboardRegions()) {
738         QValueList<DashboardRegionValue> newRegions = document->renderer()->computeDashboardRegions();
739         QValueList<DashboardRegionValue> currentRegions = document->dashboardRegions();
740         if (!(newRegions == currentRegions)) {
741             document->setDashboardRegions(newRegions);
742             KWQ(m_part)->dashboardRegionsChanged();
743         }
744     }
745 }
746 #endif
747
748 //
749 // Event Handling
750 //
751 /////////////////
752
753 void KHTMLView::viewportMousePressEvent( QMouseEvent *_mouse )
754 {
755     if(!m_part->xmlDocImpl()) return;
756
757     SharedPtr<KHTMLView> protector(this);
758
759     int xm, ym;
760     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
761
762     //kdDebug( 6000 ) << "\nmousePressEvent: x=" << xm << ", y=" << ym << endl;
763
764     d->isDoubleClick = false;
765     d->mousePressed = true;
766
767     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MousePress );
768     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
769
770 #if !APPLE_CHANGES
771     if (d->clickCount > 0 &&
772         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance())
773         d->clickCount++;
774     else {
775         d->clickCount = 1;
776         d->clickX = xm;
777         d->clickY = ym;
778     }
779 #else
780     if (KWQ(m_part)->passSubframeEventToSubframe(mev)) {
781         invalidateClick();
782         return;
783     }
784
785     d->clickCount = _mouse->clickCount();
786     if (d->clickNode)
787         d->clickNode->deref();
788     d->clickNode = mev.innerNode.handle();
789     if (d->clickNode)
790         d->clickNode->ref();
791 #endif    
792
793     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true,
794                                            d->clickCount,_mouse,true,DOM::NodeImpl::MousePress);
795
796     if (!swallowEvent) {
797         khtml::MousePressEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
798         QApplication::sendEvent( m_part, &event );
799 #if APPLE_CHANGES
800         // Many AK widgets run their own event loops and consume events while the mouse is down.
801         // When they finish, currentEvent is the mouseUp that they exited on.  We need to update
802         // the khtml state with this mouseUp, which khtml never saw.
803         // If this event isn't a mouseUp, we assume that the mouseUp will be coming later.  There
804         // is a hole here if the widget consumes the mouseUp and subsequent events.
805         if (KWQ(m_part)->lastEventIsMouseUp()) {
806             d->mousePressed = false;
807         }
808 #endif        
809         emit m_part->nodeActivated(mev.innerNode);
810     }
811 }
812
813 void KHTMLView::viewportMouseDoubleClickEvent( QMouseEvent *_mouse )
814 {
815     if(!m_part->xmlDocImpl()) return;
816
817     SharedPtr<KHTMLView> protector(this);
818
819     int xm, ym;
820     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
821
822     //kdDebug( 6000 ) << "mouseDblClickEvent: x=" << xm << ", y=" << ym << endl;
823
824     d->isDoubleClick = true;
825 #if APPLE_CHANGES
826     // We get this instead of a second mouse-up 
827     d->mousePressed = false;
828 #endif
829
830     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseDblClick );
831     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
832
833 #if APPLE_CHANGES
834     if (KWQ(m_part)->passSubframeEventToSubframe(mev))
835         return;
836
837     d->clickCount = _mouse->clickCount();
838     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),true,
839                                            d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
840
841     if (mev.innerNode.handle() == d->clickNode)
842         dispatchMouseEvent(EventImpl::CLICK_EVENT,mev.innerNode.handle(),true,
843                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseRelease);
844
845     // Qt delivers a release event AND a double click event.
846     if (!swallowEvent) {
847         khtml::MouseReleaseEvent event1( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
848         QApplication::sendEvent( m_part, &event1 );
849
850         khtml::MouseDoubleClickEvent event2( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
851         QApplication::sendEvent( m_part, &event2 );
852     }
853 #else
854     // We do the same thing as viewportMousePressEvent() here, since the DOM does not treat
855     // single and double-click events as separate (only the detail, i.e. number of clicks differs)
856     // In other words an even detail value for a mouse click event means a double click, and an
857     // odd detail value means a single click
858     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEDOWN_EVENT,mev.innerNode.handle(),true,
859                                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseDblClick);
860
861     if (!swallowEvent) {
862         khtml::MouseDoubleClickEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
863         QApplication::sendEvent( m_part, &event );
864
865         // ###
866         //if ( url.length() )
867         //emit doubleClick( url.string(), _mouse->button() );
868     }
869 #endif    
870
871     invalidateClick();
872 }
873
874 static bool isSubmitImage(DOM::NodeImpl *node)
875 {
876     return node
877         && node->isHTMLElement()
878         && node->id() == ID_INPUT
879         && static_cast<HTMLInputElementImpl*>(node)->inputType() == HTMLInputElementImpl::IMAGE;
880 }
881
882 void KHTMLView::viewportMouseMoveEvent( QMouseEvent * _mouse )
883 {
884     // in Radar 3703768 we saw frequent crashes apparently due to the
885     // part being null here, which seems impossible, so check for nil
886     // but also assert so that we can try to figure this out in debug
887     // builds, if it happens.
888     assert(m_part);
889     if(!m_part || !m_part->xmlDocImpl()) return;
890
891     int xm, ym;
892     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
893
894     // Treat mouse move events while the mouse is pressed as "read-only" in prepareMouseEvent.
895     // This means that :hover and :active freeze in the state they were in when the mouse
896     // was pressed, rather than updating for nodes the mouse moves over as you hold the mouse down.
897     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseMove );
898     m_part->xmlDocImpl()->prepareMouseEvent( d->mousePressed, xm, ym, &mev );
899 #if APPLE_CHANGES
900     if (KWQ(m_part)->passSubframeEventToSubframe(mev))
901         return;
902 #endif
903
904     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEMOVE_EVENT,mev.innerNode.handle(),false,
905                                            0,_mouse,true,DOM::NodeImpl::MouseMove);
906
907 #if !APPLE_CHANGES
908     if (d->clickCount > 0 &&
909         QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() > QApplication::startDragDistance()) {
910         d->clickCount = 0;  // moving the mouse outside the threshold invalidates the click
911     }
912 #endif
913
914     // execute the scheduled script. This is to make sure the mouseover events come after the mouseout events
915     m_part->executeScheduledScript();
916
917     khtml::RenderStyle* style = (mev.innerNode.handle() && mev.innerNode.handle()->renderer() &&
918                                  mev.innerNode.handle()->renderer()->style()) ? mev.innerNode.handle()->renderer()->style() : 0;
919     QCursor c;
920     if (style && style->cursor() == CURSOR_AUTO && style->cursorImage()
921         && !(style->cursorImage()->pixmap().isNull())) {
922         /* First of all it works: Check out http://www.iam.unibe.ch/~schlpbch/cursor.html
923          *
924          * But, I don't know what exactly we have to do here: rescale to 32*32, change to monochrome..
925          */
926         //kdDebug( 6000 ) << "using custom cursor" << endl;
927         const QPixmap p = style->cursorImage()->pixmap();
928         // ### fix
929         c = QCursor(p);
930     }
931
932     switch ( style ? style->cursor() : CURSOR_AUTO) {
933     case CURSOR_AUTO:
934         if ( d->mousePressed && m_part->hasSelection() )
935             // during selection, use an IBeam no matter what we're over
936             c = KCursor::ibeamCursor();
937         else if ( (!mev.url.isNull() || isSubmitImage(mev.innerNode.handle()))
938                   && m_part->settings()->changeCursor() )
939             c = m_part->urlCursor();
940         else if ( !mev.innerNode.isNull()
941                   && (mev.innerNode.nodeType() == Node::TEXT_NODE
942                       || mev.innerNode.nodeType() == Node::CDATA_SECTION_NODE
943                       || (mev.innerNode.isContentEditable())))
944             c = KCursor::ibeamCursor();
945         break;
946     case CURSOR_CROSS:
947         c = KCursor::crossCursor();
948         break;
949     case CURSOR_POINTER:
950         c = m_part->urlCursor();
951         break;
952     case CURSOR_MOVE:
953         c = KCursor::sizeAllCursor();
954         break;
955     case CURSOR_E_RESIZE:
956 #if APPLE_CHANGES
957         c = KCursor::eastResizeCursor();
958         break;
959 #endif
960     case CURSOR_W_RESIZE:
961 #if APPLE_CHANGES
962         c = KCursor::westResizeCursor();
963 #else
964         c = KCursor::sizeHorCursor();
965 #endif
966         break;
967     case CURSOR_N_RESIZE:
968 #if APPLE_CHANGES
969         c = KCursor::northResizeCursor();
970         break;
971 #endif
972     case CURSOR_S_RESIZE:
973 #if APPLE_CHANGES
974         c = KCursor::southResizeCursor();
975 #else
976         c = KCursor::sizeVerCursor();
977 #endif
978         break;
979     case CURSOR_NE_RESIZE:
980 #if APPLE_CHANGES
981         c = KCursor::northEastResizeCursor();
982         break;
983 #endif
984     case CURSOR_SW_RESIZE:
985 #if APPLE_CHANGES
986         c = KCursor::southWestResizeCursor();
987 #else
988         c = KCursor::sizeBDiagCursor();
989 #endif
990         break;
991     case CURSOR_NW_RESIZE:
992 #if APPLE_CHANGES
993         c = KCursor::northWestResizeCursor();
994         break;
995 #endif
996     case CURSOR_SE_RESIZE:
997 #if APPLE_CHANGES
998         c = KCursor::southEastResizeCursor();
999 #else
1000         c = KCursor::sizeFDiagCursor();
1001 #endif
1002         break;
1003     case CURSOR_TEXT:
1004         c = KCursor::ibeamCursor();
1005         break;
1006     case CURSOR_WAIT:
1007         c = KCursor::waitCursor();
1008         break;
1009     case CURSOR_HELP:
1010         c = KCursor::whatsThisCursor();
1011         break;
1012     case CURSOR_DEFAULT:
1013         break;
1014     }
1015
1016     QWidget *vp = viewport();
1017     if ( vp->cursor().handle() != c.handle() ) {
1018         if( c.handle() == KCursor::arrowCursor().handle())
1019             vp->unsetCursor();
1020         else
1021             vp->setCursor( c );
1022     }
1023     d->prevMouseX = xm;
1024     d->prevMouseY = ym;
1025
1026     if (!swallowEvent) {
1027         khtml::MouseMoveEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1028         QApplication::sendEvent( m_part, &event );
1029     }
1030 }
1031
1032 void KHTMLView::resetCursor()
1033 {
1034     viewport()->unsetCursor();
1035 }
1036
1037 void KHTMLView::invalidateClick()
1038 {
1039     d->clickCount = 0;
1040     if (d->clickNode) {
1041         d->clickNode->deref();
1042         d->clickNode = 0;
1043     }
1044 }
1045
1046 void KHTMLView::viewportMouseReleaseEvent( QMouseEvent * _mouse )
1047 {
1048     if ( !m_part->xmlDocImpl() ) return;
1049
1050     SharedPtr<KHTMLView> protector(this);
1051
1052     int xm, ym;
1053     viewportToContents(_mouse->x(), _mouse->y(), xm, ym);
1054
1055     d->mousePressed = false;
1056
1057     //kdDebug( 6000 ) << "\nmouseReleaseEvent: x=" << xm << ", y=" << ym << endl;
1058
1059     DOM::NodeImpl::MouseEvent mev( _mouse->stateAfter(), DOM::NodeImpl::MouseRelease );
1060     m_part->xmlDocImpl()->prepareMouseEvent( false, xm, ym, &mev );
1061
1062 #if APPLE_CHANGES
1063     if (KWQ(m_part)->passSubframeEventToSubframe(mev))
1064         return;
1065 #endif
1066
1067     bool swallowEvent = dispatchMouseEvent(EventImpl::MOUSEUP_EVENT,mev.innerNode.handle(),true,
1068                                            d->clickCount,_mouse,false,DOM::NodeImpl::MouseRelease);
1069
1070     if (d->clickCount > 0 && mev.innerNode.handle() == d->clickNode
1071 #if !APPLE_CHANGES
1072             && QPoint(d->clickX-xm,d->clickY-ym).manhattanLength() <= QApplication::startDragDistance()
1073 #endif
1074         )
1075         dispatchMouseEvent(EventImpl::CLICK_EVENT,mev.innerNode.handle(),true,
1076                            d->clickCount,_mouse,true,DOM::NodeImpl::MouseRelease);
1077
1078     if (!swallowEvent) {
1079         khtml::MouseReleaseEvent event( _mouse, xm, ym, mev.url, mev.target, mev.innerNode );
1080         QApplication::sendEvent( m_part, &event );
1081     }
1082
1083     invalidateClick();
1084 }
1085
1086 void KHTMLView::keyPressEvent( QKeyEvent *_ke )
1087 {
1088     if (m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()) {
1089         if (m_part->xmlDocImpl()->focusNode()->dispatchKeyEvent(_ke))
1090         {
1091             _ke->accept();
1092             return;
1093         }
1094     }
1095
1096 #if !APPLE_CHANGES
1097     int offs = (clipper()->height() < 30) ? clipper()->height() : 30;
1098     if (_ke->state()&ShiftButton)
1099       switch(_ke->key())
1100         {
1101         case Key_Space:
1102             if ( d->vmode == QScrollView::AlwaysOff )
1103                 _ke->accept();
1104             else
1105                 scrollBy( 0, -clipper()->height() - offs );
1106             break;
1107         }
1108     else
1109         switch ( _ke->key() )
1110         {
1111         case Key_Down:
1112         case Key_J:
1113             if ( d->vmode == QScrollView::AlwaysOff )
1114                 _ke->accept();
1115             else
1116                 scrollBy( 0, 10 );
1117             break;
1118
1119         case Key_Space:
1120         case Key_Next:
1121             if ( d->vmode == QScrollView::AlwaysOff )
1122                 _ke->accept();
1123             else
1124                 scrollBy( 0, clipper()->height() - offs );
1125             break;
1126
1127         case Key_Up:
1128         case Key_K:
1129             if ( d->vmode == QScrollView::AlwaysOff )
1130                 _ke->accept();
1131             else
1132                 scrollBy( 0, -10 );
1133             break;
1134
1135         case Key_Prior:
1136             if ( d->vmode == QScrollView::AlwaysOff )
1137                 _ke->accept();
1138             else
1139                 scrollBy( 0, -clipper()->height() + offs );
1140             break;
1141         case Key_Right:
1142         case Key_L:
1143             if ( d->hmode == QScrollView::AlwaysOff )
1144                 _ke->accept();
1145             else
1146                 scrollBy( 10, 0 );
1147             break;
1148         case Key_Left:
1149         case Key_H:
1150             if ( d->hmode == QScrollView::AlwaysOff )
1151                 _ke->accept();
1152             else
1153                 scrollBy( -10, 0 );
1154             break;
1155         case Key_Enter:
1156         case Key_Return:
1157             // ### FIXME:
1158             // or even better to HTMLAnchorElementImpl::event()
1159             if (m_part->xmlDocImpl()) {
1160                 NodeImpl *n = m_part->xmlDocImpl()->focusNode();
1161                 if (n)
1162                     n->setActive();
1163             }
1164             break;
1165         case Key_Home:
1166             if ( d->vmode == QScrollView::AlwaysOff )
1167                 _ke->accept();
1168             else
1169                 setContentsPos( 0, 0 );
1170             break;
1171         case Key_End:
1172             if ( d->vmode == QScrollView::AlwaysOff )
1173                 _ke->accept();
1174             else
1175                 setContentsPos( 0, contentsHeight() - visibleHeight() );
1176             break;
1177         default:
1178             _ke->ignore();
1179             return;
1180         }
1181     _ke->accept();
1182 #endif
1183 }
1184
1185 void KHTMLView::keyReleaseEvent(QKeyEvent *_ke)
1186 {
1187     if(m_part->xmlDocImpl() && m_part->xmlDocImpl()->focusNode()) {
1188         // Qt is damn buggy. we receive release events from our child
1189         // widgets. therefore, do not support keyrelease event on generic
1190         // nodes for now until we found  a workaround for the Qt bugs. (Dirk)
1191 //         if (m_part->xmlDocImpl()->focusNode()->dispatchKeyEvent(_ke)) {
1192 //             _ke->accept();
1193 //             return;
1194 //         }
1195 //        QScrollView::keyReleaseEvent(_ke);
1196         Q_UNUSED(_ke);
1197     }
1198 }
1199
1200 void KHTMLView::contentsContextMenuEvent ( QContextMenuEvent *_ce )
1201 {
1202 // ### what kind of c*** is that ?
1203 #if 0
1204     if (!m_part->xmlDocImpl()) return;
1205     int xm = _ce->x();
1206     int ym = _ce->y();
1207
1208     DOM::NodeImpl::MouseEvent mev( _ce->state(), DOM::NodeImpl::MouseMove ); // ### not a mouse event!
1209     m_part->xmlDocImpl()->prepareMouseEvent( xm, ym, &mev );
1210
1211     NodeImpl *targetNode = mev.innerNode.handle();
1212     if (targetNode && targetNode->renderer() && targetNode->renderer()->isWidget()) {
1213         int absx = 0;
1214         int absy = 0;
1215         targetNode->renderer()->absolutePosition(absx,absy);
1216         QPoint pos(xm-absx,ym-absy);
1217
1218         QWidget *w = static_cast<RenderWidget*>(targetNode->renderer())->widget();
1219         QContextMenuEvent cme(_ce->reason(),pos,_ce->globalPos(),_ce->state());
1220         setIgnoreEvents(true);
1221         QApplication::sendEvent(w,&cme);
1222         setIgnoreEvents(false);
1223     }
1224 #endif
1225 }
1226
1227 bool KHTMLView::dispatchDragEvent(int eventId, DOM::NodeImpl *dragTarget, const QPoint &loc, DOM::ClipboardImpl *clipboard)
1228 {
1229     int clientX, clientY;
1230     viewportToContents(loc.x(), loc.y(), clientX, clientY);
1231 #if APPLE_CHANGES
1232     QPoint screenLoc = viewportToGlobal(loc);
1233     int screenX = screenLoc.x();
1234     int screenY = screenLoc.y();
1235 #else
1236 #warning Need implementation of converting event location to screen location
1237     int screenX = loc.x();
1238     int screenY = loc.y();
1239 #endif
1240     bool ctrlKey = 0;   // FIXME - set up modifiers, grab from AK or CG
1241     bool altKey = 0;
1242     bool shiftKey = 0;
1243     bool metaKey = 0;
1244     
1245     MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
1246                                             true, true, m_part->xmlDocImpl()->defaultView(),
1247                                             0, screenX, screenY, clientX, clientY,
1248                                             ctrlKey, altKey, shiftKey, metaKey,
1249                                             0, 0, clipboard);
1250     me->ref();
1251     int exceptioncode = 0;
1252     dragTarget->dispatchEvent(me, exceptioncode, true);
1253     bool accept = me->defaultPrevented();
1254     me->deref();
1255     return accept;
1256 }
1257
1258 bool KHTMLView::updateDragAndDrop(const QPoint &loc, DOM::ClipboardImpl *clipboard)
1259 {
1260     bool accept = false;
1261     int xm, ym;
1262     viewportToContents(loc.x(), loc.y(), xm, ym);
1263     DOM::NodeImpl::MouseEvent mev(0, DOM::NodeImpl::MouseMove);
1264     m_part->xmlDocImpl()->prepareMouseEvent(true, xm, ym, &mev);
1265     DOM::Node newTarget = mev.innerNode;
1266
1267     // Drag events should never go to text nodes (following IE, and proper mouseover/out dispatch)
1268     if (newTarget.nodeType() == Node::TEXT_NODE) {
1269         newTarget = newTarget.parentNode();
1270     }
1271
1272     if (d->dragTarget != newTarget) {
1273         // note this ordering is explicitly chosen to match WinIE
1274         if (!newTarget.isNull()) {
1275             accept = dispatchDragEvent(EventImpl::DRAGENTER_EVENT, newTarget.handle(), loc, clipboard);
1276         }
1277         if (!d->dragTarget.isNull()) {
1278             dispatchDragEvent(EventImpl::DRAGLEAVE_EVENT, d->dragTarget.handle(), loc, clipboard);
1279         }
1280     } else if (!newTarget.isNull()) {
1281         accept = dispatchDragEvent(EventImpl::DRAGOVER_EVENT, newTarget.handle(), loc, clipboard);
1282     }
1283     d->dragTarget = newTarget;
1284
1285     return accept;
1286 }
1287
1288 void KHTMLView::cancelDragAndDrop(const QPoint &loc, DOM::ClipboardImpl *clipboard)
1289 {
1290     if (!d->dragTarget.isNull()) {
1291         dispatchDragEvent(EventImpl::DRAGLEAVE_EVENT, d->dragTarget.handle(), loc, clipboard);
1292     }
1293     d->dragTarget = 0;
1294 }
1295
1296 bool KHTMLView::performDragAndDrop(const QPoint &loc, DOM::ClipboardImpl *clipboard)
1297 {
1298     bool accept = false;
1299     if (!d->dragTarget.isNull()) {
1300         accept = dispatchDragEvent(EventImpl::DROP_EVENT, d->dragTarget.handle(), loc, clipboard);
1301     }
1302     d->dragTarget = 0;
1303     return accept;
1304 }
1305
1306 #if !APPLE_CHANGES
1307
1308 bool KHTMLView::focusNextPrevChild( bool next )
1309 {
1310     // Now try to find the next child
1311     if (m_part->xmlDocImpl()) {
1312         focusNextPrevNode(next);
1313         if (m_part->xmlDocImpl()->focusNode() != 0)
1314             return true; // focus node found
1315     }
1316
1317     // If we get here, there is no next/previous child to go to, so pass up to the next/previous child in our parent
1318     if (m_part->parentPart() && m_part->parentPart()->view()) {
1319         return m_part->parentPart()->view()->focusNextPrevChild(next);
1320     }
1321
1322     return QWidget::focusNextPrevChild(next);
1323 }
1324
1325 void KHTMLView::doAutoScroll()
1326 {
1327     QPoint pos = QCursor::pos();
1328     pos = viewport()->mapFromGlobal( pos );
1329
1330     int xm, ym;
1331     viewportToContents(pos.x(), pos.y(), xm, ym);
1332
1333     pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
1334     if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
1335          (pos.x() < 0) || (pos.x() > visibleWidth()) )
1336     {
1337         ensureVisible( xm, ym, 0, 5 );
1338     }
1339 }
1340
1341 #endif
1342
1343 DOM::NodeImpl *KHTMLView::nodeUnderMouse() const
1344 {
1345     return d->underMouse;
1346 }
1347
1348 bool KHTMLView::scrollTo(const QRect &bounds)
1349 {
1350     d->scrollingSelf = true; // so scroll events get ignored
1351
1352     int x, y, xe, ye;
1353     x = bounds.left();
1354     y = bounds.top();
1355     xe = bounds.right();
1356     ye = bounds.bottom();
1357
1358     //kdDebug(6000)<<"scrolling coords: x="<<x<<" y="<<y<<" width="<<xe-x<<" height="<<ye-y<<endl;
1359
1360     int deltax;
1361     int deltay;
1362
1363     int curHeight = visibleHeight();
1364     int curWidth = visibleWidth();
1365
1366     if (ye-y>curHeight-d->borderY)
1367         ye  = y + curHeight - d->borderY;
1368
1369     if (xe-x>curWidth-d->borderX)
1370         xe = x + curWidth - d->borderX;
1371
1372     // is xpos of target left of the view's border?
1373     if (x < contentsX() + d->borderX )
1374             deltax = x - contentsX() - d->borderX;
1375     // is xpos of target right of the view's right border?
1376     else if (xe + d->borderX > contentsX() + curWidth)
1377             deltax = xe + d->borderX - ( contentsX() + curWidth );
1378     else
1379         deltax = 0;
1380
1381     // is ypos of target above upper border?
1382     if (y < contentsY() + d->borderY)
1383             deltay = y - contentsY() - d->borderY;
1384     // is ypos of target below lower border?
1385     else if (ye + d->borderY > contentsY() + curHeight)
1386             deltay = ye + d->borderY - ( contentsY() + curHeight );
1387     else
1388         deltay = 0;
1389
1390     int maxx = curWidth-d->borderX;
1391     int maxy = curHeight-d->borderY;
1392
1393     int scrollX,scrollY;
1394
1395     scrollX = deltax > 0 ? (deltax > maxx ? maxx : deltax) : deltax == 0 ? 0 : (deltax>-maxx ? deltax : -maxx);
1396     scrollY = deltay > 0 ? (deltay > maxy ? maxy : deltay) : deltay == 0 ? 0 : (deltay>-maxy ? deltay : -maxy);
1397
1398     if (contentsX() + scrollX < 0)
1399         scrollX = -contentsX();
1400     else if (contentsWidth() - visibleWidth() - contentsX() < scrollX)
1401         scrollX = contentsWidth() - visibleWidth() - contentsX();
1402
1403     if (contentsY() + scrollY < 0)
1404         scrollY = -contentsY();
1405     else if (contentsHeight() - visibleHeight() - contentsY() < scrollY)
1406         scrollY = contentsHeight() - visibleHeight() - contentsY();
1407
1408     scrollBy(scrollX, scrollY);
1409
1410
1411
1412     // generate abs(scroll.)
1413     if (scrollX<0)
1414         scrollX=-scrollX;
1415     if (scrollY<0)
1416         scrollY=-scrollY;
1417
1418     d->scrollingSelf = false;
1419
1420     if ( (scrollX!=maxx) && (scrollY!=maxy) )
1421         return true;
1422     else return false;
1423
1424 }
1425
1426 void KHTMLView::focusNextPrevNode(bool next)
1427 {
1428     // Sets the focus node of the document to be the node after (or if next is false, before) the current focus node.
1429     // Only nodes that are selectable (i.e. for which isSelectable() returns true) are taken into account, and the order
1430     // used is that specified in the HTML spec (see DocumentImpl::nextFocusNode() and DocumentImpl::previousFocusNode()
1431     // for details).
1432
1433     DocumentImpl *doc = m_part->xmlDocImpl();
1434     NodeImpl *oldFocusNode = doc->focusNode();
1435     NodeImpl *newFocusNode;
1436
1437     // Find the next/previous node from the current one
1438     if (next)
1439         newFocusNode = doc->nextFocusNode(oldFocusNode);
1440     else
1441         newFocusNode = doc->previousFocusNode(oldFocusNode);
1442
1443     // If there was previously no focus node and the user has scrolled the document, then instead of picking the first
1444     // focusable node in the document, use the first one that lies within the visible area (if possible).
1445     if (!oldFocusNode && newFocusNode && d->scrollBarMoved) {
1446
1447       kdDebug(6000) << " searching for visible link" << endl;
1448
1449         bool visible = false;
1450         NodeImpl *toFocus = newFocusNode;
1451         while (!visible && toFocus) {
1452             QRect focusNodeRect = toFocus->getRect();
1453             if ((focusNodeRect.left() > contentsX()) && (focusNodeRect.right() < contentsX() + visibleWidth()) &&
1454                 (focusNodeRect.top() > contentsY()) && (focusNodeRect.bottom() < contentsY() + visibleHeight())) {
1455                 // toFocus is visible in the contents area
1456                 visible = true;
1457             }
1458             else {
1459                 // toFocus is _not_ visible in the contents area, pick the next node
1460                 if (next)
1461                     toFocus = doc->nextFocusNode(toFocus);
1462                 else
1463                     toFocus = doc->previousFocusNode(toFocus);
1464             }
1465         }
1466
1467         if (toFocus)
1468             newFocusNode = toFocus;
1469     }
1470
1471     d->scrollBarMoved = false;
1472
1473     if (!newFocusNode)
1474       {
1475         // No new focus node, scroll to bottom or top depending on next
1476         if (next)
1477             scrollTo(QRect(contentsX()+visibleWidth()/2,contentsHeight(),0,0));
1478         else
1479             scrollTo(QRect(contentsX()+visibleWidth()/2,0,0,0));
1480     }
1481     else {
1482         // EDIT FIXME: if it's an editable element, activate the caret
1483         // otherwise, hide it
1484         if (newFocusNode->isContentEditable()) {
1485             // make caret visible
1486         } 
1487         else {
1488             // hide caret
1489         }
1490
1491         // Scroll the view as necessary to ensure that the new focus node is visible
1492         if (oldFocusNode) {
1493             if (!scrollTo(newFocusNode->getRect()))
1494                 return;
1495         }
1496         else {
1497             ensureVisible(contentsX(), next ? 0: contentsHeight());
1498         }
1499     }
1500     // Set focus node on the document
1501     m_part->xmlDocImpl()->setFocusNode(newFocusNode);
1502     emit m_part->nodeActivated(Node(newFocusNode));
1503
1504 #if 0
1505     if (newFocusNode) {
1506
1507         // this does not belong here. it should run a query on the tree (Dirk)
1508         // I'll fix this very particular part of the code soon when I cleaned
1509         // up the positioning code
1510         // If the newly focussed node is a link, notify the part
1511
1512         HTMLAnchorElementImpl *anchor = 0;
1513         if ((newFocusNode->id() == ID_A || newFocusNode->id() == ID_AREA))
1514             anchor = static_cast<HTMLAnchorElementImpl *>(newFocusNode);
1515
1516         if (anchor && !anchor->areaHref().isNull())
1517             m_part->overURL(anchor->areaHref().string(), 0);
1518         else
1519             m_part->overURL(QString(), 0);
1520     }
1521 #endif
1522 }
1523
1524 void KHTMLView::setMediaType( const QString &medium )
1525 {
1526     m_medium = medium;
1527 }
1528
1529 QString KHTMLView::mediaType() const
1530 {
1531 #if APPLE_CHANGES
1532     // See if we have an override type.
1533     QString overrideType = KWQ(m_part)->overrideMediaType();
1534     if (!overrideType.isNull())
1535         return overrideType;
1536 #endif
1537     return m_medium;
1538 }
1539
1540 #if !APPLE_CHANGES
1541
1542 void KHTMLView::print()
1543 {
1544     if(!m_part->xmlDocImpl()) return;
1545     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
1546     if(!root) return;
1547
1548     // this only works on Unix - we assume 72dpi
1549     KPrinter *printer = new KPrinter(QPrinter::PrinterResolution);
1550     printer->addDialogPage(new KHTMLPrintSettings());
1551     if(printer->setup(this)) {
1552         viewport()->setCursor( waitCursor ); // only viewport(), no QApplication::, otherwise we get the busy cursor in kdeprint's dialogs
1553         // set up KPrinter
1554         printer->setFullPage(false);
1555         printer->setCreator("KDE 3.0 HTML Library");
1556         QString docname = m_part->xmlDocImpl()->URL();
1557         if ( !docname.isEmpty() )
1558             printer->setDocName(docname);
1559
1560         QPainter *p = new QPainter;
1561         p->begin( printer );
1562         khtml::setPrintPainter( p );
1563
1564         m_part->xmlDocImpl()->setPaintDevice( printer );
1565         QString oldMediaType = mediaType();
1566         setMediaType( "print" );
1567         // We ignore margin settings for html and body when printing
1568         // and use the default margins from the print-system
1569         // (In Qt 3.0.x the default margins are hardcoded in Qt)
1570         m_part->xmlDocImpl()->setPrintStyleSheet( printer->option("kde-khtml-printfriendly") == "true" ?
1571                                                   "* { background-image: none !important;"
1572                                                   "    background-color: white !important;"
1573                                                   "    color: black !important; }"
1574                                                   "body { margin: 0px !important; }"
1575                                                   "html { margin: 0px !important; }" :
1576                                                   "body { margin: 0px !important; }"
1577                                                   "html { margin: 0px !important; }"
1578                                                   );
1579
1580
1581         QPaintDeviceMetrics metrics( printer );
1582
1583         // this is a simple approximation... we layout the document
1584         // according to the width of the page, then just cut
1585         // pages without caring about the content. We should do better
1586         // in the future, but for the moment this is better than no
1587         // printing support
1588         kdDebug(6000) << "printing: physical page width = " << metrics.width()
1589                       << " height = " << metrics.height() << endl;
1590         root->setPrintingMode(true);
1591         root->setWidth(metrics.width());
1592
1593         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(&metrics);
1594         m_part->xmlDocImpl()->updateStyleSelector();
1595         root->setPrintImages( printer->option("kde-khtml-printimages") == "true");
1596         root->setNeedsLayoutAndMinMaxRecalc();
1597         root->layout();
1598
1599         // ok. now print the pages.
1600         kdDebug(6000) << "printing: html page width = " << root->docWidth()
1601                       << " height = " << root->docHeight() << endl;
1602         kdDebug(6000) << "printing: margins left = " << printer->margins().width()
1603                       << " top = " << printer->margins().height() << endl;
1604         kdDebug(6000) << "printing: paper width = " << metrics.width()
1605                       << " height = " << metrics.height() << endl;
1606         // if the width is too large to fit on the paper we just scale
1607         // the whole thing.
1608         int pageHeight = metrics.height();
1609         int pageWidth = metrics.width();
1610         p->setClipRect(0,0, pageWidth, pageHeight);
1611         if(root->docWidth() > metrics.width()) {
1612             double scale = ((double) metrics.width())/((double) root->docWidth());
1613 #ifndef QT_NO_TRANSFORMATIONS
1614             p->scale(scale, scale);
1615 #endif
1616             pageHeight = (int) (pageHeight/scale);
1617             pageWidth = (int) (pageWidth/scale);
1618         }
1619         kdDebug(6000) << "printing: scaled html width = " << pageWidth
1620                       << " height = " << pageHeight << endl;
1621         int top = 0;
1622         while(top < root->docHeight()) {
1623             if(top > 0) printer->newPage();
1624             root->setTruncatedAt(top+pageHeight);
1625
1626             root->print(p, 0, top, pageWidth, pageHeight, 0, 0);
1627             if (top + pageHeight >= root->docHeight())
1628                 break; // Stop if we have printed everything
1629
1630             p->translate(0, top - root->truncatedAt());
1631             top = root->truncatedAt();
1632         }
1633
1634         p->end();
1635         delete p;
1636
1637         // and now reset the layout to the usual one...
1638         root->setPrintingMode(false);
1639         khtml::setPrintPainter( 0 );
1640         setMediaType( oldMediaType );
1641         m_part->xmlDocImpl()->setPaintDevice( this );
1642         m_part->xmlDocImpl()->styleSelector()->computeFontSizes(m_part->xmlDocImpl()->paintDeviceMetrics());
1643         m_part->xmlDocImpl()->updateStyleSelector();
1644         viewport()->unsetCursor();
1645     }
1646     delete printer;
1647 }
1648
1649 void KHTMLView::slotPaletteChanged()
1650 {
1651     if(!m_part->xmlDocImpl()) return;
1652     DOM::DocumentImpl *document = m_part->xmlDocImpl();
1653     if (!document->isHTMLDocument()) return;
1654     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(document->renderer());
1655     if(!root) return;
1656     root->style()->resetPalette();
1657     NodeImpl *body = static_cast<HTMLDocumentImpl*>(document)->body();
1658     if(!body) return;
1659     body->setChanged(true);
1660     body->recalcStyle( NodeImpl::Force );
1661 }
1662
1663 void KHTMLView::paint(QPainter *p, const QRect &rc, int yOff, bool *more)
1664 {
1665     if(!m_part->xmlDocImpl()) return;
1666     khtml::RenderCanvas *root = static_cast<khtml::RenderCanvas *>(m_part->xmlDocImpl()->renderer());
1667     if(!root) return;
1668
1669     m_part->xmlDocImpl()->setPaintDevice(p->device());
1670     root->setPrintingMode(true);
1671     root->setWidth(rc.width());
1672
1673     p->save();
1674     p->setClipRect(rc);
1675     p->translate(rc.left(), rc.top());
1676     double scale = ((double) rc.width()/(double) root->docWidth());
1677     int height = (int) ((double) rc.height() / scale);
1678 #ifndef QT_NO_TRANSFORMATIONS
1679     p->scale(scale, scale);
1680 #endif
1681
1682     root->print(p, 0, yOff, root->docWidth(), height, 0, 0);
1683     if (more)
1684         *more = yOff + height < root->docHeight();
1685     p->restore();
1686
1687     root->setPrintingMode(false);
1688     m_part->xmlDocImpl()->setPaintDevice( this );
1689 }
1690
1691 #endif // !APPLE_CHANGES
1692
1693 void KHTMLView::useSlowRepaints()
1694 {
1695     kdDebug(0) << "slow repaints requested" << endl;
1696     d->useSlowRepaints = true;
1697     setStaticBackground(true);
1698 }
1699
1700 void KHTMLView::setScrollBarsMode ( ScrollBarMode mode )
1701 {
1702 #ifndef KHTML_NO_SCROLLBARS
1703     d->vmode = mode;
1704     d->hmode = mode;
1705     
1706 #if APPLE_CHANGES
1707     QScrollView::setScrollBarsMode(mode);
1708 #else
1709     QScrollView::setVScrollBarMode(mode);
1710     QScrollView::setHScrollBarMode(mode);
1711 #endif
1712 #else
1713     Q_UNUSED( mode );
1714 #endif
1715 }
1716
1717 void KHTMLView::setVScrollBarMode ( ScrollBarMode mode )
1718 {
1719 #ifndef KHTML_NO_SCROLLBARS
1720     d->vmode = mode;
1721     QScrollView::setVScrollBarMode(mode);
1722 #else
1723     Q_UNUSED( mode );
1724 #endif
1725 }
1726
1727 void KHTMLView::setHScrollBarMode ( ScrollBarMode mode )
1728 {
1729 #ifndef KHTML_NO_SCROLLBARS
1730     d->hmode = mode;
1731     QScrollView::setHScrollBarMode(mode);
1732 #else
1733     Q_UNUSED( mode );
1734 #endif
1735 }
1736
1737 void KHTMLView::restoreScrollBar ( )
1738 {
1739 #if APPLE_CHANGES
1740     suppressScrollBars(false);
1741 #else
1742     int ow = visibleWidth();
1743     QScrollView::setVScrollBarMode(d->vmode);
1744     if (visibleWidth() != ow)
1745         layout();
1746     d->prevScrollbarVisible = verticalScrollBar()->isVisible();
1747 #endif
1748 }
1749
1750 #if !APPLE_CHANGES
1751
1752 QStringList KHTMLView::formCompletionItems(const QString &name) const
1753 {
1754     if (!m_part->settings()->isFormCompletionEnabled())
1755         return QStringList();
1756     if (!d->formCompletions)
1757         d->formCompletions = new KSimpleConfig(locateLocal("data", "khtml/formcompletions"));
1758     return d->formCompletions->readListEntry(name);
1759 }
1760
1761 void KHTMLView::addFormCompletionItem(const QString &name, const QString &value)
1762 {
1763     if (!m_part->settings()->isFormCompletionEnabled())
1764         return;
1765     // don't store values that are all numbers or just numbers with
1766     // dashes or spaces as those are likely credit card numbers or
1767     // something similar
1768     bool cc_number(true);
1769     for (unsigned int i = 0; i < value.length(); ++i)
1770     {
1771       QChar c(value[i]);
1772       if (!c.isNumber() && c != '-' && !c.isSpace())
1773       {
1774         cc_number = false;
1775         break;
1776       }
1777     }
1778     if (cc_number)
1779       return;
1780     QStringList items = formCompletionItems(name);
1781     if (!items.contains(value))
1782         items.prepend(value);
1783     while ((int)items.count() > m_part->settings()->maxFormCompletionItems())
1784         items.remove(items.fromLast());
1785     d->formCompletions->writeEntry(name, items);
1786 }
1787
1788 #endif
1789
1790 bool KHTMLView::dispatchMouseEvent(int eventId, DOM::NodeImpl *targetNode, bool cancelable,
1791                                    int detail,QMouseEvent *_mouse, bool setUnder,
1792                                    int mouseEventType)
1793 {
1794     if (d->underMouse)
1795         d->underMouse->deref();
1796     d->underMouse = targetNode;
1797     if (d->underMouse)
1798         d->underMouse->ref();
1799
1800     int exceptioncode = 0;
1801     int clientX, clientY;
1802     viewportToContents(_mouse->x(), _mouse->y(), clientX, clientY);
1803 #if APPLE_CHANGES
1804     QPoint screenLoc = viewportToGlobal(_mouse->pos());
1805     int screenX = screenLoc.x();
1806     int screenY = screenLoc.y();
1807 #else
1808     int screenX = _mouse->globalX();
1809     int screenY = _mouse->globalY();
1810 #endif
1811     int button = -1;
1812     switch (_mouse->button()) {
1813         case LeftButton:
1814             button = 0;
1815             break;
1816         case MidButton:
1817             button = 1;
1818             break;
1819         case RightButton:
1820             button = 2;
1821             break;
1822         default:
1823             break;
1824     }
1825     bool ctrlKey = (_mouse->state() & ControlButton);
1826     bool altKey = (_mouse->state() & AltButton);
1827     bool shiftKey = (_mouse->state() & ShiftButton);
1828     bool metaKey = (_mouse->state() & MetaButton);
1829
1830     // mouseout/mouseover
1831     if (setUnder && (d->prevMouseX != clientX || d->prevMouseY != clientY)) {
1832
1833         // ### this code sucks. we should save the oldUnder instead of calculating
1834         // it again. calculating is expensive! (Dirk)
1835         NodeImpl *oldUnder = 0;
1836         if (d->prevMouseX >= 0 && d->prevMouseY >= 0) {
1837             NodeImpl::MouseEvent mev( _mouse->stateAfter(), static_cast<NodeImpl::MouseEventType>(mouseEventType));
1838             m_part->xmlDocImpl()->prepareMouseEvent( true, d->prevMouseX, d->prevMouseY, &mev );
1839             oldUnder = mev.innerNode.handle();
1840         }
1841         if (oldUnder != targetNode) {
1842             // send mouseout event to the old node
1843             if (oldUnder){
1844                 oldUnder->ref();
1845                 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOUT_EVENT,
1846                                                         true,true,m_part->xmlDocImpl()->defaultView(),
1847                                                         0,screenX,screenY,clientX,clientY,
1848                                                         ctrlKey,altKey,shiftKey,metaKey,
1849                                                         button,targetNode);
1850                 oldUnder->dispatchEvent(me,exceptioncode,true);
1851             }
1852
1853             // send mouseover event to the new node
1854             if (targetNode) {
1855                 MouseEventImpl *me = new MouseEventImpl(EventImpl::MOUSEOVER_EVENT,
1856                                                         true,true,m_part->xmlDocImpl()->defaultView(),
1857                                                         0,screenX,screenY,clientX,clientY,
1858                                                         ctrlKey,altKey,shiftKey,metaKey,
1859                                                         button,oldUnder);
1860                 targetNode->dispatchEvent(me,exceptioncode,true);
1861             }
1862
1863             if (oldUnder)
1864                 oldUnder->deref();
1865         }
1866     }
1867
1868     bool swallowEvent = false;
1869
1870     if (targetNode) {
1871         // send the actual event
1872         MouseEventImpl *me = new MouseEventImpl(static_cast<EventImpl::EventId>(eventId),
1873                                                 true,cancelable,m_part->xmlDocImpl()->defaultView(),
1874                                                 detail,screenX,screenY,clientX,clientY,
1875                                                 ctrlKey,altKey,shiftKey,metaKey,
1876                                                 button,0);
1877         me->ref();
1878         targetNode->dispatchEvent(me,exceptioncode,true);
1879         bool defaultHandled = me->defaultHandled();
1880         if (me->defaultHandled() || me->defaultPrevented())
1881             swallowEvent = true;
1882         me->deref();
1883
1884         // Special case: If it's a click event, we also send the KHTML_CLICK or KHTML_DBLCLICK event. This is not part
1885         // of the DOM specs, but is used for compatibility with the traditional onclick="" and ondblclick="" attributes,
1886         // as there is no way to tell the difference between single & double clicks using DOM (only the click count is
1887         // stored, which is not necessarily the same)
1888         if (eventId == EventImpl::CLICK_EVENT) {
1889             me = new MouseEventImpl(d->isDoubleClick ? EventImpl::KHTML_DBLCLICK_EVENT : EventImpl::KHTML_CLICK_EVENT,
1890                                     true,cancelable,m_part->xmlDocImpl()->defaultView(),
1891                                     detail,screenX,screenY,clientX,clientY,
1892                                     ctrlKey,altKey,shiftKey,metaKey,
1893                                     button,0);
1894
1895             me->ref();
1896             if (defaultHandled)
1897                 me->setDefaultHandled();
1898             targetNode->dispatchEvent(me,exceptioncode,true);
1899             if (me->defaultHandled() || me->defaultPrevented())
1900                 swallowEvent = true;
1901             me->deref();
1902         }
1903         else if (eventId == EventImpl::MOUSEDOWN_EVENT) {
1904             // Focus should be shifted on mouse down, not on a click.  -dwh
1905             // Blur current focus node when a link/button is clicked; this
1906             // is expected by some sites that rely on onChange handlers running
1907             // from form fields before the button click is processed.
1908             DOM::NodeImpl* nodeImpl = targetNode;
1909             for ( ; nodeImpl && !nodeImpl->isFocusable(); nodeImpl = nodeImpl->parentNode());
1910             // If focus shift is blocked, we eat the event.  Note we should never clear swallowEvent
1911             // if the page already set it (e.g., by canceling default behavior).
1912             if (nodeImpl && nodeImpl->isMouseFocusable())
1913                 swallowEvent |= !m_part->xmlDocImpl()->setFocusNode(nodeImpl);
1914             else if (!nodeImpl || !nodeImpl->focused())
1915                 swallowEvent |= !m_part->xmlDocImpl()->setFocusNode(0);
1916         }
1917     }
1918
1919     return swallowEvent;
1920 }
1921
1922 void KHTMLView::setIgnoreWheelEvents( bool e )
1923 {
1924     d->ignoreWheelEvents = e;
1925 }
1926
1927 #ifndef QT_NO_WHEELEVENT
1928
1929 void KHTMLView::viewportWheelEvent(QWheelEvent* e)
1930 {
1931 #if !APPLE_CHANGES
1932     if ( d->ignoreWheelEvents && !verticalScrollBar()->isVisible() && m_part->parentPart() ) {
1933         if ( m_part->parentPart()->view() )
1934             m_part->parentPart()->view()->wheelEvent( e );
1935         e->ignore();
1936     }
1937     else if ( d->vmode == QScrollView::AlwaysOff ) {
1938         e->accept();
1939     }
1940     else {
1941         d->scrollBarMoved = true;
1942         QScrollView::viewportWheelEvent( e );
1943     }
1944 #endif
1945 }
1946 #endif
1947
1948 #if !APPLE_CHANGES
1949 void KHTMLView::dragEnterEvent( QDragEnterEvent* ev )
1950 {
1951     // Handle drops onto frames (#16820)
1952     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
1953     // in e.g. kmail, so not handled here).
1954     if ( m_part->parentPart() )
1955     {
1956         // Duplicated from KonqView::eventFilter
1957         if ( QUriDrag::canDecode( ev ) )
1958         {
1959             KURL::List lstDragURLs;
1960             bool ok = KURLDrag::decode( ev, lstDragURLs );
1961             QObjectList *children = this->queryList( "QWidget" );
1962
1963             if ( ok &&
1964                  !lstDragURLs.first().url().contains( "javascript:", false ) && // ### this looks like a hack to me
1965                  ev->source() != this &&
1966                  children &&
1967                  children->findRef( ev->source() ) == -1 )
1968                 ev->acceptAction();
1969
1970             delete children;
1971         }
1972     }
1973     QScrollView::dragEnterEvent( ev );
1974 }
1975
1976 void KHTMLView::dropEvent( QDropEvent *ev )
1977 {
1978     // Handle drops onto frames (#16820)
1979     // Drops on the main html part is handled by Konqueror (and shouldn't do anything
1980     // in e.g. kmail, so not handled here).
1981     if ( m_part->parentPart() )
1982     {
1983         KURL::List lstDragURLs;
1984         bool ok = KURLDrag::decode( ev, lstDragURLs );
1985
1986         KHTMLPart* part = m_part->parentPart();
1987         while ( part && part->parentPart() )
1988             part = part->parentPart();
1989         KParts::BrowserExtension *ext = part->browserExtension();
1990         if ( ok && ext && lstDragURLs.first().isValid() )
1991             emit ext->openURLRequest( lstDragURLs.first() );
1992     }
1993     QScrollView::dropEvent( ev );
1994 }
1995 #endif // !APPLE_CHANGES
1996
1997 void KHTMLView::focusInEvent( QFocusEvent *e )
1998 {
1999     m_part->setCaretVisible();
2000     QScrollView::focusInEvent( e );
2001 }
2002
2003 void KHTMLView::focusOutEvent( QFocusEvent *e )
2004 {
2005     m_part->stopAutoScroll();
2006     m_part->setCaretVisible(false);
2007     QScrollView::focusOutEvent( e );
2008 }
2009
2010 void KHTMLView::slotScrollBarMoved()
2011 {
2012     if (!d->scrollingSelf)
2013         d->scrollBarMoved = true;
2014 }
2015
2016 void KHTMLView::repaintRectangle(const QRect& r, bool immediate)
2017 {
2018     updateContents(r, immediate);
2019 }
2020
2021 void KHTMLView::timerEvent ( QTimerEvent *e )
2022 {
2023     if (e->timerId()==d->layoutTimerId) {
2024 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2025         if (m_part->xmlDocImpl() && !m_part->xmlDocImpl()->ownerElement())
2026             printf("Layout timer fired at %d\n", m_part->xmlDocImpl()->elapsedTime());
2027 #endif
2028         layout();
2029     }
2030 }
2031
2032 void KHTMLView::scheduleRelayout()
2033 {
2034     if (!d->layoutSchedulingEnabled)
2035         return;
2036
2037     if (!m_part->xmlDocImpl() || !m_part->xmlDocImpl()->shouldScheduleLayout())
2038         return;
2039
2040     int delay = m_part->xmlDocImpl()->minimumLayoutDelay();
2041     if (d->layoutTimerId && d->delayedLayout && !delay)
2042         unscheduleRelayout();
2043     if (d->layoutTimerId)
2044         return;
2045
2046     d->delayedLayout = delay != 0;
2047
2048 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2049     if (!m_part->xmlDocImpl()->ownerElement())
2050         printf("Scheduling layout for %d\n", delay);
2051 #endif
2052
2053     d->layoutTimerId = startTimer(delay);
2054 }
2055
2056 bool KHTMLView::layoutPending()
2057 {
2058     return d->layoutTimerId;
2059 }
2060
2061 bool KHTMLView::haveDelayedLayoutScheduled()
2062 {
2063     return d->layoutTimerId && d->delayedLayout;
2064 }
2065
2066 void KHTMLView::unscheduleRelayout()
2067 {
2068     if (!d->layoutTimerId)
2069         return;
2070
2071 #ifdef INSTRUMENT_LAYOUT_SCHEDULING
2072     if (m_part->xmlDocImpl() && !m_part->xmlDocImpl()->ownerElement())
2073         printf("Layout timer unscheduled at %d\n", m_part->xmlDocImpl()->elapsedTime());
2074 #endif
2075     
2076     killTimer(d->layoutTimerId);
2077     d->layoutTimerId = 0;
2078     d->delayedLayout = false;
2079 }
2080
2081 bool KHTMLView::isTransparent() const
2082 {
2083     return d->isTransparent;
2084 }
2085
2086 void KHTMLView::setTransparent(bool isTransparent)
2087 {
2088     d->isTransparent = isTransparent;
2089 }
2090