This implements some events related to document/window load and unload / visibility changes. The latter is related in that native partially implements it, and only sends it when it is minimized or restored from being minimized, not on navigation or anything else.
The main issue for me is the visibilitychange patch. Since we don't control the container hwnd, and it can even be in another process, there is no way to be notified cleanly when it changes its minimization state. We can't subclass it either, as the tests show, it's not subclassed.
I implemented it now using an internal timer that polls for that, since it was the least invasive and works in all cases, including other process hwnd. Hooks wouldn't be able to do that, and are also more invasive IMO. I'm hoping for better ideas, though.
-- v2: mshtml: Implement pagehide event. mshtml: Implement unload event. mshtml: Implement pageshow event. mshtml: Add visibilitychange event stub.
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 2 + dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/tests/blank_ie10.html | 3 + dlls/mshtml/tests/documentmode.js | 5 ++ dlls/mshtml/tests/events.c | 142 +++++++++++++++++++++++++----- dlls/mshtml/tests/rsrc.rc | 3 + 6 files changed, 133 insertions(+), 23 deletions(-) create mode 100644 dlls/mshtml/tests/blank_ie10.html
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index f2c862c5b0a..1963d73a327 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -206,6 +206,8 @@ static const event_info_t event_info[] = { EVENT_BIND_TO_TARGET}, {L"unload", EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONUNLOAD, EVENT_FIXME}, + {L"visibilitychange", EVENT_TYPE_EVENT, DISPID_EVPROP_VISIBILITYCHANGE, + EVENT_FIXME | EVENT_BUBBLES},
/* EVENTID_LAST special entry */ {NULL, EVENT_TYPE_EVENT, 0, 0} diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index f78c4a0f188..97baf9eed7b 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -63,6 +63,7 @@ typedef enum { EVENTID_SUBMIT, EVENTID_TIMEOUT, EVENTID_UNLOAD, + EVENTID_VISIBILITYCHANGE, EVENTID_LAST } eventid_t;
diff --git a/dlls/mshtml/tests/blank_ie10.html b/dlls/mshtml/tests/blank_ie10.html new file mode 100644 index 00000000000..64e6dfaa172 --- /dev/null +++ b/dlls/mshtml/tests/blank_ie10.html @@ -0,0 +1,3 @@ +<html> +<head><meta http-equiv="x-ua-compatible" content="IE=10" /></head> +</html> diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 5da89349d6d..7d26add1cfc 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -19,6 +19,11 @@ var compat_version; var tests = [];
+if(window.addEventListener) { + document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); +} + + sync_test("builtin_toString", function() { var tags = [ [ "abbr", "Phrase" ], diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index dcd7160a67d..7945a2b72ae 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -97,6 +97,7 @@ DEFINE_EXPECT(submit_onclick_attached_check_cancel); DEFINE_EXPECT(submit_onclick_setret); DEFINE_EXPECT(elem2_cp_onclick); DEFINE_EXPECT(iframe_onload); +DEFINE_EXPECT(visibilitychange); DEFINE_EXPECT(doc1_onstorage); DEFINE_EXPECT(doc1_onstoragecommit); DEFINE_EXPECT(window1_onstorage); @@ -105,6 +106,7 @@ DEFINE_EXPECT(doc2_onstoragecommit); DEFINE_EXPECT(window2_onstorage);
static HWND container_hwnd = NULL; +static BOOL container_minimize; static IHTMLWindow2 *window; static IOleDocumentView *view; static BOOL is_ie9plus; @@ -1406,6 +1408,30 @@ static HRESULT WINAPI iframe_onreadystatechange(IDispatchEx *iface, DISPID id, L
EVENT_HANDLER_FUNC_OBJ(iframe_onreadystatechange);
+static HRESULT WINAPI onvisibilitychange(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + IDispatchEx *dispex; + HRESULT hres; + BSTR bstr; + + CHECK_EXPECT(visibilitychange); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + + hres = IDispatch_QueryInterface(V_DISPATCH(&pdp->rgvarg[1]), &IID_IDispatchEx, (void**)&dispex); + ok(hres == S_OK, "Could not get IDispatchEx: %08lx\n", hres); + + bstr = SysAllocString(L"toString"); + hres = IDispatchEx_GetDispID(dispex, bstr, 0, &id); + todo_wine + ok(hres == S_OK, "GetDispID("toString") failed: %08lx\n", hres); + SysFreeString(bstr); + + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(onvisibilitychange); + static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -2387,6 +2413,54 @@ static void test_focus(IHTMLDocument2 *doc) IHTMLElement4_Release(div); }
+static void test_visibilitychange(IHTMLDocument2 *doc) +{ + if(!winetest_interactive) { + ShowWindow(container_hwnd, SW_SHOW); + pump_msgs(NULL); + } + add_event_listener((IUnknown*)doc, L"visibilitychange", (IDispatch*)&onvisibilitychange_obj, VARIANT_TRUE); + + ShowWindow(container_hwnd, SW_HIDE); + pump_msgs(NULL); + + ShowWindow(container_hwnd, SW_SHOW); + pump_msgs(NULL); + + container_minimize = TRUE; + if(document_mode < 10) { + ShowWindow(container_hwnd, SW_MINIMIZE); + pump_msgs(NULL); + + container_minimize = FALSE; + ShowWindow(container_hwnd, SW_RESTORE); + pump_msgs(NULL); + }else { + /* FIXME: currently not implemented in Wine, so we can't wait for it */ + BOOL *expect = broken(1) ? &called_visibilitychange : NULL; + + SET_EXPECT(visibilitychange); + ShowWindow(container_hwnd, SW_MINIMIZE); + pump_msgs(expect); + todo_wine + CHECK_CALLED(visibilitychange); + + container_minimize = FALSE; + SET_EXPECT(visibilitychange); + ShowWindow(container_hwnd, SW_RESTORE); + pump_msgs(expect); + todo_wine + CHECK_CALLED(visibilitychange); + } + + navigate(doc, document_mode < 10 ? L"blank_ie10.html" : L"blank.html"); + + if(!winetest_interactive) { + ShowWindow(container_hwnd, SW_HIDE); + pump_msgs(NULL); + } +} + static void test_submit(IHTMLDocument2 *doc) { IHTMLElement *elem, *submit; @@ -5091,6 +5165,48 @@ static IHTMLDocument2 *create_document_with_origin(const char *str) return doc; }
+static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) { + case WM_SIZE: + if(winetest_interactive) + break; + + /* Sometimes minimizing/restoring isn't reliable due to differences in WMs, + so force it here when pumping messages if it's not what we expected... */ + switch(wParam) { + case SIZE_MINIMIZED: + if(!container_minimize) + ShowWindow(hwnd, SW_RESTORE); + break; + case SIZE_RESTORED: + case SIZE_MAXIMIZED: + if(container_minimize) + ShowWindow(hwnd, SW_MINIMIZE); + break; + } + break; + } + return DefWindowProcA(hwnd, msg, wParam, lParam); +} + +static HWND create_container_window(void) +{ + static const CHAR szHTMLDocumentTest[] = "HTMLDocumentTest"; + static WNDCLASSEXA wndclass = { + sizeof(WNDCLASSEXA), + 0, + wnd_proc, + 0, 0, NULL, NULL, NULL, NULL, NULL, + szHTMLDocumentTest, + NULL + }; + + RegisterClassExA(&wndclass); + return CreateWindowA(szHTMLDocumentTest, szHTMLDocumentTest, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, + 300, 300, NULL, NULL, NULL, NULL); +}
typedef void (*testfunc_t)(IHTMLDocument2*);
@@ -5154,6 +5270,7 @@ static void run_test_impl(const char *str, const WCHAR *res, testfunc_t test) ok(hres == S_OK, "get_parentWindow failed: %08lx\n", hres); ok(window != NULL, "window == NULL\n");
+ ok((WNDPROC)GetWindowLongPtrA(container_hwnd, GWLP_WNDPROC) == wnd_proc, "container_hwnd is subclassed\n"); test(doc);
IHTMLWindow2_Release(window); @@ -5176,29 +5293,6 @@ static void run_test_from_res(const WCHAR *res, testfunc_t test) return run_test_impl(NULL, res, test); }
-static LRESULT WINAPI wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - return DefWindowProcA(hwnd, msg, wParam, lParam); -} - -static HWND create_container_window(void) -{ - static const CHAR szHTMLDocumentTest[] = "HTMLDocumentTest"; - static WNDCLASSEXA wndclass = { - sizeof(WNDCLASSEXA), - 0, - wnd_proc, - 0, 0, NULL, NULL, NULL, NULL, NULL, - szHTMLDocumentTest, - NULL - }; - - RegisterClassExA(&wndclass); - return CreateWindowA(szHTMLDocumentTest, szHTMLDocumentTest, - WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, - 300, 300, NULL, NULL, NULL, NULL); -} - static void test_empty_document(void) { HRESULT hres; @@ -5496,6 +5590,8 @@ START_TEST(events) if(is_ie9plus) { run_test_from_res(L"doc_with_prop.html", test_doc_obj); run_test_from_res(L"doc_with_prop_ie9.html", test_doc_obj); + run_test_from_res(L"doc_with_prop_ie9.html", test_visibilitychange); + run_test_from_res(L"blank_ie10.html", test_visibilitychange); run_test(empty_doc_ie9_str, test_create_event); }
diff --git a/dlls/mshtml/tests/rsrc.rc b/dlls/mshtml/tests/rsrc.rc index 9bff32a78e9..01b2838be8b 100644 --- a/dlls/mshtml/tests/rsrc.rc +++ b/dlls/mshtml/tests/rsrc.rc @@ -73,6 +73,9 @@ blank2.html HTML "blank.html" /* @makedep: blank.html */ 123 HTML "blank.html"
+/* @makedep: blank_ie10.html */ +blank_ie10.html HTML "blank_ie10.html" + /* @makedep: doc_with_prop.html */ doc_with_prop.html HTML "doc_with_prop.html"
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmlevent.c | 120 +++++++++++++++++++++++++++ dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/mshtml_private.h | 1 + dlls/mshtml/mshtml_private_iface.idl | 14 ++++ dlls/mshtml/nsevents.c | 8 ++ dlls/mshtml/tests/documentmode.js | 17 ++++ 6 files changed, 161 insertions(+)
diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 1963d73a327..b64cba6bf81 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -68,6 +68,7 @@ typedef enum { EVENT_TYPE_MOUSE, EVENT_TYPE_FOCUS, EVENT_TYPE_UIEVENT, + EVENT_TYPE_PAGETRANSITION, EVENT_TYPE_MESSAGE, EVENT_TYPE_PROGRESS, EVENT_TYPE_STORAGE, @@ -82,6 +83,7 @@ static const WCHAR *event_types[] = { L"MouseEvent", L"Event", /* FIXME */ L"UIEvent", + L"Event", /* FIXME */ L"MessageEvent", L"ProgressEvent", L"StorageEvent", @@ -182,6 +184,8 @@ static const event_info_t event_info[] = { EVENT_FIXME}, {L"msthumbnailclick", EVENT_TYPE_MOUSE, DISPID_EVPROP_ONMSTHUMBNAILCLICK, EVENT_FIXME}, + {L"pageshow", EVENT_TYPE_PAGETRANSITION, DISPID_EVPROP_ONPAGESHOW, + 0}, {L"paste", EVENT_TYPE_CLIPBOARD, DISPID_EVMETH_ONPASTE, EVENT_FIXME | EVENT_BUBBLES | EVENT_CANCELABLE}, {L"progress", EVENT_TYPE_PROGRESS, DISPID_EVPROP_PROGRESS, @@ -2209,6 +2213,98 @@ static void DOMKeyboardEvent_destroy(DOMEvent *event) nsIDOMKeyEvent_Release(This->nsevent); }
+typedef struct { + DOMEvent event; + IWinePageTransitionEvent IWinePageTransitionEvent_iface; +} DOMPageTransitionEvent; + +static inline DOMPageTransitionEvent *impl_from_IWinePageTransitionEvent(IWinePageTransitionEvent *iface) +{ + return CONTAINING_RECORD(iface, DOMPageTransitionEvent, IWinePageTransitionEvent_iface); +} + +static HRESULT WINAPI DOMPageTransitionEvent_QueryInterface(IWinePageTransitionEvent *iface, REFIID riid, void **ppv) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDOMEvent_QueryInterface(&This->event.IDOMEvent_iface, riid, ppv); +} + +static ULONG WINAPI DOMPageTransitionEvent_AddRef(IWinePageTransitionEvent *iface) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDOMEvent_AddRef(&This->event.IDOMEvent_iface); +} + +static ULONG WINAPI DOMPageTransitionEvent_Release(IWinePageTransitionEvent *iface) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDOMEvent_Release(&This->event.IDOMEvent_iface); +} + +static HRESULT WINAPI DOMPageTransitionEvent_GetTypeInfoCount(IWinePageTransitionEvent *iface, UINT *pctinfo) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDispatchEx_GetTypeInfoCount(&This->event.dispex.IDispatchEx_iface, pctinfo); +} + +static HRESULT WINAPI DOMPageTransitionEvent_GetTypeInfo(IWinePageTransitionEvent *iface, UINT iTInfo, + LCID lcid, ITypeInfo **ppTInfo) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDispatchEx_GetTypeInfo(&This->event.dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo); +} + +static HRESULT WINAPI DOMPageTransitionEvent_GetIDsOfNames(IWinePageTransitionEvent *iface, REFIID riid, + LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDispatchEx_GetIDsOfNames(&This->event.dispex.IDispatchEx_iface, riid, rgszNames, cNames, + lcid, rgDispId); +} + +static HRESULT WINAPI DOMPageTransitionEvent_Invoke(IWinePageTransitionEvent *iface, DISPID dispIdMember, + REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + return IDispatchEx_Invoke(&This->event.dispex.IDispatchEx_iface, dispIdMember, riid, lcid, + wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); +} + +static HRESULT WINAPI DOMPageTransitionEvent_get_persisted(IWinePageTransitionEvent *iface, VARIANT_BOOL *p) +{ + DOMPageTransitionEvent *This = impl_from_IWinePageTransitionEvent(iface); + + FIXME("(%p)->(%p): always returning FALSE\n", This, p); + + *p = VARIANT_FALSE; + return S_OK; +} + +static const IWinePageTransitionEventVtbl DOMPageTransitionEventVtbl = { + DOMPageTransitionEvent_QueryInterface, + DOMPageTransitionEvent_AddRef, + DOMPageTransitionEvent_Release, + DOMPageTransitionEvent_GetTypeInfoCount, + DOMPageTransitionEvent_GetTypeInfo, + DOMPageTransitionEvent_GetIDsOfNames, + DOMPageTransitionEvent_Invoke, + DOMPageTransitionEvent_get_persisted +}; + +static DOMPageTransitionEvent *DOMPageTransitionEvent_from_DOMEvent(DOMEvent *event) +{ + return CONTAINING_RECORD(event, DOMPageTransitionEvent, event); +} + +static void *DOMPageTransitionEvent_query_interface(DOMEvent *event, REFIID riid) +{ + DOMPageTransitionEvent *page_transition_event = DOMPageTransitionEvent_from_DOMEvent(event); + if(IsEqualGUID(&IID_IWinePageTransitionEvent, riid)) + return &page_transition_event->IWinePageTransitionEvent_iface; + return NULL; +} + typedef struct { DOMEvent event; IDOMCustomEvent IDOMCustomEvent_iface; @@ -2837,6 +2933,20 @@ static dispex_static_data_t DOMKeyboardEvent_dispex = { DOMKeyboardEvent_iface_tids };
+static void DOMPageTransitionEvent_init_dispex_info(dispex_data_t *info, compat_mode_t mode) +{ + if(mode >= COMPAT_MODE_IE11) + dispex_info_add_interface(info, IWinePageTransitionEvent_tid, NULL); +} + +dispex_static_data_t DOMPageTransitionEvent_dispex = { + L"PageTransitionEvent", + NULL, + DispDOMEvent_tid, + DOMEvent_iface_tids, + DOMPageTransitionEvent_init_dispex_info +}; + static const tid_t DOMCustomEvent_iface_tids[] = { IDOMEvent_tid, IDOMCustomEvent_tid, @@ -2961,6 +3071,15 @@ static DOMEvent *keyboard_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_ return &keyboard_event->ui_event.event; }
+static DOMEvent *page_transition_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) +{ + DOMPageTransitionEvent *page_transition_event = event_ctor(sizeof(DOMCustomEvent), &DOMPageTransitionEvent_dispex, + DOMPageTransitionEvent_query_interface, NULL, nsevent, event_id, compat_mode); + if(!page_transition_event) return NULL; + page_transition_event->IWinePageTransitionEvent_iface.lpVtbl = &DOMPageTransitionEventVtbl; + return &page_transition_event->event; +} + static DOMEvent *custom_event_ctor(void *iface, nsIDOMEvent *nsevent, eventid_t event_id, compat_mode_t compat_mode) { DOMCustomEvent *custom_event = event_ctor(sizeof(DOMCustomEvent), &DOMCustomEvent_dispex, @@ -3015,6 +3134,7 @@ static const struct { [EVENT_TYPE_CLIPBOARD] = { NULL, generic_event_ctor }, [EVENT_TYPE_FOCUS] = { NULL, generic_event_ctor }, [EVENT_TYPE_DRAG] = { NULL, generic_event_ctor }, + [EVENT_TYPE_PAGETRANSITION] = { NULL, page_transition_event_ctor }, [EVENT_TYPE_CUSTOM] = { &IID_nsIDOMCustomEvent, custom_event_ctor }, [EVENT_TYPE_PROGRESS] = { &IID_nsIDOMProgressEvent, progress_event_ctor }, [EVENT_TYPE_MESSAGE] = { NULL, message_event_ctor }, diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index 97baf9eed7b..e49c47d6988 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -51,6 +51,7 @@ typedef enum { EVENTID_MOUSEUP, EVENTID_MOUSEWHEEL, EVENTID_MSTHUMBNAILCLICK, + EVENTID_PAGESHOW, EVENTID_PASTE, EVENTID_PROGRESS, EVENTID_READYSTATECHANGE, diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index e3971258b13..7e7dd358c8d 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -288,6 +288,7 @@ typedef struct EventTarget EventTarget; XIID(IWineHTMLElementPrivate) \ XIID(IWineHTMLWindowPrivate) \ XIID(IWineHTMLWindowCompatPrivate) \ + XIID(IWinePageTransitionEvent) \ XIID(IWineXMLHttpRequestPrivate) \ XIID(IWineMSHTMLConsole) \ XIID(IWineMSHTMLMediaQueryList) diff --git a/dlls/mshtml/mshtml_private_iface.idl b/dlls/mshtml/mshtml_private_iface.idl index fc023473cc9..8e4a64bda39 100644 --- a/dlls/mshtml/mshtml_private_iface.idl +++ b/dlls/mshtml/mshtml_private_iface.idl @@ -162,6 +162,20 @@ interface IWineDOMTokenList : IDispatch HRESULT toString([retval, out] BSTR *String); }
+[ + odl, + oleautomation, + dual, + hidden, + uuid(25508c5d-6a54-6888-8f41-75ff3ae8706b) +] +interface IWinePageTransitionEvent : IDispatch +{ + [propget, id(1)] + HRESULT persisted([retval, out] VARIANT_BOOL *ret); +} + + const long DISPID_IWINEXMLHTTPREQUESTPRIVATE_RESPONSE = 1; const long DISPID_IWINEXMLHTTPREQUESTPRIVATE_RESPONSETYPE = 2; const long DISPID_IWINEXMLHTTPREQUESTPRIVATE_UPLOAD = 3; diff --git a/dlls/mshtml/nsevents.c b/dlls/mshtml/nsevents.c index a8e3d503921..863970a01de 100644 --- a/dlls/mshtml/nsevents.c +++ b/dlls/mshtml/nsevents.c @@ -274,6 +274,14 @@ static nsresult NSAPI handle_load(nsIDOMEventListener *iface, nsIDOMEvent *event dispatch_event(&doc->window->event_target, load_event); IDOMEvent_Release(&load_event->IDOMEvent_iface); } + + if(doc->dom_document && doc->document_mode >= COMPAT_MODE_IE11) { + hres = create_document_event(doc, EVENTID_PAGESHOW, &load_event); + if(SUCCEEDED(hres)) { + dispatch_event(&doc->window->event_target, load_event); + IDOMEvent_Release(&load_event->IDOMEvent_iface); + } + } }else { WARN("no window\n"); } diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 7d26add1cfc..0ae5df94b3a 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -19,10 +19,27 @@ var compat_version; var tests = [];
+var pageshow_fired = false; if(window.addEventListener) { + window.addEventListener("pageshow", function(e) { + pageshow_fired = true; + + var r = Object.prototype.toString.call(e); + todo_wine. + ok(r === "[object PageTransitionEvent]", "pageshow toString = " + r); + ok("persisted" in e, "'persisted' not in pageshow event"); + ok(document.readyState === "complete", "pageshow readyState = " + document.readyState); + }, true); + document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); }
+sync_test("page transition events", function() { + if(document.documentMode < 11) + ok(pageshow_fired === false, "pageshow fired"); + else + ok(pageshow_fired === true, "pageshow not fired"); +});
sync_test("builtin_toString", function() { var tags = [
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 30 +++++++++++ dlls/mshtml/htmlevent.c | 2 +- dlls/mshtml/mshtml_private.h | 4 +- dlls/mshtml/navigate.c | 8 ++- dlls/mshtml/oleobj.c | 3 ++ dlls/mshtml/tests/documentmode.js | 14 +++++ dlls/mshtml/tests/events.c | 85 +++++++++++++++++++++++++++++++ dlls/mshtml/tests/iframe.html | 4 ++ dlls/mshtml/tests/rsrc.rc | 3 ++ dlls/mshtml/tests/script.c | 22 ++++++++ 10 files changed, 171 insertions(+), 4 deletions(-) create mode 100644 dlls/mshtml/tests/iframe.html
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index 81960f53400..dccb0c4f028 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -148,6 +148,36 @@ UINT get_document_charset(HTMLDocumentNode *doc) return doc->charset = ret; }
+static void send_unload_events_impl(HTMLInnerWindow *window) +{ + HTMLOuterWindow *child; + DOMEvent *event; + HRESULT hres; + + if(!window) + return; + + if(window->doc) { + hres = create_document_event(window->doc, EVENTID_UNLOAD, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + } + + LIST_FOR_EACH_ENTRY(child, &window->children, HTMLOuterWindow, sibling_entry) + send_unload_events_impl(child->base.inner_window); +} + +void send_unload_events(HTMLDocumentNode *doc) +{ + if(!doc->content_ready || doc->unload_sent || !doc->window || !doc->outer_window || !is_main_content_window(doc->outer_window)) + return; + doc->unload_sent = TRUE; + + send_unload_events_impl(doc->window); +} + typedef struct { HTMLDOMNode node; IDOMDocumentType IDOMDocumentType_iface; diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index b64cba6bf81..2c2b813c647 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -209,7 +209,7 @@ static const event_info_t event_info[] = { {L"timeout", EVENT_TYPE_PROGRESS, DISPID_EVPROP_TIMEOUT, EVENT_BIND_TO_TARGET}, {L"unload", EVENT_TYPE_UIEVENT, DISPID_EVMETH_ONUNLOAD, - EVENT_FIXME}, + 0}, {L"visibilitychange", EVENT_TYPE_EVENT, DISPID_EVPROP_VISIBILITYCHANGE, EVENT_FIXME | EVENT_BUBBLES},
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h index 7e7dd358c8d..cdcd15cecad 100644 --- a/dlls/mshtml/mshtml_private.h +++ b/dlls/mshtml/mshtml_private.h @@ -924,7 +924,8 @@ struct HTMLDocumentNode {
nsIDOMDocument *dom_document; nsIDOMHTMLDocument *html_document; - BOOL content_ready; + BOOL content_ready : 1; + BOOL unload_sent : 1;
IHTMLDOMImplementation *dom_implementation; IHTMLNamespaceCollection *namespaces; @@ -1010,6 +1011,7 @@ void hide_tooltip(HTMLDocumentObj*) DECLSPEC_HIDDEN; HRESULT get_client_disp_property(IOleClientSite*,DISPID,VARIANT*) DECLSPEC_HIDDEN;
UINT get_document_charset(HTMLDocumentNode*) DECLSPEC_HIDDEN; +void send_unload_events(HTMLDocumentNode*) DECLSPEC_HIDDEN;
HRESULT ProtocolFactory_Create(REFCLSID,REFIID,void**) DECLSPEC_HIDDEN;
diff --git a/dlls/mshtml/navigate.c b/dlls/mshtml/navigate.c index 5825e0f27c0..9e645caff70 100644 --- a/dlls/mshtml/navigate.c +++ b/dlls/mshtml/navigate.c @@ -1357,8 +1357,12 @@ static HRESULT nsChannelBSC_start_binding(BSCallback *bsc) { nsChannelBSC *This = nsChannelBSC_from_BSCallback(bsc);
- if(This->is_doc_channel) - This->bsc.window->base.outer_window->base.inner_window->doc->skip_mutation_notif = FALSE; + if(This->is_doc_channel) { + HTMLDocumentNode *cur_doc = This->bsc.window->base.outer_window->base.inner_window->doc; + + cur_doc->skip_mutation_notif = FALSE; + send_unload_events(cur_doc); + }
return S_OK; } diff --git a/dlls/mshtml/oleobj.c b/dlls/mshtml/oleobj.c index a8bd5751b49..b9f41c1469f 100644 --- a/dlls/mshtml/oleobj.c +++ b/dlls/mshtml/oleobj.c @@ -448,6 +448,9 @@ static HRESULT WINAPI DocObjOleObject_SetClientSite(IOleObject *iface, IOleClien if(pClientSite == This->client) return S_OK;
+ if(!pClientSite && This->doc_node) + send_unload_events(This->doc_node); + if(This->client) { IOleClientSite_Release(This->client); This->client = NULL; diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index 0ae5df94b3a..b200dacd23e 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -20,6 +20,12 @@ var compat_version; var tests = [];
var pageshow_fired = false; +document.doc_unload_events_called = false; +window.onunload = function() { + document.doc_unload_events_called = true; + ok(document.readyState === "complete", "unload readyState = " + document.readyState); +}; + if(window.addEventListener) { window.addEventListener("pageshow", function(e) { pageshow_fired = true; @@ -32,6 +38,9 @@ if(window.addEventListener) { }, true);
document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); + document.addEventListener("unload", function() { ok(false, "unload fired on document"); }); +}else { + document.attachEvent("onunload", function() { ok(false, "unload fired on document"); }); }
sync_test("page transition events", function() { @@ -39,6 +48,11 @@ sync_test("page transition events", function() { ok(pageshow_fired === false, "pageshow fired"); else ok(pageshow_fired === true, "pageshow not fired"); + + if(document.body.addEventListener) + document.body.addEventListener("unload", function() { ok(false, "unload fired on document.body"); }); + else + document.body.attachEvent("onunload", function() { ok(false, "unload fired on document.body"); }); });
sync_test("builtin_toString", function() { diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index 7945a2b72ae..bb2b2ec97b5 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -98,6 +98,8 @@ DEFINE_EXPECT(submit_onclick_setret); DEFINE_EXPECT(elem2_cp_onclick); DEFINE_EXPECT(iframe_onload); DEFINE_EXPECT(visibilitychange); +DEFINE_EXPECT(onunload); +DEFINE_EXPECT(iframe_onunload); DEFINE_EXPECT(doc1_onstorage); DEFINE_EXPECT(doc1_onstoragecommit); DEFINE_EXPECT(window1_onstorage); @@ -1432,6 +1434,27 @@ static HRESULT WINAPI onvisibilitychange(IDispatchEx *iface, DISPID id, LCID lci
EVENT_HANDLER_FUNC_OBJ(onvisibilitychange);
+static HRESULT WINAPI onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(onunload); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(onunload); + +static HRESULT WINAPI iframe_onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(iframe_onunload); + ok(called_onunload, "unload not fired on parent window before iframe\n"); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(iframe_onunload); + static HRESULT WINAPI nocall(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { @@ -2461,6 +2484,67 @@ static void test_visibilitychange(IHTMLDocument2 *doc) } }
+static void test_unload_event(IHTMLDocument2 *doc) +{ + IHTMLFrameBase2 *iframe; + IHTMLDocument6 *doc6; + IHTMLElement2 *elem; + IHTMLWindow2 *child; + HRESULT hres; + VARIANT v; + BSTR bstr; + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&onunload_obj; + hres = IHTMLWindow2_put_onunload(window, v); + ok(hres == S_OK, "put_onunload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onunload(window, &v); + ok(hres == S_OK, "get_onunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onunload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&onunload_obj, "V_DISPATCH(onunload) = %p\n", V_DISPATCH(&v)); + + hres = IHTMLDocument2_QueryInterface(doc, &IID_IHTMLDocument6, (void**)&doc6); + ok(hres == S_OK, "Could not get IHTMLDocument6 iface: %08lx\n", hres); + bstr = SysAllocString(L"ifr"); + hres = IHTMLDocument6_getElementById(doc6, bstr, &elem); + ok(hres == S_OK, "getElementById failed: %08lx\n", hres); + IHTMLDocument6_Release(doc6); + SysFreeString(bstr); + + hres = IHTMLElement2_QueryInterface(elem, &IID_IHTMLFrameBase2, (void**)&iframe); + ok(hres == S_OK, "Could not get IHTMLFrameBase2 iface: %08lx\n", hres); + IHTMLElement2_Release(elem); + hres = IHTMLFrameBase2_get_contentWindow(iframe, &child); + ok(hres == S_OK, "get_contentWindow failed: %08lx\n", hres); + IHTMLFrameBase2_Release(iframe); + + V_VT(&v) = VT_DISPATCH; + V_DISPATCH(&v) = (IDispatch*)&iframe_onunload_obj; + hres = IHTMLWindow2_put_onunload(child, v); + ok(hres == S_OK, "put_onunload failed: %08lx\n", hres); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onunload(child, &v); + ok(hres == S_OK, "get_onunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_DISPATCH, "V_VT(onunload) = %d\n", V_VT(&v)); + ok(V_DISPATCH(&v) == (IDispatch*)&iframe_onunload_obj, "V_DISPATCH(onunload) = %p\n", V_DISPATCH(&v)); + + IHTMLWindow2_Release(child); + + SET_EXPECT(onunload); + SET_EXPECT(iframe_onunload); + navigate(doc, L"blank.html"); + CHECK_CALLED(iframe_onunload); + CHECK_CALLED(onunload); + + V_VT(&v) = VT_EMPTY; + hres = IHTMLWindow2_get_onunload(window, &v); + ok(hres == S_OK, "get_onunload failed: %08lx\n", hres); + ok(V_VT(&v) == VT_NULL, "V_VT(onunload) = %d\n", V_VT(&v)); +} + static void test_submit(IHTMLDocument2 *doc) { IHTMLElement *elem, *submit; @@ -5592,6 +5676,7 @@ START_TEST(events) run_test_from_res(L"doc_with_prop_ie9.html", test_doc_obj); run_test_from_res(L"doc_with_prop_ie9.html", test_visibilitychange); run_test_from_res(L"blank_ie10.html", test_visibilitychange); + run_test_from_res(L"iframe.html", test_unload_event); run_test(empty_doc_ie9_str, test_create_event); }
diff --git a/dlls/mshtml/tests/iframe.html b/dlls/mshtml/tests/iframe.html new file mode 100644 index 00000000000..ec08a0eb19a --- /dev/null +++ b/dlls/mshtml/tests/iframe.html @@ -0,0 +1,4 @@ +<html> +<head><meta http-equiv="x-ua-compatible" content="IE=11" /></head> +<body><iframe src="about:blank" id="ifr"></iframe></body> +</html> diff --git a/dlls/mshtml/tests/rsrc.rc b/dlls/mshtml/tests/rsrc.rc index 01b2838be8b..e60e37198de 100644 --- a/dlls/mshtml/tests/rsrc.rc +++ b/dlls/mshtml/tests/rsrc.rc @@ -82,6 +82,9 @@ doc_with_prop.html HTML "doc_with_prop.html" /* @makedep: doc_with_prop_ie9.html */ doc_with_prop_ie9.html HTML "doc_with_prop_ie9.html"
+/* @makedep: iframe.html */ +iframe.html HTML "iframe.html" + /* For res: protocol test: */
/* @makedep: jstest.html */ diff --git a/dlls/mshtml/tests/script.c b/dlls/mshtml/tests/script.c index e71f178e51a..d7d7e7361c3 100644 --- a/dlls/mshtml/tests/script.c +++ b/dlls/mshtml/tests/script.c @@ -3892,8 +3892,10 @@ static void test_simple_script(void)
static void run_from_moniker(IMoniker *mon) { + DISPID dispid = DISPID_UNKNOWN; IPersistMoniker *persist; IHTMLDocument2 *doc; + BSTR bstr; MSG msg; HRESULT hres;
@@ -3921,8 +3923,28 @@ static void run_from_moniker(IMoniker *mon)
CHECK_CALLED(external_success);
+ /* check prop set by events fired during document unload */ + bstr = SysAllocString(L"doc_unload_events_called"); + hres = IHTMLDocument2_GetIDsOfNames(doc, &IID_NULL, &bstr, 1, 0, &dispid); + SysFreeString(bstr); + if(hres == DISP_E_UNKNOWNNAME) + dispid = DISPID_UNKNOWN; + else + ok(hres == S_OK, "GetIDsOfNames failed %08lx\n", hres); + free_registered_streams(); set_client_site(doc, FALSE); + + if(dispid != DISPID_UNKNOWN) { + DISPPARAMS dp = { 0 }; + UINT argerr; + VARIANT v; + + hres = IHTMLDocument2_Invoke(doc, dispid, &IID_NULL, 0, DISPATCH_PROPERTYGET, &dp, &v, NULL, &argerr); + ok(hres == S_OK, "Invoke failed %08lx\n", hres); + ok(V_VT(&v) == VT_BOOL, "V_VT(doc_unload_events_called) = %d\n", V_VT(&v)); + ok(V_BOOL(&v) == VARIANT_TRUE, "doc_unload_events_called is not true\n"); + } IHTMLDocument2_Release(doc); }
From: Gabriel Ivăncescu gabrielopcode@gmail.com
Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com --- dlls/mshtml/htmldoc.c | 10 +++++++++ dlls/mshtml/htmlevent.c | 2 ++ dlls/mshtml/htmlevent.h | 1 + dlls/mshtml/tests/documentmode.js | 17 +++++++++++++++- dlls/mshtml/tests/events.c | 34 +++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-)
diff --git a/dlls/mshtml/htmldoc.c b/dlls/mshtml/htmldoc.c index dccb0c4f028..2cb9f7e2c22 100644 --- a/dlls/mshtml/htmldoc.c +++ b/dlls/mshtml/htmldoc.c @@ -158,6 +158,16 @@ static void send_unload_events_impl(HTMLInnerWindow *window) return;
if(window->doc) { + /* Native sends pagehide events before unload on the same window + before it moves on to the next window, so they're interleaved. */ + if(window->doc->document_mode >= COMPAT_MODE_IE11) { + hres = create_document_event(window->doc, EVENTID_PAGEHIDE, &event); + if(SUCCEEDED(hres)) { + dispatch_event(&window->event_target, event); + IDOMEvent_Release(&event->IDOMEvent_iface); + } + } + hres = create_document_event(window->doc, EVENTID_UNLOAD, &event); if(SUCCEEDED(hres)) { dispatch_event(&window->event_target, event); diff --git a/dlls/mshtml/htmlevent.c b/dlls/mshtml/htmlevent.c index 2c2b813c647..c32a76aba4b 100644 --- a/dlls/mshtml/htmlevent.c +++ b/dlls/mshtml/htmlevent.c @@ -184,6 +184,8 @@ static const event_info_t event_info[] = { EVENT_FIXME}, {L"msthumbnailclick", EVENT_TYPE_MOUSE, DISPID_EVPROP_ONMSTHUMBNAILCLICK, EVENT_FIXME}, + {L"pagehide", EVENT_TYPE_PAGETRANSITION, DISPID_EVPROP_ONPAGEHIDE, + 0}, {L"pageshow", EVENT_TYPE_PAGETRANSITION, DISPID_EVPROP_ONPAGESHOW, 0}, {L"paste", EVENT_TYPE_CLIPBOARD, DISPID_EVMETH_ONPASTE, diff --git a/dlls/mshtml/htmlevent.h b/dlls/mshtml/htmlevent.h index e49c47d6988..a6d1f734a40 100644 --- a/dlls/mshtml/htmlevent.h +++ b/dlls/mshtml/htmlevent.h @@ -51,6 +51,7 @@ typedef enum { EVENTID_MOUSEUP, EVENTID_MOUSEWHEEL, EVENTID_MSTHUMBNAILCLICK, + EVENTID_PAGEHIDE, EVENTID_PAGESHOW, EVENTID_PASTE, EVENTID_PROGRESS, diff --git a/dlls/mshtml/tests/documentmode.js b/dlls/mshtml/tests/documentmode.js index b200dacd23e..3d473219b9f 100644 --- a/dlls/mshtml/tests/documentmode.js +++ b/dlls/mshtml/tests/documentmode.js @@ -19,11 +19,15 @@ var compat_version; var tests = [];
-var pageshow_fired = false; +var pageshow_fired = false, pagehide_fired = false; document.doc_unload_events_called = false; window.onunload = function() { document.doc_unload_events_called = true; ok(document.readyState === "complete", "unload readyState = " + document.readyState); + if(document.documentMode < 11) + ok(pagehide_fired === false, "pagehide fired before unload"); + else + ok(pagehide_fired === true, "pagehide not fired before unload"); };
if(window.addEventListener) { @@ -37,6 +41,16 @@ if(window.addEventListener) { ok(document.readyState === "complete", "pageshow readyState = " + document.readyState); }, true);
+ window.addEventListener("pagehide", function(e) { + pagehide_fired = true; + ok(document.documentMode >= 11, "pagehide fired"); + + var r = Object.prototype.toString.call(e); + todo_wine. + ok(r === "[object PageTransitionEvent]", "pagehide toString = " + r); + ok("persisted" in e, "'persisted' not in pagehide event"); + }, true); + document.addEventListener("visibilitychange", function() { ok(false, "visibilitychange fired"); }); document.addEventListener("unload", function() { ok(false, "unload fired on document"); }); }else { @@ -48,6 +62,7 @@ sync_test("page transition events", function() { ok(pageshow_fired === false, "pageshow fired"); else ok(pageshow_fired === true, "pageshow not fired"); + ok(pagehide_fired === false, "pagehide fired");
if(document.body.addEventListener) document.body.addEventListener("unload", function() { ok(false, "unload fired on document.body"); }); diff --git a/dlls/mshtml/tests/events.c b/dlls/mshtml/tests/events.c index bb2b2ec97b5..e66e21d95aa 100644 --- a/dlls/mshtml/tests/events.c +++ b/dlls/mshtml/tests/events.c @@ -99,7 +99,9 @@ DEFINE_EXPECT(elem2_cp_onclick); DEFINE_EXPECT(iframe_onload); DEFINE_EXPECT(visibilitychange); DEFINE_EXPECT(onunload); +DEFINE_EXPECT(pagehide); DEFINE_EXPECT(iframe_onunload); +DEFINE_EXPECT(iframe_pagehide); DEFINE_EXPECT(doc1_onstorage); DEFINE_EXPECT(doc1_onstoragecommit); DEFINE_EXPECT(window1_onstorage); @@ -1434,21 +1436,47 @@ static HRESULT WINAPI onvisibilitychange(IDispatchEx *iface, DISPID id, LCID lci
EVENT_HANDLER_FUNC_OBJ(onvisibilitychange);
+static HRESULT WINAPI pagehide(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(pagehide); + ok(!called_onunload, "unload fired before pagehide\n"); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(pagehide); + static HRESULT WINAPI onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { CHECK_EXPECT(onunload); + ok(called_pagehide, "pagehide not fired before unload\n"); test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); return S_OK; }
EVENT_HANDLER_FUNC_OBJ(onunload);
+static HRESULT WINAPI iframe_pagehide(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, + VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) +{ + CHECK_EXPECT(iframe_pagehide); + ok(called_pagehide, "pagehide not fired on parent window before iframe\n"); + ok(called_onunload, "unload not fired on parent window before pagehide on iframe\n"); + ok(!called_iframe_onunload, "unload fired before pagehide on iframe\n"); + test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); + return S_OK; +} + +EVENT_HANDLER_FUNC_OBJ(iframe_pagehide); + static HRESULT WINAPI iframe_onunload(IDispatchEx *iface, DISPID id, LCID lcid, WORD wFlags, DISPPARAMS *pdp, VARIANT *pvarRes, EXCEPINFO *pei, IServiceProvider *pspCaller) { CHECK_EXPECT(iframe_onunload); ok(called_onunload, "unload not fired on parent window before iframe\n"); + ok(called_iframe_pagehide, "pagehide not fired before unload on iframe\n"); test_event_args(NULL, id, wFlags, pdp, pvarRes, pei, pspCaller); return S_OK; } @@ -2531,12 +2559,18 @@ static void test_unload_event(IHTMLDocument2 *doc) ok(V_VT(&v) == VT_DISPATCH, "V_VT(onunload) = %d\n", V_VT(&v)); ok(V_DISPATCH(&v) == (IDispatch*)&iframe_onunload_obj, "V_DISPATCH(onunload) = %p\n", V_DISPATCH(&v));
+ add_event_listener((IUnknown*)window, L"pagehide", (IDispatch*)&pagehide_obj, VARIANT_TRUE); + add_event_listener((IUnknown*)child, L"pagehide", (IDispatch*)&iframe_pagehide_obj, VARIANT_TRUE); IHTMLWindow2_Release(child);
SET_EXPECT(onunload); + SET_EXPECT(pagehide); SET_EXPECT(iframe_onunload); + SET_EXPECT(iframe_pagehide); navigate(doc, L"blank.html"); + CHECK_CALLED(iframe_pagehide); CHECK_CALLED(iframe_onunload); + CHECK_CALLED(pagehide); CHECK_CALLED(onunload);
V_VT(&v) = VT_EMPTY;
On Wed Nov 16 14:38:34 2022 +0000, Gabriel Ivăncescu wrote:
Not aware of one specifically, but the tests are nice to have, and I don't know how to test it without actually implementing it (and sending the events). Is bailing out on Wine (in the tests) with a skip or FIXME good enough? (like we have in some js tests) The reason for the tests is that this event gets registered by apps, and according to spec it should be sent during unload as well, not just minimize. However, native doesn't seem to do that, but without tests, I wouldn't have known this… hence why they're nice to have, IMO. Any ideas here how to keep the tests? BTW in private conversation, Conor also said in WinEvents could be used here, EVENT_SYSTEM_MINIMIZESTART and EVENT_SYSTEM_MINIMIZEEND, but they're not implemented in Wine so I can't right now, but that's probably the best way to implement it at some point.
I sent a version that keeps tests but has a check for native to have proper waits then (there's still todo_wine, so when it gets implemented, we'll know to remove that FIXME part as well). Now it's just a stub.
It's slightly ugly but IMO much better to have the tests in to prevent confusion whether these events are actually needed by apps or not. I know it would've helped me.
Jacek Caban (@jacek) commented about dlls/mshtml/nsevents.c:
dispatch_event(&doc->window->event_target, load_event); IDOMEvent_Release(&load_event->IDOMEvent_iface); }
if(doc->dom_document && doc->document_mode >= COMPAT_MODE_IE11) {
hres = create_document_event(doc, EVENTID_PAGESHOW, &load_event);
if(SUCCEEDED(hres)) {
dispatch_event(&doc->window->event_target, load_event);
IDOMEvent_Release(&load_event->IDOMEvent_iface);
}
}
It seems that Gecko implements this event (and others in the series), could we just use that instead? As far as I can see we currently don't handle EVENT_BIND_TO_TARGET for window events, but that should be easy to change. Maybe we should even use window object instead of document for EVENT_DEFAULTLISTENER?
I think `pageshow` might be the only one we can use from Gecko, the other two are intertwined on native IE and must be sent on all windows interleaved. It will also be necessary to control their dispatch ourselves when implementing performance.timing.unloadEventStart (and the respective End).
Coincidentally, for the EVENT_BIND_TO_TARGET being window, while looking at a bug now, I just discovered that `handle_htmlevent` silently drops all gecko events routed to the window, because we expect a node, but the window is not one. (this is an existing issue and a pretty nasty one)
So I'll fix that, too.
BTW unless I'm missing something, EVENT_DEFAULTLISTENER already uses the window object. i.e. nsnode == NULL → get_default_document_target returns window first, document only as fallback (if no window, i.e. detached doc).
Actually nevermind, we can't use Gecko's "pageshow" even, because of two reasons:
1) There's no XPCOM interface exposed by it, which would require changing wine-gecko and frankly, it complicates it for no reason (dispatching it is simple because we already handle the load event).
2) It's only dispatched on IE11 mode. We could conceivably add some compat mode to each event, but not sure if it's worth it at this point just for this one event…
I guess I'll keep the patch as-is but I'll push in the new fixes since they're quite serious.