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