khtml Library API Documentation

kjs_window.cpp

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