khtml Library API Documentation

kjs_window.cpp

00001 // -*- c-basic-offset: 2 -*-
00002 /*
00003  *  This file is part of the KDE libraries
00004  *  Copyright (C) 2000-2003 Harri Porten (porten@kde.org)
00005  *  Copyright (C) 2001-2003 David Faure (faure@kde.org)
00006  *  Copyright (C) 2003 Apple Computer, Inc.
00007  *
00008  *  This library is free software; you can redistribute it and/or
00009  *  modify it under the terms of the GNU Library General Public
00010  *  License as published by the Free Software Foundation; either
00011  *  version 2 of the License, or (at your option) any later version.
00012  *
00013  *  This library is distributed in the hope that it will be useful,
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  *  Library General Public License for more details.
00017  *
00018  *  You should have received a copy of the GNU Library General Public
00019  *  License along with this library; if not, write to the Free Software
00020  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 #include "config.h"
00023 
00024 #include <qstylesheet.h>
00025 #include <qtimer.h>
00026 #include <qpaintdevicemetrics.h>
00027 #include <qapplication.h>
00028 #include <kdebug.h>
00029 #include <kmessagebox.h>
00030 #include <kinputdialog.h>
00031 #include <klocale.h>
00032 #include <kparts/browserinterface.h>
00033 #include <kwin.h>
00034 
00035 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00036 #include <kwinmodule.h> // schroder
00037 #endif
00038 
00039 #include <kbookmarkmanager.h>
00040 #include <kglobalsettings.h>
00041 #include <assert.h>
00042 #include <qstyle.h>
00043 #include <qobjectlist.h>
00044 #include <kstringhandler.h>
00045 
00046 #include "kjs_proxy.h"
00047 #include "kjs_window.h"
00048 #include "kjs_navigator.h"
00049 #include "kjs_mozilla.h"
00050 #include "kjs_html.h"
00051 #include "kjs_range.h"
00052 #include "kjs_traversal.h"
00053 #include "kjs_css.h"
00054 #include "kjs_events.h"
00055 #include "xmlhttprequest.h"
00056 
00057 #include "khtmlview.h"
00058 #include "khtml_part.h"
00059 #include "khtml_settings.h"
00060 #include "xml/dom2_eventsimpl.h"
00061 #include "xml/dom_docimpl.h"
00062 #include "misc/htmltags.h"
00063 #include "html/html_documentimpl.h"
00064 
00065 using namespace KJS;
00066 
00067 namespace KJS {
00068 
00069   class History : public ObjectImp {
00070     friend class HistoryFunc;
00071   public:
00072     History(ExecState *exec, KHTMLPart *p)
00073       : ObjectImp(exec->interpreter()->builtinObjectPrototype()), part(p) { }
00074     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
00075     Value getValueProperty(ExecState *exec, int token) const;
00076     virtual const ClassInfo* classInfo() const { return &info; }
00077     static const ClassInfo info;
00078     enum { Back, Forward, Go, Length };
00079   private:
00080     QGuardedPtr<KHTMLPart> part;
00081   };
00082 
00083   class External : public ObjectImp {
00084     friend class ExternalFunc;
00085   public:
00086     External(ExecState *exec, KHTMLPart *p)
00087       : ObjectImp(exec->interpreter()->builtinObjectPrototype()), part(p) { }
00088     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
00089     virtual const ClassInfo* classInfo() const { return &info; }
00090     static const ClassInfo info;
00091     enum { AddFavorite };
00092   private:
00093     QGuardedPtr<KHTMLPart> part;
00094   };
00095 
00096   class FrameArray : public ObjectImp {
00097   public:
00098     FrameArray(ExecState *exec, KHTMLPart *p)
00099       : ObjectImp(exec->interpreter()->builtinObjectPrototype()), part(p) { }
00100     virtual Value get(ExecState *exec, const Identifier &propertyName) const;
00101   private:
00102     QGuardedPtr<KHTMLPart> part;
00103   };
00104 
00105 #ifdef Q_WS_QWS
00106   class KonquerorFunc : public DOMFunction {
00107   public:
00108     KonquerorFunc(const Konqueror* k, const char* name)
00109       : DOMFunction(), konqueror(k), m_name(name) { }
00110     virtual Value tryCall(ExecState *exec, Object &thisObj, const List &args);
00111 
00112   private:
00113     const Konqueror* konqueror;
00114     QCString m_name;
00115   };
00116 #endif
00117 } // namespace KJS
00118 
00119 #include "kjs_window.lut.h"
00120 #include "rendering/render_replaced.h"
00121 
00123 
00124 // table for screen object
00125 /*
00126 @begin ScreenTable 7
00127   height        Screen::Height      DontEnum|ReadOnly
00128   width         Screen::Width       DontEnum|ReadOnly
00129   colorDepth    Screen::ColorDepth  DontEnum|ReadOnly
00130   pixelDepth    Screen::PixelDepth  DontEnum|ReadOnly
00131   availLeft     Screen::AvailLeft   DontEnum|ReadOnly
00132   availTop      Screen::AvailTop    DontEnum|ReadOnly
00133   availHeight   Screen::AvailHeight DontEnum|ReadOnly
00134   availWidth    Screen::AvailWidth  DontEnum|ReadOnly
00135 @end
00136 */
00137 
00138 const ClassInfo Screen::info = { "Screen", 0, &ScreenTable, 0 };
00139 
00140 // We set the object prototype so that toString is implemented
00141 Screen::Screen(ExecState *exec)
00142   : ObjectImp(exec->interpreter()->builtinObjectPrototype()) {}
00143 
00144 Value Screen::get(ExecState *exec, const Identifier &p) const
00145 {
00146 #ifdef KJS_VERBOSE
00147   kdDebug(6070) << "Screen::get " << p.qstring() << endl;
00148 #endif
00149   return lookupGetValue<Screen,ObjectImp>(exec,p,&ScreenTable,this);
00150 }
00151 
00152 Value Screen::getValueProperty(ExecState *exec, int token) const
00153 {
00154 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00155   KWinModule info(0, KWinModule::INFO_DESKTOP);
00156 #endif
00157   QWidget *thisWidget = Window::retrieveActive(exec)->part()->view();
00158   QRect sg = KGlobalSettings::desktopGeometry(thisWidget);
00159 
00160   switch( token ) {
00161   case Height:
00162     return Number(sg.height());
00163   case Width:
00164     return Number(sg.width());
00165   case ColorDepth:
00166   case PixelDepth: {
00167     QPaintDeviceMetrics m(QApplication::desktop());
00168     return Number(m.depth());
00169   }
00170   case AvailLeft: {
00171 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00172     QRect clipped = info.workArea().intersect(sg);
00173     return Number(clipped.x()-sg.x());
00174 #else
00175     return Number(10);
00176 #endif
00177   }
00178   case AvailTop: {
00179 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00180     QRect clipped = info.workArea().intersect(sg);
00181     return Number(clipped.y()-sg.y());
00182 #else
00183     return Number(10);
00184 #endif
00185   }
00186   case AvailHeight: {
00187 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00188     QRect clipped = info.workArea().intersect(sg);
00189     return Number(clipped.height());
00190 #else
00191     return Number(100);
00192 #endif
00193   }
00194   case AvailWidth: {
00195 #if defined Q_WS_X11 && ! defined K_WS_QTONLY
00196     QRect clipped = info.workArea().intersect(sg);
00197     return Number(clipped.width());
00198 #else
00199     return Number(100);
00200 #endif
00201   }
00202   default:
00203     kdDebug(6070) << "WARNING: Screen::getValueProperty unhandled token " << token << endl;
00204     return Undefined();
00205   }
00206 }
00207 
00209 
00210 const ClassInfo Window::info = { "Window", 0, &WindowTable, 0 };
00211 
00212 /*
00213 @begin WindowTable 87
00214   closed    Window::Closed      DontDelete|ReadOnly
00215   crypto    Window::Crypto      DontDelete|ReadOnly
00216   defaultStatus Window::DefaultStatus   DontDelete
00217   defaultstatus Window::DefaultStatus   DontDelete
00218   status    Window::Status      DontDelete
00219   document  Window::Document    DontDelete|ReadOnly
00220   Node      Window::Node        DontDelete
00221   Event     Window::EventCtor   DontDelete
00222   Range     Window::Range       DontDelete
00223   NodeFilter    Window::NodeFilter  DontDelete
00224   DOMException  Window::DOMException    DontDelete
00225   CSSRule   Window::CSSRule     DontDelete
00226   frames    Window::Frames      DontDelete|ReadOnly
00227   history   Window::_History    DontDelete|ReadOnly
00228   external  Window::_External   DontDelete|ReadOnly
00229   event     Window::Event       DontDelete|ReadOnly
00230   innerHeight   Window::InnerHeight DontDelete|ReadOnly
00231   innerWidth    Window::InnerWidth  DontDelete|ReadOnly
00232   length    Window::Length      DontDelete|ReadOnly
00233   location  Window::_Location   DontDelete
00234   name      Window::Name        DontDelete
00235   navigator Window::_Navigator  DontDelete|ReadOnly
00236   clientInformation Window::ClientInformation   DontDelete|ReadOnly
00237   konqueror Window::_Konqueror  DontDelete|ReadOnly
00238   offscreenBuffering    Window::OffscreenBuffering  DontDelete|ReadOnly
00239   opener    Window::Opener      DontDelete|ReadOnly
00240   outerHeight   Window::OuterHeight DontDelete|ReadOnly
00241   outerWidth    Window::OuterWidth  DontDelete|ReadOnly
00242   pageXOffset   Window::PageXOffset DontDelete|ReadOnly
00243   pageYOffset   Window::PageYOffset DontDelete|ReadOnly
00244   parent    Window::Parent      DontDelete|ReadOnly
00245   personalbar   Window::Personalbar DontDelete|ReadOnly
00246   screenX   Window::ScreenX     DontDelete|ReadOnly
00247   screenY   Window::ScreenY     DontDelete|ReadOnly
00248   scrollbars    Window::Scrollbars  DontDelete|ReadOnly
00249   scroll    Window::Scroll      DontDelete|Function 2
00250   scrollBy  Window::ScrollBy    DontDelete|Function 2
00251   scrollTo  Window::ScrollTo    DontDelete|Function 2
00252   moveBy    Window::MoveBy      DontDelete|Function 2
00253   moveTo    Window::MoveTo      DontDelete|Function 2
00254   resizeBy  Window::ResizeBy    DontDelete|Function 2
00255   resizeTo  Window::ResizeTo    DontDelete|Function 2
00256   self      Window::Self        DontDelete|ReadOnly
00257   window    Window::_Window     DontDelete|ReadOnly
00258   top       Window::Top     DontDelete|ReadOnly
00259   screen    Window::_Screen     DontDelete|ReadOnly
00260   Image     Window::Image       DontDelete|ReadOnly
00261   Option    Window::Option      DontDelete|ReadOnly
00262   XMLHttpRequest Window::XMLHttpRequest DontDelete|ReadOnly
00263   alert     Window::Alert       DontDelete|Function 1
00264   confirm   Window::Confirm     DontDelete|Function 1
00265   prompt    Window::Prompt      DontDelete|Function 2
00266   open      Window::Open        DontDelete|Function 3
00267   setTimeout    Window::SetTimeout  DontDelete|Function 2
00268   clearTimeout  Window::ClearTimeout    DontDelete|Function 1
00269   focus     Window::Focus       DontDelete|Function 0
00270   blur      Window::Blur        DontDelete|Function 0
00271   close     Window::Close       DontDelete|Function 0
00272   setInterval   Window::SetInterval DontDelete|Function 2
00273   clearInterval Window::ClearInterval   DontDelete|Function 1
00274   captureEvents Window::CaptureEvents   DontDelete|Function 0
00275   releaseEvents Window::ReleaseEvents   DontDelete|Function 0
00276   print     Window::Print       DontDelete|Function 0
00277   addEventListener  Window::AddEventListener    DontDelete|Function 3
00278   removeEventListener   Window::RemoveEventListener DontDelete|Function 3
00279 # IE extension
00280   navigate  Window::Navigate    DontDelete|Function 1
00281 # Mozilla extension
00282   sidebar   Window::SideBar     DontDelete|ReadOnly
00283 
00284 # Warning, when adding a function to this object you need to add a case in Window::get
00285 
00286 # Event handlers
00287 # IE also has: onactivate, onbefore/afterprint, onbeforedeactivate/unload, oncontrolselect,
00288 # ondeactivate, onhelp, onmovestart/end, onresizestart/end, onscroll.
00289 # It doesn't have onabort, onchange, ondragdrop (but NS has that last one).
00290   onabort   Window::Onabort     DontDelete
00291   onblur    Window::Onblur      DontDelete
00292   onchange  Window::Onchange    DontDelete
00293   onclick   Window::Onclick     DontDelete
00294   ondblclick    Window::Ondblclick  DontDelete
00295   ondragdrop    Window::Ondragdrop  DontDelete
00296   onerror   Window::Onerror     DontDelete
00297   onfocus   Window::Onfocus     DontDelete
00298   onkeydown Window::Onkeydown   DontDelete
00299   onkeypress    Window::Onkeypress  DontDelete
00300   onkeyup   Window::Onkeyup     DontDelete
00301   onload    Window::Onload      DontDelete
00302   onmousedown   Window::Onmousedown DontDelete
00303   onmousemove   Window::Onmousemove DontDelete
00304   onmouseout    Window::Onmouseout  DontDelete
00305   onmouseover   Window::Onmouseover DontDelete
00306   onmouseup Window::Onmouseup   DontDelete
00307   onmove    Window::Onmove      DontDelete
00308   onreset   Window::Onreset     DontDelete
00309   onresize  Window::Onresize    DontDelete
00310   onselect  Window::Onselect    DontDelete
00311   onsubmit  Window::Onsubmit    DontDelete
00312   onunload  Window::Onunload    DontDelete
00313 @end
00314 */
00315 IMPLEMENT_PROTOFUNC_DOM(WindowFunc)
00316 
00317 Window::Window(KHTMLPart *p)
00318   : ObjectImp(/*no proto*/), m_part(p), screen(0), history(0), external(0), m_frames(0), loc(0), m_evt(0)
00319 {
00320   winq = new WindowQObject(this);
00321   //kdDebug(6070) << "Window::Window this=" << this << " part=" << m_part << " " << m_part->name() << endl;
00322 }
00323 
00324 Window::~Window()
00325 {
00326   delete winq;
00327 }
00328 
00329 Window *Window::retrieveWindow(KHTMLPart *p)
00330 {
00331   Object obj = Object::dynamicCast( retrieve( p ) );
00332 #ifndef NDEBUG
00333   // obj should never be null, except when javascript has been disabled in that part.
00334   if ( p && p->jScriptEnabled() )
00335   {
00336     assert( !obj.isNull() );
00337 #ifndef QWS
00338     assert( dynamic_cast<KJS::Window*>(obj.imp()) ); // type checking
00339 #endif
00340   }
00341 #endif
00342   if ( obj.isNull() ) // JS disabled
00343     return 0;
00344   return static_cast<KJS::Window*>(obj.imp());
00345 }
00346 
00347 Window *Window::retrieveActive(ExecState *exec)
00348 {
00349   ValueImp *imp = exec->interpreter()->globalObject().imp();
00350   assert( imp );
00351 #ifndef QWS
00352   assert( dynamic_cast<KJS::Window*>(imp) );
00353 #endif
00354   return static_cast<KJS::Window*>(imp);
00355 }
00356 
00357 Value Window::retrieve(KHTMLPart *p)
00358 {
00359   assert(p);
00360   KJSProxy *proxy = p->jScript();
00361   if (proxy) {
00362 #ifdef KJS_VERBOSE
00363     kdDebug(6070) << "Window::retrieve part=" << p << " '" << p->name() << "' interpreter=" << proxy->interpreter() << " window=" << proxy->interpreter()->globalObject().imp() << endl;
00364 #endif
00365     return proxy->interpreter()->globalObject(); // the Global object is the "window"
00366   } else {
00367 #ifdef KJS_VERBOSE
00368     kdDebug(6070) << "Window::retrieve part=" << p << " '" << p->name() << "' no jsproxy." << endl;
00369 #endif
00370     return Undefined(); // This can happen with JS disabled on the domain of that window
00371   }
00372 }
00373 
00374 Location *Window::location() const
00375 {
00376   if (!loc)
00377     const_cast<Window*>(this)->loc = new Location(m_part);
00378   return loc;
00379 }
00380 
00381 ObjectImp* Window::frames( ExecState* exec ) const
00382 {
00383   return m_frames ? m_frames :
00384     (const_cast<Window*>(this)->m_frames = new FrameArray(exec,m_part));
00385 }
00386 
00387 // reference our special objects during garbage collection
00388 void Window::mark()
00389 {
00390   ObjectImp::mark();
00391   if (screen && !screen->marked())
00392     screen->mark();
00393   if (history && !history->marked())
00394     history->mark();
00395   if (external && !external->marked())
00396     external->mark();
00397   if (m_frames && !m_frames->marked())
00398     m_frames->mark();
00399   //kdDebug(6070) << "Window::mark " << this << " marking loc=" << loc << endl;
00400   if (loc && !loc->marked())
00401     loc->mark();
00402   if (winq)
00403     winq->mark();
00404 }
00405 
00406 bool Window::hasProperty(ExecState *exec, const Identifier &p) const
00407 {
00408   // we don't want any operations on a closed window
00409   if (m_part.isNull())
00410     return ( p == "closed" );
00411 
00412   if (ObjectImp::hasProperty(exec, p))
00413     return true;
00414 
00415   if (Lookup::findEntry(&WindowTable, p))
00416     return true;
00417 
00418   QString q = p.qstring();
00419   if (m_part->findFrame(p.qstring()))
00420     return true;
00421   // allow window[1] or parent[1] etc. (#56983)
00422   bool ok;
00423   unsigned int i = p.toArrayIndex(&ok);
00424   if (ok) {
00425     QPtrList<KParts::ReadOnlyPart> frames = m_part->frames();
00426     unsigned int len = frames.count();
00427     if (i < len)
00428       return true;
00429   }
00430 
00431   // allow shortcuts like 'Image1' instead of document.images.Image1
00432   if (m_part->document().isHTMLDocument()) { // might be XML
00433     DOM::HTMLDocument doc = m_part->htmlDocument();
00434     // Keep in sync with tryGet
00435     NamedTagLengthDeterminer::TagLength tags[3] = {
00436       {ID_IMG, 0, 0L}, {ID_FORM, 0, 0L}, {ID_APPLET, 0, 0L}
00437     };
00438     NamedTagLengthDeterminer(p.string(), tags, 3)(doc.handle());
00439     for (int i = 0; i < 3; i++)
00440       if (tags[i].length > 0)
00441         return true;
00442 
00443     return !doc.getElementById(p.string()).isNull();
00444   }
00445 
00446   return false;
00447 }
00448 
00449 UString Window::toString(ExecState *) const
00450 {
00451   return "[object Window]";
00452 }
00453 
00454 Value Window::get(ExecState *exec, const Identifier &p) const
00455 {
00456 #ifdef KJS_VERBOSE
00457   kdDebug(6070) << "Window("<<this<<")::get " << p.qstring() << endl;
00458 #endif
00459   // we don't want any operations on a closed window
00460   if (m_part.isNull()) {
00461     if ( p == "closed" )
00462       return Boolean( true );
00463     return Undefined();
00464   }
00465 
00466   // Look for overrides first
00467   Value val = ObjectImp::get(exec, p);
00468   if (!val.isA(UndefinedType)) {
00469     //kdDebug(6070) << "Window::get found dynamic property '" << p.ascii() << "'" << endl;
00470     return isSafeScript(exec) ? val : Undefined();
00471   }
00472 
00473   const HashEntry* entry = Lookup::findEntry(&WindowTable, p);
00474 
00475   // properties that work on all windows
00476   if (entry) {
00477     switch(entry->value) {
00478     case Closed:
00479       return Boolean( false );
00480       case _Location:
00481         // No isSafeScript test here, we must be able to _set_ location.href (#49819)
00482         return Value(location());
00483     case Frames:
00484       return Value(frames(exec));
00485     case Opener:
00486       if (!m_part->opener())
00487         return Null();    // ### a null Window might be better, but == null
00488       else                // doesn't work yet
00489         return retrieve(m_part->opener());
00490     case Parent:
00491       return retrieve(m_part->parentPart() ? m_part->parentPart() : (KHTMLPart*)m_part);
00492     case _Window:
00493     case Self:
00494       return retrieve(m_part);
00495     case Top: {
00496       KHTMLPart *p = m_part;
00497       while (p->parentPart())
00498         p = p->parentPart();
00499       return retrieve(p);
00500     }
00501     case Alert:
00502     case Confirm:
00503     case Prompt:
00504     case Open:
00505     case Focus:
00506     case Blur:
00507       return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr);
00508     default:
00509       break;
00510     }
00511   }
00512 
00513   // properties that only work on safe windows
00514   if (isSafeScript(exec) &&  entry)
00515   {
00516     //kdDebug(6070) << "token: " << entry->value << endl;
00517     switch( entry->value ) {
00518     case Crypto:
00519       return Undefined(); // ###
00520     case DefaultStatus:
00521       return String(UString(m_part->jsDefaultStatusBarText()));
00522     case Status:
00523       return String(UString(m_part->jsStatusBarText()));
00524     case Document:
00525       if (m_part->document().isNull()) {
00526         kdDebug(6070) << "Document.write: adding <HTML><BODY> to create document" << endl;
00527         m_part->begin();
00528         m_part->write("<HTML><BODY>");
00529         m_part->end();
00530       }
00531       return getDOMNode(exec,m_part->document());
00532     case Node:
00533       return getNodeConstructor(exec);
00534     case Range:
00535       return getRangeConstructor(exec);
00536     case NodeFilter:
00537       return getNodeFilterConstructor(exec);
00538     case DOMException:
00539       return getDOMExceptionConstructor(exec);
00540     case CSSRule:
00541       return getCSSRuleConstructor(exec);
00542     case EventCtor:
00543       return getEventConstructor(exec);
00544     case _History:
00545       return Value(history ? history :
00546                    (const_cast<Window*>(this)->history = new History(exec,m_part)));
00547 
00548     case _External:
00549       return Value(external ? external :
00550                    (const_cast<Window*>(this)->external = new External(exec,m_part)));
00551 
00552     case Event:
00553       if (m_evt)
00554         return getDOMEvent(exec,*m_evt);
00555       else {
00556 #ifdef KJS_VERBOSE
00557         kdDebug(6070) << "WARNING: window(" << this << "," << m_part->name() << ").event, no event!" << endl;
00558 #endif
00559         return Undefined();
00560       }
00561     case InnerHeight:
00562       if (!m_part->view())
00563         return Undefined();
00564       khtml::RenderWidget::flushWidgetResizes(); // make sure frames have their final size
00565       return Number(m_part->view()->visibleHeight());
00566     case InnerWidth:
00567       if (!m_part->view())
00568         return Undefined();
00569       khtml::RenderWidget::flushWidgetResizes(); // make sure frames have their final size
00570       return Number(m_part->view()->visibleWidth());
00571     case Length:
00572       return Number(m_part->frames().count());
00573     case Name:
00574       return String(m_part->name());
00575     case SideBar:
00576       return Value(new MozillaSidebarExtension(exec, m_part));
00577     case _Navigator:
00578     case ClientInformation: {
00579       // Store the navigator in the object so we get the same one each time.
00580       Value nav( new Navigator(exec, m_part) );
00581       const_cast<Window *>(this)->put(exec, "navigator", nav, DontDelete|ReadOnly|Internal);
00582       const_cast<Window *>(this)->put(exec, "clientInformation", nav, DontDelete|ReadOnly|Internal);
00583       return nav;
00584     }
00585 #ifdef Q_WS_QWS
00586     case _Konqueror: {
00587       Value k( new Konqueror(exec, m_part) );
00588       const_cast<Window *>(this)->put(exec, "konqueror", k, DontDelete|ReadOnly|Internal);
00589       return k;
00590     }
00591 #endif
00592     case OffscreenBuffering:
00593       return Boolean(true);
00594     case OuterHeight:
00595     case OuterWidth:
00596     {
00597       if (!m_part->widget())
00598         return Number(0);
00599       KWin::WindowInfo inf = KWin::windowInfo(m_part->widget()->topLevelWidget()->winId());
00600       return Number(entry->value == OuterHeight ?
00601                     inf.geometry().height() : inf.geometry().width());
00602     }
00603     case PageXOffset:
00604       return Number(m_part->view()->contentsX());
00605     case PageYOffset:
00606       return Number(m_part->view()->contentsY());
00607     case Personalbar:
00608       return Undefined(); // ###
00609     case ScreenLeft:
00610     case ScreenX: {
00611       if (!m_part->view())
00612         return Undefined();
00613       QRect sg = KGlobalSettings::desktopGeometry(m_part->view());
00614       return Number(m_part->view()->mapToGlobal(QPoint(0,0)).x() + sg.x());
00615     }
00616     case ScreenTop:
00617     case ScreenY: {
00618       if (!m_part->view())
00619         return Undefined();
00620       QRect sg = KGlobalSettings::desktopGeometry(m_part->view());
00621       return Number(m_part->view()->mapToGlobal(QPoint(0,0)).y() + sg.y());
00622     }
00623     case ScrollX: {
00624       if (!m_part->view())
00625         return Undefined();
00626       return Number(m_part->view()->contentsX());
00627     }
00628     case ScrollY: {
00629       if (!m_part->view())
00630         return Undefined();
00631       return Number(m_part->view()->contentsY());
00632     }
00633     case Scrollbars:
00634       return Undefined(); // ###
00635     case _Screen:
00636       return Value(screen ? screen :
00637                    (const_cast<Window*>(this)->screen = new Screen(exec)));
00638     case Image:
00639       return Value(new ImageConstructorImp(exec, m_part->document()));
00640     case Option:
00641       return Value(new OptionConstructorImp(exec, m_part->document()));
00642     case XMLHttpRequest:
00643       return Value( new XMLHttpRequestConstructorImp( exec,m_part->document() ) );
00644     case Close:
00645     case Scroll: // compatibility
00646     case ScrollBy:
00647     case ScrollTo:
00648     case MoveBy:
00649     case MoveTo:
00650     case ResizeBy:
00651     case ResizeTo:
00652     case CaptureEvents:
00653     case ReleaseEvents:
00654     case AddEventListener:
00655     case RemoveEventListener:
00656     case SetTimeout:
00657     case ClearTimeout:
00658     case SetInterval:
00659     case ClearInterval:
00660     case Print:
00661       return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr);
00662     // IE extension
00663     case Navigate:
00664       // Disabled in NS-compat mode. Supported by default - can't hurt, unless someone uses
00665       // if (navigate) to test for IE (unlikely).
00666       if ( exec->interpreter()->compatMode() == Interpreter::NetscapeCompat )
00667         return Undefined();
00668       return lookupOrCreateFunction<WindowFunc>(exec,p,this,entry->value,entry->params,entry->attr);
00669     case Onabort:
00670       return getListener(exec,DOM::EventImpl::ABORT_EVENT);
00671     case Onblur:
00672       return getListener(exec,DOM::EventImpl::BLUR_EVENT);
00673     case Onchange:
00674       return getListener(exec,DOM::EventImpl::CHANGE_EVENT);
00675     case Onclick:
00676       return getListener(exec,DOM::EventImpl::KHTML_ECMA_CLICK_EVENT);
00677     case Ondblclick:
00678       return getListener(exec,DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT);
00679     case Ondragdrop:
00680       return getListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT);
00681     case Onerror:
00682       return getListener(exec,DOM::EventImpl::KHTML_ERROR_EVENT);
00683     case Onfocus:
00684       return getListener(exec,DOM::EventImpl::FOCUS_EVENT);
00685     case Onkeydown:
00686       return getListener(exec,DOM::EventImpl::KEYDOWN_EVENT);
00687     case Onkeypress:
00688       return getListener(exec,DOM::EventImpl::KHTML_KEYPRESS_EVENT);
00689     case Onkeyup:
00690       return getListener(exec,DOM::EventImpl::KEYUP_EVENT);
00691     case Onload:
00692       return getListener(exec,DOM::EventImpl::LOAD_EVENT);
00693     case Onmousedown:
00694       return getListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT);
00695     case Onmousemove:
00696       return getListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT);
00697     case Onmouseout:
00698       return getListener(exec,DOM::EventImpl::MOUSEOUT_EVENT);
00699     case Onmouseover:
00700       return getListener(exec,DOM::EventImpl::MOUSEOVER_EVENT);
00701     case Onmouseup:
00702       return getListener(exec,DOM::EventImpl::MOUSEUP_EVENT);
00703     case Onmove:
00704       return getListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT);
00705     case Onreset:
00706       return getListener(exec,DOM::EventImpl::RESET_EVENT);
00707     case Onresize:
00708       return getListener(exec,DOM::EventImpl::RESIZE_EVENT);
00709     case Onselect:
00710       return getListener(exec,DOM::EventImpl::SELECT_EVENT);
00711     case Onsubmit:
00712       return getListener(exec,DOM::EventImpl::SUBMIT_EVENT);
00713     case Onunload:
00714       return getListener(exec,DOM::EventImpl::UNLOAD_EVENT);
00715     }
00716   }
00717   KHTMLPart *kp = m_part->findFrame( p.qstring() );
00718   if (kp)
00719     return retrieve(kp);
00720 
00721   // allow window[1] or parent[1] etc. (#56983)
00722   bool ok;
00723   unsigned int i = p.toArrayIndex(&ok);
00724   if (ok) {
00725     QPtrList<KParts::ReadOnlyPart> frames = m_part->frames();
00726     unsigned int len = frames.count();
00727     if (i < len) {
00728       KParts::ReadOnlyPart* frame = frames.at(i);
00729       if (frame && ::qt_cast<KHTMLPart*>(frame)) {
00730         KHTMLPart *khtml = static_cast<KHTMLPart*>(frame);
00731         return Window::retrieve(khtml);
00732       }
00733     }
00734   }
00735 
00736   // allow shortcuts like 'Image1' instead of document.images.Image1
00737   if (isSafeScript(exec) &&
00738       m_part->document().isHTMLDocument()) { // might be XML
00739     // This is only for images, forms and applets, see KJS::HTMLDocument::tryGet
00740     DOM::HTMLDocument doc = m_part->htmlDocument();
00741     NamedTagLengthDeterminer::TagLength tags[3] = {
00742       {ID_IMG, 0, 0L}, {ID_FORM, 0, 0L}, {ID_APPLET, 0, 0L}
00743     };
00744     NamedTagLengthDeterminer(p.string(), tags, 3)(doc.handle());
00745     for (int i = 0; i < 3; i++)
00746       if (tags[i].length > 0) {
00747         if (tags[i].length == 1)
00748           return getDOMNode(exec, tags[i].last);
00749         // Get all the items with the same name
00750         return getDOMNodeList(exec, DOM::NodeList(new DOM::NamedTagNodeListImpl(doc.handle(), tags[i].id, p.string())));
00751     }
00752 
00753     DOM::Element element = doc.getElementById(p.string() );
00754     if ( !element.isNull() )
00755       return getDOMNode(exec, element );
00756   }
00757 
00758   // This isn't necessarily a bug. Some code uses if(!window.blah) window.blah=1
00759   // But it can also mean something isn't loaded or implemented, hence the WARNING to help grepping.
00760 #ifdef KJS_VERBOSE
00761   kdDebug(6070) << "WARNING: Window::get property not found: " << p.qstring() << endl;
00762 #endif
00763   return Undefined();
00764 }
00765 
00766 void Window::put(ExecState* exec, const Identifier &propertyName, const Value &value, int attr)
00767 {
00768   // Called by an internal KJS call (e.g. InterpreterImp's constructor) ?
00769   // If yes, save time and jump directly to ObjectImp.
00770   if ( (attr != None && attr != DontDelete) ||
00771        // Same thing if we have a local override (e.g. "var location")
00772        ( isSafeScript( exec ) && ObjectImp::getDirect(propertyName) ) )
00773   {
00774     ObjectImp::put( exec, propertyName, value, attr );
00775     return;
00776   }
00777 
00778   const HashEntry* entry = Lookup::findEntry(&WindowTable, propertyName);
00779   if (entry)
00780   {
00781 #ifdef KJS_VERBOSE
00782     kdDebug(6070) << "Window("<<this<<")::put " << propertyName.qstring() << endl;
00783 #endif
00784     switch( entry->value ) {
00785     case Status: {
00786       if  (isSafeScript(exec) && m_part->settings()->windowStatusPolicy(m_part->url().host())
00787         == KHTMLSettings::KJSWindowStatusAllow) {
00788       String s = value.toString(exec);
00789       m_part->setJSStatusBarText(s.value().qstring());
00790       }
00791       return;
00792     }
00793     case DefaultStatus: {
00794       if (isSafeScript(exec) && m_part->settings()->windowStatusPolicy(m_part->url().host())
00795         == KHTMLSettings::KJSWindowStatusAllow) {
00796       String s = value.toString(exec);
00797       m_part->setJSDefaultStatusBarText(s.value().qstring());
00798       }
00799       return;
00800     }
00801     case _Location:
00802       goURL(exec, value.toString(exec).qstring(), false /*don't lock history*/);
00803       return;
00804     case Onabort:
00805       if (isSafeScript(exec))
00806         setListener(exec, DOM::EventImpl::ABORT_EVENT,value);
00807       return;
00808     case Onblur:
00809       if (isSafeScript(exec))
00810         setListener(exec, DOM::EventImpl::BLUR_EVENT,value);
00811       return;
00812     case Onchange:
00813       if (isSafeScript(exec))
00814         setListener(exec, DOM::EventImpl::CHANGE_EVENT,value);
00815       return;
00816     case Onclick:
00817       if (isSafeScript(exec))
00818         setListener(exec,DOM::EventImpl::KHTML_ECMA_CLICK_EVENT,value);
00819       return;
00820     case Ondblclick:
00821       if (isSafeScript(exec))
00822         setListener(exec,DOM::EventImpl::KHTML_ECMA_DBLCLICK_EVENT,value);
00823       return;
00824     case Ondragdrop:
00825       if (isSafeScript(exec))
00826         setListener(exec,DOM::EventImpl::KHTML_DRAGDROP_EVENT,value);
00827       return;
00828     case Onerror:
00829       if (isSafeScript(exec))
00830         setListener(exec,DOM::EventImpl::KHTML_ERROR_EVENT,value);
00831       return;
00832     case Onfocus:
00833       if (isSafeScript(exec))
00834         setListener(exec,DOM::EventImpl::FOCUS_EVENT,value);
00835       return;
00836     case Onkeydown:
00837       if (isSafeScript(exec))
00838         setListener(exec,DOM::EventImpl::KEYDOWN_EVENT,value);
00839       return;
00840     case Onkeypress:
00841       if (isSafeScript(exec))
00842         setListener(exec,DOM::EventImpl::KHTML_KEYPRESS_EVENT,value);
00843       return;
00844     case Onkeyup:
00845       if (isSafeScript(exec))
00846         setListener(exec,DOM::EventImpl::KEYUP_EVENT,value);
00847       return;
00848     case Onload:
00849       if (isSafeScript(exec))
00850         setListener(exec,DOM::EventImpl::LOAD_EVENT,value);
00851       return;
00852     case Onmousedown:
00853       if (isSafeScript(exec))
00854         setListener(exec,DOM::EventImpl::MOUSEDOWN_EVENT,value);
00855       return;
00856     case Onmousemove:
00857       if (isSafeScript(exec))
00858         setListener(exec,DOM::EventImpl::MOUSEMOVE_EVENT,value);
00859       return;
00860     case Onmouseout:
00861       if (isSafeScript(exec))
00862         setListener(exec,DOM::EventImpl::MOUSEOUT_EVENT,value);
00863       return;
00864     case Onmouseover:
00865       if (isSafeScript(exec))
00866         setListener(exec,DOM::EventImpl::MOUSEOVER_EVENT,value);
00867       return;
00868     case Onmouseup:
00869       if (isSafeScript(exec))
00870         setListener(exec,DOM::EventImpl::MOUSEUP_EVENT,value);
00871       return;
00872     case Onmove:
00873       if (isSafeScript(exec))
00874         setListener(exec,DOM::EventImpl::KHTML_MOVE_EVENT,value);
00875       return;
00876     case Onreset:
00877       if (isSafeScript(exec))
00878         setListener(exec,DOM::EventImpl::RESET_EVENT,value);
00879       return;
00880     case Onresize:
00881       if (isSafeScript(exec))
00882         setListener(exec,DOM::EventImpl::RESIZE_EVENT,value);
00883       return;
00884     case Onselect:
00885       if (isSafeScript(exec))
00886         setListener(exec,DOM::EventImpl::SELECT_EVENT,value);
00887       return;
00888     case Onsubmit:
00889       if (isSafeScript(exec))
00890         setListener(exec,DOM::EventImpl::SUBMIT_EVENT,value);
00891       return;
00892     case Onunload:
00893       if (isSafeScript(exec))
00894         setListener(exec,DOM::EventImpl::UNLOAD_EVENT,value);
00895       return;
00896     case Name:
00897       if (isSafeScript(exec))
00898         m_part->setName( value.toString(exec).qstring().local8Bit().data() );
00899       return;
00900     default:
00901       break;
00902     }
00903   }
00904   if (isSafeScript(exec)) {
00905     //kdDebug(6070) << "Window("<<this<<")::put storing " << propertyName.qstring() << endl;
00906     ObjectImp::put(exec, propertyName, value, attr);
00907   }
00908 }
00909 
00910 bool Window::toBoolean(ExecState *) const
00911 {
00912   return !m_part.isNull();
00913 }
00914 
00915 void Window::scheduleClose()
00916 {
00917   kdDebug(6070) << "Window::scheduleClose window.close() " << m_part << endl;
00918   Q_ASSERT(winq);
00919   QTimer::singleShot( 0, winq, SLOT( timeoutClose() ) );
00920 }
00921 
00922 void Window::closeNow()
00923 {
00924   if (!m_part.isNull())
00925   {
00926     //kdDebug(6070) << k_funcinfo << " -> closing window" << endl;
00927     // We want to make sure that window.open won't find this part by name.
00928     m_part->setName( 0 );
00929     m_part->deleteLater();
00930     m_part = 0;
00931   } else
00932     kdDebug(6070) << k_funcinfo << "part is deleted already" << endl;
00933 }
00934 
00935 void Window::afterScriptExecution()
00936 {
00937   DOM::DocumentImpl::updateDocumentsRendering();
00938   QValueList<DelayedAction> delayedActions = m_delayed;
00939   m_delayed.clear();
00940   QValueList<DelayedAction>::Iterator it = delayedActions.begin();
00941   for ( ; it != delayedActions.end() ; ++it )
00942   {
00943     switch ((*it).actionId) {
00944     case DelayedClose:
00945       scheduleClose();
00946       return; // stop here, in case of multiple actions
00947     case DelayedGoHistory:
00948       goHistory( (*it).param.toInt() );
00949       break;
00950     case NullAction:
00951       // FIXME: anything needs to be done here?  This is warning anyways.
00952       break;
00953     };
00954   }
00955 }
00956 
00957 bool Window::checkIsSafeScript(KHTMLPart *activePart) const
00958 {
00959   if (m_part.isNull()) { // part deleted ? can't grant access
00960     kdDebug(6070) << "Window::isSafeScript: accessing deleted part !" << endl;
00961     return false;
00962   }
00963   if (!activePart) {
00964     kdDebug(6070) << "Window::isSafeScript: current interpreter's part is 0L!" << endl;
00965     return false;
00966   }
00967    if ( activePart == m_part ) // Not calling from another frame, no problem.
00968      return true;
00969 
00970   if ( m_part->document().isNull() )
00971     return true; // allow to access a window that was just created (e.g. with window.open("about:blank"))
00972 
00973   DOM::HTMLDocument thisDocument = m_part->htmlDocument();
00974   if ( thisDocument.isNull() ) {
00975     kdDebug(6070) << "Window::isSafeScript: trying to access an XML document !?" << endl;
00976     return false;
00977   }
00978 
00979   DOM::HTMLDocument actDocument = activePart->htmlDocument();
00980   if ( actDocument.isNull() ) {
00981     kdDebug(6070) << "Window::isSafeScript: active part has no document!" << endl;
00982     return false;
00983   }
00984   DOM::DOMString actDomain = actDocument.domain();
00985   DOM::DOMString thisDomain = thisDocument.domain();
00986 
00987   if ( actDomain == thisDomain ) {
00988 #ifdef KJS_VERBOSE
00989     kdDebug(6070) << "JavaScript: access granted, domain is '" << actDomain.string() << "'" << endl;
00990 #endif
00991     return true;
00992   }
00993 
00994   kdDebug(6070) << "WARNING: JavaScript: access denied for current frame '" << actDomain.string() << "' to frame '" << thisDomain.string() << "'" << endl;
00995   // TODO after 3.1: throw security exception (exec->setException())
00996   return false;
00997 }
00998 
00999 void Window::setListener(ExecState *exec, int eventId, Value func)
01000 {
01001   if (!isSafeScript(exec))
01002     return;
01003   DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(m_part->htmlDocument().handle());
01004   if (!doc)
01005     return;
01006 
01007   doc->setWindowEventListener(eventId,getJSEventListener(func,true));
01008 }
01009 
01010 Value Window::getListener(ExecState *exec, int eventId) const
01011 {
01012   if (!isSafeScript(exec))
01013     return Undefined();
01014   DOM::DocumentImpl *doc = static_cast<DOM::DocumentImpl*>(m_part->htmlDocument().handle());
01015   if (!doc)
01016     return Undefined();
01017 
01018   DOM::EventListener *listener = doc->getWindowEventListener(eventId);
01019   if (listener)
01020     return static_cast<JSEventListener*>(listener)->listenerObj();
01021   else
01022     return Null();
01023 }
01024 
01025 
01026 JSEventListener *Window::getJSEventListener(const Value& val, bool html)
01027 {
01028   // This function is so hot that it's worth coding it directly with imps.
01029   if (val.type() != ObjectType)
01030     return 0;
01031   ObjectImp *listenerObject = static_cast<ObjectImp *>(val.imp());
01032 
01033   JSEventListener *existingListener = jsEventListeners[listenerObject];
01034   if (existingListener)
01035     return existingListener;
01036 
01037   // Note that the JSEventListener constructor adds it to our jsEventListeners list
01038   return new JSEventListener(Object(listenerObject), Object(this), html);
01039 }
01040 
01041 void Window::clear( ExecState *exec )
01042 {
01043   delete winq;
01044   winq = 0L;
01045   // Get rid of everything, those user vars could hold references to DOM nodes
01046   deleteAllProperties( exec );
01047 
01048   // Break the dependency between the listeners and their object
01049   QPtrDictIterator<JSEventListener> it(jsEventListeners);
01050   for (; it.current(); ++it)
01051     it.current()->clear();
01052   // Forget about the listeners (the DOM::NodeImpls will delete them)
01053   jsEventListeners.clear();
01054 
01055   if (!m_part.isNull()) {
01056     KJSProxy* proxy = m_part->jScript();
01057     if (proxy) // i.e. JS not disabled
01058     {
01059       winq = new WindowQObject(this);
01060       // Now recreate a working global object for the next URL that will use us
01061       KJS::Interpreter *interpreter = proxy->interpreter();
01062       interpreter->initGlobalObject();
01063     }
01064   }
01065 }
01066 
01067 void Window::setCurrentEvent( DOM::Event *evt )
01068 {
01069   m_evt = evt;
01070   //kdDebug(6070) << "Window " << this << " (part=" << m_part << ")::setCurrentEvent m_evt=" << evt << endl;
01071 }
01072 
01073 void Window::goURL(ExecState* exec, const QString& url, bool lockHistory)
01074 {
01075   Window* active = Window::retrieveActive(exec);
01076   // Complete the URL using the "active part" (running interpreter)
01077   if (active->part()) {
01078     if (url[0] == QChar('#')) {
01079       m_part->gotoAnchor(url.mid(1));
01080     } else {
01081       QString dstUrl = active->part()->htmlDocument().completeURL(url).string();
01082       KURL dst( dstUrl );
01083       KURL partURL( m_part->url() );
01084       // Remove refs for the comparison
01085       dst.setRef( QString::null );
01086       partURL.setRef( QString::null );
01087       kdDebug(6070) << "Window::goURL dstUrl=" << dst.prettyURL() << " partURL=" << partURL.prettyURL()
01088                    << " identical: " << partURL.equals( dst, true ) << endl;
01089 
01090       // check if we're allowed to inject javascript
01091       // SYNC check with khtml_part.cpp::slotRedirect!
01092       if ( isSafeScript(exec) ||
01093             dstUrl.find(QString::fromLatin1("javascript:"), 0, false) != 0 )
01094           m_part->scheduleRedirection(-1,
01095                                 dstUrl,
01096                                   lockHistory);
01097     }
01098   }
01099 }
01100 
01101 void Window::delayedGoHistory( int steps )
01102 {
01103     m_delayed.append( DelayedAction( DelayedGoHistory, steps ) );
01104 }
01105 
01106 void Window::goHistory( int steps )
01107 {
01108   KParts::BrowserExtension *ext = m_part->browserExtension();
01109   if(!ext)
01110     return;
01111   KParts::BrowserInterface *iface = ext->browserInterface();
01112 
01113   if ( !iface )
01114     return;
01115 
01116   iface->callMethod( "goHistory(int)", steps );
01117   //emit ext->goHistory(steps);
01118 }
01119 
01120 void KJS::Window::resizeTo(QWidget* tl, int width, int height)
01121 {
01122   KParts::BrowserExtension *ext = m_part->browserExtension();
01123   if (!ext) {
01124     kdDebug(6070) << "Window::resizeTo found no browserExtension" << endl;
01125     return;
01126   }
01127 
01128   // Security check: within desktop limits and bigger than 100x100 (per spec)
01129   if ( width < 100 || height < 100 ) {
01130     kdDebug(6070) << "Window::resizeTo refused, window would be too small ("<<width<<","<<height<<")" << endl;
01131     return;
01132   }
01133 
01134   QRect sg = KGlobalSettings::desktopGeometry(tl);
01135 
01136   if ( width > sg.width() || height > sg.height() ) {
01137     kdDebug(6070) << "Window::resizeTo refused, window would be too big ("<<width<<","<<height<<")" << endl;
01138     return;
01139   }
01140 
01141   // Take into account the window frame - so that (width,height) is the external window size
01142   // ### (is that correct? for window.open it's the size of the HTML area...)
01143   int deltaWidth = tl->frameGeometry().width() - tl->width();
01144   int deltaHeight = tl->frameGeometry().height() - tl->height();
01145 
01146   kdDebug() << "resizing to " << width - deltaWidth << "x" << height - deltaHeight << endl;
01147 
01148   emit ext->resizeTopLevelWidget( width - deltaWidth, height - deltaHeight );
01149 
01150   // If the window is out of the desktop, move it up/left
01151   // (maybe we should use workarea instead of sg, otherwise the window ends up below kicker)
01152   int right = tl->x() + tl->frameGeometry().width();
01153   int bottom = tl->y() + tl->frameGeometry().height();
01154   int moveByX = 0;
01155   int moveByY = 0;
01156   if ( right > sg.right() )
01157     moveByX = - right + sg.right(); // always <0
01158   if ( bottom > sg.bottom() )
01159     moveByY = - bottom + sg.bottom(); // always <0
01160   if ( moveByX || moveByY )
01161     emit ext->moveTopLevelWidget( tl->x() + moveByX , tl->y() + moveByY );
01162 }
01163 
01164 Value Window::openWindow(ExecState *exec, const List& args)
01165 {
01166   KHTMLView *widget = m_part->view();
01167   Value v = args[0];
01168   QString str = v.toString(exec).qstring();
01169 
01170   // prepare arguments
01171   KURL url;
01172   if (!str.isEmpty())
01173   {
01174     KHTMLPart* p = Window::retrieveActive(exec)->m_part;
01175     if ( p )
01176       url = p->htmlDocument().completeURL(str).string();
01177     if ( !p ||
01178          !static_cast<DOM::DocumentImpl*>(p->htmlDocument().handle())->isURLAllowed(url.url()) )
01179       return Undefined();
01180   }
01181 
01182   KHTMLSettings::KJSWindowOpenPolicy policy =
01183         m_part->settings()->windowOpenPolicy(m_part->url().host());
01184   if ( policy == KHTMLSettings::KJSWindowOpenAsk ) {
01185     if ( KMessageBox::questionYesNo(widget,
01186                                     str.isEmpty() ?
01187                                     i18n( "This site is requesting to open up a new browser "
01188                                           "window via JavaScript.\n"
01189                                           "Do you want to allow this?" ) :
01190                                     i18n( "<qt>This site is requesting to open<p>%1</p>in a new browser window via JavaScript.<br />"
01191                                           "Do you want to allow this?</qt>").arg(KStringHandler::csqueeze(url.htmlURL(),  100)),
01192                                     i18n( "Confirmation: JavaScript Popup" ) ) == KMessageBox::Yes )
01193       policy = KHTMLSettings::KJSWindowOpenAllow;
01194   } else if ( policy == KHTMLSettings::KJSWindowOpenSmart )
01195   {
01196     // window.open disabled unless from a key/mouse event
01197     if (static_cast<ScriptInterpreter *>(exec->interpreter())->isWindowOpenAllowed())
01198       policy = KHTMLSettings::KJSWindowOpenAllow;
01199   }
01200   if ( policy != KHTMLSettings::KJSWindowOpenAllow ) {
01201     return Undefined();
01202   } else {
01203     KParts::WindowArgs winargs;
01204 
01205     // scan feature argument
01206     QString features;
01207     if (args.size()>2) {
01208       features = args[2].toString(exec).qstring();
01209       // specifying window params means false defaults
01210       winargs.menuBarVisible = false;
01211       winargs.toolBarsVisible = false;
01212       winargs.statusBarVisible = false;
01213       QStringList flist = QStringList::split(',', features);
01214       QStringList::ConstIterator it = flist.begin();
01215       while (it != flist.end()) {
01216         QString s = *it++;
01217         QString key, val;
01218         int pos = s.find('=');
01219         if (pos >= 0) {
01220           key = s.left(pos).stripWhiteSpace().lower();
01221           val = s.mid(pos + 1).stripWhiteSpace().lower();
01222           QRect screen = KGlobalSettings::desktopGeometry(widget->topLevelWidget());
01223 
01224           if (key == "left" || key == "screenx") {
01225             winargs.x = (int)val.toFloat() + screen.x();
01226             if (winargs.x < screen.x() || winargs.x > screen.right())
01227               winargs.x = screen.x(); // only safe choice until size is determined
01228           } else if (key == "top" || key == "screeny") {
01229             winargs.y = (int)val.toFloat() + screen.y();
01230             if (winargs.y < screen.y() || winargs.y > screen.bottom())
01231               winargs.y = screen.y(); // only safe choice until size is determined
01232           } else if (key == "height") {
01233             winargs.height = (int)val.toFloat() + 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2;
01234             if (winargs.height > screen.height())  // should actually check workspace
01235               winargs.height = screen.height();
01236             if (winargs.height < 100)
01237               winargs.height = 100;
01238           } else if (key == "width") {
01239             winargs.width = (int)val.toFloat() + 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2;
01240             if (winargs.width > screen.width())    // should actually check workspace
01241               winargs.width = screen.width();
01242             if (winargs.width < 100)
01243               winargs.width = 100;
01244           } else {
01245             goto boolargs;
01246           }
01247           continue;
01248         } else {
01249           // leaving away the value gives true
01250           key = s.stripWhiteSpace().lower();
01251           val = "1";
01252         }
01253       boolargs:
01254         if (key == "menubar")
01255           winargs.menuBarVisible = (val == "1" || val == "yes");
01256         else if (key == "toolbar")
01257           winargs.toolBarsVisible = (val == "1" || val == "yes");
01258         else if (key == "location")  // ### missing in WindowArgs
01259           winargs.toolBarsVisible = (val == "1" || val == "yes");
01260         else if (key == "status" || key == "statusbar")
01261           winargs.statusBarVisible = (val == "1" || val == "yes");
01262         else if (key == "resizable")
01263           winargs.resizable = (val == "1" || val == "yes");
01264         else if (key == "fullscreen")
01265           winargs.fullscreen = (val == "1" || val == "yes");
01266       }
01267     }
01268 
01269     KParts::URLArgs uargs;
01270     KHTMLPart *p = m_part;
01271     uargs.frameName = args.size() > 1 ?
01272                       args[1].toString(exec).qstring()
01273                       : QString("_blank");
01274     if ( uargs.frameName.lower() == "_top" )
01275     {
01276       while ( p->parentPart() )
01277         p = p->parentPart();
01278       Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/);
01279       return Window::retrieve(p);
01280     }
01281     if ( uargs.frameName.lower() == "_parent" )
01282     {
01283       if ( p->parentPart() )
01284         p = p->parentPart();
01285       Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/);
01286       return Window::retrieve(p);
01287     }
01288     if ( uargs.frameName.lower() == "_self")
01289     {
01290       Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/);
01291       return Window::retrieve(p);
01292     }
01293     if ( uargs.frameName.lower() == "replace" )
01294     {
01295       Window::retrieveWindow(p)->goURL(exec, url.url(), true /*lock history*/);
01296       return Window::retrieve(p);
01297     }
01298     uargs.serviceType = "text/html";
01299 
01300     // request window (new or existing if framename is set)
01301     KParts::ReadOnlyPart *newPart = 0L;
01302     emit p->browserExtension()->createNewWindow(KURL(), uargs,winargs,newPart);
01303     if (newPart && ::qt_cast<KHTMLPart*>(newPart)) {
01304       KHTMLPart *khtmlpart = static_cast<KHTMLPart*>(newPart);
01305       //qDebug("opener set to %p (this Window's part) in new Window %p  (this Window=%p)",part,win,window);
01306       khtmlpart->setOpener(p);
01307       khtmlpart->setOpenedByJS(true);
01308       if (khtmlpart->document().isNull()) {
01309         khtmlpart->begin();
01310         khtmlpart->write("<HTML><BODY>");
01311         khtmlpart->end();
01312         if ( p->docImpl() ) {
01313           //kdDebug(6070) << "Setting domain to " << p->docImpl()->domain().string() << endl;
01314           khtmlpart->docImpl()->setDomain( p->docImpl()->domain());
01315           khtmlpart->docImpl()->setBaseURL( p->docImpl()->baseURL() );
01316         }
01317       }
01318       uargs.serviceType = QString::null;
01319       if (uargs.frameName.lower() == "_blank")
01320         uargs.frameName = QString::null;
01321       if (!url.isEmpty())
01322         emit khtmlpart->browserExtension()->openURLRequest(url,uargs);
01323       return Window::retrieve(khtmlpart); // global object
01324     } else
01325       return Undefined();
01326   }
01327 }
01328 
01329 Value WindowFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01330 {
01331   KJS_CHECK_THIS( Window, thisObj );
01332   Window *window = static_cast<Window *>(thisObj.imp());
01333   QString str, str2;
01334 
01335   KHTMLPart *part = window->m_part;
01336   if (!part)
01337     return Undefined();
01338 
01339   KHTMLView *widget = part->view();
01340   Value v = args[0];
01341   UString s = v.toString(exec);
01342   str = s.qstring();
01343 
01344   // functions that work everywhere
01345   switch(id) {
01346   case Window::Alert:
01347     if (!widget->dialogsAllowed())
01348       return Undefined();
01349     if ( part && part->xmlDocImpl() )
01350       part->xmlDocImpl()->updateRendering();
01351     KMessageBox::error(widget, QStyleSheet::convertFromPlainText(str), "JavaScript");
01352     return Undefined();
01353   case Window::Confirm:
01354     if (!widget->dialogsAllowed())
01355       return Undefined();
01356     if ( part && part->xmlDocImpl() )
01357       part->xmlDocImpl()->updateRendering();
01358     return Boolean((KMessageBox::warningYesNo(widget, QStyleSheet::convertFromPlainText(str), "JavaScript",
01359                                                 KStdGuiItem::ok(), KStdGuiItem::cancel()) == KMessageBox::Yes));
01360   case Window::Prompt:
01361     if (!widget->dialogsAllowed())
01362       return Undefined();
01363     if ( part && part->xmlDocImpl() )
01364       part->xmlDocImpl()->updateRendering();
01365     bool ok;
01366     if (args.size() >= 2)
01367       str2 = KInputDialog::getText(i18n("Prompt"),
01368                                    QStyleSheet::convertFromPlainText(str),
01369                                    args[1].toString(exec).qstring(), &ok, widget);
01370     else
01371       str2 = KInputDialog::getText(i18n("Prompt"),
01372                                    QStyleSheet::convertFromPlainText(str),
01373                                    QString::null, &ok, widget);
01374     if ( ok )
01375         return String(str2);
01376     else
01377         return Null();
01378   case Window::Open:
01379     return window->openWindow(exec, args);
01380   case Window::Navigate:
01381     window->goURL(exec, args[0].toString(exec).qstring(), false /*don't lock history*/);
01382     return Undefined();
01383   case Window::Focus: {
01384     KHTMLSettings::KJSWindowFocusPolicy policy =
01385         part->settings()->windowFocusPolicy(part->url().host());
01386     if(policy == KHTMLSettings::KJSWindowFocusAllow && widget) {
01387       widget->topLevelWidget()->raise();
01388       widget->setActiveWindow();
01389     }
01390     return Undefined();
01391   }
01392   case Window::Blur:
01393     // TODO
01394     return Undefined();
01395   };
01396 
01397 
01398   // now unsafe functions..
01399   if (!window->isSafeScript(exec))
01400     return Undefined();
01401 
01402   switch (id) {
01403   case Window::ScrollBy:
01404     if(args.size() == 2 && widget)
01405       widget->scrollBy(args[0].toInt32(exec), args[1].toInt32(exec));
01406     return Undefined();
01407   case Window::Scroll:
01408   case Window::ScrollTo:
01409     if(args.size() == 2 && widget)
01410       widget->setContentsPos(args[0].toInt32(exec), args[1].toInt32(exec));
01411     return Undefined();
01412   case Window::MoveBy: {
01413     KHTMLSettings::KJSWindowMovePolicy policy =
01414         part->settings()->windowMovePolicy(part->url().host());
01415     if(policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget)
01416     {
01417       KParts::BrowserExtension *ext = part->browserExtension();
01418       if (ext) {
01419         QWidget * tl = widget->topLevelWidget();
01420         QRect sg = KGlobalSettings::desktopGeometry(tl);
01421 
01422         QPoint dest = tl->pos() + QPoint( args[0].toInt32(exec), args[1].toInt32(exec) );
01423         // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
01424         if ( dest.x() >= sg.x() && dest.y() >= sg.x() &&
01425              dest.x()+tl->width() <= sg.width()+sg.x() &&
01426              dest.y()+tl->height() <= sg.height()+sg.y() )
01427           emit ext->moveTopLevelWidget( dest.x(), dest.y() );
01428       }
01429     }
01430     return Undefined();
01431   }
01432   case Window::MoveTo: {
01433     KHTMLSettings::KJSWindowMovePolicy policy =
01434         part->settings()->windowMovePolicy(part->url().host());
01435     if(policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget)
01436     {
01437       KParts::BrowserExtension *ext = part->browserExtension();
01438       if (ext) {
01439         QWidget * tl = widget->topLevelWidget();
01440         QRect sg = KGlobalSettings::desktopGeometry(tl);
01441 
01442         QPoint dest( args[0].toInt32(exec)+sg.x(), args[1].toInt32(exec)+sg.y() );
01443         // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
01444         if ( dest.x() >= sg.x() && dest.y() >= sg.y() &&
01445              dest.x()+tl->width() <= sg.width()+sg.x() &&
01446              dest.y()+tl->height() <= sg.height()+sg.y() )
01447         emit ext->moveTopLevelWidget( dest.x(), dest.y() );
01448       }
01449     }
01450     return Undefined();
01451   }
01452   case Window::ResizeBy: {
01453     KHTMLSettings::KJSWindowResizePolicy policy =
01454         part->settings()->windowResizePolicy(part->url().host());
01455     if(policy == KHTMLSettings::KJSWindowResizeAllow
01456             && args.size() == 2 && widget)
01457     {
01458       QWidget * tl = widget->topLevelWidget();
01459       QRect geom = tl->frameGeometry();
01460       window->resizeTo( tl,
01461                         geom.width() + args[0].toInt32(exec),
01462                         geom.height() + args[1].toInt32(exec) );
01463     }
01464     return Undefined();
01465   }
01466   case Window::ResizeTo: {
01467     KHTMLSettings::KJSWindowResizePolicy policy =
01468                part->settings()->windowResizePolicy(part->url().host());
01469     if(policy == KHTMLSettings::KJSWindowResizeAllow
01470                && args.size() == 2 && widget)
01471     {
01472       QWidget * tl = widget->topLevelWidget();
01473       window->resizeTo( tl, args[0].toInt32(exec), args[1].toInt32(exec) );
01474     }
01475     return Undefined();
01476   }
01477   case Window::SetTimeout:
01478   case Window::SetInterval: {
01479     bool singleShot;
01480     int i; // timeout interval
01481     if (args.size() == 0)
01482       return Undefined();
01483     if (args.size() > 1) {
01484       singleShot = (id == Window::SetTimeout);
01485       i = args[1].toInt32(exec);
01486     } else {
01487       // second parameter is missing. Emulate Mozilla behavior.
01488       singleShot = true;
01489       i = 4;
01490     }
01491     if (v.isA(StringType)) {
01492       int r = (const_cast<Window*>(window))->winq->installTimeout(Identifier(s), i, singleShot );
01493       return Number(r);
01494     }
01495     else if (v.isA(ObjectType) && Object::dynamicCast(v).implementsCall()) {
01496       Object func = Object::dynamicCast(v);
01497       List funcArgs;
01498       ListIterator it = args.begin();
01499       int argno = 0;
01500       while (it != args.end()) {
01501     Value arg = it++;
01502     if (argno++ >= 2)
01503         funcArgs.append(arg);
01504       }
01505       if (args.size() < 2)
01506     funcArgs.append(Number(i));
01507       int r = (const_cast<Window*>(window))->winq->installTimeout(func, funcArgs, i, singleShot );
01508       return Number(r);
01509     }
01510     else
01511       return Undefined();
01512   }
01513   case Window::ClearTimeout:
01514   case Window::ClearInterval:
01515     (const_cast<Window*>(window))->winq->clearTimeout(v.toInt32(exec));
01516     return Undefined();
01517   case Window::Close: {
01518     /* From http://developer.netscape.com/docs/manuals/js/client/jsref/window.htm :
01519        The close method closes only windows opened by JavaScript using the open method.
01520        If you attempt to close any other window, a confirm is generated, which
01521        lets the user choose whether the window closes.
01522        This is a security feature to prevent "mail bombs" containing self.close().
01523        However, if the window has only one document (the current one) in its
01524        session history, the close is allowed without any confirm. This is a
01525        special case for one-off windows that need to open other windows and
01526        then dispose of themselves.
01527     */
01528     bool doClose = false;
01529     if (!part->openedByJS())
01530     {
01531       // To conform to the SPEC, we only ask if the window
01532       // has more than one entry in the history (NS does that too).
01533       History history(exec,part);
01534       if ( history.get( exec, "length" ).toInt32(exec) <= 1 ||
01535            KMessageBox::questionYesNo( window->part()->widget(), i18n("Close window?"), i18n("Confirmation Required") ) == KMessageBox::Yes )
01536         doClose = true;
01537     }
01538     else
01539       doClose = true;
01540 
01541     if (doClose)
01542     {
01543       // If this is the current window (the one the interpreter runs in),
01544       // then schedule a delayed close (so that the script terminates first).
01545       // But otherwise, close immediately. This fixes w=window.open("","name");w.close();window.open("name");
01546       if ( Window::retrieveActive(exec) == window ) {
01547         if (widget) {
01548           // quit all dialogs of this view
01549           // this fixes 'setTimeout('self.close()',1000); alert("Hi");' crash
01550           widget->closeChildDialogs();
01551         }
01552         //kdDebug() << "scheduling delayed close"  << endl;
01553         // We'll close the window at the end of the script execution
01554         Window* w = const_cast<Window*>(window);
01555         w->m_delayed.append( Window::DelayedAction( Window::DelayedClose ) );
01556       } else {
01557         //kdDebug() << "closing NOW"  << endl;
01558         (const_cast<Window*>(window))->closeNow();
01559       }
01560     }
01561     return Undefined();
01562   }
01563   case Window::Print:
01564     if ( widget ) {
01565       // ### TODO emit onbeforeprint event
01566       widget->print();
01567       // ### TODO emit onafterprint event
01568     }
01569   case Window::CaptureEvents:
01570   case Window::ReleaseEvents:
01571     // Do nothing for now. These are NS-specific legacy calls.
01572     break;
01573   case Window::AddEventListener: {
01574         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
01575         DOM::Document doc = part->document();
01576         if (doc.isHTMLDocument()) {
01577             DOM::HTMLDocument htmlDoc = doc;
01578             htmlDoc.body().addEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
01579         }
01580         else
01581             doc.addEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
01582         return Undefined();
01583     }
01584   case Window::RemoveEventListener: {
01585         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
01586         DOM::Document doc = part->document();
01587         if (doc.isHTMLDocument()) {
01588             DOM::HTMLDocument htmlDoc = doc;
01589             htmlDoc.body().removeEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
01590         }
01591         else
01592             doc.removeEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
01593         return Undefined();
01594     }
01595     break;
01596   }
01597   return Undefined();
01598 }
01599 
01601 
01602 // KDE 4: Make those parameters const ... &
01603 ScheduledAction::ScheduledAction(Object _func, List _args, QTime _nextTime, int _interval, bool _singleShot,
01604                   int _timerId)
01605 {
01606   //kdDebug(6070) << "ScheduledAction::ScheduledAction(isFunction) " << this << endl;
01607   func = static_cast<ObjectImp*>(_func.imp());
01608   args = _args;
01609   isFunction = true;
01610   singleShot = _singleShot;
01611   nextTime = _nextTime;
01612   interval = _interval;
01613   executing = false;
01614   timerId = _timerId;
01615 }
01616 
01617 // KDE 4: Make it const QString &
01618 ScheduledAction::ScheduledAction(QString _code, QTime _nextTime, int _interval, bool _singleShot, int _timerId)
01619 {
01620   //kdDebug(6070) << "ScheduledAction::ScheduledAction(!isFunction) " << this << endl;
01621   //func = 0;
01622   //args = 0;
01623   func = 0;
01624   code = _code;
01625   isFunction = false;
01626   singleShot = _singleShot;
01627   nextTime = _nextTime;
01628   interval = _interval;
01629   executing = false;
01630   timerId = _timerId;
01631 }
01632 
01633 void ScheduledAction::execute(Window *window)
01634 {
01635   ScriptInterpreter *interpreter = static_cast<ScriptInterpreter *>(window->m_part->jScript()->interpreter());
01636 
01637   interpreter->setProcessingTimerCallback(true);
01638 
01639   //kdDebug(6070) << "ScheduledAction::execute " << this << endl;
01640   if (isFunction) {
01641     if (func->implementsCall()) {
01642       // #### check this
01643       Q_ASSERT( window->m_part );
01644       if ( window->m_part )
01645       {
01646         KJS::Interpreter *interpreter = window->m_part->jScript()->interpreter();
01647         ExecState *exec = interpreter->globalExec();
01648         Q_ASSERT( window == interpreter->globalObject().imp() );
01649         Object obj( window );
01650         func->call(exec,obj,args); // note that call() creates its own execution state for the func call
01651         if (exec->hadException())
01652           exec->clearException();
01653 
01654         // Update our document's rendering following the execution of the timeout callback.
01655         window->m_part->document().updateRendering();
01656       }
01657     }
01658   }
01659   else {
01660     window->m_part->executeScript(DOM::Node(), code);
01661   }
01662 
01663   interpreter->setProcessingTimerCallback(false);
01664 }
01665 
01666 void ScheduledAction::mark()
01667 {
01668   if (func && !func->marked())
01669     func->mark();
01670   args.mark();
01671 }
01672 
01673 ScheduledAction::~ScheduledAction()
01674 {
01675   //kdDebug(6070) << "ScheduledAction::~ScheduledAction " << this << endl;
01676 }
01677 
01679 
01680 WindowQObject::WindowQObject(Window *w)
01681   : parent(w)
01682 {
01683   //kdDebug(6070) << "WindowQObject::WindowQObject " << this << endl;
01684   part = parent->m_part;
01685   if ( !part )
01686       kdDebug(6070) << "WARNING: null part in " << k_funcinfo << endl;
01687   else
01688       connect( part, SIGNAL( destroyed() ),
01689                this, SLOT( parentDestroyed() ) );
01690   pausedTime = 0;
01691   lastTimerId = 0;
01692 }
01693 
01694 WindowQObject::~WindowQObject()
01695 {
01696   //kdDebug(6070) << "WindowQObject::~WindowQObject " << this << endl;
01697   parentDestroyed(); // reuse same code
01698 }
01699 
01700 void WindowQObject::parentDestroyed()
01701 {
01702   killTimers();
01703 
01704   QPtrListIterator<ScheduledAction> it(scheduledActions);
01705   for (; it.current(); ++it)
01706     delete it.current();
01707   scheduledActions.clear();
01708 }
01709 
01710 int WindowQObject::installTimeout(const Identifier &handler, int t, bool singleShot)
01711 {
01712   int id = ++lastTimerId;
01713   if (t < 10) t = 10;
01714   QTime nextTime = QTime::currentTime().addMSecs(-pausedTime).addMSecs(t);
01715   ScheduledAction *action = new ScheduledAction(handler.qstring(),nextTime,t,singleShot,id);
01716   scheduledActions.append(action);
01717   setNextTimer();
01718   return id;
01719 }
01720 
01721 int WindowQObject::installTimeout(const Value &func, List args, int t, bool singleShot)
01722 {
01723   Object objFunc = Object::dynamicCast( func );
01724   if (!objFunc.isValid())
01725     return 0;
01726   int id = ++lastTimerId;
01727   if (t < 10) t = 10;
01728   QTime nextTime = QTime::currentTime().addMSecs(-pausedTime).addMSecs(t);
01729   ScheduledAction *action = new ScheduledAction(objFunc,args,nextTime,t,singleShot,id);
01730   scheduledActions.append(action);
01731   setNextTimer();
01732   return id;
01733 }
01734 
01735 void WindowQObject::clearTimeout(int timerId)
01736 {
01737   QPtrListIterator<ScheduledAction> it(scheduledActions);
01738   for (; it.current(); ++it) {
01739     ScheduledAction *action = it.current();
01740     if (action->timerId == timerId) {
01741       scheduledActions.removeRef(action);
01742       if (!action->executing)
01743     delete action;
01744       return;
01745     }
01746   }
01747 }
01748 
01749 void WindowQObject::mark()
01750 {
01751   QPtrListIterator<ScheduledAction> it(scheduledActions);
01752   for (; it.current(); ++it)
01753     it.current()->mark();
01754 }
01755 
01756 void WindowQObject::timerEvent(QTimerEvent *)
01757 {
01758   killTimers();
01759 
01760   if (scheduledActions.isEmpty())
01761     return;
01762 
01763   QTime currentActual = QTime::currentTime();
01764   QTime currentAdjusted = currentActual.addMSecs(-pausedTime);
01765 
01766   // Work out which actions are to be executed. We take a separate copy of
01767   // this list since the main one may be modified during action execution
01768   QPtrList<ScheduledAction> toExecute;
01769   QPtrListIterator<ScheduledAction> it(scheduledActions);
01770   for (; it.current(); ++it)
01771     if (currentAdjusted >= it.current()->nextTime)
01772       toExecute.append(it.current());
01773 
01774   // ### verify that the window can't be closed (and action deleted) during execution
01775   it = QPtrListIterator<ScheduledAction>(toExecute);
01776   for (; it.current(); ++it) {
01777     ScheduledAction *action = it.current();
01778     if (!scheduledActions.containsRef(action)) // removed by clearTimeout()
01779       continue;
01780 
01781     action->executing = true; // prevent deletion in clearTimeout()
01782 
01783     if (action->singleShot)
01784       scheduledActions.removeRef(action);
01785     if (!parent->part().isNull())
01786       action->execute(parent);
01787 
01788     action->executing = false;
01789 
01790     if (!scheduledActions.containsRef(action))
01791       delete action;
01792     else
01793       action->nextTime = action->nextTime.addMSecs(action->interval);
01794   }
01795 
01796   pausedTime += currentActual.msecsTo(QTime::currentTime());
01797 
01798   // Work out when next event is to occur
01799   setNextTimer();
01800 }
01801 
01802 void WindowQObject::setNextTimer()
01803 {
01804   if (scheduledActions.isEmpty())
01805     return;
01806 
01807   QPtrListIterator<ScheduledAction> it(scheduledActions);
01808   QTime nextTime = it.current()->nextTime;
01809   for (++it; it.current(); ++it)
01810     if (nextTime > it.current()->nextTime)
01811       nextTime = it.current()->nextTime;
01812 
01813   QTime nextTimeActual = nextTime.addMSecs(pausedTime);
01814   int nextInterval = QTime::currentTime().msecsTo(nextTimeActual);
01815   if (nextInterval < 0)
01816     nextInterval = 0;
01817   startTimer(nextInterval);
01818 }
01819 
01820 void WindowQObject::timeoutClose()
01821 {
01822   parent->closeNow();
01823 }
01824 
01825 Value FrameArray::get(ExecState *exec, const Identifier &p) const
01826 {
01827 #ifdef KJS_VERBOSE
01828   kdDebug(6070) << "FrameArray::get " << p.qstring() << " part=" << (void*)part << endl;
01829 #endif
01830   if (part.isNull())
01831     return Undefined();
01832 
01833   QPtrList<KParts::ReadOnlyPart> frames = part->frames();
01834   unsigned int len = frames.count();
01835   if (p == lengthPropertyName)
01836     return Number(len);
01837   else if (p== "location") // non-standard property, but works in NS and IE
01838   {
01839     Object obj = Object::dynamicCast( Window::retrieve( part ) );
01840     if ( !obj.isNull() )
01841       return obj.get( exec, "location" );
01842     return Undefined();
01843   }
01844 
01845   // check for the name or number
01846   KParts::ReadOnlyPart *frame = part->findFrame(p.qstring());
01847   if (!frame) {
01848     bool ok;
01849     unsigned int i = p.toArrayIndex(&ok);
01850     if (ok && i < len)
01851       frame = frames.at(i);
01852   }
01853 
01854   // we are potentially fetching a reference to a another Window object here.
01855   // i.e. we may be accessing objects from another interpreter instance.
01856   // Therefore we have to be a bit careful with memory management.
01857   if (frame && ::qt_cast<KHTMLPart*>(frame)) {
01858     KHTMLPart *khtml = static_cast<KHTMLPart*>(frame);
01859     return Window::retrieve(khtml);
01860   }
01861 
01862   return ObjectImp::get(exec, p);
01863 }
01864 
01866 
01867 const ClassInfo Location::info = { "Location", 0, &LocationTable, 0 };
01868 /*
01869 @begin LocationTable 11
01870   hash      Location::Hash      DontDelete
01871   host      Location::Host      DontDelete
01872   hostname  Location::Hostname  DontDelete
01873   href      Location::Href      DontDelete
01874   pathname  Location::Pathname  DontDelete
01875   port      Location::Port      DontDelete
01876   protocol  Location::Protocol  DontDelete
01877   search    Location::Search    DontDelete
01878   [[==]]    Location::EqualEqual    DontDelete|ReadOnly
01879   assign    Location::Assign    DontDelete|Function 1
01880   toString  Location::ToString  DontDelete|Function 0
01881   replace   Location::Replace   DontDelete|Function 1
01882   reload    Location::Reload    DontDelete|Function 0
01883 @end
01884 */
01885 IMPLEMENT_PROTOFUNC_DOM(LocationFunc)
01886 Location::Location(KHTMLPart *p) : m_part(p)
01887 {
01888   //kdDebug(6070) << "Location::Location " << this << " m_part=" << (void*)m_part << endl;
01889 }
01890 
01891 Location::~Location()
01892 {
01893   //kdDebug(6070) << "Location::~Location " << this << " m_part=" << (void*)m_part << endl;
01894 }
01895 
01896 Value Location::get(ExecState *exec, const Identifier &p) const
01897 {
01898 #ifdef KJS_VERBOSE
01899   kdDebug(6070) << "Location::get " << p.qstring() << " m_part=" << (void*)m_part << endl;
01900 #endif
01901 
01902   if (m_part.isNull())
01903     return Undefined();
01904 
01905   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
01906 
01907   // properties that work on all Location objects
01908   if ( entry && entry->value == Replace )
01909       return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr);
01910 
01911   // XSS check
01912   const Window* window = Window::retrieveWindow( m_part );
01913   if ( !window || !window->isSafeScript(exec) )
01914     return Undefined();
01915 
01916   KURL url = m_part->url();
01917   if (entry)
01918     switch (entry->value) {
01919     case Hash:
01920       return String( url.ref().isNull() ? QString("") : "#" + url.ref() );
01921     case Host: {
01922       UString str = url.host();
01923       if (url.port())
01924         str += ":" + QString::number((int)url.port());
01925       return String(str);
01926       // Note: this is the IE spec. The NS spec swaps the two, it says
01927       // "The hostname property is the concatenation of the host and port properties, separated by a colon."
01928       // Bleh.
01929     }
01930     case Hostname:
01931       return String( url.host() );
01932     case Href:
01933       if (!url.hasPath())
01934         return String( url.prettyURL()+"/" );
01935       else
01936         return String( url.prettyURL() );
01937     case Pathname:
01938       return String( url.path().isEmpty() ? QString("/") : url.path() );
01939     case Port:
01940       return String( url.port() ? QString::number((int)url.port()) : QString::fromLatin1("") );
01941     case Protocol:
01942       return String( url.protocol()+":" );
01943     case Search:
01944       return String( url.query() );
01945     case EqualEqual: // [[==]]
01946       return String(toString(exec));
01947     case ToString:
01948       return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr);
01949     }
01950   // Look for overrides
01951   ValueImp * val = ObjectImp::getDirect(p);
01952   if (val)
01953     return Value(val);
01954   if (entry && (entry->attr & Function))
01955     return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr);
01956 
01957   return Undefined();
01958 }
01959 
01960 void Location::put(ExecState *exec, const Identifier &p, const Value &v, int attr)
01961 {
01962 #ifdef KJS_VERBOSE
01963   kdDebug(6070) << "Location::put " << p.qstring() << " m_part=" << (void*)m_part << endl;
01964 #endif
01965   if (m_part.isNull())
01966     return;
01967 
01968   // XSS check
01969   const Window* window = Window::retrieveWindow( m_part );
01970   if ( !window || !window->isSafeScript(exec) )
01971     return;
01972 
01973   QString str = v.toString(exec).qstring();
01974   KURL url = m_part->url();
01975   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
01976   if (entry)
01977     switch (entry->value) {
01978     case Href: {
01979       KHTMLPart* p = Window::retrieveActive(exec)->part();
01980       if ( p )
01981         url = p->htmlDocument().completeURL( str ).string();
01982       else
01983         url = str;
01984       break;
01985     }
01986     case Hash:
01987       // when the hash is already the same ignore it
01988       if (str == url.ref()) return;
01989       url.setRef(str);
01990       break;
01991     case Host: {
01992       QString host = str.left(str.find(":"));
01993       QString port = str.mid(str.find(":")+1);
01994       url.setHost(host);
01995       url.setPort(port.toUInt());
01996       break;
01997     }
01998     case Hostname:
01999       url.setHost(str);
02000       break;
02001     case Pathname:
02002       url.setPath(str);
02003       break;
02004     case Port:
02005       url.setPort(str.toUInt());
02006       break;
02007     case Protocol:
02008       url.setProtocol(str);
02009       break;
02010     case Search:
02011       url.setQuery(str);
02012       break;
02013     }
02014   else {
02015     ObjectImp::put(exec, p, v, attr);
02016     return;
02017   }
02018 
02019   Window::retrieveWindow(m_part)->goURL(exec, url.url(), false /* don't lock history*/ );
02020 }
02021 
02022 Value Location::toPrimitive(ExecState *exec, Type) const
02023 {
02024   Window* window = Window::retrieveWindow( m_part );
02025   if ( window && window->isSafeScript(exec) )
02026     return String(toString(exec));
02027   return Undefined();
02028 }
02029 
02030 UString Location::toString(ExecState *exec) const
02031 {
02032   Window* window = Window::retrieveWindow( m_part );
02033   if ( window && window->isSafeScript(exec) )
02034   {
02035     if (!m_part->url().hasPath())
02036       return m_part->url().prettyURL()+"/";
02037     else
02038       return m_part->url().prettyURL();
02039   }
02040   return "";
02041 }
02042 
02043 Value LocationFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
02044 {
02045   KJS_CHECK_THIS( Location, thisObj );
02046   Location *location = static_cast<Location *>(thisObj.imp());
02047   KHTMLPart *part = location->part();
02048 
02049   if (!part) return Undefined();
02050 
02051   Window* window = Window::retrieveWindow(part);
02052 
02053   if ( !window->isSafeScript(exec) && id != Location::Replace)
02054       return Undefined();
02055 
02056   switch (id) {
02057   case Location::Assign:
02058   case Location::Replace:
02059     Window::retrieveWindow(part)->goURL(exec, args[0].toString(exec).qstring(),
02060             id == Location::Replace);
02061     break;
02062   case Location::Reload:
02063     part->scheduleRedirection(-1, part->url().url(), true/*lock history*/);
02064     break;
02065   case Location::ToString:
02066     return String(location->toString(exec));
02067   }
02068   return Undefined();
02069 }
02070 
02072 
02073 const ClassInfo External::info = { "External", 0, 0, 0 };
02074 /*
02075 @begin ExternalTable 4
02076   addFavorite   External::AddFavorite   DontDelete|Function 1
02077 @end
02078 */
02079 IMPLEMENT_PROTOFUNC_DOM(ExternalFunc)
02080 
02081 Value External::get(ExecState *exec, const Identifier &p) const
02082 {
02083   return lookupGetFunction<ExternalFunc,ObjectImp>(exec,p,&ExternalTable,this);
02084 }
02085 
02086 Value ExternalFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
02087 {
02088   KJS_CHECK_THIS( External, thisObj );
02089   External *external = static_cast<External *>(thisObj.imp());
02090 
02091   KHTMLPart *part = external->part;
02092   if (!part)
02093     return Undefined();
02094 
02095   KHTMLView *widget = part->view();
02096 
02097   switch (id) {
02098   case External::AddFavorite:
02099   {
02100     if (!widget->dialogsAllowed())
02101       return Undefined();
02102     part->xmlDocImpl()->updateRendering();
02103     if (args.size() != 1 && args.size() != 2)
02104       return Undefined();
02105 
02106     QString url = args[0].toString(exec).qstring();
02107     QString title;
02108     if (args.size() == 2)
02109       title = args[1].toString(exec).qstring();
02110 
02111     // AK - don't do anything yet, for the moment i
02112     // just wanted the base js handling code in cvs
02113     return Undefined();
02114 
02115     QString question;
02116     if ( title.isEmpty() )
02117       question = i18n("Do you want a bookmark pointing to the location \"%1\" to be added to your collection?")
02118                  .arg(url);
02119     else
02120       question = i18n("Do you want a bookmark pointing to the location \"%1\" titled \"%2\" to be added to your collection?")
02121                  .arg(url).arg(title);
02122 
02123     if (KMessageBox::warningYesNo(
02124           widget, question,
02125           i18n("JavaScript Attempted Bookmark Insert"),
02126           i18n("Insert"), i18n("Disallow")) == KMessageBox::Yes)
02127     {
02128       KBookmarkManager *mgr = KBookmarkManager::userBookmarksManager();
02129       mgr->addBookmarkDialog(url,title);
02130     }
02131     break;
02132   }
02133   default:
02134     return Undefined();
02135   }
02136 
02137   return Undefined();
02138 }
02139 
02141 
02142 const ClassInfo History::info = { "History", 0, 0, 0 };
02143 /*
02144 @begin HistoryTable 4
02145   length    History::Length     DontDelete|ReadOnly
02146   back      History::Back       DontDelete|Function 0
02147   forward   History::Forward    DontDelete|Function 0
02148   go        History::Go     DontDelete|Function 1
02149 @end
02150 */
02151 IMPLEMENT_PROTOFUNC_DOM(HistoryFunc)
02152 
02153 Value History::get(ExecState *exec, const Identifier &p) const
02154 {
02155   return lookupGet<HistoryFunc,History,ObjectImp>(exec,p,&HistoryTable,this);
02156 }
02157 
02158 Value History::getValueProperty(ExecState *, int token) const
02159 {
02160   // if previous or next is implemented, make sure its not a major
02161   // privacy leak (see i.e. http://security.greymagic.com/adv/gm005-op/)
02162   switch (token) {
02163   case Length:
02164   {
02165     KParts::BrowserExtension *ext = part->browserExtension();
02166     if ( !ext )
02167       return Number( 0 );
02168 
02169     KParts::BrowserInterface *iface = ext->browserInterface();
02170     if ( !iface )
02171       return Number( 0 );
02172 
02173     QVariant length = iface->property( "historyLength" );
02174 
02175     if ( length.type() != QVariant::UInt )
02176       return Number( 0 );
02177 
02178     return Number( length.toUInt() );
02179   }
02180   default:
02181     kdDebug(6070) << "WARNING: Unhandled token in History::getValueProperty : " << token << endl;
02182     return Undefined();
02183   }
02184 }
02185 
02186 Value HistoryFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
02187 {
02188   KJS_CHECK_THIS( History, thisObj );
02189   History *history = static_cast<History *>(thisObj.imp());
02190 
02191   Value v = args[0];
02192   Number n;
02193   if(!v.isNull())
02194     n = v.toInteger(exec);
02195 
02196   int steps;
02197   switch (id) {
02198   case History::Back:
02199     steps = -1;
02200     break;
02201   case History::Forward:
02202     steps = 1;
02203     break;
02204   case History::Go:
02205     steps = n.intValue();
02206     break;
02207   default:
02208     return Undefined();
02209   }
02210 
02211   // Special case for go(0) from a frame -> reload only the frame
02212   // go(i!=0) from a frame navigates into the history of the frame only,
02213   // in both IE and NS (but not in Mozilla).... we can't easily do that
02214   // in Konqueror...
02215   if (!steps) // add && history->part->parentPart() to get only frames, but doesn't matter
02216   {
02217     history->part->openURL( history->part->url() ); 
02218   } else
02219   {
02220     // Delay it.
02221     // Testcase: history.back(); alert("hello");
02222     Window* window = Window::retrieveWindow( history->part );
02223     window->delayedGoHistory( steps );
02224   }
02225   return Undefined();
02226 }
02227 
02229 
02230 #ifdef Q_WS_QWS
02231 
02232 const ClassInfo Konqueror::info = { "Konqueror", 0, 0, 0 };
02233 
02234 bool Konqueror::hasProperty(ExecState *exec, const Identifier &p) const
02235 {
02236   if ( p.qstring().startsWith( "goHistory" ) ) return false;
02237 
02238   return true;
02239 }
02240 
02241 Value Konqueror::get(ExecState *exec, const Identifier &p) const
02242 {
02243   if ( p == "goHistory" || part->url().protocol() != "http" || part->url().host() != "localhost" )
02244     return Undefined();
02245 
02246   KParts::BrowserExtension *ext = part->browserExtension();
02247   if ( ext ) {
02248     KParts::BrowserInterface *iface = ext->browserInterface();
02249     if ( iface ) {
02250       QVariant prop = iface->property( p.qstring().latin1() );
02251 
02252       if ( prop.isValid() ) {
02253         switch( prop.type() ) {
02254         case QVariant::Int:
02255           return Number( prop.toInt() );
02256         case QVariant::String:
02257           return String( prop.toString() );
02258         default:
02259           break;
02260         }
02261       }
02262     }
02263   }
02264 
02265   return Value( new KonquerorFunc(this, p.qstring().latin1() ) );
02266 }
02267 
02268 Value KonquerorFunc::tryCall(ExecState *exec, Object &, const List &args)
02269 {
02270   KParts::BrowserExtension *ext = konqueror->part->browserExtension();
02271 
02272   if(!ext)
02273     return Undefined();
02274 
02275   KParts::BrowserInterface *iface = ext->browserInterface();
02276 
02277   if ( !iface )
02278     return Undefined();
02279 
02280   QCString n = m_name.data();
02281   n += "()";
02282   iface->callMethod( n.data(), QVariant() );
02283 
02284   return Undefined();
02285 }
02286 
02287 UString Konqueror::toString(ExecState *) const
02288 {
02289   return UString("[object Konqueror]");
02290 }
02291 
02292 #endif
02293 
02294 
02295 #include "kjs_window.moc"
KDE Logo
This file is part of the documentation for khtml Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Aug 4 05:28:58 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2003