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     emit m_part->browserExtension()->requestFocus(m_part);
01214     QString caption;
01215     if (!m_part->url().host().isEmpty())
01216       caption = m_part->url().host() + " - ";
01217     caption += i18n( "Confirmation: JavaScript Popup" );
01218     if ( KMessageBox::questionYesNo(widget,
01219                                     str.isEmpty() ?
01220                                     i18n( "This site is requesting to open up a new browser "
01221                                           "window via JavaScript.\n"
01222                                           "Do you want to allow this?" ) :
01223                                     i18n( "<qt>This site is requesting to open<p>%1</p>in a new browser window via JavaScript.<br />"
01224                                           "Do you want to allow this?</qt>").arg(KStringHandler::csqueeze(url.htmlURL(),  100)),
01225                                     caption ) == KMessageBox::Yes )
01226       policy = KHTMLSettings::KJSWindowOpenAllow;
01227   } else if ( policy == KHTMLSettings::KJSWindowOpenSmart )
01228   {
01229     // window.open disabled unless from a key/mouse event
01230     if (static_cast<ScriptInterpreter *>(exec->interpreter())->isWindowOpenAllowed())
01231       policy = KHTMLSettings::KJSWindowOpenAllow;
01232   }
01233   if ( policy != KHTMLSettings::KJSWindowOpenAllow ) {
01234     return Undefined();
01235   } else {
01236     KParts::WindowArgs winargs;
01237 
01238     // scan feature argument
01239     QString features;
01240     if (args.size()>2) {
01241       features = args[2].toString(exec).qstring();
01242       // specifying window params means false defaults
01243       winargs.menuBarVisible = false;
01244       winargs.toolBarsVisible = false;
01245       winargs.statusBarVisible = false;
01246       QStringList flist = QStringList::split(',', features);
01247       QStringList::ConstIterator it = flist.begin();
01248       while (it != flist.end()) {
01249         QString s = *it++;
01250         QString key, val;
01251         int pos = s.find('=');
01252         if (pos >= 0) {
01253           key = s.left(pos).stripWhiteSpace().lower();
01254           val = s.mid(pos + 1).stripWhiteSpace().lower();
01255           QRect screen = KGlobalSettings::desktopGeometry(widget->topLevelWidget());
01256 
01257           if (key == "left" || key == "screenx") {
01258             winargs.x = (int)val.toFloat() + screen.x();
01259             if (winargs.x < screen.x() || winargs.x > screen.right())
01260               winargs.x = screen.x(); // only safe choice until size is determined
01261           } else if (key == "top" || key == "screeny") {
01262             winargs.y = (int)val.toFloat() + screen.y();
01263             if (winargs.y < screen.y() || winargs.y > screen.bottom())
01264               winargs.y = screen.y(); // only safe choice until size is determined
01265           } else if (key == "height") {
01266             winargs.height = (int)val.toFloat() + 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2;
01267             if (winargs.height > screen.height())  // should actually check workspace
01268               winargs.height = screen.height();
01269             if (winargs.height < 100)
01270               winargs.height = 100;
01271           } else if (key == "width") {
01272             winargs.width = (int)val.toFloat() + 2*qApp->style().pixelMetric( QStyle::PM_DefaultFrameWidth ) + 2;
01273             if (winargs.width > screen.width())    // should actually check workspace
01274               winargs.width = screen.width();
01275             if (winargs.width < 100)
01276               winargs.width = 100;
01277           } else {
01278             goto boolargs;
01279           }
01280           continue;
01281         } else {
01282           // leaving away the value gives true
01283           key = s.stripWhiteSpace().lower();
01284           val = "1";
01285         }
01286       boolargs:
01287         if (key == "menubar")
01288           winargs.menuBarVisible = (val == "1" || val == "yes");
01289         else if (key == "toolbar")
01290           winargs.toolBarsVisible = (val == "1" || val == "yes");
01291         else if (key == "location")  // ### missing in WindowArgs
01292           winargs.toolBarsVisible = (val == "1" || val == "yes");
01293         else if (key == "status" || key == "statusbar")
01294           winargs.statusBarVisible = (val == "1" || val == "yes");
01295         else if (key == "resizable")
01296           winargs.resizable = (val == "1" || val == "yes");
01297         else if (key == "fullscreen")
01298           winargs.fullscreen = (val == "1" || val == "yes");
01299       }
01300     }
01301 
01302     KParts::URLArgs uargs;
01303     KHTMLPart *p = m_part;
01304     uargs.frameName = args.size() > 1 ?
01305                       args[1].toString(exec).qstring()
01306                       : QString("_blank");
01307     if ( uargs.frameName.lower() == "_top" )
01308     {
01309       while ( p->parentPart() )
01310         p = p->parentPart();
01311       Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/);
01312       return Window::retrieve(p);
01313     }
01314     if ( uargs.frameName.lower() == "_parent" )
01315     {
01316       if ( p->parentPart() )
01317         p = p->parentPart();
01318       Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/);
01319       return Window::retrieve(p);
01320     }
01321     if ( uargs.frameName.lower() == "_self")
01322     {
01323       Window::retrieveWindow(p)->goURL(exec, url.url(), false /*don't lock history*/);
01324       return Window::retrieve(p);
01325     }
01326     if ( uargs.frameName.lower() == "replace" )
01327     {
01328       Window::retrieveWindow(p)->goURL(exec, url.url(), true /*lock history*/);
01329       return Window::retrieve(p);
01330     }
01331     uargs.serviceType = "text/html";
01332 
01333     // request window (new or existing if framename is set)
01334     KParts::ReadOnlyPart *newPart = 0L;
01335     emit p->browserExtension()->createNewWindow(KURL(), uargs,winargs,newPart);
01336     if (newPart && ::qt_cast<KHTMLPart*>(newPart)) {
01337       KHTMLPart *khtmlpart = static_cast<KHTMLPart*>(newPart);
01338       //qDebug("opener set to %p (this Window's part) in new Window %p  (this Window=%p)",part,win,window);
01339       khtmlpart->setOpener(p);
01340       khtmlpart->setOpenedByJS(true);
01341       if (khtmlpart->document().isNull()) {
01342         khtmlpart->begin();
01343         khtmlpart->write("<HTML><BODY>");
01344         khtmlpart->end();
01345         if ( p->docImpl() ) {
01346           //kdDebug(6070) << "Setting domain to " << p->docImpl()->domain().string() << endl;
01347           khtmlpart->docImpl()->setDomain( p->docImpl()->domain());
01348           khtmlpart->docImpl()->setBaseURL( p->docImpl()->baseURL() );
01349         }
01350       }
01351       uargs.serviceType = QString::null;
01352       if (uargs.frameName.lower() == "_blank")
01353         uargs.frameName = QString::null;
01354       if (!url.isEmpty())
01355         emit khtmlpart->browserExtension()->openURLRequest(url,uargs);
01356       return Window::retrieve(khtmlpart); // global object
01357     } else
01358       return Undefined();
01359   }
01360 }
01361 
01362 Value WindowFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
01363 {
01364   KJS_CHECK_THIS( Window, thisObj );
01365   Window *window = static_cast<Window *>(thisObj.imp());
01366   QString str, str2;
01367 
01368   KHTMLPart *part = window->m_part;
01369   if (!part)
01370     return Undefined();
01371 
01372   KHTMLView *widget = part->view();
01373   Value v = args[0];
01374   UString s = v.toString(exec);
01375   str = s.qstring();
01376 
01377   QString caption;
01378   if (part && !part->url().host().isEmpty())
01379     caption = part->url().host() + " - ";
01380   caption += "JavaScript"; // TODO: i18n
01381   // functions that work everywhere
01382   switch(id) {
01383   case Window::Alert:
01384     if (!widget->dialogsAllowed())
01385       return Undefined();
01386     if ( part && part->xmlDocImpl() )
01387       part->xmlDocImpl()->updateRendering();
01388     if ( part )
01389       emit part->browserExtension()->requestFocus(part);
01390     KMessageBox::error(widget, QStyleSheet::convertFromPlainText(str), caption);
01391     return Undefined();
01392   case Window::Confirm:
01393     if (!widget->dialogsAllowed())
01394       return Undefined();
01395     if ( part && part->xmlDocImpl() )
01396       part->xmlDocImpl()->updateRendering();
01397     if ( part )
01398       emit part->browserExtension()->requestFocus(part);
01399     return Boolean((KMessageBox::warningYesNo(widget, QStyleSheet::convertFromPlainText(str), caption,
01400                                                 KStdGuiItem::ok(), KStdGuiItem::cancel()) == KMessageBox::Yes));
01401   case Window::Prompt:
01402     if (!widget->dialogsAllowed())
01403       return Undefined();
01404     if ( part && part->xmlDocImpl() )
01405       part->xmlDocImpl()->updateRendering();
01406     if ( part )
01407       emit part->browserExtension()->requestFocus(part);
01408     bool ok;
01409     if (args.size() >= 2)
01410       str2 = KInputDialog::getText(caption,
01411                                    QStyleSheet::convertFromPlainText(str),
01412                                    args[1].toString(exec).qstring(), &ok, widget);
01413     else
01414       str2 = KInputDialog::getText(caption,
01415                                    QStyleSheet::convertFromPlainText(str),
01416                                    QString::null, &ok, widget);
01417     if ( ok )
01418         return String(str2);
01419     else
01420         return Null();
01421   case Window::Open:
01422     return window->openWindow(exec, args);
01423   case Window::Navigate:
01424     window->goURL(exec, args[0].toString(exec).qstring(), false /*don't lock history*/);
01425     return Undefined();
01426   case Window::Focus: {
01427     KHTMLSettings::KJSWindowFocusPolicy policy =
01428         part->settings()->windowFocusPolicy(part->url().host());
01429     if(policy == KHTMLSettings::KJSWindowFocusAllow && widget) {
01430       widget->topLevelWidget()->raise();
01431       widget->setActiveWindow();
01432       emit part->browserExtension()->requestFocus(part);
01433     }
01434     return Undefined();
01435   }
01436   case Window::Blur:
01437     // TODO
01438     return Undefined();
01439   };
01440 
01441 
01442   // now unsafe functions..
01443   if (!window->isSafeScript(exec))
01444     return Undefined();
01445 
01446   switch (id) {
01447   case Window::ScrollBy:
01448     if(args.size() == 2 && widget)
01449       widget->scrollBy(args[0].toInt32(exec), args[1].toInt32(exec));
01450     return Undefined();
01451   case Window::Scroll:
01452   case Window::ScrollTo:
01453     if(args.size() == 2 && widget)
01454       widget->setContentsPos(args[0].toInt32(exec), args[1].toInt32(exec));
01455     return Undefined();
01456   case Window::MoveBy: {
01457     KHTMLSettings::KJSWindowMovePolicy policy =
01458         part->settings()->windowMovePolicy(part->url().host());
01459     if(policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget)
01460     {
01461       KParts::BrowserExtension *ext = part->browserExtension();
01462       if (ext) {
01463         QWidget * tl = widget->topLevelWidget();
01464         QRect sg = KGlobalSettings::desktopGeometry(tl);
01465 
01466         QPoint dest = tl->pos() + QPoint( args[0].toInt32(exec), args[1].toInt32(exec) );
01467         // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
01468         if ( dest.x() >= sg.x() && dest.y() >= sg.x() &&
01469              dest.x()+tl->width() <= sg.width()+sg.x() &&
01470              dest.y()+tl->height() <= sg.height()+sg.y() )
01471           emit ext->moveTopLevelWidget( dest.x(), dest.y() );
01472       }
01473     }
01474     return Undefined();
01475   }
01476   case Window::MoveTo: {
01477     KHTMLSettings::KJSWindowMovePolicy policy =
01478         part->settings()->windowMovePolicy(part->url().host());
01479     if(policy == KHTMLSettings::KJSWindowMoveAllow && args.size() == 2 && widget)
01480     {
01481       KParts::BrowserExtension *ext = part->browserExtension();
01482       if (ext) {
01483         QWidget * tl = widget->topLevelWidget();
01484         QRect sg = KGlobalSettings::desktopGeometry(tl);
01485 
01486         QPoint dest( args[0].toInt32(exec)+sg.x(), args[1].toInt32(exec)+sg.y() );
01487         // Security check (the spec talks about UniversalBrowserWrite to disable this check...)
01488         if ( dest.x() >= sg.x() && dest.y() >= sg.y() &&
01489              dest.x()+tl->width() <= sg.width()+sg.x() &&
01490              dest.y()+tl->height() <= sg.height()+sg.y() )
01491         emit ext->moveTopLevelWidget( dest.x(), dest.y() );
01492       }
01493     }
01494     return Undefined();
01495   }
01496   case Window::ResizeBy: {
01497     KHTMLSettings::KJSWindowResizePolicy policy =
01498         part->settings()->windowResizePolicy(part->url().host());
01499     if(policy == KHTMLSettings::KJSWindowResizeAllow
01500             && args.size() == 2 && widget)
01501     {
01502       QWidget * tl = widget->topLevelWidget();
01503       QRect geom = tl->frameGeometry();
01504       window->resizeTo( tl,
01505                         geom.width() + args[0].toInt32(exec),
01506                         geom.height() + args[1].toInt32(exec) );
01507     }
01508     return Undefined();
01509   }
01510   case Window::ResizeTo: {
01511     KHTMLSettings::KJSWindowResizePolicy policy =
01512                part->settings()->windowResizePolicy(part->url().host());
01513     if(policy == KHTMLSettings::KJSWindowResizeAllow
01514                && args.size() == 2 && widget)
01515     {
01516       QWidget * tl = widget->topLevelWidget();
01517       window->resizeTo( tl, args[0].toInt32(exec), args[1].toInt32(exec) );
01518     }
01519     return Undefined();
01520   }
01521   case Window::SetTimeout:
01522   case Window::SetInterval: {
01523     bool singleShot;
01524     int i; // timeout interval
01525     if (args.size() == 0)
01526       return Undefined();
01527     if (args.size() > 1) {
01528       singleShot = (id == Window::SetTimeout);
01529       i = args[1].toInt32(exec);
01530     } else {
01531       // second parameter is missing. Emulate Mozilla behavior.
01532       singleShot = true;
01533       i = 4;
01534     }
01535     if (v.isA(StringType)) {
01536       int r = (const_cast<Window*>(window))->winq->installTimeout(Identifier(s), i, singleShot );
01537       return Number(r);
01538     }
01539     else if (v.isA(ObjectType) && Object::dynamicCast(v).implementsCall()) {
01540       Object func = Object::dynamicCast(v);
01541       List funcArgs;
01542       ListIterator it = args.begin();
01543       int argno = 0;
01544       while (it != args.end()) {
01545     Value arg = it++;
01546     if (argno++ >= 2)
01547         funcArgs.append(arg);
01548       }
01549       if (args.size() < 2)
01550     funcArgs.append(Number(i));
01551       int r = (const_cast<Window*>(window))->winq->installTimeout(func, funcArgs, i, singleShot );
01552       return Number(r);
01553     }
01554     else
01555       return Undefined();
01556   }
01557   case Window::ClearTimeout:
01558   case Window::ClearInterval:
01559     (const_cast<Window*>(window))->winq->clearTimeout(v.toInt32(exec));
01560     return Undefined();
01561   case Window::Close: {
01562     /* From http://developer.netscape.com/docs/manuals/js/client/jsref/window.htm :
01563        The close method closes only windows opened by JavaScript using the open method.
01564        If you attempt to close any other window, a confirm is generated, which
01565        lets the user choose whether the window closes.
01566        This is a security feature to prevent "mail bombs" containing self.close().
01567        However, if the window has only one document (the current one) in its
01568        session history, the close is allowed without any confirm. This is a
01569        special case for one-off windows that need to open other windows and
01570        then dispose of themselves.
01571     */
01572     bool doClose = false;
01573     if (!part->openedByJS())
01574     {
01575       // To conform to the SPEC, we only ask if the window
01576       // has more than one entry in the history (NS does that too).
01577       History history(exec,part);
01578 
01579       if ( history.get( exec, "length" ).toInt32(exec) <= 1 )
01580       {
01581         doClose = true;
01582       }
01583       else
01584       {
01585         // Can we get this dialog with tabs??? Does it close the window or the tab in that case?
01586         emit part->browserExtension()->requestFocus(part);
01587         if ( KMessageBox::questionYesNo( window->part()->widget(), i18n("Close window?"), i18n("Confirmation Required") )
01588              == KMessageBox::Yes )
01589           doClose = true;
01590       }
01591     }
01592     else
01593       doClose = true;
01594 
01595     if (doClose)
01596     {
01597       // If this is the current window (the one the interpreter runs in),
01598       // then schedule a delayed close (so that the script terminates first).
01599       // But otherwise, close immediately. This fixes w=window.open("","name");w.close();window.open("name");
01600       if ( Window::retrieveActive(exec) == window ) {
01601         if (widget) {
01602           // quit all dialogs of this view
01603           // this fixes 'setTimeout('self.close()',1000); alert("Hi");' crash
01604           widget->closeChildDialogs();
01605         }
01606         //kdDebug() << "scheduling delayed close"  << endl;
01607         // We'll close the window at the end of the script execution
01608         Window* w = const_cast<Window*>(window);
01609         w->m_delayed.append( Window::DelayedAction( Window::DelayedClose ) );
01610       } else {
01611         //kdDebug() << "closing NOW"  << endl;
01612         (const_cast<Window*>(window))->closeNow();
01613       }
01614     }
01615     return Undefined();
01616   }
01617   case Window::Print:
01618     if ( widget ) {
01619       // ### TODO emit onbeforeprint event
01620       widget->print();
01621       // ### TODO emit onafterprint event
01622     }
01623   case Window::CaptureEvents:
01624   case Window::ReleaseEvents:
01625     // Do nothing for now. These are NS-specific legacy calls.
01626     break;
01627   case Window::AddEventListener: {
01628         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
01629         DOM::Document doc = part->document();
01630         if (doc.isHTMLDocument()) {
01631             DOM::HTMLDocument htmlDoc = doc;
01632             htmlDoc.body().addEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
01633         }
01634         else
01635             doc.addEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
01636         return Undefined();
01637     }
01638   case Window::RemoveEventListener: {
01639         JSEventListener *listener = Window::retrieveActive(exec)->getJSEventListener(args[1]);
01640         DOM::Document doc = part->document();
01641         if (doc.isHTMLDocument()) {
01642             DOM::HTMLDocument htmlDoc = doc;
01643             htmlDoc.body().removeEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
01644         }
01645         else
01646             doc.removeEventListener(args[0].toString(exec).string(),listener,args[2].toBoolean(exec));
01647         return Undefined();
01648     }
01649     break;
01650   }
01651   return Undefined();
01652 }
01653 
01655 
01656 // KDE 4: Make those parameters const ... &
01657 ScheduledAction::ScheduledAction(Object _func, List _args, QTime _nextTime, int _interval, bool _singleShot,
01658                   int _timerId)
01659 {
01660   //kdDebug(6070) << "ScheduledAction::ScheduledAction(isFunction) " << this << endl;
01661   func = static_cast<ObjectImp*>(_func.imp());
01662   args = _args;
01663   isFunction = true;
01664   singleShot = _singleShot;
01665   nextTime = _nextTime;
01666   interval = _interval;
01667   executing = false;
01668   timerId = _timerId;
01669 }
01670 
01671 // KDE 4: Make it const QString &
01672 ScheduledAction::ScheduledAction(QString _code, QTime _nextTime, int _interval, bool _singleShot, int _timerId)
01673 {
01674   //kdDebug(6070) << "ScheduledAction::ScheduledAction(!isFunction) " << this << endl;
01675   //func = 0;
01676   //args = 0;
01677   func = 0;
01678   code = _code;
01679   isFunction = false;
01680   singleShot = _singleShot;
01681   nextTime = _nextTime;
01682   interval = _interval;
01683   executing = false;
01684   timerId = _timerId;
01685 }
01686 
01687 void ScheduledAction::execute(Window *window)
01688 {
01689   ScriptInterpreter *interpreter = static_cast<ScriptInterpreter *>(window->m_part->jScript()->interpreter());
01690 
01691   interpreter->setProcessingTimerCallback(true);
01692 
01693   //kdDebug(6070) << "ScheduledAction::execute " << this << endl;
01694   if (isFunction) {
01695     if (func->implementsCall()) {
01696       // #### check this
01697       Q_ASSERT( window->m_part );
01698       if ( window->m_part )
01699       {
01700         KJS::Interpreter *interpreter = window->m_part->jScript()->interpreter();
01701         ExecState *exec = interpreter->globalExec();
01702         Q_ASSERT( window == interpreter->globalObject().imp() );
01703         Object obj( window );
01704         func->call(exec,obj,args); // note that call() creates its own execution state for the func call
01705         if (exec->hadException())
01706           exec->clearException();
01707 
01708         // Update our document's rendering following the execution of the timeout callback.
01709         window->m_part->document().updateRendering();
01710       }
01711     }
01712   }
01713   else {
01714     window->m_part->executeScript(DOM::Node(), code);
01715   }
01716 
01717   interpreter->setProcessingTimerCallback(false);
01718 }
01719 
01720 void ScheduledAction::mark()
01721 {
01722   if (func && !func->marked())
01723     func->mark();
01724   args.mark();
01725 }
01726 
01727 ScheduledAction::~ScheduledAction()
01728 {
01729   //kdDebug(6070) << "ScheduledAction::~ScheduledAction " << this << endl;
01730 }
01731 
01733 
01734 WindowQObject::WindowQObject(Window *w)
01735   : parent(w)
01736 {
01737   //kdDebug(6070) << "WindowQObject::WindowQObject " << this << endl;
01738   part = parent->m_part;
01739   if ( !part )
01740       kdDebug(6070) << "WARNING: null part in " << k_funcinfo << endl;
01741   else
01742       connect( part, SIGNAL( destroyed() ),
01743                this, SLOT( parentDestroyed() ) );
01744   pausedTime = 0;
01745   lastTimerId = 0;
01746 }
01747 
01748 WindowQObject::~WindowQObject()
01749 {
01750   //kdDebug(6070) << "WindowQObject::~WindowQObject " << this << endl;
01751   parentDestroyed(); // reuse same code
01752 }
01753 
01754 void WindowQObject::parentDestroyed()
01755 {
01756   killTimers();
01757 
01758   QPtrListIterator<ScheduledAction> it(scheduledActions);
01759   for (; it.current(); ++it)
01760     delete it.current();
01761   scheduledActions.clear();
01762 }
01763 
01764 int WindowQObject::installTimeout(const Identifier &handler, int t, bool singleShot)
01765 {
01766   int id = ++lastTimerId;
01767   if (t < 10) t = 10;
01768   QTime nextTime = QTime::currentTime().addMSecs(-pausedTime).addMSecs(t);
01769   ScheduledAction *action = new ScheduledAction(handler.qstring(),nextTime,t,singleShot,id);
01770   scheduledActions.append(action);
01771   setNextTimer();
01772   return id;
01773 }
01774 
01775 int WindowQObject::installTimeout(const Value &func, List args, int t, bool singleShot)
01776 {
01777   Object objFunc = Object::dynamicCast( func );
01778   if (!objFunc.isValid())
01779     return 0;
01780   int id = ++lastTimerId;
01781   if (t < 10) t = 10;
01782   QTime nextTime = QTime::currentTime().addMSecs(-pausedTime).addMSecs(t);
01783   ScheduledAction *action = new ScheduledAction(objFunc,args,nextTime,t,singleShot,id);
01784   scheduledActions.append(action);
01785   setNextTimer();
01786   return id;
01787 }
01788 
01789 void WindowQObject::clearTimeout(int timerId)
01790 {
01791   QPtrListIterator<ScheduledAction> it(scheduledActions);
01792   for (; it.current(); ++it) {
01793     ScheduledAction *action = it.current();
01794     if (action->timerId == timerId) {
01795       scheduledActions.removeRef(action);
01796       if (!action->executing)
01797     delete action;
01798       return;
01799     }
01800   }
01801 }
01802 
01803 void WindowQObject::mark()
01804 {
01805   QPtrListIterator<ScheduledAction> it(scheduledActions);
01806   for (; it.current(); ++it)
01807     it.current()->mark();
01808 }
01809 
01810 void WindowQObject::timerEvent(QTimerEvent *)
01811 {
01812   killTimers();
01813 
01814   if (scheduledActions.isEmpty())
01815     return;
01816 
01817   QTime currentActual = QTime::currentTime();
01818   QTime currentAdjusted = currentActual.addMSecs(-pausedTime);
01819 
01820   // Work out which actions are to be executed. We take a separate copy of
01821   // this list since the main one may be modified during action execution
01822   QPtrList<ScheduledAction> toExecute;
01823   QPtrListIterator<ScheduledAction> it(scheduledActions);
01824   for (; it.current(); ++it)
01825     if (currentAdjusted >= it.current()->nextTime)
01826       toExecute.append(it.current());
01827 
01828   // ### verify that the window can't be closed (and action deleted) during execution
01829   it = QPtrListIterator<ScheduledAction>(toExecute);
01830   for (; it.current(); ++it) {
01831     ScheduledAction *action = it.current();
01832     if (!scheduledActions.containsRef(action)) // removed by clearTimeout()
01833       continue;
01834 
01835     action->executing = true; // prevent deletion in clearTimeout()
01836 
01837     if (action->singleShot)
01838       scheduledActions.removeRef(action);
01839     if (!parent->part().isNull())
01840       action->execute(parent);
01841 
01842     action->executing = false;
01843 
01844     if (!scheduledActions.containsRef(action))
01845       delete action;
01846     else
01847       action->nextTime = action->nextTime.addMSecs(action->interval);
01848   }
01849 
01850   pausedTime += currentActual.msecsTo(QTime::currentTime());
01851 
01852   // Work out when next event is to occur
01853   setNextTimer();
01854 }
01855 
01856 void WindowQObject::setNextTimer()
01857 {
01858   if (scheduledActions.isEmpty())
01859     return;
01860 
01861   QPtrListIterator<ScheduledAction> it(scheduledActions);
01862   QTime nextTime = it.current()->nextTime;
01863   for (++it; it.current(); ++it)
01864     if (nextTime > it.current()->nextTime)
01865       nextTime = it.current()->nextTime;
01866 
01867   QTime nextTimeActual = nextTime.addMSecs(pausedTime);
01868   int nextInterval = QTime::currentTime().msecsTo(nextTimeActual);
01869   if (nextInterval < 0)
01870     nextInterval = 0;
01871   startTimer(nextInterval);
01872 }
01873 
01874 void WindowQObject::timeoutClose()
01875 {
01876   parent->closeNow();
01877 }
01878 
01879 Value FrameArray::get(ExecState *exec, const Identifier &p) const
01880 {
01881 #ifdef KJS_VERBOSE
01882   kdDebug(6070) << "FrameArray::get " << p.qstring() << " part=" << (void*)part << endl;
01883 #endif
01884   if (part.isNull())
01885     return Undefined();
01886 
01887   QPtrList<KParts::ReadOnlyPart> frames = part->frames();
01888   unsigned int len = frames.count();
01889   if (p == lengthPropertyName)
01890     return Number(len);
01891   else if (p== "location") // non-standard property, but works in NS and IE
01892   {
01893     Object obj = Object::dynamicCast( Window::retrieve( part ) );
01894     if ( !obj.isNull() )
01895       return obj.get( exec, "location" );
01896     return Undefined();
01897   }
01898 
01899   // check for the name or number
01900   KParts::ReadOnlyPart *frame = part->findFrame(p.qstring());
01901   if (!frame) {
01902     bool ok;
01903     unsigned int i = p.toArrayIndex(&ok);
01904     if (ok && i < len)
01905       frame = frames.at(i);
01906   }
01907 
01908   // we are potentially fetching a reference to a another Window object here.
01909   // i.e. we may be accessing objects from another interpreter instance.
01910   // Therefore we have to be a bit careful with memory management.
01911   if (frame && ::qt_cast<KHTMLPart*>(frame)) {
01912     KHTMLPart *khtml = static_cast<KHTMLPart*>(frame);
01913     return Window::retrieve(khtml);
01914   }
01915 
01916   return ObjectImp::get(exec, p);
01917 }
01918 
01920 
01921 const ClassInfo Location::info = { "Location", 0, &LocationTable, 0 };
01922 /*
01923 @begin LocationTable 11
01924   hash      Location::Hash      DontDelete
01925   host      Location::Host      DontDelete
01926   hostname  Location::Hostname  DontDelete
01927   href      Location::Href      DontDelete
01928   pathname  Location::Pathname  DontDelete
01929   port      Location::Port      DontDelete
01930   protocol  Location::Protocol  DontDelete
01931   search    Location::Search    DontDelete
01932   [[==]]    Location::EqualEqual    DontDelete|ReadOnly
01933   assign    Location::Assign    DontDelete|Function 1
01934   toString  Location::ToString  DontDelete|Function 0
01935   replace   Location::Replace   DontDelete|Function 1
01936   reload    Location::Reload    DontDelete|Function 0
01937 @end
01938 */
01939 IMPLEMENT_PROTOFUNC_DOM(LocationFunc)
01940 Location::Location(KHTMLPart *p) : m_part(p)
01941 {
01942   //kdDebug(6070) << "Location::Location " << this << " m_part=" << (void*)m_part << endl;
01943 }
01944 
01945 Location::~Location()
01946 {
01947   //kdDebug(6070) << "Location::~Location " << this << " m_part=" << (void*)m_part << endl;
01948 }
01949 
01950 Value Location::get(ExecState *exec, const Identifier &p) const
01951 {
01952 #ifdef KJS_VERBOSE
01953   kdDebug(6070) << "Location::get " << p.qstring() << " m_part=" << (void*)m_part << endl;
01954 #endif
01955 
01956   if (m_part.isNull())
01957     return Undefined();
01958 
01959   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
01960 
01961   // properties that work on all Location objects
01962   if ( entry && entry->value == Replace )
01963       return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr);
01964 
01965   // XSS check
01966   const Window* window = Window::retrieveWindow( m_part );
01967   if ( !window || !window->isSafeScript(exec) )
01968     return Undefined();
01969 
01970   KURL url = m_part->url();
01971   if (entry)
01972     switch (entry->value) {
01973     case Hash:
01974       return String( url.ref().isNull() ? QString("") : "#" + url.ref() );
01975     case Host: {
01976       UString str = url.host();
01977       if (url.port())
01978         str += ":" + QString::number((int)url.port());
01979       return String(str);
01980       // Note: this is the IE spec. The NS spec swaps the two, it says
01981       // "The hostname property is the concatenation of the host and port properties, separated by a colon."
01982       // Bleh.
01983     }
01984     case Hostname:
01985       return String( url.host() );
01986     case Href:
01987       if (!url.hasPath())
01988         return String( url.prettyURL()+"/" );
01989       else
01990         return String( url.prettyURL() );
01991     case Pathname:
01992       return String( url.path().isEmpty() ? QString("/") : url.path() );
01993     case Port:
01994       return String( url.port() ? QString::number((int)url.port()) : QString::fromLatin1("") );
01995     case Protocol:
01996       return String( url.protocol()+":" );
01997     case Search:
01998       return String( url.query() );
01999     case EqualEqual: // [[==]]
02000       return String(toString(exec));
02001     case ToString:
02002       return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr);
02003     }
02004   // Look for overrides
02005   ValueImp * val = ObjectImp::getDirect(p);
02006   if (val)
02007     return Value(val);
02008   if (entry && (entry->attr & Function))
02009     return lookupOrCreateFunction<LocationFunc>(exec,p,this,entry->value,entry->params,entry->attr);
02010 
02011   return Undefined();
02012 }
02013 
02014 void Location::put(ExecState *exec, const Identifier &p, const Value &v, int attr)
02015 {
02016 #ifdef KJS_VERBOSE
02017   kdDebug(6070) << "Location::put " << p.qstring() << " m_part=" << (void*)m_part << endl;
02018 #endif
02019   if (m_part.isNull())
02020     return;
02021 
02022   // XSS check
02023   const Window* window = Window::retrieveWindow( m_part );
02024   if ( !window || !window->isSafeScript(exec) )
02025     return;
02026 
02027   QString str = v.toString(exec).qstring();
02028   KURL url = m_part->url();
02029   const HashEntry *entry = Lookup::findEntry(&LocationTable, p);
02030   if (entry)
02031     switch (entry->value) {
02032     case Href: {
02033       KHTMLPart* p = Window::retrieveActive(exec)->part();
02034       if ( p )
02035         url = p->htmlDocument().completeURL( str ).string();
02036       else
02037         url = str;
02038       break;
02039     }
02040     case Hash:
02041       // when the hash is already the same ignore it
02042       if (str == url.ref()) return;
02043       url.setRef(str);
02044       break;
02045     case Host: {
02046       QString host = str.left(str.find(":"));
02047       QString port = str.mid(str.find(":")+1);
02048       url.setHost(host);
02049       url.setPort(port.toUInt());
02050       break;
02051     }
02052     case Hostname:
02053       url.setHost(str);
02054       break;
02055     case Pathname:
02056       url.setPath(str);
02057       break;
02058     case Port:
02059       url.setPort(str.toUInt());
02060       break;
02061     case Protocol:
02062       url.setProtocol(str);
02063       break;
02064     case Search:
02065       url.setQuery(str);
02066       break;
02067     }
02068   else {
02069     ObjectImp::put(exec, p, v, attr);
02070     return;
02071   }
02072 
02073   Window::retrieveWindow(m_part)->goURL(exec, url.url(), false /* don't lock history*/ );
02074 }
02075 
02076 Value Location::toPrimitive(ExecState *exec, Type) const
02077 {
02078   Window* window = Window::retrieveWindow( m_part );
02079   if ( window && window->isSafeScript(exec) )
02080     return String(toString(exec));
02081   return Undefined();
02082 }
02083 
02084 UString Location::toString(ExecState *exec) const
02085 {
02086   Window* window = Window::retrieveWindow( m_part );
02087   if ( window && window->isSafeScript(exec) )
02088   {
02089     if (!m_part->url().hasPath())
02090       return m_part->url().prettyURL()+"/";
02091     else
02092       return m_part->url().prettyURL();
02093   }
02094   return "";
02095 }
02096 
02097 Value LocationFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
02098 {
02099   KJS_CHECK_THIS( Location, thisObj );
02100   Location *location = static_cast<Location *>(thisObj.imp());
02101   KHTMLPart *part = location->part();
02102 
02103   if (!part) return Undefined();
02104 
02105   Window* window = Window::retrieveWindow(part);
02106 
02107   if ( !window->isSafeScript(exec) && id != Location::Replace)
02108       return Undefined();
02109 
02110   switch (id) {
02111   case Location::Assign:
02112   case Location::Replace:
02113     Window::retrieveWindow(part)->goURL(exec, args[0].toString(exec).qstring(),
02114             id == Location::Replace);
02115     break;
02116   case Location::Reload:
02117     part->scheduleRedirection(-1, part->url().url(), true/*lock history*/);
02118     break;
02119   case Location::ToString:
02120     return String(location->toString(exec));
02121   }
02122   return Undefined();
02123 }
02124 
02126 
02127 const ClassInfo External::info = { "External", 0, 0, 0 };
02128 /*
02129 @begin ExternalTable 4
02130   addFavorite   External::AddFavorite   DontDelete|Function 1
02131 @end
02132 */
02133 IMPLEMENT_PROTOFUNC_DOM(ExternalFunc)
02134 
02135 Value External::get(ExecState *exec, const Identifier &p) const
02136 {
02137   return lookupGetFunction<ExternalFunc,ObjectImp>(exec,p,&ExternalTable,this);
02138 }
02139 
02140 Value ExternalFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
02141 {
02142   KJS_CHECK_THIS( External, thisObj );
02143   External *external = static_cast<External *>(thisObj.imp());
02144 
02145   KHTMLPart *part = external->part;
02146   if (!part)
02147     return Undefined();
02148 
02149   KHTMLView *widget = part->view();
02150 
02151   switch (id) {
02152   case External::AddFavorite:
02153   {
02154     if (!widget->dialogsAllowed())
02155       return Undefined();
02156     part->xmlDocImpl()->updateRendering();
02157     if (args.size() != 1 && args.size() != 2)
02158       return Undefined();
02159 
02160     QString url = args[0].toString(exec).qstring();
02161     QString title;
02162     if (args.size() == 2)
02163       title = args[1].toString(exec).qstring();
02164 
02165     // AK - don't do anything yet, for the moment i
02166     // just wanted the base js handling code in cvs
02167     return Undefined();
02168 
02169     QString question;
02170     if ( title.isEmpty() )
02171       question = i18n("Do you want a bookmark pointing to the location \"%1\" to be added to your collection?")
02172                  .arg(url);
02173     else
02174       question = i18n("Do you want a bookmark pointing to the location \"%1\" titled \"%2\" to be added to your collection?")
02175                  .arg(url).arg(title);
02176 
02177     emit part->browserExtension()->requestFocus(part);
02178 
02179     QString caption;
02180     if (!part->url().host().isEmpty())
02181        caption = part->url().host() + " - ";
02182     caption += i18n("JavaScript Attempted Bookmark Insert");
02183 
02184     if (KMessageBox::warningYesNo(
02185           widget, question, caption,
02186           i18n("Insert"), i18n("Disallow")) == KMessageBox::Yes)
02187     {
02188       KBookmarkManager *mgr = KBookmarkManager::userBookmarksManager();
02189       mgr->addBookmarkDialog(url,title);
02190     }
02191     break;
02192   }
02193   default:
02194     return Undefined();
02195   }
02196 
02197   return Undefined();
02198 }
02199 
02201 
02202 const ClassInfo History::info = { "History", 0, 0, 0 };
02203 /*
02204 @begin HistoryTable 4
02205   length    History::Length     DontDelete|ReadOnly
02206   back      History::Back       DontDelete|Function 0
02207   forward   History::Forward    DontDelete|Function 0
02208   go        History::Go     DontDelete|Function 1
02209 @end
02210 */
02211 IMPLEMENT_PROTOFUNC_DOM(HistoryFunc)
02212 
02213 Value History::get(ExecState *exec, const Identifier &p) const
02214 {
02215   return lookupGet<HistoryFunc,History,ObjectImp>(exec,p,&HistoryTable,this);
02216 }
02217 
02218 Value History::getValueProperty(ExecState *, int token) const
02219 {
02220   // if previous or next is implemented, make sure its not a major
02221   // privacy leak (see i.e. http://security.greymagic.com/adv/gm005-op/)
02222   switch (token) {
02223   case Length:
02224   {
02225     KParts::BrowserExtension *ext = part->browserExtension();
02226     if ( !ext )
02227       return Number( 0 );
02228 
02229     KParts::BrowserInterface *iface = ext->browserInterface();
02230     if ( !iface )
02231       return Number( 0 );
02232 
02233     QVariant length = iface->property( "historyLength" );
02234 
02235     if ( length.type() != QVariant::UInt )
02236       return Number( 0 );
02237 
02238     return Number( length.toUInt() );
02239   }
02240   default:
02241     kdDebug(6070) << "WARNING: Unhandled token in History::getValueProperty : " << token << endl;
02242     return Undefined();
02243   }
02244 }
02245 
02246 Value HistoryFunc::tryCall(ExecState *exec, Object &thisObj, const List &args)
02247 {
02248   KJS_CHECK_THIS( History, thisObj );
02249   History *history = static_cast<History *>(thisObj.imp());
02250 
02251   Value v = args[0];
02252   Number n;
02253   if(!v.isNull())
02254     n = v.toInteger(exec);
02255 
02256   int steps;
02257   switch (id) {
02258   case History::Back:
02259     steps = -1;
02260     break;
02261   case History::Forward:
02262     steps = 1;
02263     break;
02264   case History::Go:
02265     steps = n.intValue();
02266     break;
02267   default:
02268     return Undefined();
02269   }
02270 
02271   // Special case for go(0) from a frame -> reload only the frame
02272   // go(i!=0) from a frame navigates into the history of the frame only,
02273   // in both IE and NS (but not in Mozilla).... we can't easily do that
02274   // in Konqueror...
02275   if (!steps) // add && history->part->parentPart() to get only frames, but doesn't matter
02276   {
02277     history->part->openURL( history->part->url() ); 
02278   } else
02279   {
02280     // Delay it.
02281     // Testcase: history.back(); alert("hello");
02282     Window* window = Window::retrieveWindow( history->part );
02283     window->delayedGoHistory( steps );
02284   }
02285   return Undefined();
02286 }
02287 
02289 
02290 #ifdef Q_WS_QWS
02291 
02292 const ClassInfo Konqueror::info = { "Konqueror", 0, 0, 0 };
02293 
02294 bool Konqueror::hasProperty(ExecState *exec, const Identifier &p) const
02295 {
02296   if ( p.qstring().startsWith( "goHistory" ) ) return false;
02297 
02298   return true;
02299 }
02300 
02301 Value Konqueror::get(ExecState *exec, const Identifier &p) const
02302 {
02303   if ( p == "goHistory" || part->url().protocol() != "http" || part->url().host() != "localhost" )
02304     return Undefined();
02305 
02306   KParts::BrowserExtension *ext = part->browserExtension();
02307   if ( ext ) {
02308     KParts::BrowserInterface *iface = ext->browserInterface();
02309     if ( iface ) {
02310       QVariant prop = iface->property( p.qstring().latin1() );
02311 
02312       if ( prop.isValid() ) {
02313         switch( prop.type() ) {
02314         case QVariant::Int:
02315           return Number( prop.toInt() );
02316         case QVariant::String:
02317           return String( prop.toString() );
02318         default:
02319           break;
02320         }
02321       }
02322     }
02323   }
02324 
02325   return Value( new KonquerorFunc(this, p.qstring().latin1() ) );
02326 }
02327 
02328 Value KonquerorFunc::tryCall(ExecState *exec, Object &, const List &args)
02329 {
02330   KParts::BrowserExtension *ext = konqueror->part->browserExtension();
02331 
02332   if(!ext)
02333     return Undefined();
02334 
02335   KParts::BrowserInterface *iface = ext->browserInterface();
02336 
02337   if ( !iface )
02338     return Undefined();
02339 
02340   QCString n = m_name.data();
02341   n += "()";
02342   iface->callMethod( n.data(), QVariant() );
02343 
02344   return Undefined();
02345 }
02346 
02347 UString Konqueror::toString(ExecState *) const
02348 {
02349   return UString("[object Konqueror]");
02350 }
02351 
02352 #endif
02353 
02354 
02355 #include "kjs_window.moc"
KDE Logo
This file is part of the documentation for khtml Library Version 3.3.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jan 22 16:52:08 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003