Merge remote-tracking branch 'github/osx-fixes'

Several fixes for wxOSX, including several focus-related changes.

See https://github.com/wxWidgets/wxWidgets/pull/1620
This commit is contained in:
Vadim Zeitlin
2019-10-27 14:52:37 +01:00
21 changed files with 252 additions and 212 deletions

View File

@@ -59,6 +59,11 @@ Translating your application involves several steps:
given language: see wxLocale.
@note Under macOS you also need to list all the supported languages under
@c CFBundleLocalizations key in your application @c Info.plist file
in order to allow the application to support the corresponding locale.
@section overview_i18n_mofiles Installing translation catalogs
The .mo files with compiled catalogs must be included with the application.

View File

@@ -3,7 +3,7 @@ wxWidgets for OS X installation {#plat_osx_install}
[TOC]
wxWidgets can be compiled using Apple's Cocoa library.
wxWidgets can be compiled using Apple's Cocoa toolkit.
Most OS X developers should start by downloading and installing Xcode
from the App Store. It is a free IDE from Apple that provides
@@ -45,6 +45,11 @@ Advanced topics {#osx_advanced}
Installing library {#osx_install}
------------------
It is rarely desirable to install non-Apple software into system directories,
so the recommended way of using wxWidgets under macOS is to skip the `make
install` step and simply use the full path to `wx-config` under the build
directory when building application using the library.
If you want to install the library into the system directories you'll need
to do this as root. The accepted way of running commands as root is to
use the built-in sudo mechanism. First of all, you must be using an
@@ -53,18 +58,15 @@ account marked as a "Computer Administrator". Then
sudo make install
type \<YOUR OWN PASSWORD\>
Note that while using this method is okay for development, it is not
recommended that you require endusers to install wxWidgets into their
system directories in order to use your program. One way to avoid this
is to configure wxWidgets with --disable-shared. Another way to avoid
it is to make a framework for wxWidgets. Making frameworks is beyond
the scope of this document.
**Note:**
It is rarely desirable to install non-Apple software into system directories.
By configuring the library with --disable-shared and using the full path
to wx-config with the --in-place option you can avoid installing the library.
Distributing applications using wxWidgets
-----------------------------------------
If you build wxWidgets as static libraries, i.e. pass `--disable-shared` option
to configure, you don't need to do anything special to distribute them, as all
the required code is linked into your application itself. When using shared
libraries (which is the default), you need to copy the libraries into your
application bundle and change their paths using `install_name_tool` so that
they are loaded from their new locations.
Apple Developer Tools: Xcode {#osx_xcode}
----------------------------
@@ -80,45 +82,3 @@ the libraries using commands like this:
$ cd utils/wxrc
$ g++ -o wxrc wxrc.cpp `wx-config --cxxflags --libs base,xml`
Creating universal binaries {#osx_universal_bin}
---------------------------
The Xcode projects for the wxWidgets library and minimal project are set up
to create universal binaries.
If using the Apple command line tools, pass --enable-universal_binary when
configuring wxWidgets. This will create the libraries for all the supported
architectures, currently ppc, i386 and x86_64 . You may explicitly specify
the architectures to use as a comma-separated list,
e.g. --enable-universal_binary=i386,x86_64.
Notice that if you use wx-config --libs to link your application, the -arch
flags are not added automatically as it is possible to link e.g. x86_64-only
program to a "fat" library containing other architectures. If you want to
build a universal application, you need to add the necessary "-arch xxx" flags
to your project or makefile separately.
As an alternative to using --enable-universal_binary, you can build for
each architecture separately and then use the lipo tool to glue the
binaries together. Assuming building on a PPC system:
1. First build in the usual way to get the PPC library.
2. Then, build for Intel, in a different folder. This time use:
export CFLAGS="-g -isysroot /Developer/SDKs/MacOSX10.7.sdk -arch i386"
export LDFLAGS="-syslibroot,/Developer/SDKs/MacOSX10.7.sdk"
./configure --disable-dependency-tracking --enable-static=yes --enable-shared=no \
--target=i386-apple-darwin8 --host=powerpc-apple-darwin8 --build=i386-apple-darwin8
You will need to reverse the powerpc and i386 parameters everywhere to build PPC on an Intel
machine.
3. Use lipo to glue the binaries together.
See also:
http://developer.apple.com/technotes/tn2005/tn2137.html

View File

@@ -44,9 +44,6 @@ public:
// By default, we accept focus ourselves.
m_acceptsFocusSelf = true;
// But we don't have any children accepting it yet.
m_acceptsFocusChildren = false;
m_inSetFocus = false;
m_winLastFocused = NULL;
}
@@ -79,8 +76,7 @@ public:
// Returns whether we or one of our children accepts focus.
bool AcceptsFocusRecursively() const
{ return AcceptsFocus() ||
(m_acceptsFocusChildren && HasAnyChildrenAcceptingFocus()); }
{ return AcceptsFocus() || HasAnyChildrenAcceptingFocus(); }
// We accept focus from keyboard if we accept it at all.
bool AcceptsFocusFromKeyboard() const { return AcceptsFocusRecursively(); }
@@ -119,7 +115,11 @@ protected:
private:
// Update the window status to reflect whether it is getting focus or not.
void UpdateParentCanFocus();
void UpdateParentCanFocus(bool acceptsFocusChildren);
void UpdateParentCanFocus()
{
UpdateParentCanFocus(HasAnyFocusableChildren());
}
// Indicates whether the associated window can ever have focus itself.
//
@@ -129,9 +129,6 @@ private:
// ourselves and can only get it if we have any focusable children.
bool m_acceptsFocusSelf;
// Cached value remembering whether we have any children accepting focus.
bool m_acceptsFocusChildren;
// a guard against infinite recursion
bool m_inSetFocus;
};

View File

@@ -81,7 +81,7 @@ protected:
// true if the status bar shows the size grip: for this it must have
// wxSTB_SIZEGRIP style and the window it is attached to must be resizable
// and not maximized
// and not maximized (note that currently size grip is only used in wxGTK)
bool ShowsSizeGrip() const;
// returns the position and the size of the size grip

View File

@@ -398,7 +398,7 @@ protected:
static bool ms_locked;
private:
protected:
// Common part of SendEvent() and ProcessMenuEvent(): sends the event to
// its intended recipients, returns true if it was processed.
static bool DoProcessEvent(wxMenuBase* menu, wxEvent& event, wxWindow* win);

View File

@@ -185,7 +185,6 @@ public :
virtual void keyEvent(WX_NSEvent event, WXWidget slf, void* _cmd);
virtual void insertText(NSString* text, WXWidget slf, void* _cmd);
virtual void doCommandBySelector(void* sel, WXWidget slf, void* _cmd);
virtual bool performKeyEquivalent(WX_NSEvent event, WXWidget slf, void* _cmd);
virtual bool acceptsFirstResponder(WXWidget slf, void* _cmd);
virtual bool becomeFirstResponder(WXWidget slf, void* _cmd);
virtual bool resignFirstResponder(WXWidget slf, void* _cmd);

View File

@@ -21,8 +21,6 @@ public:
virtual ~wxScreenDCImpl();
virtual wxBitmap DoGetAsBitmap(const wxRect *subrect) const wxOVERRIDE;
private:
void* m_overlayWindow;
private:
wxDECLARE_CLASS(wxScreenDCImpl);

View File

@@ -315,7 +315,12 @@ private:
renderer.DrawItemText(this, dc, "DrawItemText()",
wxRect(x2, y, widthListItem, heightListItem).Inflate(-2, -2), m_align, m_flags | wxCONTROL_SELECTED);
y += lineHeight + heightListItem;
y += heightListItem;
dc.DrawText("DrawChoice()", x1, y + 20);
renderer.DrawChoice(this, dc, wxRect(x2, y, 80, 50), m_flags);
y += 50;
}
int m_flags;

View File

@@ -668,13 +668,28 @@ void MyFrame::OnShowFieldsRect(wxCommandEvent& WXUNUSED(event))
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
// Not all systems support drawing using wxClientDC, so also show the
// coordinates in a message box.
wxString msg;
const wxSize size = pStat->GetClientSize();
msg.Printf("Status bar client size is (%d,%d)\n\n", size.x, size.y);
const int n = pStat->GetFieldsCount();
for ( int i = 0; i < n; i++ )
{
wxRect r;
if ( pStat->GetFieldRect(i, r) )
{
msg += wxString::Format("Field %d rectangle is (%d,%d)-(%d,%d)\n",
i,
r.x, r.y,
r.x + r.width,
r.y + r.height);
dc.DrawRectangle(r);
}
}
wxLogMessage("%s", msg);
}
void MyFrame::OnUpdateStatusBarToggle(wxUpdateUIEvent& event)

View File

@@ -228,15 +228,12 @@ void wxAuiGenericToolBarArt::DrawBackground(
void wxAuiGenericToolBarArt::DrawPlainBackground(wxDC& dc,
wxWindow* WXUNUSED(wnd),
const wxRect& _rect)
const wxRect& rect)
{
wxRect rect = _rect;
rect.height++;
dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
dc.SetPen(*wxTRANSPARENT_PEN);
dc.DrawRectangle(rect.GetX() - 1, rect.GetY() - 1,
rect.GetWidth() + 2, rect.GetHeight() + 1);
dc.DrawRectangle(rect);
}
void wxAuiGenericToolBarArt::DrawLabel(

View File

@@ -50,25 +50,21 @@
// wxControlContainerBase
// ----------------------------------------------------------------------------
void wxControlContainerBase::UpdateParentCanFocus()
void wxControlContainerBase::UpdateParentCanFocus(bool acceptsFocusChildren)
{
// In the ports where it does something non trivial, the parent window
// should only be focusable if it doesn't have any focusable children
// (e.g. native focus handling in wxGTK totally breaks down otherwise).
m_winParent->SetCanFocus(m_acceptsFocusSelf && !m_acceptsFocusChildren);
m_winParent->SetCanFocus(m_acceptsFocusSelf && !acceptsFocusChildren);
}
bool wxControlContainerBase::UpdateCanFocusChildren()
{
const bool acceptsFocusChildren = HasAnyFocusableChildren();
if ( acceptsFocusChildren != m_acceptsFocusChildren )
{
m_acceptsFocusChildren = acceptsFocusChildren;
UpdateParentCanFocus();
}
UpdateParentCanFocus(acceptsFocusChildren);
return m_acceptsFocusChildren;
return acceptsFocusChildren;
}
bool wxControlContainerBase::HasAnyFocusableChildren() const

View File

@@ -194,12 +194,17 @@ void wxStatusBarGeneric::DoUpdateFieldWidths()
bool wxStatusBarGeneric::ShowsSizeGrip() const
{
// Currently drawing size grip is implemented only in wxGTK.
#ifdef __WXGTK20__
if ( !HasFlag(wxSTB_SIZEGRIP) )
return false;
wxTopLevelWindow * const
tlw = wxDynamicCast(wxGetTopLevelParent(GetParent()), wxTopLevelWindow);
return tlw && !tlw->IsMaximized() && tlw->HasFlag(wxRESIZE_BORDER);
#else // !__WXGTK20__
return false;
#endif // __WXGTK20__/!__WXGTK20__
}
void wxStatusBarGeneric::DrawFieldText(wxDC& dc, const wxRect& rect, int i, int textHeight)

View File

@@ -26,37 +26,17 @@ wxIMPLEMENT_ABSTRACT_CLASS(wxScreenDCImpl, wxWindowDCImpl);
wxScreenDCImpl::wxScreenDCImpl( wxDC *owner ) :
wxWindowDCImpl( owner )
{
#if wxOSX_USE_COCOA_OR_CARBON
CGRect cgbounds ;
cgbounds = CGDisplayBounds(CGMainDisplayID());
m_width = (wxCoord)cgbounds.size.width;
m_height = (wxCoord)cgbounds.size.height;
#else
wxDisplaySize( &m_width, &m_height );
#endif
#if wxOSX_USE_COCOA_OR_IPHONE
SetGraphicsContext( wxGraphicsContext::Create() );
#else
Rect bounds;
bounds.top = (short)cgbounds.origin.y;
bounds.left = (short)cgbounds.origin.x;
bounds.bottom = bounds.top + (short)cgbounds.size.height;
bounds.right = bounds.left + (short)cgbounds.size.width;
WindowAttributes overlayAttributes = kWindowIgnoreClicksAttribute;
CreateNewWindow( kOverlayWindowClass, overlayAttributes, &bounds, (WindowRef*) &m_overlayWindow );
ShowWindow((WindowRef)m_overlayWindow);
SetGraphicsContext( wxGraphicsContext::CreateFromNativeWindow( m_overlayWindow ) );
#endif
m_ok = true ;
}
wxScreenDCImpl::~wxScreenDCImpl()
{
wxDELETE(m_graphicContext);
#if wxOSX_USE_COCOA_OR_IPHONE
#else
DisposeWindow((WindowRef) m_overlayWindow );
#endif
}
#if wxOSX_USE_IPHONE

View File

@@ -150,6 +150,13 @@ WXGLPixelFormat WXGLChoosePixelFormat(const int *GLAttrs,
impl->doCommandBySelector(aSelector, self, _cmd);
}
- (NSOpenGLContext *) openGLContext
{
// Prevent the NSOpenGLView from making it's own context
// We want to force using wxGLContexts
return NULL;
}
@end
bool wxGLCanvas::DoCreate(wxWindow *parent,
@@ -201,24 +208,6 @@ bool wxGLContext::SetCurrent(const wxGLCanvas& win) const
[m_glContext makeCurrentContext];
// the missing redraw upon resize problem only happens when linked against 10.14
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14
// At least under macOS 10.14.5 we need to do this in order to update the
// context with the new size information after the window is resized.
if ( WX_IS_MACOS_AVAILABLE_FULL(10, 14, 5) )
{
if ( WX_IS_MACOS_AVAILABLE(10, 15) )
{
// no workaround needed under 10.15 anymore
}
else
{
NSOpenGLView *v = (NSOpenGLView *)win.GetHandle();
[v setOpenGLContext: m_glContext];
}
}
#endif
return true;
}

View File

@@ -368,12 +368,6 @@ NSView* wxMacEditHelper::ms_viewCurrentlyEdited = nil;
[super flagsChanged:event];
}
- (BOOL) performKeyEquivalent:(NSEvent*) event
{
BOOL retval = [super performKeyEquivalent:event];
return retval;
}
- (void) insertText:(id) str
{
// We should never generate char events for the text being inserted

View File

@@ -41,6 +41,39 @@
#include <objc/objc-runtime.h>
#define TRACE_FOCUS "focus"
#define TRACE_KEYS "keyevent"
// ----------------------------------------------------------------------------
// debugging helpers
// ----------------------------------------------------------------------------
// This one is defined in window_osx.cpp.
extern wxString wxDumpWindow(wxWindowMac* win);
// These functions are called from the code but are also useful in the debugger
// (especially wxDumpNSView(), as selectors can be printed out directly anyhow),
// so make them just static instead of putting them in an anonymous namespace
// to make it easier to call them.
static wxString wxDumpSelector(SEL cmd)
{
return wxStringWithNSString(NSStringFromSelector(cmd));
}
static wxString wxDumpNSView(NSView* view)
{
wxWidgetImpl* const impl = wxWidgetImpl::FindFromWXWidget(view);
if ( !impl )
return wxStringWithNSString([view description]);
return wxString::Format("%s belonging to %s",
wxStringWithNSString([view className]),
wxDumpWindow(impl->GetWXPeer())
);
}
// Get the window with the focus
NSView* wxOSXGetViewFromResponder( NSResponder* responder )
@@ -1076,7 +1109,11 @@ void wxOSX_keyEvent(NSView* self, SEL _cmd, NSEvent *event)
{
wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
if (impl == NULL)
{
wxLogTrace(TRACE_KEYS, "Dropping %s for %s",
wxDumpSelector(_cmd), wxDumpNSView(self));
return;
}
impl->keyEvent(event, self, _cmd);
}
@@ -1162,15 +1199,6 @@ void wxOSX_touchesEnded(NSView* self, SEL _cmd, NSEvent *event)
}
#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_10
BOOL wxOSX_performKeyEquivalent(NSView* self, SEL _cmd, NSEvent *event)
{
wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
if (impl == NULL)
return NO;
return impl->performKeyEquivalent(event, self, _cmd);
}
BOOL wxOSX_acceptsFirstResponder(NSView* self, SEL _cmd)
{
wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
@@ -1520,6 +1548,9 @@ bool wxWidgetCocoaImpl::SetupCursor(WX_NSEvent event)
void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
{
wxLogTrace(TRACE_KEYS, "Got %s for %s",
wxDumpSelector((SEL)_cmd), wxDumpNSView(slf));
if ( !m_wxPeer->IsEnabled() )
return;
@@ -1528,8 +1559,12 @@ void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
// there are key equivalents that are not command-combos and therefore not handled by cocoa automatically,
// therefore we call the menubar directly here, exit if the menu is handling the shortcut
if ( [[[NSApplication sharedApplication] mainMenu] performKeyEquivalent:event] )
{
wxLogTrace(TRACE_KEYS, "%s processed as key equivalent by the menu",
wxDumpSelector((SEL)_cmd));
return;
}
m_lastKeyDownEvent = event;
}
@@ -2108,6 +2143,9 @@ void wxCocoaGesturesImpl::TouchesEnded(NSEvent* event)
void wxWidgetCocoaImpl::insertText(NSString* text, WXWidget slf, void *_cmd)
{
wxLogTrace(TRACE_KEYS, "Insert text \"%s\" for %s",
wxStringWithNSString(text), wxDumpNSView(slf));
bool result = false;
if ( HasUserKeyHandling() && !m_hasEditor && [text length] > 0)
{
@@ -2140,6 +2178,9 @@ void wxWidgetCocoaImpl::insertText(NSString* text, WXWidget slf, void *_cmd)
void wxWidgetCocoaImpl::doCommandBySelector(void* sel, WXWidget slf, void* _cmd)
{
wxLogTrace(TRACE_KEYS, "Selector %s for %s",
wxDumpSelector((SEL)_cmd), wxDumpNSView(slf));
if ( m_lastKeyDownEvent!=NULL )
{
// If we have a corresponding key event, send wxEVT_KEY_DOWN now.
@@ -2158,42 +2199,10 @@ void wxWidgetCocoaImpl::doCommandBySelector(void* sel, WXWidget slf, void* _cmd)
GetWXPeer()->OSXHandleKeyEvent(wxevent2);
}
}
}
bool wxWidgetCocoaImpl::performKeyEquivalent(WX_NSEvent event, WXWidget slf, void *_cmd)
{
bool handled = false;
wxKeyEvent wxevent(wxEVT_KEY_DOWN);
SetupKeyEvent( wxevent, event );
// because performKeyEquivalent is going up the entire view hierarchy, we don't have to
// walk up the ancestors ourselves but let cocoa do it
#if wxUSE_ACCEL
int command = m_wxPeer->GetAcceleratorTable()->GetCommand( wxevent );
if (command != -1)
else
{
wxEvtHandler * const handler = m_wxPeer->GetEventHandler();
wxCommandEvent command_event( wxEVT_MENU, command );
command_event.SetEventObject( wxevent.GetEventObject() );
handled = handler->ProcessEvent( command_event );
if ( !handled )
{
// accelerators can also be used with buttons, try them too
command_event.SetEventType(wxEVT_BUTTON);
handled = handler->ProcessEvent( command_event );
}
wxLogTrace(TRACE_KEYS, "Doing nothing in doCommandBySelector:");
}
#endif // wxUSE_ACCEL
if ( !handled )
{
wxOSX_PerformKeyEventHandlerPtr superimpl = (wxOSX_PerformKeyEventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
return superimpl(slf, (SEL)_cmd, event);
}
return YES;
}
bool wxWidgetCocoaImpl::acceptsFirstResponder(WXWidget slf, void *_cmd)
@@ -2476,8 +2485,6 @@ void wxOSXCocoaClassAddWXMethods(Class c, wxOSXSkipOverrides skipFlags)
wxOSX_CLASS_ADD_METHOD(c, @selector(insertText:), (IMP) wxOSX_insertText, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(performKeyEquivalent:), (IMP) wxOSX_performKeyEquivalent, "c@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(acceptsFirstResponder), (IMP) wxOSX_acceptsFirstResponder, "c@:" )
wxOSX_CLASS_ADD_METHOD(c, @selector(becomeFirstResponder), (IMP) wxOSX_becomeFirstResponder, "c@:" )
wxOSX_CLASS_ADD_METHOD(c, @selector(resignFirstResponder), (IMP) wxOSX_resignFirstResponder, "c@:" )
@@ -3083,10 +3090,23 @@ bool wxWidgetCocoaImpl::GetNeedsDisplay() const
bool wxWidgetCocoaImpl::CanFocus() const
{
if ( !IsVisible() )
{
// It's useless to call canBecomeKeyView in this case, it will always
// return false. Try to return something reasonable ourselves, knowing
// that most controls are not focusable when full keyboard access if
// off and wxNSTextViewControl overrides CanFocus() to always return
// true anyhow.
return [NSApp isFullKeyboardAccessEnabled];
}
NSView* targetView = m_osxView;
if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
targetView = [(NSScrollView*) m_osxView documentView];
return [targetView canBecomeKeyView] == YES;
const bool canFocus = [targetView canBecomeKeyView] == YES;
wxLogTrace(TRACE_FOCUS, "CanFocus(%s) -> %s",
wxDumpNSView(m_osxView), canFocus ? "YES" : "NO");
return canFocus;
}
bool wxWidgetCocoaImpl::HasFocus() const
@@ -3099,14 +3119,45 @@ bool wxWidgetCocoaImpl::HasFocus() const
bool wxWidgetCocoaImpl::SetFocus()
{
if ( !CanFocus() )
return false;
NSView* targetView = m_osxView;
if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
targetView = [(NSScrollView*) m_osxView documentView];
[[m_osxView window] makeFirstResponder: targetView] ;
if ( [targetView canBecomeKeyView] )
{
wxLogTrace(TRACE_FOCUS, "Setting focus to %s", wxDumpNSView(m_osxView));
[[m_osxView window] makeFirstResponder: targetView] ;
}
else // can't become key view
{
// This most commonly happens because the window is still hidden, as
// canBecomeKeyView: always returns NO in this case, so schedule this
// window to become focused when it's shown later in this case.
//
// Note that this may still fail to work: if full keyboard access is
// off and this window is not a text control or similar, setting
// initial first responder won't do anything. But this is not really a
// problem and at least it will do the right thing if the window turns
// out to be focusable (i.e. it's a text control or full keyboard
// access is on).
if ( !IsVisible() )
{
wxLogTrace(TRACE_FOCUS, "Setting initial focus to %s",
wxDumpNSView(m_osxView));
[[m_osxView window] setInitialFirstResponder: targetView] ;
}
else // window is shown but doesn't accept focus
{
// Not sure when exactly can this happen, for now just don't do
// anything in this case.
wxLogTrace(TRACE_FOCUS, "Not setting focus to %s",
wxDumpNSView(m_osxView));
return false;
}
}
return true;
}
@@ -3632,6 +3683,9 @@ bool wxWidgetCocoaImpl::ShouldHandleKeyNavigation(const wxKeyEvent &WXUNUSED(eve
bool wxWidgetCocoaImpl::DoHandleKeyNavigation(const wxKeyEvent &event)
{
wxLogTrace(TRACE_KEYS, "Handling key navigation event for %s",
wxDumpNSView(m_osxView));
bool handled = false;
wxWindow *focus = GetWXPeer();
if (focus && event.GetKeyCode() == WXK_TAB)
@@ -3661,6 +3715,9 @@ bool wxWidgetCocoaImpl::DoHandleKeyNavigation(const wxKeyEvent &event)
bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event)
{
wxLogTrace(TRACE_KEYS, "Handling key event for %s",
wxDumpNSView(m_osxView));
wxKeyEvent wxevent(wxEVT_KEY_DOWN);
SetupKeyEvent( wxevent, event );
@@ -3672,10 +3729,16 @@ bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event)
wxKeyEvent eventHook(wxEVT_CHAR_HOOK, wxevent);
if ( GetWXPeer()->OSXHandleKeyEvent(eventHook)
&& !eventHook.IsNextEventAllowed() )
{
wxLogTrace(TRACE_KEYS, "Key down event handled");
return true;
}
if (DoHandleKeyNavigation(wxevent))
{
wxLogTrace(TRACE_KEYS, "Key down event handled as navigation event");
return true;
}
}
if ( HasUserKeyHandling() && [event type] == NSKeyDown)
@@ -3742,7 +3805,7 @@ void wxWidgetCocoaImpl::DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* oth
if ( receivedFocus )
{
wxLogTrace(wxT("Focus"), wxT("focus set(%p)"), static_cast<void*>(thisWindow));
wxLogTrace(TRACE_FOCUS, "Set focus for %s", wxDumpWindow(thisWindow));
wxChildFocusEvent eventFocus((wxWindow*)thisWindow);
thisWindow->HandleWindowEvent(eventFocus);
@@ -3764,7 +3827,7 @@ void wxWidgetCocoaImpl::DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* oth
thisWindow->GetCaret()->OnKillFocus();
#endif
wxLogTrace(wxT("Focus"), wxT("focus lost(%p)"), static_cast<void*>(thisWindow));
wxLogTrace(TRACE_FOCUS, "Lost focus in %s", wxDumpWindow(thisWindow));
wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId());
event.SetEventObject(thisWindow);

View File

@@ -326,23 +326,7 @@ bool wxMenu::HandleCommandUpdateStatus( wxMenuItem* item, wxWindow* senderWindow
wxUpdateUIEvent event(menuid);
event.SetEventObject( this );
bool processed = false;
// Try the menu's event handler
{
wxEvtHandler *handler = GetEventHandler();
if ( handler )
processed = handler->ProcessEvent(event);
}
// Try the window the menu was popped up from
// (and up through the hierarchy)
if ( !processed )
{
wxWindow *win = GetWindow();
if ( win )
processed = win->HandleWindowEvent(event);
}
bool processed = DoProcessEvent(this, event, GetWindow());
if ( !processed && senderWindow != NULL)
{

View File

@@ -102,6 +102,9 @@ bool wxRadioBox::Create( wxWindow *parent,
if ( !wxControl::Create( parent, id, pos, size, style, val, name ) )
return false;
// The radio box itself never accepts focus, only its child buttons do.
m_container.DisableSelfFocus();
// during construction we must keep this at 0, otherwise GetBestSize fails
m_noItems = 0;
m_noRowsOrCols = majorDim;

View File

@@ -71,6 +71,8 @@
#include <string.h>
#define TRACE_KEYS "keyevent"
#ifdef __WXUNIVERSAL__
wxIMPLEMENT_ABSTRACT_CLASS(wxWindowMac, wxWindowBase);
#endif
@@ -177,6 +179,27 @@ wxIMPLEMENT_DYNAMIC_CLASS(wxBlindPlateWindow, wxWindow);
wxBEGIN_EVENT_TABLE(wxBlindPlateWindow, wxWindow)
wxEND_EVENT_TABLE()
// ----------------------------------------------------------------------------
// debug helpers
// ----------------------------------------------------------------------------
// Function used to dump a brief description of a window.
extern
wxString wxDumpWindow(wxWindowMac* win)
{
if ( !win )
return "(no window)";
wxString s = wxString::Format("%s(%p",
win->GetClassInfo()->GetClassName(), win);
wxString label = win->GetLabel();
if ( !label.empty() )
s += wxString::Format(", \"%s\"", label);
s += ")";
return s;
}
// ----------------------------------------------------------------------------
// constructors and such
@@ -542,23 +565,9 @@ bool wxWindowMac::SetBackgroundColour(const wxColour& col )
return true ;
}
static bool wxIsWindowOrParentDisabled(wxWindow* w)
{
while (w && !w->IsTopLevel())
{
if (!w->IsEnabled())
return true;
w = w->GetParent();
}
return false;
}
void wxWindowMac::SetFocus()
{
if ( !AcceptsFocus() )
return ;
if (wxIsWindowOrParentDisabled((wxWindow*) this))
if ( !IsEnabled() )
return;
wxWindow* former = FindFocus() ;
@@ -2570,6 +2579,18 @@ bool wxWindowMac::UnregisterHotKey(int hotkeyId)
bool wxWindowMac::OSXHandleKeyEvent( wxKeyEvent& event )
{
wxLogTrace(TRACE_KEYS, "Handling %s event in %s",
event.GetEventType() == wxEVT_KEY_DOWN
? "key down"
: event.GetEventType() == wxEVT_CHAR
? "char"
: event.GetEventType() == wxEVT_KEY_UP
? "key up"
: event.GetEventType() == wxEVT_CHAR_HOOK
? "char hook"
: "unknown",
wxDumpWindow(this));
bool handled = false;
// moved the ordinary key event sending AFTER the accel evaluation

View File

@@ -686,6 +686,13 @@ void wxRibbonButtonBar::SetArtProvider(wxRibbonArtProvider* art)
wxRibbonControl::SetArtProvider(art);
// There is no need to do anything else when the art provider is reset to
// null during our destruction and this actually results in problems during
// program shutdown due to trying to get DPI of the already destroyed TLW
// parent.
if (!art)
return;
wxClientDC temp_dc(this);
size_t btn_count = m_buttons.Count();
size_t btn_i;

View File

@@ -364,6 +364,28 @@ TEST_CASE_METHOD(WindowTestCase, "Window::Enable", "[window]")
m_window->Enable(false);
CHECK(!m_window->IsEnabled());
m_window->Enable();
wxWindow* const child = new wxWindow(m_window, wxID_ANY);
CHECK(child->IsEnabled());
CHECK(child->IsThisEnabled());
m_window->Disable();
CHECK(!child->IsEnabled());
CHECK(child->IsThisEnabled());
child->Disable();
CHECK(!child->IsEnabled());
CHECK(!child->IsThisEnabled());
m_window->Enable();
CHECK(!child->IsEnabled());
CHECK(!child->IsThisEnabled());
child->Enable();
CHECK(child->IsEnabled());
CHECK(child->IsThisEnabled());
}
TEST_CASE_METHOD(WindowTestCase, "Window::FindWindowBy", "[window]")