New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make macOS date picker control locale aware #23956
base: master
Are you sure you want to change the base?
Make macOS date picker control locale aware #23956
Conversation
utelle
commented
Oct 11, 2023
- Add global variable for pointer to current NSLocale
- Set global NSLocale pointer in method wxUILocaleImplCF::Use()
- Add helper function to retrieve the global NSLocale pointer
- Add function declaration of the helper function in private/uilocale.h
- Call wxUILocaleImpl::Use() in method wxUILocale::GetCurrent(), so that the current wxUILocale instance is always valid, even if wxUILocale::UseDefault() was not explicitly called
- Add global variable for pointer to current NSLocale - Set global NSLocale pointer in method wxUILocaleImplCF::Use() - Add helper function to retrieve the global NSLocale pointer - Add function declaration of the helper function in private/uilocale.h - Call wxUILocaleImpl::Use() in method wxUILocale::GetCurrent(), so that the current wxUILocale instance is always valid, even if wxUILocale::UseDefault() was not explicitly called
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your work on this, but I think it could be improved a bit.
Please let me know if I'm missing anything here.
src/common/uilocale.cpp
Outdated
@@ -520,7 +520,14 @@ const wxUILocale& wxUILocale::GetCurrent() | |||
// We initialize it on demand. | |||
if ( !ms_current.m_impl ) | |||
{ | |||
ms_current = wxUILocale(wxUILocaleImpl::CreateStdC()); | |||
// Instantiate standard C locale (should never fail) ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure that calling Use()
on C locale is a good idea. At least under Unix it's not a NOP.
Why not set g_nsloc
in Mac-specific CreateStdC()
instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not 100% sure that calling
Use()
on C locale is a good idea. At least under Unix it's not a NOP.
Yes, wxUILocale::Use()
is not a NOP under Unix. It sets the C runtime locale via setlocale
. But does that matter in our case? IMHO no, because we would call wxUILocale::Use()
only, if wxUILocale::Use()
was not called. In that case we can assume that the current C runtime locale is the "C" locale anyway. Setting it in wxUILocale::Use()
wouldn't cause any harm, would it?
Why not set
g_nsloc
in Mac-specificCreateStdC()
instead?
Unfortunately, this is not possible. CreateStdC()
can be called from various places, not only from Use()
or GetCurrent()
, but also from the wxUILocale()
constructor. Only in Use()
you can be sure that the locale is the current locale.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're probably right, but the trouble is that it's not immediately obvious and for me it's a bad sign when you need to carefully think about something instead of it just being immediately clear.
And it just seems suspicious to call Use()
from an accessor. In fact I am still not sure to understand why do we need to remember this locale as the default one here, i.e. why does querying the default locale should change anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're probably right, but the trouble is that it's not immediately obvious and for me it's a bad sign when you need to carefully think about something instead of it just being immediately clear.
I fully agree. And you asked for a more detailed explanation in the general comments. However, I hope I could make my point in my answer there.
And it just seems suspicious to call
Use()
from an accessor. In fact I am still not sure to understand why do we need to remember this locale as the default one here, i.e. why does querying the default locale should change anything?
Well, actually it is the same as with any method that instantiates a static global object when called for the first time: it checks whether the global object already exists and is initialized; if yes, a reference to the global object is returned; if no, the global object will allocated and initialized, before a reference to it will be returned.
Here we have the situation that on the first call to GetCurrent()
the global object ms_current
is not initialized, because UseDefault()
was not called. One option would have been to call UseDefault()
from GetCurrent()
, because it was not done before by the application. However, that would force the application to use the default user locale, but it is unlikely that that is the intention of the application, when it did not call UseDefault()
. More likely is that the application wants to stay with the standard C locale. Therefore we would need a method UseStdC()
to make clear that we want to use the standard C locale. But we don't have it. Therefore GetCurrent()
calls CreateStdC()
... and misses to call Use()
for it (which would be part of UseStdC()
. That is adding the call to Use()
actually fixes a bug.
- Rename global pointer to current NSLocale - Declare function to retrieve the pointer in private OSX header file
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates and sorry for being so cautious, but I'm still not sure if calling Use()
from GetCurrent()
is a good idea. Could you please re-explain why should we do it from there?
include/wx/osx/private/uilocale.h
Outdated
// Name: wx/osx/private/uilocale.h | ||
// Purpose: Helper for making pointer to current NSLocale available | ||
// for locale-dependent controls under macOS. | ||
// Author: Vadim Zeitlin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just copied the comments from another file, adjusting the purpose but not paying attention to the other items.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will you change it or should I, when merging?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed the author name.
include/wx/osx/private/uilocale.h
Outdated
|
||
#if wxUSE_INTL | ||
|
||
#ifdef __WXOSX_COCOA__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not needed here, is it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, probably not. At least if that header is not included from some non-Cocoa build. I don't know whether the latter can happen or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd still remove it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed.
src/common/uilocale.cpp
Outdated
@@ -520,7 +520,14 @@ const wxUILocale& wxUILocale::GetCurrent() | |||
// We initialize it on demand. | |||
if ( !ms_current.m_impl ) | |||
{ | |||
ms_current = wxUILocale(wxUILocaleImpl::CreateStdC()); | |||
// Instantiate standard C locale (should never fail) ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're probably right, but the trouble is that it's not immediately obvious and for me it's a bad sign when you need to carefully think about something instead of it just being immediately clear.
And it just seems suspicious to call Use()
from an accessor. In fact I am still not sure to understand why do we need to remember this locale as the default one here, i.e. why does querying the default locale should change anything?
Sure. We have to differentiate between creating and using a Both use methods create a Now, let us look at the implementation of However, we have to handle one special case, namely if the application did not call one of the use methods. In that case the global instance The only assumption we can make is that the application uses (:bangbang:) the standard C locale. So, what should we do to reflect that? Yes, we should call another use method, namely The current implementation of To cut a long story short: calling Yes, calling |
Thanks for the explanations but I have to say that I very much disagree with the basic assumption underlying them, namely that calling In fact, now I'm quite sure that doing this is wrong because you've allowed me to understand what exactly is wrong with it: calling |
Oh, and sorry for not putting this in the previous reply, but for the same reason |
Well, obviouly I was not able to make myself clear, unfortunately. The wxWidgets documentation states
That is, for a localized application that calls It is only the special case, if IMHO it is a fair assumption in this situation that the current C locale is the standard C locale. Actually, that's why Actually, nobody knows which locale the application wants to use. It's up to the developer to call the right methods. For a localized application If The only change I introduced in my PR is that additionally Under MacOS and under Windows the method Under Linux the net effect is also zero, because each application starts with the standard C locale as the C runtime
Sorry, we are talking about the special case that a
As explained above this is simply not true. If the application did not instantiate
Again: we are talking about a special case that |
|
Just to make it clear: I'm only speaking about the case in which Sorry, but I still don't see at all why do you think that I guess (but I could be wrong here, so please feel free to ignore this paragraph in this case...) that you're looking at it from macOS-centric point of view, and macOS is weird because it doesn't use "C" locale by default. This weirdness should, however, be dealt with in wxOSX itself and doesn't change anything for the other platforms and shouldn't result in calling |
Calling Use() on MacOS is necessary to reduce locale-related inconsistencies.
Me too.
Agreed.
My point is that the current C runtime locale in this situation is "C". And therefore calling
Regarding Windows and Linux I agree. But under MacOS calling
Correct.
Ok. I hope you can accept the compromise I just committed. Namely calling |
It shouldn't because the program might call
I could live with this, even though I'd prefer not to have any unnecessary platform checks in the common code, but I still don't understand why are you so convinced that it is necessary. If the program doesn't call So if it were up to me, I would still just delete this code. And if you really want to use C locale in the dialog by default, it looks like you could easily do it by just handling the case of |
IMHO it is not unnecessary.
My understanding is that we want consistent behaviour as far as it is possible. Since the Standard C locale is assumed, if no locale was explicitly set, it should be used throughout. That is, not mixing C locale and default user locale where possible.
I speak of number and date formatting. I would find it irritating, if a date is formatted according to US English for display, but according to German for editing.
Yes, in principle this could be done, but I find it inconvenient, because you need then to instantiate each time a NSLocale for C, instead of simply reusing the NSLocale of the current wxUILocale. |
If no locale was explicitly set (UseDefault not called), then the global pointer gs_currentNSLocale will be null. In this case assign the standard C locale to gs_currentNSLocale .
@vadz I hope you will be satisfied by the latest changes. I removed the MacOS-specific code from |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the update! IMO it's indeed much better now, as there is less code and it's perfectly clear what's going on, so I'd be glad to merge it, just please let me know what do you think of the small issues below.
Thanks again!
include/wx/osx/private/uilocale.h
Outdated
// Name: wx/osx/private/uilocale.h | ||
// Purpose: Helper for making pointer to current NSLocale available | ||
// for locale-dependent controls under macOS. | ||
// Author: Vadim Zeitlin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will you change it or should I, when merging?
include/wx/osx/private/uilocale.h
Outdated
|
||
#if wxUSE_INTL | ||
|
||
#ifdef __WXOSX_COCOA__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd still remove it.
src/osx/core/uilocale.mm
Outdated
|
||
NSLocale* wxGetCurrentNSLocale() | ||
{ | ||
static NSLocale* stdCLocale([[NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"] retain]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be inside if
, why even instantiate it if it's never going to be needed?
It's also going to leak currently, not sure if it's really important, but using wxCFRef<NSLocale>
for it would avoid it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved the static locale into the if condition. And I used wxCFRef
. However, I was not sure whether I have to keep the retain
keyword or not.
This avoids to allocate a standard C locale if not needed.