m_mouseInWindow = FALSE;
m_lastKeydownProcessed = FALSE;
+ m_childrenDisabled = NULL;
+
// wxWnd
m_hMenu = 0;
// remove hWnd <-> wxWindow association
wxRemoveHandleAssociation(this);
}
+
+ delete m_childrenDisabled;
}
// real construction (Init() must have been called before!)
{
wxCHECK_MSG( parent, FALSE, wxT("can't create wxWindow without parent") );
-#if wxUSE_STATBOX
- // wxGTK doesn't allow to create controls with static box as the parent so
- // this will result in a crash when the program is ported to wxGTK - warn
- // about it
- //
- // the correct solution is to create the controls as siblings of the
- // static box
- wxASSERT_MSG( !wxDynamicCast(parent, wxStaticBox),
- _T("wxStaticBox can't be used as a window parent!") );
-#endif // wxUSE_STATBOX
-
if ( !CreateBase(parent, id, pos, size, style, wxDefaultValidator, name) )
return FALSE;
if ( hWnd )
::EnableWindow(hWnd, (BOOL)enable);
- // VZ: no, this is a bad idea: imagine that you have a dialog with some
- // disabled controls and disable it - you really wouldn't like the
- // disabled controls be reenabled too when you reenable the dialog!
-#if 0
- wxWindowList::Node *node = GetChildren().GetFirst();
- while ( node )
+ // the logic below doesn't apply to the top level windows -- otherwise
+ // showing a modal dialog would result in total greying out (and ungreying
+ // out later) of everything which would be really ugly
+ if ( IsTopLevel() )
+ return TRUE;
+
+ // when the parent is disabled, all of its children should be disabled as
+ // well but when it is enabled back, only those of the children which
+ // hadn't been already disabled in the beginning should be enabled again,
+ // so we have to keep the list of those children
+ for ( wxWindowList::Node *node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
{
wxWindow *child = node->GetData();
- child->Enable(enable);
+ if ( child->IsTopLevel() )
+ {
+ // the logic below doesn't apply to top level children
+ continue;
+ }
- node = node->GetNext();
+ if ( enable )
+ {
+ // enable the child back unless it had been disabled before us
+ if ( !m_childrenDisabled || !m_childrenDisabled->Find(child) )
+ child->Enable();
+ }
+ else // we're being disabled
+ {
+ if ( child->IsEnabled() )
+ {
+ // disable it as children shouldn't stay enabled while the
+ // parent is not
+ child->Disable();
+ }
+ else // child already disabled, remember it
+ {
+ // have we created the list of disabled children already?
+ if ( !m_childrenDisabled )
+ m_childrenDisabled = new wxWindowList;
+
+ m_childrenDisabled->Append(child);
+ }
+ }
+ }
+
+ if ( enable && m_childrenDisabled )
+ {
+ // we don't need this list any more, don't keep unused memory
+ delete m_childrenDisabled;
+ m_childrenDisabled = NULL;
}
-#endif // 0
return TRUE;
}
bool wxCheckWindowWndProc(WXHWND hWnd, WXFARPROC wndProc)
{
-#if wxUSE_UNICODE_MSLU
- // VS: We can't use GetWindowLong(hwnd, GWL_WNDPROC) together with unicows.dll
- // because it doesn't return pointer to the real wnd proc but rather a handle
- // of a fake proc that does Unicode<->ANSI translation.
- //
- // The hack bellow works, because WNDCLASS contains original window handler
- // rather that the unicows fake one. This may not be on purpose, though; if
- // it stops working with future versions of unicows.dll, we can override
- // unicows hooks by setting Unicows_{Set,Get}WindowLong and
- // Unicows_RegisterClass to our own versions that keep track of
- // fake<->real wnd proc mapping.
- //
- // FIXME: Doesn't handle wnd procs set by SetWindowLong, only these set
- // with RegisterClass!!
-
- if ( wxUsingUnicowsDll() )
+ // Unicows note: the code below works, but only because WNDCLASS contains
+ // original window handler rather that the unicows fake one. This may not
+ // be on purpose, though; if it stops working with future versions of
+ // unicows.dll, we can override unicows hooks by setting
+ // Unicows_{Set,Get}WindowLong and Unicows_RegisterClass to our own
+ // versions that keep track of fake<->real wnd proc mapping.
+ WNDCLASS cls;
+ if ( !::GetClassInfo(wxGetInstance(), wxGetWindowClass(hWnd), &cls) )
{
- static wxChar buffer[512];
- WNDCLASS cls;
+ wxLogLastError(_T("GetClassInfo"));
- ::GetClassName((HWND)hWnd, buffer, 512);
- ::GetClassInfo(wxGetInstance(), buffer, &cls);
- return wndProc == (WXFARPROC)cls.lpfnWndProc;
- }
- else
-#endif
- {
- return wndProc == (WXFARPROC)::GetWindowLong((HWND)hWnd, GWL_WNDPROC);
+ return FALSE;
}
+
+ return wndProc == (WXFARPROC)cls.lpfnWndProc;
}
// ----------------------------------------------------------------------------
wxWindowBase::DoSetToolTip(tooltip);
if ( m_tooltip )
- m_tooltip->SetWindow(this);
+ m_tooltip->SetWindow((wxWindow *)this);
}
#endif // wxUSE_TOOLTIPS
{
wxTheApp->DoMessage((WXMSG *)&msg);
}
+
+ // If we retrieved a WM_QUIT, insert back into the message queue.
+ if (msg.message == WM_QUIT)
+ ::PostQuitMessage(0);
}
bool wxWindowMSW::DoPopupMenu(wxMenu *menu, int x, int y)
if ( !bCtrlDown )
{
lDlgCode = ::SendMessage(msg->hwnd, WM_GETDLGCODE, 0, 0);
+
+ // surprizingly, DLGC_WANTALLKEYS bit mask doesn't contain the
+ // DLGC_WANTTAB nor DLGC_WANTARROWS bits although, logically,
+ // it, of course, implies them
+ if ( lDlgCode & DLGC_WANTALLKEYS )
+ {
+ lDlgCode |= DLGC_WANTTAB | DLGC_WANTARROWS;
+ }
}
bool bForward = TRUE,
// eat the Enter events sometimes
return FALSE;
}
+ else if (!IsTopLevel())
+ {
+ // if not a top level window, let parent
+ // handle it
+ return FALSE;
+ }
//else: treat Enter as TAB: pass to the next
// control as this is the best thing to do
// if the text doesn't handle Enter itself
{
// trace all messages - useful for the debugging
#ifdef __WXDEBUG__
+#if wxUSE_LOG
wxLogTrace(wxTraceMessages, wxT("Processing %s(wParam=%8lx, lParam=%8lx)"),
- wxGetMessageName(message), wParam, lParam);
+ wxGetMessageName(message), (long) wParam, lParam);
+#endif // wxUSE_LOG
#endif // __WXDEBUG__
wxWindowMSW *wnd = wxFindWinFromHandle((WXHWND) hWnd);
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);
else
{
win = FindWindowForMouseEvent(this, &x, &y);
+
+ // this should never happen
+ wxCHECK_MSG( win, 0,
+ _T("FindWindowForMouseEvent() returned NULL") );
+
+ // for the standard classes their WndProc sets the focus to
+ // them anyhow and doing it from here results in some weird
+ // problems, but for our windows we want them to acquire
+ // focus when clicked
+ if ( !win->IsOfStandardClass() )
+ {
+ if ( message == WM_LBUTTONDOWN && win->AcceptsFocus() )
+ win->SetFocus();
+ }
}
processed = win->HandleMouseEvent(message, x, y, wParam);
if ( m_lastKeydownProcessed )
{
processed = TRUE;
- break;
}
- switch ( wParam )
+ if ( !processed )
{
- // 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;
+ 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;
- 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;
+ // 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;
+ 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);
-
+ default:
+ // do generate a CHAR event
+ processed = HandleChar((WORD)wParam, lParam);
+ }
}
+ if (message == WM_SYSKEYDOWN) // Let Windows still handle the SYSKEYs
+ processed = FALSE;
break;
case WM_SYSKEYUP:
processed = GetEventHandler()->ProcessEvent(evtCtx);
}
break;
+
+ case WM_MENUCHAR:
+ // we're only interested in our own menus, not MF_SYSMENU
+ if ( HIWORD(wParam) == MF_POPUP )
+ {
+ // handle menu chars for ownerdrawn menu items
+ int i = HandleMenuChar(toupper(LOWORD(wParam)), lParam);
+ if ( i != wxNOT_FOUND )
+ {
+ rc.result = MAKELRESULT(i, MNC_EXECUTE);
+ processed = TRUE;
+ }
+ }
+ break;
#endif // __WIN32__
}
if ( !processed )
{
#ifdef __WXDEBUG__
+#if wxUSE_LOG
wxLogTrace(wxTraceMessages, wxT("Forwarding %s to DefWindowProc."),
wxGetMessageName(message));
+#endif // wxUSE_LOG
#endif // __WXDEBUG__
rc.result = MSWDefWindowProc(message, wParam, lParam);
}
if ( oldWin && (oldWin != win) )
{
wxLogDebug(wxT("HWND %X already associated with another window (%s)"),
- hWnd, win->GetClassInfo()->GetClassName());
+ (int) hWnd, win->GetClassInfo()->GetClassName());
}
else
#endif // __WXDEBUG__
WXHWND wxWindowMSW::MSWGetParent() const
{
- return m_parent ? m_parent->GetHWND() : NULL;
+ return m_parent ? m_parent->GetHWND() : WXHWND(NULL);
}
bool wxWindowMSW::MSWCreate(const wxChar *wclass,
// ---------------------------------------------------------------------------
#ifdef __WIN95__
-// FIXME: VZ: I'm not sure at all that the order of processing is correct
+
bool wxWindowMSW::HandleNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
{
#ifndef __WXMICROWIN__
HWND hWnd = hdr->hwndFrom;
wxWindow *win = wxFindWinFromHandle((WXHWND)hWnd);
- // is this one of our windows?
+ // 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 )
node = node->GetNext();
}
+#endif // 0
- // finally try this window too (catches toolbar case)
+ // by default, handle it ourselves
return MSWOnNotify(idCtrl, lParam, result);
#else // __WXMICROWIN__
return FALSE;
// we need to handle it as well, otherwise no tooltips will be shown in
// this case
- if ( !(code == TTN_NEEDTEXTA || code == TTN_NEEDTEXTW) || ttip.empty() )
+ 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 == TTN_NEEDTEXTA )
+#if !wxUSE_UNICODE
+ if ( code == (WXUINT) TTN_NEEDTEXTA )
{
- ttText->lpszText = (wxChar *)ttip.c_str();
+ // we pass just the pointer as we store the string internally anyhow
+ ttText->lpszText = (char *)ttip.c_str();
}
- else
+ else // TTN_NEEDTEXTW
+#endif // !Unicode
{
#if wxUSE_UNICODE
+ // in Unicode mode this is just what we need
ttText->lpszText = (wxChar *)ttip.c_str();
#else // !Unicode
- size_t lenAnsi = ttip.length();
+ // in ANSI mode we have to convert the string and put it into the
+ // provided buffer: be careful not to overrun it
+ const size_t lenAnsi = ttip.length();
// some compilers (MetroWerks and Cygwin) don't like calling mbstowcs
// with NULL argument
wchar_t *dst = (wchar_t *)ttText->szText,
*pwz = new wchar_t[lenUnicode + 1];
mbstowcs(pwz, ttip, lenAnsi + 1);
+
+ // stay inside the buffer (-1 because it must be NUL-terminated)
+ if ( lenUnicode > WXSIZEOF(ttText->szText) - 1 )
+ {
+ lenUnicode = WXSIZEOF(ttText->szText) - 1;
+ }
+
memcpy(dst, pwz, lenUnicode*sizeof(wchar_t));
// put the terminating wide NUL
return FALSE;
}
+
#endif // __WIN95__
// ---------------------------------------------------------------------------
{
// there is no need to do anything for the top level windows
const wxWindow *parent = GetParent();
- if ( parent && !parent->IsTopLevel() )
+ while ( parent && !parent->IsTopLevel() )
{
LONG exStyle = ::GetWindowLong(GetHwndOf(parent), GWL_EXSTYLE);
if ( !(exStyle & WS_EX_CONTROLPARENT) )
::SetWindowLong(GetHwndOf(parent), GWL_EXSTYLE,
exStyle | WS_EX_CONTROLPARENT);
}
+
+ parent = parent->GetParent();
}
}
}
#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);
if ( hcursor )
{
+// wxLogDebug("HandleSetCursor: Setting cursor %ld", (long) hcursor);
+
::SetCursor(hcursor);
// cursor set, stop here
if ( hWndPalChange != GetHWND() )
{
// check to see if we our our parents have a custom palette
- wxWindow *win = this;
+ wxWindowMSW *win = this;
while ( win && !win->HasCustomPalette() )
{
win = win->GetParent();
#if wxUSE_PALETTE
// check to see if we our our parents have a custom palette
- wxWindow *win = this;
+ wxWindowMSW *win = this;
while (!win->HasCustomPalette() && win->GetParent()) win = win->GetParent();
if (win->HasCustomPalette()) {
/* realize the palette to see whether redrawing is needed */
int id;
if ( isASCII )
{
- // If 1 -> 26, translate to CTRL plus a letter.
+ // If 1 -> 26, translate to either special keycode or just set
+ // ctrlDown. IOW, Ctrl-C should result in keycode == 3 and
+ // ControlDown() == TRUE.
id = wParam;
if ( (id > 0) && (id < 27) )
{
default:
ctrlDown = TRUE;
- id = id + 'a' - 1;
+ break;
}
}
}
}
wxKeyEvent event(CreateKeyEvent(wxEVT_CHAR, id, lParam, wParam));
- if ( ctrlDown )
+
+ // the alphanumeric keys produced by pressing AltGr+something on European
+ // keyboards have both Ctrl and Alt modifiers which may confuse the user
+ // code as, normally, keys with Ctrl and/or Alt don't result in anything
+ // alphanumeric, so pretend that there are no modifiers at all (the
+ // KEY_DOWN event would still have the correct modifiers if they're really
+ // needed)
+ if ( event.m_controlDown && event.m_altDown &&
+ (id >= 32 && id < 256) )
{
- event.m_controlDown = TRUE;
+ event.m_controlDown =
+ event.m_altDown = FALSE;
}
return GetEventHandler()->ProcessEvent(event);
return FALSE;
}
+#ifdef __WIN32__
+
+int wxWindowMSW::HandleMenuChar(int chAccel, WXLPARAM lParam)
+{
+ const HMENU hmenu = (HMENU)lParam;
+
+ MENUITEMINFO mii;
+ wxZeroMemory(mii);
+ mii.cbSize = sizeof(MENUITEMINFO);
+ mii.fMask = MIIM_TYPE | MIIM_DATA;
+
+ // find if we have this letter in any owner drawn item
+ const int count = ::GetMenuItemCount(hmenu);
+ for ( int i = 0; i < count; i++ )
+ {
+ if ( ::GetMenuItemInfo(hmenu, i, TRUE, &mii) )
+ {
+ if ( mii.fType == MFT_OWNERDRAW )
+ {
+ // dwItemData member of the MENUITEMINFO is a
+ // pointer to the associated wxMenuItem -- see the
+ // menu creation code
+ wxMenuItem *item = (wxMenuItem*)mii.dwItemData;
+
+ const wxChar *p = wxStrchr(item->GetText(), _T('&'));
+ while ( p++ )
+ {
+ if ( *p == _T('&') )
+ {
+ // this is not the accel char, find the real one
+ p = wxStrchr(p + 1, _T('&'));
+ }
+ else // got the accel char
+ {
+ // FIXME-UNICODE: this comparison doesn't risk to work
+ // for non ASCII accelerator characters I'm afraid, but
+ // what can we do?
+ if ( wxToupper(*p) == chAccel )
+ {
+ return i;
+ }
+ else
+ {
+ // this one doesn't match
+ break;
+ }
+ }
+ }
+ }
+ }
+ else // failed ot get the menu text?
+ {
+ // it's not fatal, so don't show error, but still log
+ // it
+ wxLogLastError(_T("GetMenuItemInfo"));
+ }
+ }
+
+ return wxNOT_FOUND;
+}
+
+#endif // __WIN32__
+
// ---------------------------------------------------------------------------
// joystick
// ---------------------------------------------------------------------------
// avoids warning about statement with no effect (FreeProcInstance
// doesn't do anything under Win32)
-#if !defined(WIN32) && !defined(_WIN32) && !defined(__WIN32__) && !defined(__NT__) && !defined(__GNUWIN32__)
+#if !defined(__WIN32__) && !defined(__NT__)
FreeProcInstance(wxTheKeyboardHookProc);
#endif
}
// Find the wxWindow at the current mouse position, returning the mouse
// position.
-wxWindow* wxFindWindowAtPointer(wxPoint& WXUNUSED(pt))
+wxWindow* wxFindWindowAtPointer(wxPoint& pt)
{
- return wxFindWindowAtPoint(wxGetMousePosition());
+ pt = wxGetMousePosition();
+ return wxFindWindowAtPoint(pt);
}
wxWindow* wxFindWindowAtPoint(const wxPoint& pt)