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