+ case WM_PAINT:
+ processed = HandlePaint();
+ break;
+
+ case WM_CLOSE:
+#ifdef __WXUNIVERSAL__
+ // Universal uses its own wxFrame/wxDialog, so we don't receive
+ // close events unless we have this.
+ Close();
+ processed = TRUE;
+ rc.result = TRUE;
+#else
+ // don't let the DefWindowProc() destroy our window - we'll do it
+ // ourselves in ~wxWindow
+ processed = TRUE;
+ rc.result = TRUE;
+#endif
+ break;
+
+ case WM_SHOWWINDOW:
+ processed = HandleShow(wParam != 0, (int)lParam);
+ break;
+
+ case WM_MOUSEMOVE:
+ processed = HandleMouseMove(GET_X_LPARAM(lParam),
+ GET_Y_LPARAM(lParam),
+ wParam);
+ break;
+
+#if wxUSE_MOUSEWHEEL
+ case WM_MOUSEWHEEL:
+ processed = HandleMouseWheel(wParam, lParam);
+ break;
+#endif
+
+ case WM_LBUTTONDOWN:
+ case WM_LBUTTONUP:
+ case WM_LBUTTONDBLCLK:
+ case WM_RBUTTONDOWN:
+ case WM_RBUTTONUP:
+ case WM_RBUTTONDBLCLK:
+ case WM_MBUTTONDOWN:
+ case WM_MBUTTONUP:
+ case WM_MBUTTONDBLCLK:
+ {
+#ifdef __WXMICROWIN__
+ // MicroWindows seems to ignore the fact that a window is
+ // disabled. So catch mouse events and throw them away if
+ // necessary.
+ wxWindowMSW* win = this;
+ for ( ;; )
+ {
+ if (!win->IsEnabled())
+ {
+ processed = TRUE;
+ break;
+ }
+
+ win = win->GetParent();
+ if ( !win || win->IsTopLevel() )
+ break;
+ }
+
+ if ( processed )
+ break;
+
+#endif // __WXMICROWIN__
+ // VZ: if you find a situation when this is needed, tell
+ // me about it, do *not* uncomment this code as it
+ // causes other strange problems
+#if 0
+ if ( message == WM_LBUTTONDOWN && AcceptsFocus() )
+ SetFocus();
+#endif // 0
+
+ int x = GET_X_LPARAM(lParam),
+ y = GET_Y_LPARAM(lParam);
+
+ // redirect the event to a static control if necessary by
+ // finding one under mouse
+ wxWindowMSW *win;
+ if ( GetCapture() == this )
+ {
+ // but don't do it if the mouse is captured by this window
+ // because then it should really get this event itself
+ win = this;
+ }
+ else
+ {
+ win = FindWindowForMouseEvent(this, &x, &y);
+ }
+
+ processed = win->HandleMouseEvent(message, x, y, wParam);
+ }
+ break;
+
+#ifdef MM_JOY1MOVE
+ case MM_JOY1MOVE:
+ case MM_JOY2MOVE:
+ case MM_JOY1ZMOVE:
+ case MM_JOY2ZMOVE:
+ case MM_JOY1BUTTONDOWN:
+ case MM_JOY2BUTTONDOWN:
+ case MM_JOY1BUTTONUP:
+ case MM_JOY2BUTTONUP:
+ processed = HandleJoystickEvent(message,
+ GET_X_LPARAM(lParam),
+ GET_Y_LPARAM(lParam),
+ wParam);
+ break;
+#endif // __WXMICROWIN__
+
+ case WM_SYSCOMMAND:
+ processed = HandleSysCommand(wParam, lParam);
+ break;
+
+ case WM_COMMAND:
+ {
+ WORD id, cmd;
+ WXHWND hwnd;
+ UnpackCommand(wParam, lParam, &id, &hwnd, &cmd);
+
+ processed = HandleCommand(id, cmd, hwnd);
+ }
+ break;
+
+#ifdef __WIN95__
+ case WM_NOTIFY:
+ processed = HandleNotify((int)wParam, lParam, &rc.result);
+ break;
+#endif // Win95
+
+ // for these messages we must return TRUE if process the message
+#ifdef WM_DRAWITEM
+ case WM_DRAWITEM:
+ case WM_MEASUREITEM:
+ {
+ int idCtrl = (UINT)wParam;
+ if ( message == WM_DRAWITEM )
+ {
+ processed = MSWOnDrawItem(idCtrl,
+ (WXDRAWITEMSTRUCT *)lParam);
+ }
+ else
+ {
+ processed = MSWOnMeasureItem(idCtrl,
+ (WXMEASUREITEMSTRUCT *)lParam);
+ }
+
+ if ( processed )
+ rc.result = TRUE;
+ }
+ break;
+#endif // defined(WM_DRAWITEM)
+
+ case WM_GETDLGCODE:
+ if ( !IsOfStandardClass() )
+ {
+ // we always want to get the char events
+ rc.result = DLGC_WANTCHARS;
+
+ if ( GetWindowStyleFlag() & wxWANTS_CHARS )
+ {
+ // in fact, we want everything
+ rc.result |= DLGC_WANTARROWS |
+ DLGC_WANTTAB |
+ DLGC_WANTALLKEYS;
+ }
+
+ processed = TRUE;
+ }
+ //else: get the dlg code from the DefWindowProc()
+ break;
+
+ case WM_SYSKEYDOWN:
+ case WM_KEYDOWN:
+ // If this has been processed by an event handler, return 0 now
+ // (we've handled it).
+ m_lastKeydownProcessed = HandleKeyDown((WORD) wParam, lParam);
+ if ( m_lastKeydownProcessed )
+ {
+ processed = TRUE;
+ break;
+ }
+
+ switch ( wParam )
+ {
+ // we consider these message "not interesting" to OnChar, so
+ // just don't do anything more with them
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ case VK_CAPITAL:
+ case VK_NUMLOCK:
+ case VK_SCROLL:
+ processed = TRUE;
+ break;
+
+ // avoid duplicate messages to OnChar for these ASCII keys:
+ // they will be translated by TranslateMessage() and received
+ // in WM_CHAR
+ case VK_ESCAPE:
+ case VK_SPACE:
+ case VK_RETURN:
+ case VK_BACK:
+ case VK_TAB:
+ case VK_ADD:
+ case VK_SUBTRACT:
+ case VK_MULTIPLY:
+ case VK_DIVIDE:
+ case VK_OEM_1:
+ case VK_OEM_2:
+ case VK_OEM_3:
+ case VK_OEM_4:
+ case VK_OEM_5:
+ case VK_OEM_6:
+ case VK_OEM_7:
+ case VK_OEM_PLUS:
+ case VK_OEM_COMMA:
+ case VK_OEM_MINUS:
+ case VK_OEM_PERIOD:
+ // but set processed to FALSE, not TRUE to still pass them
+ // to the control's default window proc - otherwise
+ // built-in keyboard handling won't work
+ processed = FALSE;
+
+ break;
+
+#ifdef VK_APPS
+ // special case of VK_APPS: treat it the same as right mouse
+ // click because both usually pop up a context menu
+ case VK_APPS:
+ {
+ WPARAM flags;
+ int x, y;
+
+ TranslateKbdEventToMouse(this, &x, &y, &flags);
+ processed = HandleMouseEvent(WM_RBUTTONDOWN, x, y, flags);
+ }
+ break;
+#endif // VK_APPS
+
+ default:
+ // do generate a CHAR event
+ processed = HandleChar((WORD)wParam, lParam);
+
+ }
+ break;
+
+ case WM_SYSKEYUP:
+ case WM_KEYUP:
+#ifdef VK_APPS
+ // special case of VK_APPS: treat it the same as right mouse button
+ if ( wParam == VK_APPS )
+ {
+ WPARAM flags;
+ int x, y;
+
+ TranslateKbdEventToMouse(this, &x, &y, &flags);
+ processed = HandleMouseEvent(WM_RBUTTONUP, x, y, flags);
+ }
+ else
+#endif // VK_APPS
+ {
+ processed = HandleKeyUp((WORD) wParam, lParam);
+ }
+ break;
+
+ case WM_SYSCHAR:
+ case WM_CHAR: // Always an ASCII character
+ if ( m_lastKeydownProcessed )
+ {
+ // The key was handled in the EVT_KEY_DOWN and handling
+ // a key in an EVT_KEY_DOWN handler is meant, by
+ // design, to prevent EVT_CHARs from happening
+ m_lastKeydownProcessed = FALSE;
+ processed = TRUE;
+ }
+ else
+ {
+ processed = HandleChar((WORD)wParam, lParam, TRUE);
+ }
+ break;
+
+ case WM_HSCROLL:
+ case WM_VSCROLL:
+ {
+ WXWORD code, pos;
+ WXHWND hwnd;
+ UnpackScroll(wParam, lParam, &code, &pos, &hwnd);
+
+ processed = MSWOnScroll(message == WM_HSCROLL ? wxHORIZONTAL
+ : wxVERTICAL,
+ code, pos, hwnd);
+ }
+ break;
+
+ // CTLCOLOR messages are sent by children to query the parent for their
+ // colors#ifndef __WXMICROWIN__
+#ifndef __WXMICROWIN__
+#ifdef __WIN32__
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLOREDIT:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORSTATIC:
+#else // Win16
+ case WM_CTLCOLOR:
+#endif // Win32/16
+ {
+ WXWORD nCtlColor;
+ WXHDC hdc;
+ WXHWND hwnd;
+ UnpackCtlColor(wParam, lParam, &nCtlColor, &hdc, &hwnd);
+
+ processed = HandleCtlColor(&rc.hBrush,
+ (WXHDC)hdc,
+ (WXHWND)hwnd,
+ nCtlColor,
+ message,
+ wParam,
+ lParam);
+ }
+ break;
+#endif // !__WXMICROWIN__
+
+ case WM_SYSCOLORCHANGE:
+ // the return value for this message is ignored
+ processed = HandleSysColorChange();
+ break;
+
+ case WM_DISPLAYCHANGE:
+ processed = HandleDisplayChange();
+ break;
+
+ case WM_PALETTECHANGED:
+ processed = HandlePaletteChanged((WXHWND) (HWND) wParam);
+ break;
+
+ case WM_CAPTURECHANGED:
+ processed = HandleCaptureChanged((WXHWND) (HWND) lParam);
+ break;
+
+ case WM_QUERYNEWPALETTE:
+ processed = HandleQueryNewPalette();
+ break;
+
+ case WM_ERASEBKGND:
+ processed = HandleEraseBkgnd((WXHDC)(HDC)wParam);
+ if ( processed )
+ {
+ // we processed the message, i.e. erased the background
+ rc.result = TRUE;
+ }
+ break;
+
+ case WM_DROPFILES:
+ processed = HandleDropFiles(wParam);
+ break;
+
+ case WM_INITDIALOG:
+ processed = HandleInitDialog((WXHWND)(HWND)wParam);
+
+ if ( processed )
+ {
+ // we never set focus from here
+ rc.result = FALSE;
+ }
+ break;
+
+ case WM_QUERYENDSESSION:
+ processed = HandleQueryEndSession(lParam, &rc.allow);
+ break;
+
+ case WM_ENDSESSION:
+ processed = HandleEndSession(wParam != 0, lParam);
+ break;
+
+ case WM_GETMINMAXINFO:
+ processed = HandleGetMinMaxInfo((MINMAXINFO*)lParam);
+ break;
+
+ case WM_SETCURSOR:
+ processed = HandleSetCursor((WXHWND)(HWND)wParam,
+ LOWORD(lParam), // hit test
+ HIWORD(lParam)); // mouse msg
+
+ if ( processed )
+ {
+ // returning TRUE stops the DefWindowProc() from further
+ // processing this message - exactly what we need because we've
+ // just set the cursor.
+ rc.result = TRUE;
+ }
+ break;
+
+#if defined(__WIN32__) && defined(WM_HELP)
+ case WM_HELP:
+ {
+ HELPINFO* info = (HELPINFO*) lParam;
+ // Don't yet process menu help events, just windows
+ if (info->iContextType == HELPINFO_WINDOW)
+ {
+ wxWindowMSW* subjectOfHelp = this;
+ bool eventProcessed = FALSE;
+ while (subjectOfHelp && !eventProcessed)
+ {
+ wxHelpEvent helpEvent(wxEVT_HELP,
+ subjectOfHelp->GetId(),
+ wxPoint(info->MousePos.x,
+ info->MousePos.y) );
+ helpEvent.SetEventObject(this);
+ eventProcessed =
+ GetEventHandler()->ProcessEvent(helpEvent);
+
+ // Go up the window hierarchy until the event is
+ // handled (or not)
+ subjectOfHelp = subjectOfHelp->GetParent();
+ }
+
+ processed = eventProcessed;
+ }
+ else if (info->iContextType == HELPINFO_MENUITEM)
+ {
+ wxHelpEvent helpEvent(wxEVT_HELP, info->iCtrlId);
+ helpEvent.SetEventObject(this);
+ processed = GetEventHandler()->ProcessEvent(helpEvent);
+
+ }
+ //else: processed is already FALSE
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ {
+ // we don't convert from screen to client coordinates as
+ // the event may be handled by a parent window
+ wxPoint pt(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
+
+ wxContextMenuEvent evtCtx(wxEVT_CONTEXT_MENU, GetId(), pt);
+ processed = GetEventHandler()->ProcessEvent(evtCtx);
+ }
+ break;
+#endif // __WIN32__
+ }
+
+ if ( !processed )
+ {
+#ifdef __WXDEBUG__
+ wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
+ wxGetMessageName(message));
+#endif // __WXDEBUG__
+ rc.result = MSWDefWindowProc(message, wParam, lParam);
+ }
+
+ return rc.result;
+}
+
+// ----------------------------------------------------------------------------
+// wxWindow <-> HWND map
+// ----------------------------------------------------------------------------
+
+wxWinHashTable *wxWinHandleHash = NULL;
+
+wxWindow *wxFindWinFromHandle(WXHWND hWnd)
+{
+ return wxWinHandleHash->Get((long)hWnd);
+}
+
+void wxAssociateWinWithHandle(HWND hWnd, wxWindowMSW *win)
+{
+ // adding NULL hWnd is (first) surely a result of an error and
+ // (secondly) breaks menu command processing
+ wxCHECK_RET( hWnd != (HWND)NULL,
+ wxT("attempt to add a NULL hWnd to window list ignored") );
+
+ wxWindow *oldWin = wxFindWinFromHandle((WXHWND) hWnd);
+#ifdef __WXDEBUG__
+ if ( oldWin && (oldWin != win) )
+ {
+ wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
+ (int) hWnd, win->GetClassInfo()->GetClassName());
+ }
+ else
+#endif // __WXDEBUG__
+ if (!oldWin)
+ {
+ wxWinHandleHash->Put((long)hWnd, (wxWindow *)win);
+ }
+}
+
+void wxRemoveHandleAssociation(wxWindowMSW *win)
+{
+ wxWinHandleHash->Delete((long)win->GetHWND());
+}
+
+// ----------------------------------------------------------------------------
+// various MSW speciic class dependent functions
+// ----------------------------------------------------------------------------
+
+// Default destroyer - override if you destroy it in some other way
+// (e.g. with MDI child windows)
+void wxWindowMSW::MSWDestroyWindow()
+{
+}
+
+bool wxWindowMSW::MSWGetCreateWindowCoords(const wxPoint& pos,
+ const wxSize& size,
+ int& x, int& y,
+ int& w, int& h) const
+{
+ static const int DEFAULT_Y = 200;
+ static const int DEFAULT_H = 250;
+
+ bool nonDefault = FALSE;
+
+ if ( pos.x == -1 )
+ {
+ // if set x to CW_USEDEFAULT, y parameter is ignored anyhow so we can
+ // just as well set it to CW_USEDEFAULT as well
+ x =
+ y = CW_USEDEFAULT;
+ }
+ else
+ {
+ // OTOH, if x is not set to CW_USEDEFAULT, y shouldn't be set to it
+ // neither because it is not handled as a special value by Windows then
+ // and so we have to choose some default value for it
+ x = pos.x;
+ y = pos.y == -1 ? DEFAULT_Y : pos.y;
+
+ nonDefault = TRUE;
+ }
+
+ /*
+ NB: there used to be some code here which set the initial size of the
+ window to the client size of the parent if no explicit size was
+ specified. This was wrong because wxWindows programs often assume
+ that they get a WM_SIZE (EVT_SIZE) upon creation, however this broke
+ it. To see why, you should understand that Windows sends WM_SIZE from
+ inside ::CreateWindow() anyhow. However, ::CreateWindow() is called
+ from some base class ctor and so this WM_SIZE is not processed in the
+ real class' OnSize() (because it's not fully constructed yet and the
+ event goes to some base class OnSize() instead). So the WM_SIZE we
+ rely on is the one sent when the parent frame resizes its children
+ but here is the problem: if the child already has just the right
+ size, nothing will happen as both wxWindows and Windows check for
+ this and ignore any attempts to change the window size to the size it
+ already has - so no WM_SIZE would be sent.
+ */
+ if ( size.x == -1 )
+ {
+ // as above, h is not used at all in this case anyhow
+ w =
+ h = CW_USEDEFAULT;
+ }
+ else
+ {
+ // and, again as above, we can't set the height to CW_USEDEFAULT here
+ w = size.x;
+ h = size.y == -1 ? DEFAULT_H : size.y;
+
+ nonDefault = TRUE;
+ }
+
+ return nonDefault;
+}
+
+WXHWND wxWindowMSW::MSWGetParent() const
+{
+ return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
+}
+
+bool wxWindowMSW::MSWCreate(const wxChar *wclass,
+ const wxChar *title,
+ const wxPoint& pos,
+ const wxSize& size,
+ WXDWORD style,
+ WXDWORD extendedStyle)
+{
+ // choose the position/size for the new window
+ int x, y, w, h;
+ (void)MSWGetCreateWindowCoords(pos, size, x, y, w, h);
+
+ // controlId is menu handle for the top level windows, so set it to 0
+ // unless we're creating a child window
+ int controlId = style & WS_CHILD ? GetId() : 0;
+
+ // for each class "Foo" we have we also have "FooNR" ("no repaint") class
+ // which is the same but without CS_[HV]REDRAW class styles so using it
+ // ensures that the window is not fully repainted on each resize
+ wxString className(wclass);
+ if ( GetWindowStyleFlag() & wxNO_FULL_REPAINT_ON_RESIZE )
+ {
+ className += wxT("NR");
+ }
+
+ // do create the window
+ wxWindowCreationHook hook(this);
+
+ m_hWnd = (WXHWND)::CreateWindowEx
+ (
+ extendedStyle,
+ className,
+ title ? title : wxT(""),
+ style,
+ x, y, w, h,
+ (HWND)MSWGetParent(),
+ (HMENU)controlId,
+ wxGetInstance(),
+ NULL // no extra data
+ );
+
+ if ( !m_hWnd )
+ {
+ wxLogSysError(_("Can't create window of class %s"), wclass);
+
+ return FALSE;
+ }
+
+ SubclassWin(m_hWnd);
+
+ SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
+
+ return TRUE;
+}
+
+// ===========================================================================
+// MSW message handlers
+// ===========================================================================
+
+// ---------------------------------------------------------------------------
+// WM_NOTIFY
+// ---------------------------------------------------------------------------
+
+#ifdef __WIN95__
+
+bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
+{
+#ifndef __WXMICROWIN__
+ LPNMHDR hdr = (LPNMHDR)lParam;
+ HWND hWnd = hdr->hwndFrom;
+ wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
+
+ // if the control is one of our windows, let it handle the message itself
+ if ( win )
+ {
+ return win->MSWOnNotify(idCtrl, lParam, result);
+ }
+
+ // VZ: why did we do it? normally this is unnecessary and, besides, it
+ // breaks the message processing for the toolbars because the tooltip
+ // notifications were being forwarded to the toolbar child controls
+ // (if it had any) before being passed to the toolbar itself, so in my
+ // example the tooltip for the combobox was always shown instead of the
+ // correct button tooltips
+#if 0
+ // try all our children
+ wxWindowList::Node *node = GetChildren().GetFirst();
+ while ( node )
+ {
+ wxWindow *child = node->GetData();
+ if ( child->MSWOnNotify(idCtrl, lParam, result) )
+ {
+ return TRUE;
+ }
+
+ node = node->GetNext();
+ }
+#endif // 0
+
+ // by default, handle it ourselves
+ return MSWOnNotify(idCtrl, lParam, result);
+#else // __WXMICROWIN__
+ return FALSE;
+#endif
+}
+
+#if wxUSE_TOOLTIPS
+
+bool wxWindowMSW::HandleTooltipNotify(WXUINT code,
+ WXLPARAM lParam,
+ const wxString& ttip)
+{
+ // I don't know why it happens, but the versions of comctl32.dll starting
+ // from 4.70 sometimes send TTN_NEEDTEXTW even to ANSI programs (normally,
+ // this message is supposed to be sent to Unicode programs only) -- hence
+ // we need to handle it as well, otherwise no tooltips will be shown in
+ // this case
+
+ if ( !(code == (WXUINT) TTN_NEEDTEXTA || code == (WXUINT) TTN_NEEDTEXTW) || ttip.empty() )
+ {
+ // not a tooltip message or no tooltip to show anyhow
+ return FALSE;
+ }
+
+ LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
+
+ if ( code == (WXUINT) TTN_NEEDTEXTA )
+ {
+ ttText->lpszText = (wxChar *)ttip.c_str();
+ }
+ else
+ {
+#if wxUSE_UNICODE
+ ttText->lpszText = (wxChar *)ttip.c_str();
+#else // !Unicode
+ size_t lenAnsi = ttip.length();
+
+ // some compilers (MetroWerks and Cygwin) don't like calling mbstowcs
+ // with NULL argument
+ #if defined( __MWERKS__ ) || defined( __CYGWIN__ )
+ size_t lenUnicode = 2*lenAnsi;
+ #else
+ size_t lenUnicode = mbstowcs(NULL, ttip, lenAnsi);
+ #endif
+
+ // using the pointer of right type avoids us doing all sorts of
+ // pointer arithmetics ourselves
+ wchar_t *dst = (wchar_t *)ttText->szText,
+ *pwz = new wchar_t[lenUnicode + 1];
+ mbstowcs(pwz, ttip, lenAnsi + 1);
+ memcpy(dst, pwz, lenUnicode*sizeof(wchar_t));
+
+ // put the terminating wide NUL
+ dst[lenUnicode] = L'\0';
+
+ delete [] pwz;
+#endif // Unicode/!Unicode
+ }
+
+ return TRUE;
+}
+
+#endif // wxUSE_TOOLTIPS
+
+bool wxWindowMSW::MSWOnNotify(int WXUNUSED(idCtrl),
+ WXLPARAM lParam,
+ WXLPARAM* WXUNUSED(result))
+{
+#if wxUSE_TOOLTIPS
+ if ( m_tooltip )
+ {
+ NMHDR* hdr = (NMHDR *)lParam;
+ if ( HandleTooltipNotify(hdr->code, lParam, m_tooltip->GetTip()))
+ {
+ // processed
+ return TRUE;
+ }
+ }
+#endif // wxUSE_TOOLTIPS
+
+ return FALSE;
+}
+
+#endif // __WIN95__
+
+// ---------------------------------------------------------------------------
+// end session messages
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandleQueryEndSession(long logOff, bool *mayEnd)
+{
+ wxCloseEvent event(wxEVT_QUERY_END_SESSION, -1);
+ event.SetEventObject(wxTheApp);
+ event.SetCanVeto(TRUE);
+ event.SetLoggingOff(logOff == (long)ENDSESSION_LOGOFF);
+
+ bool rc = wxTheApp->ProcessEvent(event);
+
+ if ( rc )
+ {
+ // we may end only if the app didn't veto session closing (double
+ // negation...)
+ *mayEnd = !event.GetVeto();
+ }
+
+ return rc;
+}
+
+bool wxWindowMSW::HandleEndSession(bool endSession, long logOff)
+{
+ // do nothing if the session isn't ending
+ if ( !endSession )
+ return FALSE;
+
+ // only send once
+ if ( (this != wxTheApp->GetTopWindow()) )
+ return FALSE;
+
+ wxCloseEvent event(wxEVT_END_SESSION, -1);
+ event.SetEventObject(wxTheApp);
+ event.SetCanVeto(FALSE);
+ event.SetLoggingOff( (logOff == (long)ENDSESSION_LOGOFF) );
+
+ return wxTheApp->ProcessEvent(event);
+}
+
+// ---------------------------------------------------------------------------
+// window creation/destruction
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandleCreate(WXLPCREATESTRUCT cs, bool *mayCreate)
+{
+ // if we have WS_EX_CONTROLPARENT flag we absolutely *must* set it for our
+ // parent as well as otherwise several Win32 functions using
+ // GetNextDlgTabItem() to iterate over all controls such as
+ // IsDialogMessage() or DefDlgProc() would enter an infinite loop: indeed,
+ // all of them iterate over all the controls starting from the focus and
+ // stop iterating when they get back to the focus but unless all parents
+ // have WS_EX_CONTROLPARENT bit set, they would never get back to focus
+ if ( ((CREATESTRUCT *)cs)->dwExStyle & WS_EX_CONTROLPARENT )
+ {
+ // there is no need to do anything for the top level windows
+ const wxWindow *parent = GetParent();
+ while ( parent && !parent->IsTopLevel() )
+ {
+ LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE);
+ if ( !(exStyle & WS_EX_CONTROLPARENT) )
+ {
+ // force the parent to have this style
+ ::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE,
+ exStyle | WS_EX_CONTROLPARENT);
+ }
+
+ parent = parent->GetParent();
+ }
+ }
+
+ // TODO: should generate this event from WM_NCCREATE
+ wxWindowCreateEvent event((wxWindow *)this);
+ (void)GetEventHandler()->ProcessEvent(event);
+
+ *mayCreate = TRUE;
+
+ return TRUE;
+}
+
+bool wxWindowMSW::HandleDestroy()
+{
+ wxWindowDestroyEvent event((wxWindow *)this);
+ (void)GetEventHandler()->ProcessEvent(event);
+
+ // delete our drop target if we've got one
+#if wxUSE_DRAG_AND_DROP
+ if ( m_dropTarget != NULL )
+ {
+ m_dropTarget->Revoke(m_hWnd);
+
+ delete m_dropTarget;
+ m_dropTarget = NULL;
+ }
+#endif // wxUSE_DRAG_AND_DROP
+
+ // WM_DESTROY handled
+ return TRUE;
+}
+
+// ---------------------------------------------------------------------------
+// activation/focus
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandleActivate(int state,
+ bool WXUNUSED(minimized),
+ WXHWND WXUNUSED(activate))
+{
+ wxActivateEvent event(wxEVT_ACTIVATE,
+ (state == WA_ACTIVE) || (state == WA_CLICKACTIVE),
+ m_windowId);
+ event.SetEventObject(this);
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleSetFocus(WXHWND hwnd)
+{
+ // notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it
+ wxChildFocusEvent eventFocus((wxWindow *)this);
+ (void)GetEventHandler()->ProcessEvent(eventFocus);
+
+#if wxUSE_CARET
+ // Deal with caret
+ if ( m_caret )
+ {
+ m_caret->OnSetFocus();
+ }
+#endif // wxUSE_CARET
+
+#if wxUSE_TEXTCTRL
+ // If it's a wxTextCtrl don't send the event as it will be done
+ // after the control gets to process it from EN_FOCUS handler
+ if ( wxDynamicCastThis(wxTextCtrl) )
+ {
+ return FALSE;
+ }
+#endif // wxUSE_TEXTCTRL
+
+ wxFocusEvent event(wxEVT_SET_FOCUS, m_windowId);
+ event.SetEventObject(this);
+
+ // wxFindWinFromHandle() may return NULL, it is ok
+ event.SetWindow(wxFindWinFromHandle(hwnd));
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleKillFocus(WXHWND hwnd)
+{
+#if wxUSE_CARET
+ // Deal with caret
+ if ( m_caret )
+ {
+ m_caret->OnKillFocus();
+ }
+#endif // wxUSE_CARET
+
+#if wxUSE_TEXTCTRL
+ // If it's a wxTextCtrl don't send the event as it will be done
+ // after the control gets to process it.
+ wxTextCtrl *ctrl = wxDynamicCastThis(wxTextCtrl);
+ if ( ctrl )
+ {
+ return FALSE;
+ }
+#endif
+
+ // Don't send the event when in the process of being deleted. This can
+ // only cause problems if the event handler tries to access the object.
+ if ( m_isBeingDeleted )
+ {
+ return FALSE;
+ }
+
+ wxFocusEvent event(wxEVT_KILL_FOCUS, m_windowId);
+ event.SetEventObject(this);
+
+ // wxFindWinFromHandle() may return NULL, it is ok
+ event.SetWindow(wxFindWinFromHandle(hwnd));
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+// ---------------------------------------------------------------------------
+// miscellaneous
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::HandleShow(bool show, int WXUNUSED(status))
+{
+ wxShowEvent event(GetId(), show);
+ event.m_eventObject = this;
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleInitDialog(WXHWND WXUNUSED(hWndFocus))
+{
+ wxInitDialogEvent event(GetId());
+ event.m_eventObject = this;
+
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+bool wxWindowMSW::HandleDropFiles(WXWPARAM wParam)
+{
+#ifndef __WXMICROWIN__
+ HDROP hFilesInfo = (HDROP) wParam;
+
+ // Get the total number of files dropped
+ UINT gwFilesDropped = ::DragQueryFile
+ (
+ (HDROP)hFilesInfo,
+ (UINT)-1,
+ (LPTSTR)0,
+ (UINT)0
+ );
+
+ wxString *files = new wxString[gwFilesDropped];
+ for ( UINT wIndex = 0; wIndex < gwFilesDropped; wIndex++ )
+ {
+ // first get the needed buffer length (+1 for terminating NUL)
+ size_t len = ::DragQueryFile(hFilesInfo, wIndex, NULL, 0) + 1;
+
+ // and now get the file name
+ ::DragQueryFile(hFilesInfo, wIndex,
+ files[wIndex].GetWriteBuf(len), len);
+
+ files[wIndex].UngetWriteBuf();
+ }
+ DragFinish (hFilesInfo);
+
+ wxDropFilesEvent event(wxEVT_DROP_FILES, gwFilesDropped, files);
+ event.m_eventObject = this;
+
+ POINT dropPoint;
+ DragQueryPoint(hFilesInfo, (LPPOINT) &dropPoint);
+ event.m_pos.x = dropPoint.x;
+ event.m_pos.y = dropPoint.y;
+
+ return GetEventHandler()->ProcessEvent(event);
+#else // __WXMICROWIN__
+ return FALSE;
+#endif
+}
+
+bool wxWindowMSW::HandleSetCursor(WXHWND WXUNUSED(hWnd),
+ short nHitTest,
+ int WXUNUSED(mouseMsg))
+{
+#ifndef __WXMICROWIN__
+ // the logic is as follows:
+ // -1. don't set cursor for non client area, including but not limited to
+ // the title bar, scrollbars, &c
+ // 0. allow the user to override default behaviour by using EVT_SET_CURSOR
+ // 1. if we have the cursor set it unless wxIsBusy()
+ // 2. if we're a top level window, set some cursor anyhow
+ // 3. if wxIsBusy(), set the busy cursor, otherwise the global one
+
+ if ( nHitTest != HTCLIENT )
+ {
+ return FALSE;
+ }
+
+ HCURSOR hcursor = 0;
+
+ // first ask the user code - it may wish to set the cursor in some very
+ // specific way (for example, depending on the current position)
+ POINT pt;
+#ifdef __WIN32__
+ if ( !::GetCursorPos(&pt) )
+ {
+ wxLogLastError(wxT("GetCursorPos"));
+ }
+#else
+ // In WIN16 it doesn't return a value.
+ ::GetCursorPos(&pt);
+#endif
+
+ int x = pt.x,
+ y = pt.y;
+ ScreenToClient(&x, &y);
+ wxSetCursorEvent event(x, y);
+
+ bool processedEvtSetCursor = GetEventHandler()->ProcessEvent(event);
+ if ( processedEvtSetCursor && event.HasCursor() )
+ {
+ hcursor = GetHcursorOf(event.GetCursor());
+ }
+
+ if ( !hcursor )
+ {
+ bool isBusy = wxIsBusy();
+
+ // the test for processedEvtSetCursor is here to prevent using m_cursor
+ // if the user code caught EVT_SET_CURSOR() and returned nothing from
+ // it - this is a way to say that our cursor shouldn't be used for this
+ // point
+ if ( !processedEvtSetCursor && m_cursor.Ok() )
+ {
+ hcursor = GetHcursorOf(m_cursor);
+ }
+
+ if ( !GetParent() )
+ {
+ if ( isBusy )
+ {
+ hcursor = wxGetCurrentBusyCursor();
+ }
+ else if ( !hcursor )
+ {
+ const wxCursor *cursor = wxGetGlobalCursor();
+ if ( cursor && cursor->Ok() )
+ {
+ hcursor = GetHcursorOf(*cursor);
+ }
+ }
+ }
+ }
+
+ if ( hcursor )
+ {
+ ::SetCursor(hcursor);
+
+ // cursor set, stop here
+ return TRUE;
+ }
+#endif // __WXMICROWIN__
+
+ // pass up the window chain
+ return FALSE;
+}
+
+// ---------------------------------------------------------------------------
+// owner drawn stuff
+// ---------------------------------------------------------------------------
+
+bool wxWindowMSW::MSWOnDrawItem(int id, WXDRAWITEMSTRUCT *itemStruct)
+{
+#if wxUSE_OWNER_DRAWN
+
+#if wxUSE_MENUS_NATIVE
+ // is it a menu item?
+ DRAWITEMSTRUCT *pDrawStruct = (DRAWITEMSTRUCT *)itemStruct;
+ if ( id == 0 && pDrawStruct->CtlType == ODT_MENU )
+ {
+ wxMenuItem *pMenuItem = (wxMenuItem *)(pDrawStruct->itemData);