void nsSystemTrayIconBase::DispatchEvent(const nsAString& aType,
                                         PRUint16 aButton, PRInt32 aDetail,
                                         bool aCtrlKey, bool aAltKey,
                                         bool aShiftKey, bool aMetaKey)
{
  nsresult rv;

  // first, create an event...
  nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mEventTarget, &rv));
  if (NS_FAILED(rv)) return;
  
  nsCOMPtr<nsIDOMDocument> doc;
  rv = node->GetOwnerDocument(getter_AddRefs(doc));
  if (NS_FAILED(rv)) return;
  
  nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(doc, &rv));
  if (NS_FAILED(rv)) return;
  
  nsCOMPtr<nsIDOMEvent> event;
  rv = docEvent->CreateEvent(NS_LITERAL_STRING("mouseevent"),
                             getter_AddRefs(event));
  if (NS_FAILED(rv)) return;
  
  nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(event, &rv));
  if (NS_FAILED(rv)) return;
  
  // get the view the event occurred on
  nsCOMPtr<nsIDOMDocumentView> documentView(do_QueryInterface(doc, &rv));
  if (NS_FAILED(rv)) return;
  
  nsCOMPtr<nsIDOMAbstractView> view;
  rv = documentView->GetDefaultView(getter_AddRefs(view));
  if (NS_FAILED(rv)) return;
  
  // figure out where to position the popup
  nsPoint position = GetPopupPosition();
  
  // initialize the event
  // TODO: give useful arguments here
  rv = mouseEvent->InitMouseEvent(aType,
                                  PR_FALSE, PR_TRUE, view, aDetail,
                                  position.x, position.y, position.x, position.y,
                                  aCtrlKey, aAltKey, aShiftKey, aMetaKey,
                                  aButton, nsnull);
  if (NS_FAILED(rv)) return;
  
  // and dispatch it. (yes, return value is ignored; we can't do anything)
  bool result;
  mEventTarget->DispatchEvent(event, &result);
}
LRESULT CALLBACK
nsWindowUtil::WindowProc(HWND hwnd,
                         UINT uMsg,
                         WPARAM wParam,
                         LPARAM lParam)
{
  bool handled = true;
  WNDPROC proc;
  nsWindowUtil* self =
    (nsWindowUtil*)GetProp(hwnd, S_PROPINST);

  if (self && self->mOldProc && self->mDOMWindow) {
    proc = self->mOldProc;
  } else {
    // property not found - we don't exist anymore
    // use the original window proc
    proc = (WNDPROC)GetProp(hwnd, S_PROPPROC);
    if (!proc)
      // can't find the right process... skip over to the default
      // (this will, at the minimum, totally break the app)
      proc = DefWindowProc;
    handled = false;
  }
 
  /*
   * For this next section, including all the switches, we are simply
   * collecting messages we feel are important to collect.  Once we collect
   * all the windows messages that may be important to us, then these messages
   * are dispatched as DOM events to the window.
   */

  nsAutoString typeArg;

  POINT clientPos = { 0, 0};
  POINT screenPos = { 0, 0};

  if (handled) {
    switch (uMsg) {
      case WM_NCLBUTTONDOWN:
        switch(wParam) {
          // these are the min, max, and close buttons for
          case HTMINBUTTON:
            typeArg = NS_LITERAL_STRING("minimizing");
            break;
          case HTMAXBUTTON:
            typeArg = NS_LITERAL_STRING("maximizing");
            break;
          case HTCLOSE:
            typeArg = NS_LITERAL_STRING("closing");
            break;
          default:
            handled = false;
        }
        clientPos.x = screenPos.x = LOWORD(lParam);
        clientPos.y = screenPos.y = LOWORD(lParam);
        ::ClientToScreen(hwnd, &screenPos);
        break;
      case WM_ACTIVATE:
        switch (LOWORD(wParam)) {
          case WA_ACTIVE:
          case WA_CLICKACTIVE:
            // window is being activated
            typeArg = NS_LITERAL_STRING("activating");
            break;
          default:
            handled = false;
        }
        break;
      case WM_SIZE:
        switch (wParam) {
          case SIZE_MINIMIZED:
            typeArg = NS_LITERAL_STRING("minimizing");
            break;
          default:
            // for some reason this message is received with wParam ==
            // SIZE_MAXIMIZED when the browser is shutting down, and calling
            // Restore() results in the maximized window being "restored"
            // (returned to non-maximized) size. This size is preserved
            // after restarting, which is annoying, so I'm commenting it out
            // until someone can prove that this is actually useful.
            //
            // we're resizing, but not minimized, so some part must be visible
            //typeArg = NS_LITERAL_STRING("activating");
            break;
        }
        break;
      case WM_SYSCOMMAND:
        switch (wParam) {
          case SC_CLOSE:
            //The user has clicked on the top left window icon and selected close...
            //Or the user typed Alt+F4.
            typeArg = NS_LITERAL_STRING("closing");
            break;
          default:
            handled = false;
        }
    		break;
      default:
        handled = false;
        break;
    }
  }
  
  PRBool ctrlArg = PR_FALSE;
  PRBool altArg = PR_FALSE;
  PRBool shiftArg = PR_FALSE;

  if (handled) {
    // check modifier key states
    if (::GetKeyState(VK_CONTROL) & 0x8000)
      ctrlArg = PR_TRUE;
    if (::GetKeyState(VK_MENU) & 0x8000)
      altArg = PR_TRUE;
    if (::GetKeyState(VK_SHIFT) & 0x8000)
      shiftArg = PR_TRUE;
    
    // dispatch the event
    PRBool ret = TRUE;
    nsresult rv;
    
    nsCOMPtr<nsIDOMEventTarget> eventTarget(do_QueryInterface(self->mDOMWindow, &rv));
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr<nsIDOMDocument> document;
    rv = self->mDOMWindow->GetDocument(getter_AddRefs(document));
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr<nsIDOMDocumentEvent> documentEvent(do_QueryInterface(document, &rv));
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr<nsIDOMDocumentView> documentView(do_QueryInterface(document, &rv));
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr<nsIDOMAbstractView> abstractView;
    rv = documentView->GetDefaultView(getter_AddRefs(abstractView));
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr<nsIDOMEvent> event;
    rv = documentEvent->CreateEvent(NS_LITERAL_STRING("mouseevent"), getter_AddRefs(event));
    NS_ENSURE_SUCCESS(rv, rv);

    nsCOMPtr<nsIDOMMouseEvent> mouseEvent(do_QueryInterface(event, &rv));
    NS_ENSURE_SUCCESS(rv, rv);

    rv = mouseEvent->InitMouseEvent(typeArg, PR_TRUE, PR_TRUE, abstractView,
      1, screenPos.x, screenPos.y, clientPos.x, clientPos.y, ctrlArg, altArg,
      shiftArg, PR_FALSE, 0, nsnull);
    NS_ENSURE_SUCCESS(rv, rv);

    rv = eventTarget->DispatchEvent(mouseEvent, &ret);
    NS_ENSURE_SUCCESS(rv, rv);

    if (!ret)
      // event was hooked
      return FALSE;
  }
  
  return CallWindowProc(proc, hwnd, uMsg, wParam, lParam);
}