a0b5ccd4c39b80198ebef8bb840e8b91c0154636
[WebKit-https.git] / WebCore / khtml / ecma / kjs_window.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  This file is part of the KDE libraries
4  *  Copyright (C) 2000 Harri Porten (porten@kde.org)
5  *  Copyright (C) 2003 Apple Computer, Inc.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include <qstylesheet.h>
23 #include <qtimer.h>
24 #include <qinputdialog.h>
25 #include <qpaintdevicemetrics.h>
26 #include <qapplication.h>
27 #include <kdebug.h>
28 #include <kmessagebox.h>
29 #include <klocale.h>
30 #include <kparts/browserinterface.h>
31 #include <kwin.h>
32 #include <kwinmodule.h>
33 #include <kconfig.h>
34 #include <assert.h>
35 #include <qstyle.h>
36 #include "rendering/render_canvas.h"
37
38 #if APPLE_CHANGES
39 #include "KWQLogging.h"
40 #include "KWQKConfigBase.h"
41 #endif
42 #include <kjs/collector.h>
43 #include "kjs_proxy.h"
44 #include "kjs_window.h"
45 #include "kjs_navigator.h"
46 #include "kjs_html.h"
47 #include "kjs_range.h"
48 #include "kjs_traversal.h"
49 #include "kjs_css.h"
50 #include "kjs_events.h"
51 #include "xmlhttprequest.h"
52 #include "xmlserializer.h"
53
54 #include "khtmlview.h"
55 #include "khtml_part.h"
56 #include "dom/dom_string.h"
57 #include "dom/dom_node.h"
58 #include "editing/htmlediting.h"
59 #include "xml/dom2_eventsimpl.h"
60 #include "xml/dom_docimpl.h"
61 #include "xml/dom_position.h"
62 #include "xml/dom_selection.h"
63 #include "html/html_documentimpl.h"
64
65 using DOM::DocumentImpl;
66 using DOM::DOMString;
67 using DOM::Node;
68 using DOM::Position;
69 using khtml::TypingCommand;
70
71 using namespace KJS;
72
73 namespace KJS {
74
75 ////////////////////// History Object ////////////////////////
76
77   class History : public ObjectImp {
78     friend class HistoryFunc;
79   public:
80     History(ExecState *exec, KHTMLPart *p)
81       : ObjectImp(exec->lexicalInterpreter()->builtinObjectPrototype()), part(p) { }
82     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
83     Value getValueProperty(ExecState *exec, int token) const;
84     virtual const ClassInfo* classInfo() const { return &info; }
85     static const ClassInfo info;
86     enum { Back, Forward, Go, Length };
87     virtual UString toString(ExecState *exec) const;
88   private:
89     QGuardedPtr<KHTMLPart> part;
90   };
91
92   class FrameArray : public ObjectImp {
93   public:
94     FrameArray(ExecState *exec, KHTMLPart *p)
95       : ObjectImp(exec->lexicalInterpreter()->builtinObjectPrototype()), part(p) { }
96     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
97     virtual UString toString(ExecState *exec) const;
98   private:
99     QGuardedPtr<KHTMLPart> part;
100   };
101
102 #ifdef Q_WS_QWS
103   class KonquerorFunc : public DOMFunction {
104   public:
105     KonquerorFunc(const Konqueror* k, const char* name)
106       : DOMFunction(), konqueror(k), m_name(name) { }
107     virtual Value tryCall(ExecState *exec, Object &thisObj, const List &args);
108
109   private:
110     const Konqueror* konqueror;
111     QCString m_name;
112   };
113 #endif
114 }; // namespace KJS
115
116 #include "kjs_window.lut.h"
117
118 ////////////////////// Screen Object ////////////////////////
119
120 // table for screen object
121 /*
122 @begin ScreenTable 7
123   height        Screen::Height          DontEnum|ReadOnly
124   width         Screen::Width           DontEnum|ReadOnly
125   colorDepth    Screen::ColorDepth      DontEnum|ReadOnly
126   pixelDepth    Screen::PixelDepth      DontEnum|ReadOnly
127   availLeft     Screen::AvailLeft       DontEnum|ReadOnly
128   availTop      Screen::AvailTop        DontEnum|ReadOnly
129   availHeight   Screen::AvailHeight     DontEnum|ReadOnly
130   availWidth    Screen::AvailWidth      DontEnum|ReadOnly
131 @end
132 */
133
134 const ClassInfo Screen::info = { "Screen", 0, &ScreenTable, 0 };
135
136 // We set the object prototype so that toString is implemented
137 Screen::Screen(ExecState *exec)
138   : ObjectImp(exec->lexicalInterpreter()->builtinObjectPrototype()) {}
139
140 Value Screen::get(ExecState *exec, const Identifier &p) const
141 {
142 #ifdef KJS_VERBOSE
143   kdDebug(6070) << "Screen::get " << p.qstring() << endl;
144 #endif
145   return lookupGetValue<Screen,ObjectImp>(exec,p,&ScreenTable,this);
146 }
147
148 Value Screen::getValueProperty(ExecState *exec, int token) const
149 {
150   KWinModule info;
151   QWidget *thisWidget = Window::retrieveActive(exec)->part()->view();
152   QRect sg = QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(thisWidget));
153
154   switch( token ) {
155   case Height:
156     return Number(sg.height());
157   case Width:
158     return Number(sg.width());
159   case ColorDepth:
160   case PixelDepth: {
161     QPaintDeviceMetrics m(QApplication::desktop());
162     return Number(m.depth());
163   }
164   case AvailLeft: {
165     QRect clipped = info.workArea().intersect(sg);
166     return Number(clipped.x()-sg.x());
167   }
168   case AvailTop: {
169     QRect clipped = info.workArea().intersect(sg);
170     return Number(clipped.y()-sg.y());
171   }
172   case AvailHeight: {
173     QRect clipped = info.workArea().intersect(sg);
174     return Number(clipped.height());
175   }
176   case AvailWidth: {
177     QRect clipped = info.workArea().intersect(sg);
178     return Number(clipped.width());
179   }
180   default:
181     kdWarning() << "Screen::getValueProperty unhandled token " << token << endl;
182     return Undefined();
183   }
184 }
185
186 ////////////////////// Window Object ////////////////////////
187
188 const ClassInfo Window::info = { "Window", 0, &WindowTable, 0 };
189
190 /*
191 @begin WindowTable 91
192   closed        Window::Closed          DontDelete|ReadOnly
193   crypto        Window::Crypto          DontDelete|ReadOnly
194   defaultStatus Window::DefaultStatus   DontDelete
195   defaultstatus Window::DefaultStatus   DontDelete
196   status        Window::Status          DontDelete
197   document      Window::Document        DontDelete|ReadOnly
198   Node          Window::Node            DontDelete
199   Event         Window::EventCtor       DontDelete
200   Range         Window::Range           DontDelete
201   NodeFilter    Window::NodeFilter      DontDelete
202   DOMException  Window::DOMException    DontDelete
203   CSSRule       Window::CSSRule         DontDelete
204   frames        Window::Frames          DontDelete|ReadOnly
205   history       Window::_History        DontDelete|ReadOnly
206   event         Window::Event           DontDelete
207   innerHeight   Window::InnerHeight     DontDelete|ReadOnly
208   innerWidth    Window::InnerWidth      DontDelete|ReadOnly
209   length        Window::Length          DontDelete|ReadOnly
210   location      Window::_Location       DontDelete
211   name          Window::Name            DontDelete
212   navigator     Window::_Navigator      DontDelete|ReadOnly
213   clientInformation     Window::ClientInformation       DontDelete|ReadOnly
214   konqueror     Window::_Konqueror      DontDelete|ReadOnly
215   offscreenBuffering    Window::OffscreenBuffering      DontDelete|ReadOnly
216   opener        Window::Opener          DontDelete|ReadOnly
217   outerHeight   Window::OuterHeight     DontDelete|ReadOnly
218   outerWidth    Window::OuterWidth      DontDelete|ReadOnly
219   pageXOffset   Window::PageXOffset     DontDelete|ReadOnly
220   pageYOffset   Window::PageYOffset     DontDelete|ReadOnly
221   parent        Window::Parent          DontDelete|ReadOnly
222   personalbar   Window::Personalbar     DontDelete|ReadOnly
223   screenX       Window::ScreenX         DontDelete|ReadOnly
224   screenY       Window::ScreenY         DontDelete|ReadOnly
225   screenLeft    Window::ScreenLeft      DontDelete|ReadOnly
226   screenTop     Window::ScreenTop       DontDelete|ReadOnly
227   scrollbars    Window::Scrollbars      DontDelete|ReadOnly
228   scroll        Window::Scroll          DontDelete|Function 2
229   scrollBy      Window::ScrollBy        DontDelete|Function 2
230   scrollTo      Window::ScrollTo        DontDelete|Function 2
231   scrollX       Window::ScrollX         DontDelete|ReadOnly
232   scrollY       Window::ScrollY         DontDelete|ReadOnly
233   moveBy        Window::MoveBy          DontDelete|Function 2
234   moveTo        Window::MoveTo          DontDelete|Function 2
235   resizeBy      Window::ResizeBy        DontDelete|Function 2
236   resizeTo      Window::ResizeTo        DontDelete|Function 2
237   self          Window::Self            DontDelete|ReadOnly
238   window        Window::_Window         DontDelete|ReadOnly
239   top           Window::Top             DontDelete|ReadOnly
240   screen        Window::_Screen         DontDelete|ReadOnly
241   Image         Window::Image           DontDelete|ReadOnly
242   Option        Window::Option          DontDelete|ReadOnly
243   XMLHttpRequest        Window::XMLHttpRequest  DontDelete|ReadOnly
244   XMLSerializer Window::XMLSerializer   DontDelete|ReadOnly
245   alert         Window::Alert           DontDelete|Function 1
246   confirm       Window::Confirm         DontDelete|Function 1
247   prompt        Window::Prompt          DontDelete|Function 2
248   open          Window::Open            DontDelete|Function 3
249   print         Window::Print           DontDelete|Function 2
250   setTimeout    Window::SetTimeout      DontDelete|Function 2
251   clearTimeout  Window::ClearTimeout    DontDelete|Function 1
252   focus         Window::Focus           DontDelete|Function 0
253   getSelection  Window::GetSelection    DontDelete|Function 0
254   blur          Window::Blur            DontDelete|Function 0
255   close         Window::Close           DontDelete|Function 0
256   setInterval   Window::SetInterval     DontDelete|Function 2
257   clearInterval Window::ClearInterval   DontDelete|Function 1
258   captureEvents Window::CaptureEvents   DontDelete|Function 0
259   releaseEvents Window::ReleaseEvents   DontDelete|Function 0
260 # Warning, when adding a function to this object you need to add a case in Window::get
261   addEventListener      Window::AddEventListener        DontDelete|Function 3
262   removeEventListener   Window::RemoveEventListener     DontDelete|Function 3
263   onabort       Window::Onabort         DontDelete
264   onblur        Window::Onblur          DontDelete
265   onchange      Window::Onchange        DontDelete
266   onclick       Window::Onclick         DontDelete
267   ondblclick    Window::Ondblclick      DontDelete
268   ondragdrop    Window::Ondragdrop      DontDelete
269   onerror       Window::Onerror         DontDelete
270   onfocus       Window::Onfocus         DontDelete
271   onkeydown     Window::Onkeydown       DontDelete
272   onkeypress    Window::Onkeypress      DontDelete
273   onkeyup       Window::Onkeyup         DontDelete
274   onload        Window::Onload          DontDelete
275   onmousedown   Window::Onmousedown     DontDelete
276   onmousemove   Window::Onmousemove     DontDelete
277   onmouseout    Window::Onmouseout      DontDelete
278   onmouseover   Window::Onmouseover     DontDelete
279   onmouseup     Window::Onmouseup       DontDelete
280   onmove        Window::Onmove          DontDelete
281   onreset       Window::Onreset         DontDelete
282   onresize      Window::Onresize        DontDelete
283   onscroll      Window::Onscroll        DontDelete
284   onsearch      Window::Onsearch        DontDelete
285   onselect      Window::Onselect        DontDelete
286   onsubmit      Window::Onsubmit        DontDelete
287   onunload      Window::Onunload        DontDelete
288 @end
289 */
290 IMPLEMENT_PROTOFUNC(WindowFunc)
291
292 Window::Window(KHTMLPart *p)
293   : ObjectImp(/*no proto*/), m_part(p), screen(0), history(0), frames(0), loc(0), m_selection(0), m_evt(0)
294 {
295   winq = new WindowQObject(this);
296   //kdDebug(6070) << "Window::Window this=" << this << " part=" << m_part << " " << m_part->name() << endl;
297 }
298
299 Window::~Window()
300 {
301   kdDebug(6070) << "Window::~Window this=" << this << " part=" << m_part << endl;
302   delete winq;
303 }
304
305 Window *Window::retrieveWindow(KHTMLPart *p)
306 {
307   Object obj = Object::dynamicCast( retrieve( p ) );
308 #ifndef NDEBUG
309   // obj should never be null, except when javascript has been disabled in that part.
310   if ( p && p->jScriptEnabled() )
311   {
312     assert( !obj.isNull() );
313 #ifndef QWS
314     assert( dynamic_cast<KJS::Window*>(obj.imp()) ); // type checking
315 #endif
316   }
317 #endif
318   if ( obj.isNull() ) // JS disabled
319     return 0;
320   return static_cast<KJS::Window*>(obj.imp());
321 }
322
323 Window *Window::retrieveActive(ExecState *exec)
324 {
325   ValueImp *imp = exec->dynamicInterpreter()->globalObject().imp();
326   assert( imp );
327 #ifndef QWS
328   assert( dynamic_cast<KJS::Window*>(imp) );
329 #endif
330   return static_cast<KJS::Window*>(imp);
331 }
332
333 Value Window::retrieve(KHTMLPart *p)
334 {
335   assert(p);
336   KJSProxy *proxy = KJSProxy::proxy( p );
337   if (proxy) {
338 #ifdef KJS_VERBOSE
339     kdDebug(6070) << "Window::retrieve part=" << p << " interpreter=" << proxy->interpreter() << " window=" << proxy->interpreter()->globalObject().imp() << endl;
340 #endif
341     return proxy->interpreter()->globalObject(); // the Global object is the "window"
342   } else
343     return Undefined(); // This can happen with JS disabled on the domain of that window
344 }
345
346 Location *Window::location() const
347 {
348   if (!loc)
349     const_cast<Window*>(this)->loc = new Location(m_part);
350   return loc;
351 }
352
353 Selection *Window::selection() const
354 {
355   if (!m_selection)
356     const_cast<Window*>(this)->m_selection = new Selection(m_part);
357   return m_selection;
358 }
359
360 // reference our special objects during garbage collection
361 void Window::mark()
362 {
363   ObjectImp::mark();
364   if (screen && !screen->marked())
365     screen->mark();
366   if (history && !history->marked())
367     history->mark();
368   if (frames && !frames->marked())
369     frames->mark();
370   //kdDebug(6070) << "Window::mark " << this << " marking loc=" << loc << endl;
371   if (loc && !loc->marked())
372     loc->mark();
373   if (m_selection && !m_selection->marked())
374     m_selection->mark();
375 }
376
377 bool Window::hasProperty(ExecState * /*exec*/, const Identifier &/*p*/) const
378 {
379   //fprintf( stderr, "Window::hasProperty: always saying true\n" );
380
381   // emulate IE behaviour: it doesn't throw exceptions when undeclared
382   // variables are used. Returning true here will lead to get() returning
383   // 'undefined' in those cases.
384   return true;
385 }
386
387 UString Window::toString(ExecState *) const
388 {
389   return "[object Window]";
390 }
391
392 Value Window::get(ExecState *exec, const Identifier &p) const
393 {
394 #ifdef KJS_VERBOSE
395   kdDebug(6070) << "Window("<<this<<")::get " << p.qstring() << endl;
396 #endif
397   if ( p == "closed" )
398     return Boolean(m_part.isNull());
399
400   // we don't want any operations on a closed window
401   if (m_part.isNull())
402     return Undefined();
403
404   // Look for overrides first
405   ValueImp * val = ObjectImp::getDirect(p);
406   if (val) {
407     //kdDebug(6070) << "Window::get found dynamic property '" << p.ascii() << "'" << endl;
408     if (isSafeScript(exec))
409       return Value(val);
410   }
411
412   const HashEntry* entry = Lookup::findEntry(&WindowTable, p);
413   if (entry)
414   {
415     //kdDebug(6070) << "token: " << entry->value << endl;
416     switch( entry->value ) {
417     case Crypto:
418       return Undefined(); // ###
419     case DefaultStatus:
420       return String(UString(m_part->jsDefaultStatusBarText()));
421     case Status:
422       return String(UString(m_part->jsStatusBarText()));
423     case Document:
424       if (isSafeScript(exec))
425       {
426         if (m_part->document().isNull()) {
427 #if APPLE_CHANGES
428           KWQ(m_part)->createEmptyDocument();
429 #endif
430           kdDebug(6070) << "Document.write: adding <HTML><BODY> to create document" << endl;
431           m_part->begin();
432           m_part->write("<HTML><BODY>");
433           m_part->end();
434         }
435         Value val = getDOMNode(exec,m_part->document());
436         return val;
437       }
438       else
439         return Undefined();
440     case Node:
441       return getNodeConstructor(exec);
442     case Range:
443       return getRangeConstructor(exec);
444     case NodeFilter:
445       return getNodeFilterConstructor(exec);
446     case DOMException:
447       return getDOMExceptionConstructor(exec);
448     case CSSRule:
449       return getCSSRuleConstructor(exec);
450     case EventCtor:
451       return getEventConstructor(exec);
452     case Frames:
453       return Value(frames ? frames :
454                    (const_cast<Window*>(this)->frames = new FrameArray(exec,m_part)));
455     case _History:
456       return Value(history ? history :
457                    (const_cast<Window*>(this)->history = new History(exec,m_part)));
458
459     case Event:
460       if (m_evt)
461         return getDOMEvent(exec,*m_evt);
462       else {
463 #ifdef KJS_VERBOSE
464         kdWarning(6070) << "window(" << this << "," << m_part->name() << ").event, no event!" << endl;
465 #endif
466         return Undefined();
467       }
468     case InnerHeight:
469       if (!m_part->view())
470         return Undefined();
471       updateLayout();
472       return Number(m_part->view()->visibleHeight());
473     case InnerWidth:
474       if (!m_part->view())
475         return Undefined();
476       updateLayout();
477       return Number(m_part->view()->visibleWidth());
478     case Length:
479       return Number(m_part->frames().count());
480     case _Location:
481       return Value(location());
482     case Name:
483       return String(m_part->name());
484     case _Navigator:
485     case ClientInformation: {
486       // Store the navigator in the object so we get the same one each time.
487       Navigator *n = new Navigator(exec, m_part);
488       const_cast<Window *>(this)->putDirect("navigator", n, DontDelete|ReadOnly);
489       const_cast<Window *>(this)->putDirect("clientInformation", n, DontDelete|ReadOnly);
490       return Value(n);
491     }
492 #ifdef Q_WS_QWS
493     case _Konqueror:
494       return Value(new Konqueror(m_part));
495 #endif
496     case OffscreenBuffering:
497       return Boolean(true);
498     case Opener:
499       if (!m_part->opener())
500         return Null();    // ### a null Window might be better, but == null
501       else                // doesn't work yet
502         return retrieve(m_part->opener());
503     case OuterHeight:
504     case OuterWidth:
505     {
506       if (!m_part->view())
507         return Number(0);
508       KWin::Info inf = KWin::info(m_part->view()->topLevelWidget()->winId());
509       return Number(entry->value == OuterHeight ?
510                     inf.geometry.height() : inf.geometry.width());
511     }
512     case PageXOffset:
513       if (!m_part->view())
514         return Undefined();
515       updateLayout();
516       return Number(m_part->view()->contentsX());
517     case PageYOffset:
518       if (!m_part->view())
519         return Undefined();
520       updateLayout();
521       return Number(m_part->view()->contentsY());
522     case Parent:
523       return Value(retrieve(m_part->parentPart() ? m_part->parentPart() : (KHTMLPart*)m_part));
524     case Personalbar:
525       return Undefined(); // ###
526     case ScreenLeft:
527     case ScreenX: {
528       if (!m_part->view())
529         return Undefined();
530       QRect sg = QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(m_part->view()));
531       return Number(m_part->view()->mapToGlobal(QPoint(0,0)).x() + sg.x());
532     }
533     case ScreenTop:
534     case ScreenY: {
535       if (!m_part->view())
536         return Undefined();
537       QRect sg = QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(m_part->view()));
538       return Number(m_part->view()->mapToGlobal(QPoint(0,0)).y() + sg.y());
539     }
540     case ScrollX: {
541       if (!m_part->view())
542         return Undefined();
543       updateLayout();
544       return Number(m_part->view()->contentsX());
545     }
546     case ScrollY: {
547       if (!m_part->view())
548         return Undefined();
549       updateLayout();
550       return Number(m_part->view()->contentsY());
551     }
552     case Scrollbars:
553       return Undefined(); // ###
554     case Self:
555     case _Window:
556       return Value(retrieve(m_part));
557     case Top: {
558       KHTMLPart *p = m_part;
559       while (p->parentPart())
560         p = p->parentPart();
561       return Value(retrieve(p));
562     }
563     case _Screen:
564       return Value(screen ? screen :
565                    (const_cast<Window*>(this)->screen = new Screen(exec)));
566     case Image:
567       return Value(new ImageConstructorImp(exec, m_part->document()));
568     case Option:
569       return Value(new OptionConstructorImp(exec, m_part->document()));
570     case XMLHttpRequest:
571       return Value(new XMLHttpRequestConstructorImp(exec, m_part->document()));
572     case XMLSerializer:
573       return Value(new XMLSerializerConstructorImp(exec));
574     case Alert:
575     case Confirm:
576     case Prompt:
577     case Open:
578 #if APPLE_CHANGES
579     case Print:
580 #endif
581     case Focus:
582     case Blur:
583     case Close:
584     case Scroll: // compatibility
585     case ScrollBy:
586     case ScrollTo:
587     case MoveBy:
588     case MoveTo:
589     case ResizeBy:
590     case ResizeTo:
591         return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr);
592     case CaptureEvents:
593     case ReleaseEvents:
594     case AddEventListener:
595     case RemoveEventListener:
596     case SetTimeout:
597     case ClearTimeout:
598     case SetInterval:
599     case ClearInterval:
600     case GetSelection:
601       if (isSafeScript(exec))
602         return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr);
603       else
604         return Undefined();
605     case Onabort:
606       if (isSafeScript(exec))
607         return getListener(exec,DOM::EventImpl::ABORT_EVENT);
608       else
609         return Undefined();
610     case Onblur:
611       if (isSafeScript(exec))
612         return getListener(exec,DOM::EventImpl::BLUR_EVENT);
613       else
614         return Undefined();
615     case Onchange:
616       if (isSafeScript(exec))
617         return getListener(exec,DOM::EventImpl::CHANGE_EVENT);
618       else
619         return Undefined();
620     case Onclick:
621       if (isSafeScript(exec))
622         return getListener(exec,DOM::EventImpl::KHTML_CLICK_EVENT);
623       else
624         return Undefined();
625     case Ondblclick:
626       if (isSafeScript(exec))
627         return getListener(exec,DOM::EventImpl::KHTML_DBLCLICK_EVENT);
628       else
629         return Undefined();
630     case Ondragdrop:
631       if (isSafeScript(exec))
632         return getListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT);
633       else
634         return Undefined();
635     case Onerror:
636       if (isSafeScript(exec))
637         return getListener(exec,DOM::EventImpl::KHTML_ERROR_EVENT);
638       else
639         return Undefined();
640     case Onfocus:
641       if (isSafeScript(exec))
642         return getListener(exec,DOM::EventImpl::FOCUS_EVENT);
643       else
644         return Undefined();
645     case Onkeydown:
646       if (isSafeScript(exec))
647         return getListener(exec,DOM::EventImpl::KEYDOWN_EVENT);
648       else
649         return Undefined();
650     case Onkeypress:
651       if (isSafeScript(exec))
652         return getListener(exec,DOM::EventImpl::KEYPRESS_EVENT);
653       else
654         return Undefined();
655     case Onkeyup:
656       if (isSafeScript(exec))
657         return getListener(exec,DOM::EventImpl::KEYUP_EVENT);
658       else
659         return Undefined();
660     case Onload:
661       if (isSafeScript(exec))
662         return getListener(exec,DOM::EventImpl::LOAD_EVENT);
663       else
664         return Undefined();
665     case Onmousedown:
666       if (isSafeScript(exec))
667         return getListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT);
668       else
669         return Undefined();
670     case Onmousemove:
671       if (isSafeScript(exec))
672         return getListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT);
673       else
674         return Undefined();
675     case Onmouseout:
676       if (isSafeScript(exec))
677         return getListener(exec,DOM::EventImpl::MOUSEOUT_EVENT);
678       else
679         return Undefined();
680     case Onmouseover:
681       if (isSafeScript(exec))
682         return getListener(exec,DOM::EventImpl::MOUSEOVER_EVENT);
683       else
684         return Undefined();
685     case Onmouseup:
686       if (isSafeScript(exec))
687         return getListener(exec,DOM::EventImpl::MOUSEUP_EVENT);
688       else
689         return Undefined();
690     case Onmove:
691       if (isSafeScript(exec))
692         return getListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT);
693       else
694         return Undefined();
695     case Onreset:
696       if (isSafeScript(exec))
697         return getListener(exec,DOM::EventImpl::RESET_EVENT);
698       else
699         return Undefined();
700     case Onresize:
701       if (isSafeScript(exec))
702         return getListener(exec,DOM::EventImpl::RESIZE_EVENT);
703       else
704         return Undefined();
705     case Onscroll:
706         if (isSafeScript(exec))
707             return getListener(exec,DOM::EventImpl::SCROLL_EVENT);
708         else
709             return Undefined();
710 #if APPLE_CHANGES
711     case Onsearch:
712         if (isSafeScript(exec))
713             return getListener(exec,DOM::EventImpl::SEARCH_EVENT);
714         else
715             return Undefined();
716 #endif
717     case Onselect:
718       if (isSafeScript(exec))
719         return getListener(exec,DOM::EventImpl::SELECT_EVENT);
720       else
721         return Undefined();
722     case Onsubmit:
723       if (isSafeScript(exec))
724         return getListener(exec,DOM::EventImpl::SUBMIT_EVENT);
725       else
726         return Undefined();
727     case Onunload:
728       if (isSafeScript(exec))
729         return getListener(exec,DOM::EventImpl::UNLOAD_EVENT);
730       else
731         return Undefined();
732     }
733   }
734
735   KHTMLPart *kp = m_part->findFrame( p.qstring() );
736   if (kp)
737     return Value(retrieve(kp));
738
739   // allow window[1] or parent[1] etc. (#56983)
740   bool ok;
741   unsigned int i = p.toArrayIndex(&ok);
742   if (ok) {
743     QPtrList<KParts::ReadOnlyPart> frames = m_part->frames();
744     unsigned int len = frames.count();
745     if (i < len) {
746       KParts::ReadOnlyPart* frame = frames.at(i);
747       if (frame && frame->inherits("KHTMLPart")) {
748         KHTMLPart *khtml = static_cast<KHTMLPart*>(frame);
749         return Window::retrieve(khtml);
750       }
751     }
752   }
753
754   // allow shortcuts like 'Image1' instead of document.images.Image1
755   if (isSafeScript(exec) &&
756       m_part->document().isHTMLDocument()) { // might be XML
757     DOM::HTMLCollection coll = m_part->htmlDocument().all();
758     DOM::HTMLElement element = coll.namedItem(p.string());
759     if (!element.isNull()) {
760       return getDOMNode(exec,element);
761     }
762   }
763
764   // This isn't necessarily a bug. Some code uses if(!window.blah) window.blah=1
765   // But it can also mean something isn't loaded or implemented, hence the WARNING to help grepping.
766 #ifdef KJS_VERBOSE
767   kdDebug(6070) << "WARNING: Window::get property not found: " << p.qstring() << endl;
768 #endif
769   return Undefined();
770 }
771
772 void Window::put(ExecState* exec, const Identifier &propertyName, const Value &value, int attr)
773 {
774   // Called by an internal KJS call (e.g. InterpreterImp's constructor) ?
775   // If yes, save time and jump directly to ObjectImp.
776   if ( (attr != None && attr != DontDelete)
777        // Same thing if we have a local override (e.g. "var location")
778        || ( ObjectImp::getDirect(propertyName) && isSafeScript(exec)) )
779   {
780     ObjectImp::put( exec, propertyName, value, attr );
781     return;
782   }
783
784   const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName);
785   if (entry)
786   {
787 #ifdef KJS_VERBOSE
788     kdDebug(6070) << "Window("<<this<<")::put " << propertyName.qstring() << endl;
789 #endif
790     switch( entry->value ) {
791     case Status: {
792       String s = value.toString(exec);
793       m_part->setJSStatusBarText(s.value().qstring());
794       return;
795     }
796     case DefaultStatus: {
797       String s = value.toString(exec);
798       m_part->setJSDefaultStatusBarText(s.value().qstring());
799       return;
800     }
801     case _Location: {
802       KHTMLPart* p = Window::retrieveActive(exec)->m_part;
803       if (p) {
804         QString dstUrl = p->htmlDocument().completeURL(value.toString(exec).string()).string();
805         if (dstUrl.find("javascript:", 0, false) || isSafeScript(exec))
806         {
807           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
808 #if APPLE_CHANGES
809           // We want a new history item if this JS was called via a user gesture
810           m_part->scheduleRedirection(0, dstUrl, !userGesture, userGesture);
811 #else
812           m_part->scheduleRedirection(0,
813                                       dstUrl,
814                                       false /*don't lock history*/, userGesture);
815 #endif
816         }
817       }
818       return;
819     }
820     case Onabort:
821       if (isSafeScript(exec))
822         setListener(exec, DOM::EventImpl::ABORT_EVENT,value);
823       return;
824     case Onblur:
825       if (isSafeScript(exec))
826         setListener(exec, DOM::EventImpl::BLUR_EVENT,value);
827       return;
828     case Onchange:
829       if (isSafeScript(exec))
830         setListener(exec, DOM::EventImpl::CHANGE_EVENT,value);
831       return;
832     case Onclick:
833       if (isSafeScript(exec))
834         setListener(exec,DOM::EventImpl::KHTML_CLICK_EVENT,value);
835       return;
836     case Ondblclick:
837       if (isSafeScript(exec))
838         setListener(exec,DOM::EventImpl::KHTML_DBLCLICK_EVENT,value);
839       return;
840     case Ondragdrop:
841       if (isSafeScript(exec))
842         setListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT,value);
843       return;
844     case Onerror:
845       if (isSafeScript(exec))
846         setListener(exec,DOM::EventImpl::KHTML_ERROR_EVENT,value);
847       return;
848     case Onfocus:
849       if (isSafeScript(exec))
850         setListener(exec,DOM::EventImpl::FOCUS_EVENT,value);
851       return;
852     case Onkeydown:
853       if (isSafeScript(exec))
854         setListener(exec,DOM::EventImpl::KEYDOWN_EVENT,value);
855       return;
856     case Onkeypress:
857       if (isSafeScript(exec))
858         setListener(exec,DOM::EventImpl::KEYPRESS_EVENT,value);
859       return;
860     case Onkeyup:
861       if (isSafeScript(exec))
862         setListener(exec,DOM::EventImpl::KEYUP_EVENT,value);
863       return;
864     case Onload:
865       if (isSafeScript(exec))
866         setListener(exec,DOM::EventImpl::LOAD_EVENT,value);
867       return;
868     case Onmousedown:
869       if (isSafeScript(exec))
870         setListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT,value);
871       return;
872     case Onmousemove:
873       if (isSafeScript(exec))
874         setListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT,value);
875       return;
876     case Onmouseout:
877       if (isSafeScript(exec))
878         setListener(exec,DOM::EventImpl::MOUSEOUT_EVENT,value);
879       return;
880     case Onmouseover:
881       if (isSafeScript(exec))
882         setListener(exec,DOM::EventImpl::MOUSEOVER_EVENT,value);
883       return;
884     case Onmouseup:
885       if (isSafeScript(exec))
886         setListener(exec,DOM::EventImpl::MOUSEUP_EVENT,value);
887       return;
888     case Onmove:
889       if (isSafeScript(exec))
890         setListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT,value);
891       return;
892     case Onreset:
893       if (isSafeScript(exec))
894         setListener(exec,DOM::EventImpl::RESET_EVENT,value);
895       return;
896     case Onresize:
897       if (isSafeScript(exec))
898         setListener(exec,DOM::EventImpl::RESIZE_EVENT,value);
899       return;
900     case Onscroll:
901       if (isSafeScript(exec))
902         setListener(exec,DOM::EventImpl::SCROLL_EVENT,value);
903       return;
904 #if APPLE_CHANGES
905     case Onsearch:
906         if (isSafeScript(exec))
907             setListener(exec,DOM::EventImpl::SEARCH_EVENT,value);
908         return;
909 #endif
910     case Onselect:
911       if (isSafeScript(exec))
912         setListener(exec,DOM::EventImpl::SELECT_EVENT,value);
913       return;
914     case Onsubmit:
915       if (isSafeScript(exec))
916         setListener(exec,DOM::EventImpl::SUBMIT_EVENT,value);
917       return;
918     case Onunload:
919       if (isSafeScript(exec))
920         setListener(exec,DOM::EventImpl::UNLOAD_EVENT,value);
921       return;
922     case Name:
923       if (isSafeScript(exec))
924 #if APPLE_CHANGES
925         m_part->setName( value.toString(exec).qstring() );
926 #else
927         m_part->setName( value.toString(exec).qstring().local8Bit().data() );
928 #endif
929       return;
930     default:
931       break;
932     }
933   }
934   if (isSafeScript(exec)) {
935     //kdDebug(6070) << "Window("<<this<<")::put storing " << propertyName.qstring() << endl;
936     ObjectImp::put(exec, propertyName, value, attr);
937   }
938 }
939
940 bool Window::toBoolean(ExecState *) const
941 {
942   return !m_part.isNull();
943 }
944
945 int Window::installTimeout(const UString &handler, int t, bool singleShot)
946 {
947   return winq->installTimeout(handler, t, singleShot);
948 }
949
950 int Window::installTimeout(const Value &function, List &args, int t, bool singleShot)
951 {
952   return winq->installTimeout(function, args, t, singleShot);
953 }
954
955 void Window::clearTimeout(int timerId)
956 {
957   winq->clearTimeout(timerId);
958 }
959
960 #if APPLE_CHANGES
961 bool Window::hasTimeouts()
962 {
963     return winq->hasTimeouts();
964 }
965
966 QMap<int, ScheduledAction*> *Window::pauseTimeouts(const void *key)
967 {
968     return winq->pauseTimeouts(key);
969 }
970
971 void Window::resumeTimeouts(QMap<int, ScheduledAction*> *sa, const void *key)
972 {
973     return winq->resumeTimeouts(sa, key);
974 }
975 #endif
976
977 void Window::scheduleClose()
978 {
979   kdDebug(6070) << "Window::scheduleClose window.close() " << m_part << endl;
980   Q_ASSERT(winq);
981 #if APPLE_CHANGES
982   KWQ(m_part)->scheduleClose();
983 #else
984   QTimer::singleShot( 0, winq, SLOT( timeoutClose() ) );
985 #endif
986 }
987
988 static bool shouldLoadAsEmptyDocument(const KURL &url)
989 {
990   return url.protocol().lower() == "about" || url.isEmpty();
991 }
992
993 bool Window::isSafeScript(ExecState *exec) const
994 {
995   if (m_part.isNull()) { // part deleted ? can't grant access
996     kdDebug(6070) << "Window::isSafeScript: accessing deleted part !" << endl;
997     return false;
998   }
999   KHTMLPart *activePart = static_cast<KJS::ScriptInterpreter *>( exec->dynamicInterpreter() )->part();
1000   if (!activePart) {
1001     kdDebug(6070) << "Window::isSafeScript: current interpreter's part is 0L!" << endl;
1002     return false;
1003   }
1004   if ( activePart == m_part ) // Not calling from another frame, no problem.
1005     return true;
1006
1007   // JS may be attempting to access the "window" object, which should be valid,
1008   // even if the document hasn't been constructed yet.  If the document doesn't
1009   // exist yet allow JS to access the window object.
1010   if (!m_part->xmlDocImpl())
1011       return true;
1012
1013   DOM::DocumentImpl* thisDocument = m_part->xmlDocImpl();
1014   DOM::DocumentImpl* actDocument = activePart->xmlDocImpl();
1015
1016   if (!actDocument) {
1017     kdDebug(6070) << "Window::isSafeScript: active part has no document!" << endl;
1018     return false;
1019   }
1020
1021   DOM::DOMString actDomain = actDocument->domain();
1022   
1023   // Always allow local pages to execute any JS.
1024   if (actDomain.isNull())
1025     return true;
1026   
1027   DOM::DOMString thisDomain = thisDocument->domain();
1028
1029   // if this document is being initially loaded as empty by its parent
1030   // or opener, allow access from any document in the same domain as
1031   // the parent or opener.
1032   if (shouldLoadAsEmptyDocument(m_part->url())) {
1033     KHTMLPart *ancestorPart = m_part->opener() ? m_part->opener() : m_part->parentPart();
1034     while (ancestorPart && shouldLoadAsEmptyDocument(ancestorPart->url())) {
1035       ancestorPart = ancestorPart->parentPart();
1036     }
1037     
1038     if (ancestorPart)
1039       thisDomain = ancestorPart->docImpl()->domain();
1040   }
1041
1042   //kdDebug(6070) << "current domain:" << actDomain.string() << ", frame domain:" << thisDomain.string() << endl;
1043   if ( actDomain == thisDomain )
1044     return true;
1045
1046 #if APPLE_CHANGES
1047   if (Interpreter::shouldPrintExceptions()) {
1048       printf("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
1049              thisDocument->URL().latin1(), actDocument->URL().latin1());
1050       QString message;
1051       message.sprintf("Unsafe JavaScript attempt to access frame with URL %s from frame with URL %s. Domains must match.\n", 
1052                       thisDocument->URL().latin1(), actDocument->URL().latin1());
1053       KWQ(m_part)->addMessageToConsole(message, 1, QString()); //fixme: provide a real line number and sourceurl
1054   }
1055 #endif
1056   
1057   kdWarning(6070) << "Javascript: access denied for current frame '" << actDomain.string() << "' to frame '" << thisDomain.string() << "'" << endl;
1058   return false;
1059 }
1060
1061 void Window::setListener(ExecState *exec, int eventId, Value func)
1062 {
1063   if (!isSafeScript(exec))
1064     return;
1065   DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(m_part->htmlDocument().handle());
1066   if (!doc)
1067     return;
1068
1069   doc->setHTMLWindowEventListener(eventId,getJSEventListener(func,true));
1070 }
1071
1072 Value Window::getListener(ExecState *exec, int eventId) const
1073 {
1074   if (!isSafeScript(exec))
1075     return Undefined();
1076   DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(m_part->htmlDocument().handle());
1077   if (!doc)
1078     return Undefined();
1079
1080   DOM::EventListener *listener = doc->getHTMLWindowEventListener(eventId);
1081   if (listener && static_cast<JSEventListener*>(listener)->listenerObjImp())
1082     return static_cast<JSEventListener*>(listener)->listenerObj();
1083   else
1084     return Null();
1085 }
1086
1087
1088 JSEventListener *Window::getJSEventListener(const Value& val, bool html)
1089 {
1090   // This function is so hot that it's worth coding it directly with imps.
1091   if (val.type() != ObjectType)
1092     return 0;
1093   ObjectImp *listenerObject = static_cast<ObjectImp *>(val.imp());
1094
1095   JSEventListener *existingListener = jsEventListeners[listenerObject];
1096   if (existingListener)
1097     return existingListener;
1098
1099   // Note that the JSEventListener constructor adds it to our jsEventListeners list
1100   return new JSEventListener(Object(listenerObject), Object(this), html);
1101 }
1102
1103 JSLazyEventListener *Window::getJSLazyEventListener(const QString& code, bool html, int lineNumber)
1104 {
1105   return new JSLazyEventListener(code, Object(this), html, lineNumber);
1106 }
1107
1108 void Window::clear( ExecState *exec )
1109 {
1110   KJS::Interpreter::lock();
1111   kdDebug(6070) << "Window::clear " << this << endl;
1112   delete winq;
1113   winq = new WindowQObject(this);;
1114   // Get rid of everything, those user vars could hold references to DOM nodes
1115   deleteAllProperties( exec );
1116   // Really delete those properties, so that the DOM nodes get deref'ed
1117   KJS::Collector::collect();
1118   // Now recreate a working global object for the next URL that will use us
1119   KJS::Interpreter *interpreter = KJSProxy::proxy( m_part )->interpreter();
1120   interpreter->initGlobalObject();
1121   KJS::Interpreter::unlock();
1122 }
1123
1124 void Window::setCurrentEvent( DOM::Event *evt )
1125 {
1126   m_evt = evt;
1127   //kdDebug(6070) << "Window " << this << " (part=" << m_part << ")::setCurrentEvent m_evt=" << evt << endl;
1128 }
1129
1130 Value WindowFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
1131 {
1132   if (!thisObj.inherits(&Window::info)) {
1133     Object err = Error::create(exec,TypeError);
1134     exec->setException(err);
1135     return err;
1136   }
1137   Window *window = static_cast<Window *>(thisObj.imp());
1138   QString str, str2;
1139
1140   KHTMLPart *part = window->m_part;
1141   if (!part)
1142     return Undefined();
1143
1144   KHTMLView *widget = part->view();
1145   Value v = args[0];
1146   UString s = v.toString(exec);
1147   str = s.qstring();
1148
1149   switch (id) {
1150   case Window::Alert:
1151     if (part && part->xmlDocImpl())
1152       part->xmlDocImpl()->updateRendering();
1153 #if APPLE_CHANGES
1154     KWQ(part)->runJavaScriptAlert(str);
1155 #else
1156     KMessageBox::error(widget, QStyleSheet::convertFromPlainText(str), "JavaScript");
1157 #endif
1158     return Undefined();
1159   case Window::Confirm:
1160     if (part && part->xmlDocImpl())
1161       part->xmlDocImpl()->updateRendering();
1162 #if APPLE_CHANGES
1163     return Boolean(KWQ(part)->runJavaScriptConfirm(str));
1164 #else
1165     return Boolean((KMessageBox::warningYesNo(widget, QStyleSheet::convertFromPlainText(str), "JavaScript",
1166                                                 i18n("OK"), i18n("Cancel")) == KMessageBox::Yes));
1167 #endif
1168   case Window::Prompt:
1169     if (part && part->xmlDocImpl())
1170       part->xmlDocImpl()->updateRendering();
1171     bool ok;
1172 #if APPLE_CHANGES
1173     ok = KWQ(part)->runJavaScriptPrompt(str, args.size() >= 2 ? args[1].toString(exec).qstring() : QString::null, str2);
1174 #else
1175     if (args.size() >= 2)
1176       str2 = QInputDialog::getText(i18n("Konqueror: Prompt"),
1177                                    QStyleSheet::convertFromPlainText(str),
1178                                    QLineEdit::Normal,
1179                                    args[1].toString(exec).qstring(), &ok);
1180     else
1181       str2 = QInputDialog::getText(i18n("Konqueror: Prompt"),
1182                                    QStyleSheet::convertFromPlainText(str),
1183                                    QLineEdit::Normal,
1184                                    QString::null, &ok);
1185 #endif
1186     if ( ok )
1187         return String(str2);
1188     else
1189         return Null();
1190   case Window::Open:
1191   {
1192     KConfig *config = new KConfig("konquerorrc");
1193     config->setGroup("Java/JavaScript Settings");
1194 #if !APPLE_CHANGES
1195     int policy = config->readUnsignedNumEntry( "WindowOpenPolicy", 0 ); // 0=allow, 1=ask, 2=deny, 3=smart
1196 #else    
1197     int policy = config->readUnsignedNumEntry( part->settings(), "WindowOpenPolicy", 0 ); // 0=allow, 1=ask, 2=deny, 3=smart
1198 #endif
1199     delete config;
1200     if ( policy == 1 ) {
1201 #if !APPLE_CHANGES
1202       if ( KMessageBox::questionYesNo(widget,
1203                                       i18n( "This site is trying to open up a new browser "
1204                                             "window using Javascript.\n"
1205                                             "Do you want to allow this?" ),
1206                                       i18n( "Confirmation: Javascript Popup" ) ) == KMessageBox::Yes )
1207 #endif
1208         policy = 0;
1209     } else if ( policy == 3 ) // smart
1210     {
1211       // window.open disabled unless from a key/mouse event
1212       if (static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture())
1213 #if !APPLE_CHANGES
1214         policy = 0;
1215 #else
1216       {
1217         policy = 0;
1218         LOG(PopupBlocking, "Allowed JavaScript window open of %s", args[0].toString(exec).qstring().ascii());
1219       } else {
1220         LOG(PopupBlocking, "Blocked JavaScript window open of %s", args[0].toString(exec).qstring().ascii());
1221       }
1222 #endif
1223     }
1224
1225     QString frameName = !args[1].isNull() && args[1].type() != UndefinedType ?
1226                         args[1].toString(exec).qstring()
1227                         : QString("_blank");
1228
1229     if ( policy != 0 && !(part->findFrame(frameName) || frameName == "_top" || frameName == "_parent" || frameName == "_self")) {
1230       return Undefined();
1231     } else {
1232       if (v.type() == UndefinedType)
1233         str = QString();
1234
1235       KParts::WindowArgs winargs;
1236
1237       // scan feature argument
1238       v = args[2];
1239       QString features;
1240       if (!v.isNull() && v.type() != UndefinedType && v.toString(exec).size() > 0) {
1241         features = v.toString(exec).qstring();
1242         // specifying window params means false defaults
1243         winargs.menuBarVisible = false;
1244         winargs.toolBarsVisible = false;
1245         winargs.statusBarVisible = false;
1246 #if APPLE_CHANGES
1247         winargs.scrollbarsVisible = true;
1248 #endif
1249         QStringList flist = QStringList::split(',', features);
1250         QStringList::ConstIterator it = flist.begin();
1251         while (it != flist.end()) {
1252           QString s = *it++;
1253           QString key, val;
1254           int pos = s.find('=');
1255           if (pos >= 0) {
1256             key = s.left(pos).stripWhiteSpace().lower();
1257             val = s.mid(pos + 1).stripWhiteSpace().lower();
1258             int spacePos = val.find(' ');
1259             if (spacePos != -1) {
1260               val = val.left(spacePos);
1261             }
1262
1263             int scnum = QApplication::desktop()->screenNumber(widget->topLevelWidget());
1264
1265             QRect screen = QApplication::desktop()->screenGeometry(scnum);
1266             if (key == "left" || key == "screenx") {
1267               bool ok;
1268               double d = val.toDouble(&ok);
1269               if (d != 0 || ok) {
1270                 d += screen.x();
1271                 if (d < screen.x() || d > screen.right())
1272                   d = screen.x(); // only safe choice until size is determined
1273                 winargs.x = (int)d;
1274 #if APPLE_CHANGES
1275                 winargs.xSet = true;
1276 #endif
1277               }
1278             } else if (key == "top" || key == "screeny") {
1279               bool ok;
1280               double d = val.toDouble(&ok);
1281               if (d != 0 || ok) {
1282                 d += screen.y();
1283                 if (d < screen.y() || d > screen.bottom())
1284                   d = screen.y(); // only safe choice until size is determined
1285                 winargs.y = (int)d;
1286 #if APPLE_CHANGES
1287                 winargs.ySet = true;
1288 #endif
1289               }
1290             } else if (key == "height") {
1291               bool ok;
1292               double d = val.toDouble(&ok);
1293               if (d != 0 || ok) {
1294 #if !APPLE_CHANGES
1295                 d += 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2;
1296 #endif
1297                 if (d > screen.height())  // should actually check workspace
1298                   d = screen.height();
1299                 if (d < 100)
1300                   d = 100;
1301                 winargs.height = (int)d;
1302 #if APPLE_CHANGES
1303                 winargs.heightSet = true;
1304 #endif
1305               }
1306             } else if (key == "width") {
1307               bool ok;
1308               double d = val.toDouble(&ok);
1309               if (d != 0 || ok) {
1310 #if !APPLE_CHANGES
1311                 d += 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2;
1312 #endif
1313                 if (d > screen.width())    // should actually check workspace
1314                   d = screen.width();
1315                 if (d < 100)
1316                   d = 100;
1317                 winargs.width = (int)d;
1318 #if APPLE_CHANGES
1319                 winargs.widthSet = true;
1320 #endif
1321               }
1322             } else {
1323               goto boolargs;
1324             }
1325             continue;
1326           } else {
1327             // leaving away the value gives true
1328             key = s.stripWhiteSpace().lower();
1329             val = "1";
1330           }
1331         boolargs:
1332           if (key == "menubar")
1333             winargs.menuBarVisible = (val == "1" || val == "yes");
1334           else if (key == "toolbar")
1335             winargs.toolBarsVisible = (val == "1" || val == "yes");
1336           else if (key == "location")  // ### missing in WindowArgs
1337             winargs.toolBarsVisible = (val == "1" || val == "yes");
1338           else if (key == "status" || key == "statusbar")
1339             winargs.statusBarVisible = (val == "1" || val == "yes");
1340           else if (key == "resizable")
1341             winargs.resizable = (val == "1" || val == "yes");
1342           else if (key == "fullscreen")
1343             winargs.fullscreen = (val == "1" || val == "yes");
1344 #if APPLE_CHANGES
1345           else if (key == "scrollbars")
1346             winargs.scrollbarsVisible = !(val == "0" || val == "no");
1347 #endif
1348         }
1349       }
1350
1351       // prepare arguments
1352       KURL url;
1353       if (!str.isEmpty())
1354       {
1355         KHTMLPart* p = Window::retrieveActive(exec)->m_part;
1356         if ( p )
1357           url = p->htmlDocument().completeURL(str).string();
1358       }
1359
1360       KParts::URLArgs uargs;
1361       uargs.frameName = frameName;
1362       if ( uargs.frameName == "_top" )
1363       {
1364           // FIXME: referrer?
1365           while ( part->parentPart() )
1366               part = part->parentPart();
1367           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1368           part->scheduleRedirection(0, url.url(), false/*don't lock history*/, userGesture);
1369           return Window::retrieve(part);
1370       }
1371       if ( uargs.frameName == "_parent" )
1372       {
1373           // FIXME: referrer?
1374           if ( part->parentPart() )
1375               part = part->parentPart();
1376           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1377           part->scheduleRedirection(0, url.url(), false/*don't lock history*/, userGesture);
1378           return Window::retrieve(part);
1379       }
1380       uargs.serviceType = "text/html";
1381
1382       // request window (new or existing if framename is set)
1383       KParts::ReadOnlyPart *newPart = 0L;
1384       emit part->browserExtension()->createNewWindow("", uargs,winargs,newPart);
1385       if (newPart && newPart->inherits("KHTMLPart")) {
1386         KHTMLPart *khtmlpart = static_cast<KHTMLPart*>(newPart);
1387         //qDebug("opener set to %p (this Window's part) in new Window %p  (this Window=%p)",part,win,window);
1388         khtmlpart->setOpener(part);
1389         khtmlpart->setOpenedByJS(true);
1390         if (khtmlpart->document().isNull()) {
1391           khtmlpart->begin();
1392           khtmlpart->write("<HTML><BODY>");
1393           khtmlpart->end();
1394
1395           if (part->xmlDocImpl()) {
1396             kdDebug(6070) << "Setting domain to " << part->xmlDocImpl()->domain().string() << endl;
1397             khtmlpart->xmlDocImpl()->setDomain( part->docImpl()->domain(), true );
1398           }
1399           
1400           if ( part->docImpl() )
1401             khtmlpart->docImpl()->setBaseURL( part->docImpl()->baseURL() );
1402         }
1403 #if APPLE_CHANGES
1404         if (!url.isEmpty()) {
1405           bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
1406           // FIXME: Need to pass referrer here.
1407           khtmlpart->scheduleRedirection(0, url.url(), false, userGesture);
1408         }
1409 #else
1410         uargs.serviceType = QString::null;
1411         if (uargs.frameName == "_blank")
1412           uargs.frameName = QString::null;
1413         if (!url.isEmpty())
1414           // FIXME: need to pass referrer here
1415           emit khtmlpart->browserExtension()->openURLRequest(url,uargs);
1416 #endif
1417         return Window::retrieve(khtmlpart); // global object
1418       } else
1419         return Undefined();
1420     }
1421   }
1422 #if APPLE_CHANGES
1423   case Window::Print:
1424     part->print();
1425     return Undefined();
1426 #endif
1427   case Window::ScrollBy:
1428     window->updateLayout();
1429     if(args.size() >= 2 && widget)
1430       widget->scrollBy(args[0].toInt32(exec), args[1].toInt32(exec));
1431     return Undefined();
1432   case Window::Scroll:
1433   case Window::ScrollTo:
1434     window->updateLayout();
1435     if(args.size() >= 2 && widget)
1436       widget->setContentsPos(args[0].toInt32(exec), args[1].toInt32(exec));
1437     return Undefined();
1438   case Window::MoveBy:
1439     if(args.size() >= 2 && widget)
1440     {
1441       QWidget * tl = widget->topLevelWidget();
1442           QRect sg = QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(tl));
1443       QPoint dest = tl->pos() + QPoint( args[0].toInt32(exec), args[1].toInt32(exec) );
1444       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1445       if ( dest.x() >= sg.x() && dest.y() >= sg.x() &&
1446            dest.x()+tl->width() <= sg.width()+sg.x() &&
1447            dest.y()+tl->height() <= sg.height()+sg.y() )
1448         tl->move( dest );
1449     }
1450     return Undefined();
1451   case Window::MoveTo:
1452     if(args.size() >= 2 && widget)
1453     {
1454       QWidget * tl = widget->topLevelWidget();
1455           QRect sg = QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(tl));
1456       QPoint dest( args[0].toInt32(exec)+sg.x(), args[1].toInt32(exec)+sg.y() );
1457       // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
1458       if ( dest.x() >= sg.x() && dest.y() >= sg.y() &&
1459            dest.x()+tl->width() <= sg.width()+sg.x() &&
1460            dest.y()+tl->height() <= sg.height()+sg.y() )
1461         tl->move( dest );
1462     }
1463     return Undefined();
1464   case Window::ResizeBy:
1465     if(args.size() >= 2 && widget)
1466     {
1467       QWidget * tl = widget->topLevelWidget();
1468       QSize dest = tl->size() + QSize( args[0].toInt32(exec), args[1].toInt32(exec) );
1469           QRect sg = QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(tl));
1470       // Security check: within desktop limits and bigger than 100x100 (per spec)
1471       if ( tl->x()+dest.width() <= sg.x()+sg.width() &&
1472            tl->y()+dest.height() <= sg.y()+sg.height() &&
1473            dest.width() >= 100 && dest.height() >= 100 )
1474       {
1475         // Take into account the window frame
1476         int deltaWidth = tl->frameGeometry().width() - tl->width();
1477         int deltaHeight = tl->frameGeometry().height() - tl->height();
1478         tl->resize( dest.width() - deltaWidth, dest.height() - deltaHeight );
1479       }
1480     }
1481     return Undefined();
1482   case Window::ResizeTo:
1483     if(args.size() >= 2 && widget)
1484     {
1485       QWidget * tl = widget->topLevelWidget();
1486       QSize dest = QSize( args[0].toInt32(exec), args[1].toInt32(exec) );
1487           QRect sg = QApplication::desktop()->screenGeometry(QApplication::desktop()->screenNumber(tl));
1488       // Security check: within desktop limits and bigger than 100x100 (per spec)
1489       if ( tl->x()+dest.width() <= sg.x()+sg.width() &&
1490            tl->y()+dest.height() <= sg.y()+sg.height() &&
1491            dest.width() >= 100 && dest.height() >= 100 )
1492       {
1493         // Take into account the window frame
1494         int deltaWidth = tl->frameGeometry().width() - tl->width();
1495         int deltaHeight = tl->frameGeometry().height() - tl->height();
1496         tl->resize( dest.width() - deltaWidth, dest.height() - deltaHeight );
1497       }
1498     }
1499     return Undefined();
1500   case Window::SetTimeout:
1501     if (!window->isSafeScript(exec))
1502         return Undefined();
1503     if (args.size() >= 2 && v.isA(StringType)) {
1504       int i = args[1].toInt32(exec);
1505       int r = (const_cast<Window*>(window))->installTimeout(s, i, true /*single shot*/);
1506       return Number(r);
1507     }
1508     else if (args.size() >= 2 && v.isA(ObjectType) && Object::dynamicCast(v).implementsCall()) {
1509       Value func = args[0];
1510       int i = args[1].toInt32(exec);
1511
1512       // All arguments after the second should go to the function
1513       // FIXME: could be more efficient
1514       List funcArgs = args.copyTail().copyTail();
1515
1516       int r = (const_cast<Window*>(window))->installTimeout(func, funcArgs, i, true /*single shot*/);
1517       return Number(r);
1518     }
1519     else
1520       return Undefined();
1521   case Window::SetInterval:
1522     if (!window->isSafeScript(exec))
1523         return Undefined();
1524     if (args.size() >= 2 && v.isA(StringType)) {
1525       int i = args[1].toInt32(exec);
1526       int r = (const_cast<Window*>(window))->installTimeout(s, i, false);
1527       return Number(r);
1528     }
1529     else if (args.size() >= 2 && !Object::dynamicCast(v).isNull() &&
1530              Object::dynamicCast(v).implementsCall()) {
1531       Value func = args[0];
1532       int i = args[1].toInt32(exec);
1533
1534       // All arguments after the second should go to the function
1535       // FIXME: could be more efficient
1536       List funcArgs = args.copyTail().copyTail();
1537
1538       int r = (const_cast<Window*>(window))->installTimeout(func, funcArgs, i, false);
1539       return Number(r);
1540     }
1541     else
1542       return Undefined();
1543   case Window::ClearTimeout:
1544   case Window::ClearInterval:
1545     if (!window->isSafeScript(exec))
1546         return Undefined();
1547     (const_cast<Window*>(window))->clearTimeout(v.toInt32(exec));
1548     return Undefined();
1549   case Window::Focus:
1550     if (widget)
1551       widget->setActiveWindow();
1552     return Undefined();
1553   case Window::GetSelection:
1554     if (!window->isSafeScript(exec))
1555         return Undefined();
1556     return Value(window->selection());
1557   case Window::Blur:
1558 #if APPLE_CHANGES
1559     KWQ(part)->unfocusWindow();
1560 #else
1561     // TODO
1562 #endif
1563     return Undefined();
1564   case Window::Close:
1565     /* From http://developer.netscape.com/docs/manuals/js/client/jsref/window.htm :
1566        The close method closes only windows opened by JavaScript using the open method.
1567        If you attempt to close any other window, a confirm is generated, which
1568        lets the user choose whether the window closes.
1569        This is a security feature to prevent "mail bombs" containing self.close().
1570        However, if the window has only one document (the current one) in its
1571        session history, the close is allowed without any confirm. This is a
1572        special case for one-off windows that need to open other windows and
1573        then dispose of themselves.
1574     */
1575     if (!part->openedByJS())
1576     {
1577       // To conform to the SPEC, we only ask if the window
1578       // has more than one entry in the history (NS does that too).
1579       History history(exec,part);
1580       if ( history.get( exec, lengthPropertyName ).toInt32(exec) <= 1
1581 #if APPLE_CHANGES
1582            // FIXME: How are we going to handle this?
1583 #else
1584            || KMessageBox::questionYesNo( window->part()->view(), i18n("Close window?"), i18n("Confirmation Required") ) == KMessageBox::Yes
1585 #endif
1586            )
1587         (const_cast<Window*>(window))->scheduleClose();
1588     }
1589     else
1590     {
1591       (const_cast<Window*>(window))->scheduleClose();
1592     }
1593     return Undefined();
1594   case Window::CaptureEvents:
1595   case Window::ReleaseEvents:
1596         // If anyone implements these, they need the safescript security check.
1597         if (!window->isSafeScript(exec))
1598             return Undefined();
1599
1600     // Do nothing for now. These are NS-specific legacy calls.
1601     break;
1602   case Window::AddEventListener: {
1603         if (!window->isSafeScript(exec))
1604             return Undefined();
1605         
1606         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
1607         if (listener) {
1608             DOM::DocumentImpl* docimpl = static_cast<DOM::DocumentImpl *>(part->document().handle());
1609             docimpl->addWindowEventListener(DOM::EventImpl::typeToId(args[0].toString(exec).string()),listener,args[2].toBoolean(exec));
1610         }
1611         return Undefined();
1612     }
1613   case Window::RemoveEventListener: {
1614         if (!window->isSafeScript(exec))
1615             return Undefined();
1616         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
1617         if (listener) {
1618             DOM::DocumentImpl* docimpl = static_cast<DOM::DocumentImpl *>(part->document().handle());
1619             docimpl->removeWindowEventListener(DOM::EventImpl::typeToId(args[0].toString(exec).string()),listener,args[2].toBoolean(exec));
1620         }
1621         return Undefined();
1622     }
1623
1624   }
1625   return Undefined();
1626 }
1627
1628 void Window::updateLayout() const
1629 {
1630   DOM::DocumentImpl* docimpl = static_cast<DOM::DocumentImpl *>(m_part->document().handle());
1631   if (docimpl) {
1632     docimpl->updateLayout();
1633   }
1634 }
1635
1636
1637 ////////////////////// ScheduledAction ////////////////////////
1638
1639 ScheduledAction::ScheduledAction(Object _func, List _args, bool _singleShot)
1640 {
1641   //kdDebug(6070) << "ScheduledAction::ScheduledAction(isFunction) " << this << endl;
1642   func = _func;
1643   args = _args;
1644   isFunction = true;
1645   singleShot = _singleShot;
1646 }
1647
1648 ScheduledAction::ScheduledAction(const QString &_code, bool _singleShot)
1649 {
1650   //kdDebug(6070) << "ScheduledAction::ScheduledAction(!isFunction) " << this << endl;
1651   //func = 0;
1652   //args = 0;
1653   code = _code;
1654   isFunction = false;
1655   singleShot = _singleShot;
1656 }
1657
1658 void ScheduledAction::execute(Window *window)
1659 {
1660   ScriptInterpreter *interpreter = static_cast<ScriptInterpreter *>(KJSProxy::proxy(window->m_part)->interpreter());
1661
1662   interpreter->setProcessingTimerCallback(true);
1663
1664   //kdDebug(6070) << "ScheduledAction::execute " << this << endl;
1665   if (isFunction) {
1666     if (func.implementsCall()) {
1667       // #### check this
1668       Q_ASSERT( window->m_part );
1669       if ( window->m_part )
1670       {
1671         KJS::Interpreter *interpreter = KJSProxy::proxy( window->m_part )->interpreter();
1672         ExecState *exec = interpreter->globalExec();
1673         Q_ASSERT( window == interpreter->globalObject().imp() );
1674         Object obj( window );
1675         Interpreter::lock();
1676         func.call(exec,obj,args); // note that call() creates its own execution state for the func call
1677         Interpreter::unlock();
1678         if ( exec->hadException() ) {
1679 #if APPLE_CHANGES
1680           Interpreter::lock();
1681           char *message = exec->exception().toObject(exec).get(exec, messagePropertyName).toString(exec).ascii();
1682           int lineNumber =  exec->exception().toObject(exec).get(exec, "line").toInt32(exec);
1683           Interpreter::unlock();
1684           if (Interpreter::shouldPrintExceptions()) {
1685             printf("(timer):%s\n", message);
1686           }
1687           KWQ(window->m_part)->addMessageToConsole(message, lineNumber, QString());
1688 #endif
1689           exec->clearException();
1690         }
1691       }
1692     }
1693   }
1694   else {
1695     window->m_part->executeScript(code);
1696   }
1697
1698   // Update our document's rendering following the execution of the timeout callback.
1699   DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(window->m_part->document().handle());
1700   doc->updateRendering();
1701   
1702   interpreter->setProcessingTimerCallback(false);
1703 }
1704
1705 ScheduledAction::~ScheduledAction()
1706 {
1707   //kdDebug(6070) << "ScheduledAction::~ScheduledAction " << this << endl;
1708 }
1709
1710 ////////////////////// WindowQObject ////////////////////////
1711
1712 WindowQObject::WindowQObject(Window *w)
1713   : parent(w)
1714 {
1715   //kdDebug(6070) << "WindowQObject::WindowQObject " << this << endl;
1716   part = parent->m_part;
1717   connect( parent->m_part, SIGNAL( destroyed() ),
1718            this, SLOT( parentDestroyed() ) );
1719 }
1720
1721 WindowQObject::~WindowQObject()
1722 {
1723   //kdDebug(6070) << "WindowQObject::~WindowQObject " << this << endl;
1724   parentDestroyed(); // reuse same code
1725 }
1726
1727 void WindowQObject::parentDestroyed()
1728 {
1729   //kdDebug(6070) << "WindowQObject::parentDestroyed " << this << " we have " << scheduledActions.count() << " actions in the map" << endl;
1730   killTimers();
1731   QMapIterator<int,ScheduledAction*> it;
1732   for (it = scheduledActions.begin(); it != scheduledActions.end(); ++it) {
1733     ScheduledAction *action = *it;
1734     //kdDebug(6070) << "WindowQObject::parentDestroyed deleting action " << action << endl;
1735     delete action;
1736   }
1737   scheduledActions.clear();
1738 }
1739
1740 int WindowQObject::installTimeout(const UString &handler, int t, bool singleShot)
1741 {
1742   //kdDebug(6070) << "WindowQObject::installTimeout " << this << " " << handler.ascii() << endl;
1743   int id = startTimer(t);
1744   ScheduledAction *action = new ScheduledAction(handler.qstring(),singleShot);
1745   scheduledActions.insert(id, action);
1746   //kdDebug(6070) << this << " got id=" << id << " action=" << action << " - now having " << scheduledActions.count() << " actions"<<endl;
1747   return id;
1748 }
1749
1750 int WindowQObject::installTimeout(const Value &func, List args, int t, bool singleShot)
1751 {
1752   Object objFunc = Object::dynamicCast( func );
1753   int id = startTimer(t);
1754   scheduledActions.insert(id, new ScheduledAction(objFunc,args,singleShot));
1755   return id;
1756 }
1757
1758 QMap<int, ScheduledAction*> *WindowQObject::pauseTimeouts(const void *key)
1759 {
1760     QMapIterator<int,ScheduledAction*> it;
1761
1762     QMap<int, KJS::ScheduledAction*>*pausedActions = new QMap<int, KJS::ScheduledAction*>;
1763     for (it = scheduledActions.begin(); it != scheduledActions.end(); ++it) {
1764         int timerId = it.key();
1765         pauseTimer (timerId, key);
1766         pausedActions->insert(timerId, it.data());
1767     }
1768     scheduledActions.clear();
1769     return pausedActions;
1770 }
1771
1772 void WindowQObject::resumeTimeouts(QMap<int, ScheduledAction*> *sa, const void *key)
1773 {
1774     QMapIterator<int,ScheduledAction*> it;
1775     for (it = sa->begin(); it != sa->end(); ++it) {
1776         int timerId = it.key();
1777         scheduledActions.insert(timerId, it.data());
1778     }
1779     sa->clear();
1780     resumeTimers (key, this);
1781 }
1782
1783 void WindowQObject::clearTimeout(int timerId, bool delAction)
1784 {
1785   //kdDebug(6070) << "WindowQObject::clearTimeout " << this << " timerId=" << timerId << " delAction=" << delAction << endl;
1786   killTimer(timerId);
1787   if (delAction) {
1788     QMapIterator<int,ScheduledAction*> it = scheduledActions.find(timerId);
1789     if (it != scheduledActions.end()) {
1790       ScheduledAction *action = *it;
1791       scheduledActions.remove(it);
1792       delete action;
1793     }
1794   }
1795 }
1796
1797 void WindowQObject::timerEvent(QTimerEvent *e)
1798 {
1799   QMapIterator<int,ScheduledAction*> it = scheduledActions.find(e->timerId());
1800   if (it != scheduledActions.end()) {
1801     ScheduledAction *action = *it;
1802     bool singleShot = action->singleShot;
1803     //kdDebug(6070) << "WindowQObject::timerEvent " << this << " action=" << action << " singleShot:" << singleShot << endl;
1804
1805     // remove single shots installed by setTimeout()
1806     if (singleShot)
1807     {
1808       clearTimeout(e->timerId(),false);
1809       scheduledActions.remove(it);
1810     }
1811         
1812     if (!parent->part().isNull())
1813       action->execute(parent);
1814
1815     // It is important to test singleShot and not action->singleShot here - the
1816     // action could have been deleted already if not single shot and if the
1817     // JS code called by execute() calls clearTimeout().
1818     if (singleShot)
1819       delete action;
1820   } else
1821     kdWarning(6070) << "WindowQObject::timerEvent this=" << this << " timer " << e->timerId()
1822                     << " not found (" << scheduledActions.count() << " actions in map)" << endl;
1823 }
1824
1825 void WindowQObject::timeoutClose()
1826 {
1827   if (!parent->part().isNull())
1828   {
1829     //kdDebug(6070) << "WindowQObject::timeoutClose -> closing window" << endl;
1830     delete parent->m_part;
1831   }
1832 }
1833
1834 #if APPLE_CHANGES
1835 bool WindowQObject::hasTimeouts()
1836 {
1837     return scheduledActions.count();
1838 }
1839 #endif
1840
1841 Value FrameArray::get(ExecState *exec, const Identifier &p) const
1842 {
1843 #ifdef KJS_VERBOSE
1844   kdDebug(6070) << "FrameArray::get " << p.qstring() << " part=" << (void*)part << endl;
1845 #endif
1846   if (part.isNull())
1847     return Undefined();
1848
1849   QPtrList<KParts::ReadOnlyPart> frames = part->frames();
1850   unsigned int len = frames.count();
1851   if (p == lengthPropertyName)
1852     return Number(len);
1853   else if (p== "location") // non-standard property, but works in NS and IE
1854   {
1855     Object obj = Object::dynamicCast( Window::retrieve( part ) );
1856     if ( !obj.isNull() )
1857       return obj.get( exec, "location" );
1858     return Undefined();
1859   }
1860
1861   // check for the name or number
1862   KParts::ReadOnlyPart *frame = part->findFrame(p.qstring());
1863   if (!frame) {
1864     bool ok;
1865     unsigned int i = p.toArrayIndex(&ok);
1866     if (ok && i < len)
1867       frame = frames.at(i);
1868   }
1869
1870   // we are potentially fetching a reference to a another Window object here.
1871   // i.e. we may be accessing objects from another interpreter instance.
1872   // Therefore we have to be a bit careful with memory managment.
1873   if (frame && frame->inherits("KHTMLPart")) {
1874     KHTMLPart *khtml = static_cast<KHTMLPart*>(frame);
1875     return Window::retrieve(khtml);
1876   }
1877
1878   return ObjectImp::get(exec, p);
1879 }
1880
1881 UString FrameArray::toString(ExecState *) const
1882 {
1883   return "[object FrameArray]";
1884 }
1885
1886 ////////////////////// Location Object ////////////////////////
1887
1888 const ClassInfo Location::info = { "Location", 0, 0, 0 };
1889 /*
1890 @begin LocationTable 11
1891   hash          Location::Hash          DontDelete
1892   host          Location::Host          DontDelete
1893   hostname      Location::Hostname      DontDelete
1894   href          Location::Href          DontDelete
1895   pathname      Location::Pathname      DontDelete
1896   port          Location::Port          DontDelete
1897   protocol      Location::Protocol      DontDelete
1898   search        Location::Search        DontDelete
1899   [[==]]        Location::EqualEqual    DontDelete|ReadOnly
1900   toString      Location::ToString      DontDelete|Function 0
1901   replace       Location::Replace       DontDelete|Function 1
1902   reload        Location::Reload        DontDelete|Function 0
1903 @end
1904 */
1905 IMPLEMENT_PROTOFUNC(LocationFunc)
1906 Location::Location(KHTMLPart *p) : m_part(p)
1907 {
1908   //kdDebug(6070) << "Location::Location " << this << " m_part=" << (void*)m_part << endl;
1909 }
1910
1911 Location::~Location()
1912 {
1913   //kdDebug(6070) << "Location::~Location " << this << " m_part=" << (void*)m_part << endl;
1914 }
1915
1916 Value Location::get(ExecState *exec, const Identifier &p) const
1917 {
1918 #ifdef KJS_VERBOSE
1919   kdDebug(6070) << "Location::get " << p.qstring() << " m_part=" << (void*)m_part << endl;
1920 #endif
1921
1922   if (m_part.isNull())
1923     return Undefined();
1924   
1925   const Window* window = Window::retrieveWindow(m_part);
1926   if (!window || !window->isSafeScript(exec))
1927       return Undefined();
1928
1929   KURL url = m_part->url();
1930   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
1931   if (entry)
1932     switch (entry->value) {
1933     case Hash:
1934       return String( url.ref().isNull() ? QString("") : "#" + url.ref() );
1935     case Host: {
1936       UString str = url.host();
1937       if (url.port())
1938         str += ":" + QString::number((int)url.port());
1939       return String(str);
1940       // Note: this is the IE spec. The NS spec swaps the two, it says
1941       // "The hostname property is the concatenation of the host and port properties, separated by a colon."
1942       // Bleh.
1943     }
1944     case Hostname:
1945       return String( url.host() );
1946     case Href:
1947       if (!url.hasPath())
1948         return String( url.prettyURL()+"/" );
1949       else
1950         return String( url.prettyURL() );
1951     case Pathname:
1952       return String( url.path().isEmpty() ? QString("/") : url.path() );
1953     case Port:
1954       return String( url.port() ? QString::number((int)url.port()) : QString::fromLatin1("") );
1955     case Protocol:
1956       return String( url.protocol()+":" );
1957     case Search:
1958       return String( url.query() );
1959     case EqualEqual: // [[==]]
1960       return String(toString(exec));
1961     case ToString:
1962       return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr);
1963     }
1964   // Look for overrides
1965   ValueImp * val = ObjectImp::getDirect(p);
1966   if (val)
1967     return Value(val);
1968   if (entry)
1969     switch (entry->value) {
1970     case Replace:
1971       return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr);
1972     case Reload:
1973       return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr);
1974     }
1975
1976   return Undefined();
1977 }
1978
1979 void Location::put(ExecState *exec, const Identifier &p, const Value &v, int attr)
1980 {
1981 #ifdef KJS_VERBOSE
1982   kdDebug(6070) << "Location::put " << p.qstring() << " m_part=" << (void*)m_part << endl;
1983 #endif
1984   if (m_part.isNull())
1985     return;
1986
1987   QString str = v.toString(exec).qstring();
1988   KURL url = m_part->url();
1989   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
1990   if (entry)
1991     switch (entry->value) {
1992     case Href: {
1993       KHTMLPart* p = Window::retrieveActive(exec)->part();
1994       if ( p )
1995         url = p->htmlDocument().completeURL( str ).string();
1996       else
1997         url = str;
1998       break;
1999     }
2000     case Hash:
2001       url.setRef(str);
2002       break;
2003     case Host: {
2004       QString host = str.left(str.find(":"));
2005       QString port = str.mid(str.find(":")+1);
2006       url.setHost(host);
2007       url.setPort(port.toUInt());
2008       break;
2009     }
2010     case Hostname:
2011       url.setHost(str);
2012       break;
2013     case Pathname:
2014       url.setPath(str);
2015       break;
2016     case Port:
2017       url.setPort(str.toUInt());
2018       break;
2019     case Protocol:
2020       url.setProtocol(str);
2021       break;
2022     case Search:
2023       url.setQuery(str);
2024       break;
2025     }
2026   else {
2027     ObjectImp::put(exec, p, v, attr);
2028     return;
2029   }
2030   bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2031 #if APPLE_CHANGES
2032   // We want a new history item if this JS was called via a user gesture
2033   m_part->scheduleRedirection(0, url.url(), !userGesture, userGesture);
2034 #else
2035   m_part->scheduleRedirection(0, url.url(), false /*don't lock history*/, userGesture);
2036 #endif
2037 }
2038
2039 Value Location::toPrimitive(ExecState *exec, Type) const
2040 {
2041   return String(toString(exec));
2042 }
2043
2044 UString Location::toString(ExecState *) const
2045 {
2046   if (!m_part->url().hasPath())
2047     return m_part->url().prettyURL()+"/";
2048   else
2049     return m_part->url().prettyURL();
2050 }
2051
2052 Value LocationFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
2053 {
2054   if (!thisObj.inherits(&Location::info)) {
2055     Object err = Error::create(exec,TypeError);
2056     exec->setException(err);
2057     return err;
2058   }
2059   Location *location = static_cast<Location *>(thisObj.imp());
2060   KHTMLPart *part = location->part();
2061   if (part) {
2062       
2063     Window* window = Window::retrieveWindow(part);
2064     if (!window->isSafeScript(exec) && id != Location::Replace)
2065         return Undefined();
2066       
2067     switch (id) {
2068     case Location::Replace:
2069     {
2070       QString str = args[0].toString(exec).qstring();
2071       KHTMLPart* p = Window::retrieveActive(exec)->part();
2072       if ( p ) {
2073         bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2074         part->scheduleRedirection(0, p->htmlDocument().completeURL(str).string(), true /*lock history*/, userGesture);
2075       }
2076       break;
2077     }
2078     case Location::Reload:
2079     {
2080       bool userGesture = static_cast<ScriptInterpreter *>(exec->dynamicInterpreter())->wasRunByUserGesture();
2081       part->scheduleRedirection(0, part->url().url(), true/*lock history*/, userGesture);
2082       break;
2083     }
2084     case Location::ToString:
2085       return String(location->toString(exec));
2086     }
2087   } else
2088     kdDebug(6070) << "LocationFunc::tryExecute - no part!" << endl;
2089   return Undefined();
2090 }
2091
2092 ////////////////////// Selection Object ////////////////////////
2093
2094 const ClassInfo Selection::info = { "Selection", 0, 0, 0 };
2095 /*
2096 @begin SelectionTable 19
2097   anchorNode                Selection::AnchorNode                        DontDelete|ReadOnly
2098   anchorOffset              Selection::AnchorOffset                  DontDelete|ReadOnly
2099   focusNode                 Selection::FocusNode                         DontDelete|ReadOnly
2100   focusOffset               Selection::FocusOffset                       DontDelete|ReadOnly
2101   baseNode                  Selection::AnchorNode                        DontDelete|ReadOnly
2102   baseOffset                Selection::AnchorOffset              DontDelete|ReadOnly
2103   extentNode                Selection::FocusNode                 DontDelete|ReadOnly
2104   extentOffset              Selection::FocusOffset                       DontDelete|ReadOnly
2105   isCollapsed               Selection::IsCollapsed                       DontDelete|ReadOnly
2106   type                      Selection::_Type                     DontDelete|ReadOnly
2107   [[==]]                        Selection::EqualEqual                DontDelete|ReadOnly
2108   toString                  Selection::ToString                  DontDelete|Function 0
2109   collapse                  Selection::Collapse                  DontDelete|Function 2
2110   collapseToEnd             Selection::CollapseToEnd             DontDelete|Function 0
2111   collapseToStart           Selection::CollapseToStart           DontDelete|Function 0
2112   empty                     Selection::Empty                     DontDelete|Function 0
2113   setBaseAndExtent          Selection::SetBaseAndExtent          DontDelete|Function 4
2114   setPosition               Selection::SetPosition               DontDelete|Function 2
2115   modify                    Selection::Modify                    DontDelete|Function 3
2116 @end
2117 */
2118 IMPLEMENT_PROTOFUNC(SelectionFunc)
2119 Selection::Selection(KHTMLPart *p) : m_part(p)
2120 {
2121   //kdDebug(6070) << "Selection::Selection " << this << " m_part=" << (void*)m_part << endl;
2122 }
2123
2124 Selection::~Selection()
2125 {
2126   //kdDebug(6070) << "Selection::~Selection " << this << " m_part=" << (void*)m_part << endl;
2127 }
2128
2129 Value Selection::get(ExecState *exec, const Identifier &p) const
2130 {
2131 #ifdef KJS_VERBOSE
2132   kdDebug(6070) << "Selection::get " << p.qstring() << " m_part=" << (void*)m_part << endl;
2133 #endif
2134
2135   if (m_part.isNull())
2136     return Undefined();
2137   
2138   const Window* window = Window::retrieveWindow(m_part);
2139   if (!window || !window->isSafeScript(exec))
2140       return Undefined();
2141
2142   DocumentImpl *docimpl = m_part->xmlDocImpl();
2143   if (docimpl)
2144     docimpl->updateLayout();
2145
2146   KURL url = m_part->url();
2147   const HashEntry *entry = Lookup::findEntry(&SelectionTable, p);
2148   if (entry)
2149     switch (entry->value) {
2150         case AnchorNode:
2151         case BaseNode:
2152             return getDOMNode(exec, Node(m_part->selection().base().node()));
2153         case AnchorOffset:
2154         case BaseOffset:
2155             return Number(m_part->selection().base().offset());
2156         case FocusNode:
2157         case ExtentNode:
2158             return getDOMNode(exec, Node(m_part->selection().extent().node()));
2159         case FocusOffset:
2160         case ExtentOffset:
2161             return Number(m_part->selection().extent().offset());
2162         case IsCollapsed:
2163             return Boolean(m_part->selection().state() == DOM::Selection::CARET);
2164         case _Type: {
2165             switch (m_part->selection().state()) {
2166                 case DOM::Selection::NONE:
2167                     return String("None");
2168                 case DOM::Selection::CARET:
2169                     return String("Caret");
2170                 case DOM::Selection::RANGE:
2171                     return String("Range");
2172             }
2173         }
2174         case EqualEqual:
2175             return String(toString(exec));
2176         case ToString:
2177           return lookupOrCreateFunction<SelectionFunc>(exec,p,this,entry->value,entry->params,entry->attr);
2178     }
2179     // Look for overrides
2180     ValueImp * val = ObjectImp::getDirect(p);
2181     if (val)
2182         return Value(val);
2183     if (entry)
2184         switch (entry->value) {
2185             case Collapse:
2186             case CollapseToEnd:
2187             case CollapseToStart:
2188             case Empty:
2189             case SetBaseAndExtent:
2190             case SetPosition:
2191             case Modify:
2192                 return lookupOrCreateFunction<SelectionFunc>(exec,p,this,entry->value,entry->params,entry->attr);
2193         }
2194
2195     return Undefined();
2196 }
2197
2198 void Selection::put(ExecState *exec, const Identifier &p, const Value &v, int attr)
2199 {
2200 }
2201
2202 Value Selection::toPrimitive(ExecState *exec, Type) const
2203 {
2204   return String(toString(exec));
2205 }
2206
2207 UString Selection::toString(ExecState *) const
2208 {
2209     if (m_part->selection().state() != DOM::Selection::RANGE)
2210         return UString("");
2211     return UString(m_part->selection().toRange().toString());
2212 }
2213
2214 Value SelectionFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
2215 {
2216     if (!thisObj.inherits(&Selection::info)) {
2217         Object err = Error::create(exec,TypeError);
2218         exec->setException(err);
2219         return err;
2220     }
2221     Selection *selection = static_cast<Selection *>(thisObj.imp());
2222     KHTMLPart *part = selection->part();
2223     if (part) {
2224         DocumentImpl *docimpl = part->xmlDocImpl();
2225         if (docimpl)
2226             docimpl->updateLayout();
2227             
2228         switch (id) {
2229             case Selection::Collapse:
2230                 TypingCommand::closeTyping(part->lastEditCommand());
2231                 part->setSelection(DOM::Selection(Position(KJS::toNode(args[0]).handle(), args[1].toInt32(exec))));
2232                 break;
2233             case Selection::CollapseToEnd:
2234                 TypingCommand::closeTyping(part->lastEditCommand());
2235                 part->setSelection(DOM::Selection(part->selection().end()));
2236                 break;
2237             case Selection::CollapseToStart:
2238                 TypingCommand::closeTyping(part->lastEditCommand());
2239                 part->setSelection(DOM::Selection(part->selection().start()));
2240                 break;
2241             case Selection::Empty:
2242                 TypingCommand::closeTyping(part->lastEditCommand());
2243                 part->clearSelection();
2244                 break;
2245             case Selection::SetBaseAndExtent: {
2246                 TypingCommand::closeTyping(part->lastEditCommand());
2247                 Position base(KJS::toNode(args[0]).handle(), args[1].toInt32(exec));
2248                 Position extent(KJS::toNode(args[2]).handle(), args[3].toInt32(exec));
2249                 part->setSelection(DOM::Selection(base, extent));
2250                 break;
2251             }
2252             case Selection::SetPosition:
2253                 TypingCommand::closeTyping(part->lastEditCommand());
2254                 part->setSelection(DOM::Selection(Position(KJS::toNode(args[0]).handle(), args[1].toInt32(exec))));
2255                 break;
2256             case Selection::Modify: {
2257                 TypingCommand::closeTyping(part->lastEditCommand());
2258                 DOM::Selection s(part->selection());
2259                 DOM::Selection::EAlter alter = DOM::Selection::MOVE;
2260                 if (args[0].toString(exec).string().lower() == "extend")
2261                     alter = DOM::Selection::EXTEND;
2262                 DOMString directionString = args[1].toString(exec).string().lower();
2263                 DOM::Selection::EDirection direction = DOM::Selection::FORWARD;
2264                 if (directionString == "backward")
2265                     direction = DOM::Selection::BACKWARD;
2266                 else if (directionString == "left")
2267                     direction = DOM::Selection::LEFT;
2268                 if (directionString == "right")
2269                     direction = DOM::Selection::RIGHT;
2270                 DOM::Selection::ETextGranularity granularity = DOM::Selection::CHARACTER;
2271                 DOMString granularityString = args[2].toString(exec).string().lower();
2272                 if (granularityString == "word")
2273                     granularity = DOM::Selection::WORD;
2274                 else if (granularityString == "line")
2275                     granularity = DOM::Selection::LINE;
2276                 s.modify(alter, direction, granularity);
2277                 part->setSelection(s);
2278             }
2279         }
2280     }
2281
2282     return Undefined();
2283 }
2284
2285 ////////////////////// History Object ////////////////////////
2286
2287 const ClassInfo History::info = { "History", 0, 0, 0 };
2288 /*
2289 @begin HistoryTable 4
2290   length        History::Length         DontDelete|ReadOnly
2291   back          History::Back           DontDelete|Function 0
2292   forward       History::Forward        DontDelete|Function 0
2293   go            History::Go             DontDelete|Function 1
2294 @end
2295 */
2296 IMPLEMENT_PROTOFUNC(HistoryFunc)
2297
2298 Value History::get(ExecState *exec, const Identifier &p) const
2299 {
2300   return lookupGet<HistoryFunc,History,ObjectImp>(exec,p,&HistoryTable,this);
2301 }
2302
2303 Value History::getValueProperty(ExecState *, int token) const
2304 {
2305   switch (token) {
2306   case Length:
2307   {
2308     KParts::BrowserExtension *ext = part->browserExtension();
2309     if ( !ext )
2310       return Number( 0 );
2311
2312     KParts::BrowserInterface *iface = ext->browserInterface();
2313     if ( !iface )
2314       return Number( 0 );
2315
2316     QVariant length = iface->property( "historyLength" );
2317
2318     if ( length.type() != QVariant::UInt )
2319       return Number( 0 );
2320
2321     return Number( length.toUInt() );
2322   }
2323   default:
2324     kdWarning() << "Unhandled token in History::getValueProperty : " << token << endl;
2325     return Undefined();
2326   }
2327 }
2328
2329 UString History::toString(ExecState *exec) const
2330 {
2331   return "[object History]";
2332 }
2333
2334 Value HistoryFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
2335 {
2336   if (!thisObj.inherits(&History::info)) {
2337     Object err = Error::create(exec,TypeError);
2338     exec->setException(err);
2339     return err;
2340   }
2341   History *history = static_cast<History *>(thisObj.imp());
2342
2343   int steps;
2344   switch (id) {
2345   case History::Back:
2346     steps = -1;
2347     break;
2348   case History::Forward:
2349     steps = 1;
2350     break;
2351   case History::Go:
2352     steps = args[0].toInt32(exec);
2353     break;
2354   default:
2355     return Undefined();
2356   }
2357
2358   history->part->scheduleHistoryNavigation(steps);
2359   return Undefined();
2360 }
2361
2362 /////////////////////////////////////////////////////////////////////////////
2363
2364 #ifdef Q_WS_QWS
2365
2366 const ClassInfo Konqueror::info = { "Konqueror", 0, 0, 0 };
2367
2368 bool Konqueror::hasProperty(ExecState *exec, const Identifier &p) const
2369 {
2370   if ( p.qstring().startsWith( "goHistory" ) ) return false;
2371
2372   return true;
2373 }
2374
2375 Value Konqueror::get(ExecState *exec, const Identifier &p) const
2376 {
2377   if ( p == "goHistory" || part->url().protocol() != "http" || part->url().host() != "localhost" )
2378     return Undefined();
2379
2380   KParts::BrowserExtension *ext = part->browserExtension();
2381   if ( ext ) {
2382     KParts::BrowserInterface *iface = ext->browserInterface();
2383     if ( iface ) {
2384       QVariant prop = iface->property( p.qstring().latin1() );
2385
2386       if ( prop.isValid() ) {
2387         switch( prop.type() ) {
2388         case QVariant::Int:
2389           return Number( prop.toInt() );
2390         case QVariant::String:
2391           return String( prop.toString() );
2392         default:
2393           break;
2394         }
2395       }
2396     }
2397   }
2398
2399   return /*Function*/( new KonquerorFunc(this, p.qstring().latin1() ) );
2400 }
2401
2402 Value KonquerorFunc::tryCall(ExecState *exec, Object &, const List &args)
2403 {
2404   KParts::BrowserExtension *ext = konqueror->part->browserExtension();
2405
2406   if(!ext)
2407     return Undefined();
2408
2409   KParts::BrowserInterface *iface = ext->browserInterface();
2410
2411   if ( !iface )
2412     return Undefined();
2413
2414   QCString n = m_name.data();
2415   n += "()";
2416   iface->callMethod( n.data(), QVariant() );
2417
2418   return Undefined();
2419 }
2420
2421 UString Konqueror::toString(ExecState *) const
2422 {
2423   return UString("[object Konqueror]");
2424 }
2425
2426 #endif
2427 /////////////////////////////////////////////////////////////////////////////
2428
2429 #include "kjs_window.moc"
2430