summaryrefslogtreecommitdiffstats
path: root/dom/plugins/test/mochitest/dialog_watcher.js
diff options
context:
space:
mode:
Diffstat (limited to 'dom/plugins/test/mochitest/dialog_watcher.js')
-rw-r--r--dom/plugins/test/mochitest/dialog_watcher.js183
1 files changed, 183 insertions, 0 deletions
diff --git a/dom/plugins/test/mochitest/dialog_watcher.js b/dom/plugins/test/mochitest/dialog_watcher.js
new file mode 100644
index 000000000..8a8c82997
--- /dev/null
+++ b/dom/plugins/test/mochitest/dialog_watcher.js
@@ -0,0 +1,183 @@
+const EVENT_OBJECT_SHOW = 0x8002;
+const EVENT_OBJECT_HIDE = 0x8003;
+const WINEVENT_OUTOFCONTEXT = 0;
+const WINEVENT_SKIPOWNPROCESS = 2;
+const QS_ALLINPUT = 0x04FF;
+const INFINITE = 0xFFFFFFFF;
+const WAIT_OBJECT_0 = 0;
+const WAIT_TIMEOUT = 258;
+const PM_NOREMOVE = 0;
+
+function DialogWatcher(titleText, onDialogStart, onDialogEnd) {
+ this.titleText = titleText;
+ this.onDialogStart = onDialogStart;
+ this.onDialogEnd = onDialogEnd;
+}
+
+DialogWatcher.prototype.init = function() {
+ this.hwnd = undefined;
+ if (!this.user32) {
+ this.user32 = ctypes.open("user32.dll");
+ }
+ if (!this.findWindow) {
+ this.findWindow = user32.declare("FindWindowW",
+ ctypes.winapi_abi,
+ ctypes.uintptr_t,
+ ctypes.char16_t.ptr,
+ ctypes.char16_t.ptr);
+ }
+ if (!this.winEventProcType) {
+ this.winEventProcType = ctypes.FunctionType(ctypes.stdcall_abi,
+ ctypes.void_t,
+ [ctypes.uintptr_t,
+ ctypes.uint32_t,
+ ctypes.uintptr_t,
+ ctypes.long,
+ ctypes.long,
+ ctypes.uint32_t,
+ ctypes.uint32_t]).ptr;
+ }
+ if (!this.setWinEventHook) {
+ this.setWinEventHook = user32.declare("SetWinEventHook",
+ ctypes.winapi_abi,
+ ctypes.uintptr_t,
+ ctypes.uint32_t,
+ ctypes.uint32_t,
+ ctypes.uintptr_t,
+ this.winEventProcType,
+ ctypes.uint32_t,
+ ctypes.uint32_t,
+ ctypes.uint32_t);
+ }
+ if (!this.unhookWinEvent) {
+ this.unhookWinEvent = user32.declare("UnhookWinEvent",
+ ctypes.winapi_abi,
+ ctypes.int,
+ ctypes.uintptr_t);
+ }
+ if (!this.pointType) {
+ this.pointType = ctypes.StructType("tagPOINT",
+ [ { "x": ctypes.long },
+ { "y": ctypes.long } ] );
+ }
+ if (!this.msgType) {
+ this.msgType = ctypes.StructType("tagMSG",
+ [ { "hwnd": ctypes.uintptr_t },
+ { "message": ctypes.uint32_t },
+ { "wParam": ctypes.uintptr_t },
+ { "lParam": ctypes.intptr_t },
+ { "time": ctypes.uint32_t },
+ { "pt": this.pointType } ] );
+ }
+ if (!this.peekMessage) {
+ this.peekMessage = user32.declare("PeekMessageW",
+ ctypes.winapi_abi,
+ ctypes.int,
+ this.msgType.ptr,
+ ctypes.uintptr_t,
+ ctypes.uint32_t,
+ ctypes.uint32_t,
+ ctypes.uint32_t);
+ }
+ if (!this.msgWaitForMultipleObjects) {
+ this.msgWaitForMultipleObjects = user32.declare("MsgWaitForMultipleObjects",
+ ctypes.winapi_abi,
+ ctypes.uint32_t,
+ ctypes.uint32_t,
+ ctypes.uintptr_t.ptr,
+ ctypes.int,
+ ctypes.uint32_t,
+ ctypes.uint32_t);
+ }
+ if (!this.getWindowTextW) {
+ this.getWindowTextW = user32.declare("GetWindowTextW",
+ ctypes.winapi_abi,
+ ctypes.int,
+ ctypes.uintptr_t,
+ ctypes.char16_t.ptr,
+ ctypes.int);
+ }
+ if (!this.messageBox) {
+ // Handy for debugging this code
+ this.messageBox = user32.declare("MessageBoxW",
+ ctypes.winapi_abi,
+ ctypes.int,
+ ctypes.uintptr_t,
+ ctypes.char16_t.ptr,
+ ctypes.char16_t.ptr,
+ ctypes.uint32_t);
+ }
+};
+
+DialogWatcher.prototype.getWindowText = function(hwnd) {
+ var bufType = ctypes.ArrayType(ctypes.char16_t);
+ var buffer = new bufType(256);
+
+ if (this.getWindowTextW(hwnd, buffer, buffer.length)) {
+ return buffer.readString();
+ }
+};
+
+DialogWatcher.prototype.processWindowEvents = function(timeout) {
+ var onWinEvent = function(self, hook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
+ var nhwnd = Number(hwnd)
+ if (event == EVENT_OBJECT_SHOW) {
+ if (nhwnd == self.hwnd) {
+ // We've already picked up this event via FindWindow
+ return;
+ }
+ var windowText = self.getWindowText(hwnd);
+ if (windowText == self.titleText && self.onDialogStart) {
+ self.hwnd = nhwnd;
+ self.onDialogStart(nhwnd);
+ }
+ } else if (event == EVENT_OBJECT_HIDE && nhwnd == self.hwnd && self.onDialogEnd) {
+ self.onDialogEnd();
+ self.hwnd = null;
+ }
+ };
+ var self = this;
+ var callback = this.winEventProcType(function(hook, event, hwnd, idObject,
+ idChild, dwEventThread,
+ dwmsEventTime) {
+ onWinEvent(self, hook, event, hwnd, idObject, idChild, dwEventThread,
+ dwmsEventTime);
+ } );
+ var hook = this.setWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
+ 0, callback, 0, 0,
+ WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
+ if (!hook) {
+ return;
+ }
+ // Check if the window is already showing
+ var hwnd = this.findWindow(null, this.titleText);
+ if (hwnd && hwnd > 0) {
+ this.hwnd = Number(hwnd);
+ if (this.onDialogStart) {
+ this.onDialogStart(this.hwnd);
+ }
+ }
+
+ if (!timeout) {
+ timeout = INFINITE;
+ }
+
+ var waitStatus = WAIT_OBJECT_0;
+ var expectingStart = this.onDialogStart && this.hwnd === undefined;
+ var startWaitTime = Date.now();
+ while (this.hwnd === undefined || this.onDialogEnd && this.hwnd) {
+ waitStatus = this.msgWaitForMultipleObjects(0, null, 0, expectingStart ?
+ INFINITE : timeout, 0);
+ if (waitStatus == WAIT_OBJECT_0) {
+ var msg = new this.msgType;
+ this.peekMessage(msg.address(), 0, 0, 0, PM_NOREMOVE);
+ }
+ if (waitStatus == WAIT_TIMEOUT || (Date.now() - startWaitTime) >= timeout) {
+ break;
+ }
+ }
+
+ this.unhookWinEvent(hook);
+ // Returns true if the hook was successful, something was found, and we never timed out
+ return this.hwnd !== undefined && waitStatus == WAIT_OBJECT_0;
+};