dom/plugins/test/mochitest/dialog_watcher.js

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 const EVENT_OBJECT_SHOW = 0x8002;
     2 const EVENT_OBJECT_HIDE = 0x8003;
     3 const WINEVENT_OUTOFCONTEXT = 0;
     4 const WINEVENT_SKIPOWNPROCESS = 2;
     5 const QS_ALLINPUT = 0x04FF;
     6 const INFINITE = 0xFFFFFFFF;
     7 const WAIT_OBJECT_0 = 0;
     8 const WAIT_TIMEOUT = 258;
     9 const PM_NOREMOVE = 0;
    11 function DialogWatcher(titleText, onDialogStart, onDialogEnd) {
    12   this.titleText = titleText;
    13   this.onDialogStart = onDialogStart;
    14   this.onDialogEnd = onDialogEnd;
    15 }
    17 DialogWatcher.prototype.init = function() {
    18   this.hwnd = undefined;
    19   if (!this.user32) {
    20     this.user32 = ctypes.open("user32.dll");
    21   }
    22   if (!this.findWindow) {
    23     this.findWindow = user32.declare("FindWindowW",
    24                                      ctypes.winapi_abi,
    25                                      ctypes.uintptr_t,
    26                                      ctypes.jschar.ptr,
    27                                      ctypes.jschar.ptr);
    28   }
    29   if (!this.winEventProcType) {
    30     this.winEventProcType = ctypes.FunctionType(ctypes.stdcall_abi,
    31                                                 ctypes.void_t,
    32                                                 [ctypes.uintptr_t,
    33                                                 ctypes.uint32_t,
    34                                                 ctypes.uintptr_t,
    35                                                 ctypes.long,
    36                                                 ctypes.long,
    37                                                 ctypes.uint32_t,
    38                                                 ctypes.uint32_t]).ptr;
    39   }
    40   if (!this.setWinEventHook) {
    41     this.setWinEventHook = user32.declare("SetWinEventHook",
    42                                           ctypes.winapi_abi,
    43                                           ctypes.uintptr_t,
    44                                           ctypes.uint32_t,
    45                                           ctypes.uint32_t,
    46                                           ctypes.uintptr_t,
    47                                           this.winEventProcType,
    48                                           ctypes.uint32_t,
    49                                           ctypes.uint32_t,
    50                                           ctypes.uint32_t);
    51   }
    52   if (!this.unhookWinEvent) {
    53     this.unhookWinEvent = user32.declare("UnhookWinEvent",
    54                                          ctypes.winapi_abi,
    55                                          ctypes.int,
    56                                          ctypes.uintptr_t);
    57   }
    58   if (!this.pointType) {
    59     this.pointType = ctypes.StructType("tagPOINT",
    60                                        [ { "x": ctypes.long },
    61                                          { "y": ctypes.long } ] );
    62   }
    63   if (!this.msgType) {
    64     this.msgType = ctypes.StructType("tagMSG",
    65                                      [ { "hwnd": ctypes.uintptr_t },
    66                                        { "message": ctypes.uint32_t },
    67                                        { "wParam": ctypes.uintptr_t },
    68                                        { "lParam": ctypes.intptr_t },
    69                                        { "time": ctypes.uint32_t },
    70                                        { "pt": this.pointType } ] );
    71   }
    72   if (!this.peekMessage) {
    73     this.peekMessage = user32.declare("PeekMessageW",
    74                                       ctypes.winapi_abi,
    75                                       ctypes.int,
    76                                       this.msgType.ptr,
    77                                       ctypes.uintptr_t,
    78                                       ctypes.uint32_t,
    79                                       ctypes.uint32_t,
    80                                       ctypes.uint32_t);
    81   }
    82   if (!this.msgWaitForMultipleObjects) {
    83     this.msgWaitForMultipleObjects = user32.declare("MsgWaitForMultipleObjects",
    84                                                     ctypes.winapi_abi,
    85                                                     ctypes.uint32_t,
    86                                                     ctypes.uint32_t,
    87                                                     ctypes.uintptr_t.ptr,
    88                                                     ctypes.int,
    89                                                     ctypes.uint32_t,
    90                                                     ctypes.uint32_t);
    91   }
    92   if (!this.getWindowTextW) {
    93     this.getWindowTextW = user32.declare("GetWindowTextW",
    94                                          ctypes.winapi_abi,
    95                                          ctypes.int,
    96                                          ctypes.uintptr_t,
    97                                          ctypes.jschar.ptr,
    98                                          ctypes.int);
    99   }
   100   if (!this.messageBox) {
   101     // Handy for debugging this code
   102     this.messageBox = user32.declare("MessageBoxW",
   103                                      ctypes.winapi_abi,
   104                                      ctypes.int,
   105                                      ctypes.uintptr_t,
   106                                      ctypes.jschar.ptr,
   107                                      ctypes.jschar.ptr,
   108                                      ctypes.uint32_t);
   109   }
   110 };
   112 DialogWatcher.prototype.getWindowText = function(hwnd) {
   113   var bufType = ctypes.ArrayType(ctypes.jschar);
   114   var buffer = new bufType(256);
   116   if (this.getWindowTextW(hwnd, buffer, buffer.length)) {
   117     return buffer.readString();
   118   }
   119 };
   121 DialogWatcher.prototype.processWindowEvents = function(timeout) {
   122   var onWinEvent = function(self, hook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime) {
   123     var nhwnd = Number(hwnd)
   124     if (event == EVENT_OBJECT_SHOW) {
   125       if (nhwnd == self.hwnd) {
   126         // We've already picked up this event via FindWindow
   127         return;
   128       }
   129       var windowText = self.getWindowText(hwnd);
   130       if (windowText == self.titleText && self.onDialogStart) {
   131         self.hwnd = nhwnd;
   132         self.onDialogStart(nhwnd);
   133       }
   134     } else if (event == EVENT_OBJECT_HIDE && nhwnd == self.hwnd && self.onDialogEnd) {
   135       self.onDialogEnd();
   136       self.hwnd = null;
   137     }
   138   };
   139   var self = this;
   140   var callback = this.winEventProcType(function(hook, event, hwnd, idObject,
   141                                                 idChild, dwEventThread,
   142                                                 dwmsEventTime) {
   143       onWinEvent(self, hook, event, hwnd, idObject, idChild, dwEventThread,
   144                  dwmsEventTime);
   145     } );
   146   var hook = this.setWinEventHook(EVENT_OBJECT_SHOW, EVENT_OBJECT_HIDE,
   147                                   0, callback, 0, 0,
   148                                   WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS);
   149   if (!hook) {
   150     return;
   151   }
   152   // Check if the window is already showing
   153   var hwnd = this.findWindow(null, this.titleText);
   154   if (hwnd && hwnd > 0) {
   155     this.hwnd = Number(hwnd);
   156     if (this.onDialogStart) {
   157       this.onDialogStart(this.hwnd);
   158     }
   159   }
   161   if (!timeout) {
   162     timeout = INFINITE;
   163   }
   165   var waitStatus = WAIT_OBJECT_0;
   166   var expectingStart = this.onDialogStart && this.hwnd === undefined;
   167   var startWaitTime = Date.now();
   168   while (this.hwnd === undefined || this.onDialogEnd && this.hwnd) {
   169     waitStatus = this.msgWaitForMultipleObjects(0, null, 0, expectingStart ?
   170                                                             INFINITE : timeout, 0);
   171     if (waitStatus == WAIT_OBJECT_0) {
   172       var msg = new this.msgType;
   173       this.peekMessage(msg.address(), 0, 0, 0, PM_NOREMOVE);
   174     }
   175     if (waitStatus == WAIT_TIMEOUT || (Date.now() - startWaitTime) >= timeout) {
   176       break;
   177     }
   178   }
   180   this.unhookWinEvent(hook);
   181   // Returns true if the hook was successful, something was found, and we never timed out
   182   return this.hwnd !== undefined && waitStatus == WAIT_OBJECT_0;
   183 };

mercurial