diff --git a/docs/doxygen/overviews/internationalization.h b/docs/doxygen/overviews/internationalization.h index dc84c9007f..3d4f7821ec 100644 --- a/docs/doxygen/overviews/internationalization.h +++ b/docs/doxygen/overviews/internationalization.h @@ -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. diff --git a/docs/osx/install.md b/docs/osx/install.md index 9313a6f737..763fc3877f 100644 --- a/docs/osx/install.md +++ b/docs/osx/install.md @@ -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 \ -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 - - diff --git a/include/wx/containr.h b/include/wx/containr.h index c9eb5857c5..aa5ffd625c 100644 --- a/include/wx/containr.h +++ b/include/wx/containr.h @@ -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; }; diff --git a/include/wx/generic/statusbr.h b/include/wx/generic/statusbr.h index 6d0edd6ec2..996012b07a 100644 --- a/include/wx/generic/statusbr.h +++ b/include/wx/generic/statusbr.h @@ -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 diff --git a/include/wx/menu.h b/include/wx/menu.h index eb262bc2da..af9f2e7364 100644 --- a/include/wx/menu.h +++ b/include/wx/menu.h @@ -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); diff --git a/include/wx/osx/cocoa/private.h b/include/wx/osx/cocoa/private.h index 0f8bff0b67..7e35c0e43c 100644 --- a/include/wx/osx/cocoa/private.h +++ b/include/wx/osx/cocoa/private.h @@ -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); diff --git a/include/wx/osx/dcscreen.h b/include/wx/osx/dcscreen.h index 77d7832f70..1ebcc5e75d 100644 --- a/include/wx/osx/dcscreen.h +++ b/include/wx/osx/dcscreen.h @@ -21,8 +21,6 @@ public: virtual ~wxScreenDCImpl(); virtual wxBitmap DoGetAsBitmap(const wxRect *subrect) const wxOVERRIDE; -private: - void* m_overlayWindow; private: wxDECLARE_CLASS(wxScreenDCImpl); diff --git a/samples/render/render.cpp b/samples/render/render.cpp index 835490840f..404c8eb54a 100644 --- a/samples/render/render.cpp +++ b/samples/render/render.cpp @@ -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; diff --git a/samples/statbar/statbar.cpp b/samples/statbar/statbar.cpp index 9a4f0e4128..3811033306 100644 --- a/samples/statbar/statbar.cpp +++ b/samples/statbar/statbar.cpp @@ -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) diff --git a/src/aui/auibar.cpp b/src/aui/auibar.cpp index 3722a1b34f..742c8e200f 100644 --- a/src/aui/auibar.cpp +++ b/src/aui/auibar.cpp @@ -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( diff --git a/src/common/containr.cpp b/src/common/containr.cpp index bdf72218af..196ada8172 100644 --- a/src/common/containr.cpp +++ b/src/common/containr.cpp @@ -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 diff --git a/src/generic/statusbr.cpp b/src/generic/statusbr.cpp index eecc549de6..53ca7e1a8c 100644 --- a/src/generic/statusbr.cpp +++ b/src/generic/statusbr.cpp @@ -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) diff --git a/src/osx/carbon/dcscreen.cpp b/src/osx/carbon/dcscreen.cpp index df7b09db24..3db95c5a51 100644 --- a/src/osx/carbon/dcscreen.cpp +++ b/src/osx/carbon/dcscreen.cpp @@ -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 diff --git a/src/osx/cocoa/glcanvas.mm b/src/osx/cocoa/glcanvas.mm index b2df34d9df..505b3a5e4b 100644 --- a/src/osx/cocoa/glcanvas.mm +++ b/src/osx/cocoa/glcanvas.mm @@ -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; } diff --git a/src/osx/cocoa/textctrl.mm b/src/osx/cocoa/textctrl.mm index c27e2eaf81..d4d18a5200 100644 --- a/src/osx/cocoa/textctrl.mm +++ b/src/osx/cocoa/textctrl.mm @@ -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 diff --git a/src/osx/cocoa/window.mm b/src/osx/cocoa/window.mm index c182de7fc5..8a8a12b948 100644 --- a/src/osx/cocoa/window.mm +++ b/src/osx/cocoa/window.mm @@ -41,6 +41,39 @@ #include +#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(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(thisWindow)); + wxLogTrace(TRACE_FOCUS, "Lost focus in %s", wxDumpWindow(thisWindow)); wxFocusEvent event( wxEVT_KILL_FOCUS, thisWindow->GetId()); event.SetEventObject(thisWindow); diff --git a/src/osx/menu_osx.cpp b/src/osx/menu_osx.cpp index e24ce81579..75251bc06a 100644 --- a/src/osx/menu_osx.cpp +++ b/src/osx/menu_osx.cpp @@ -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) { diff --git a/src/osx/radiobox_osx.cpp b/src/osx/radiobox_osx.cpp index 50dbb33b2f..2a7b33c827 100644 --- a/src/osx/radiobox_osx.cpp +++ b/src/osx/radiobox_osx.cpp @@ -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; diff --git a/src/osx/window_osx.cpp b/src/osx/window_osx.cpp index a069d652b7..f3c4260ac7 100644 --- a/src/osx/window_osx.cpp +++ b/src/osx/window_osx.cpp @@ -71,6 +71,8 @@ #include +#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 diff --git a/src/ribbon/buttonbar.cpp b/src/ribbon/buttonbar.cpp index b0976c1750..17cbd00827 100644 --- a/src/ribbon/buttonbar.cpp +++ b/src/ribbon/buttonbar.cpp @@ -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; diff --git a/tests/controls/windowtest.cpp b/tests/controls/windowtest.cpp index a9ff914f5d..1c3fcc1b81 100644 --- a/tests/controls/windowtest.cpp +++ b/tests/controls/windowtest.cpp @@ -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]")