After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 661588 - Set the global locale in Glib::init()
Set the global locale in Glib::init()
Status: RESOLVED FIXED
Product: glibmm
Classification: Bindings
Component: strings
unspecified
Other All
: Normal normal
: ---
Assigned To: gtkmm-forge
gtkmm-forge
Depends on:
Blocks:
 
 
Reported: 2011-10-12 20:15 UTC by Debarshi Ray
Modified: 2016-12-15 16:00 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Proposed fix (1.26 KB, patch)
2011-10-12 20:23 UTC, Debarshi Ray
none Details | Review
More complicated test case (2.12 KB, text/plain)
2011-10-23 13:51 UTC, Kjell Ahlstedt
  Details
patch: Glib::init(): Set global locale. (5.24 KB, patch)
2012-11-08 15:59 UTC, Kjell Ahlstedt
none Details | Review
testinit.cc (1.07 KB, text/plain)
2016-07-25 11:15 UTC, Kjell Ahlstedt
  Details

Description Debarshi Ray 2011-10-12 20:15:25 UTC
Glib::ustring's overloaded << and >> operators use g_locale_from_utf8 and g_locale_to_utf8 which won't work unless the global C locale is set. Ofcourse, since we are using C++ streams the C++ locale should be set too.
Comment 1 Debarshi Ray 2011-10-12 20:23:22 UTC
Created attachment 198883 [details] [review]
Proposed fix
Comment 2 Murray Cumming 2011-10-12 20:27:35 UTC
I thought we started doing something like this in the glibmm or gtkmm initialization, though I can't find the email now.
Comment 3 Debarshi Ray 2011-10-13 09:24:14 UTC
The following program crashes:

#include <sstream>
#include <glibmm.h>

int main(void)
{
  Glib::init();
  Glib::ustring str("ó");
  std::ostringstream oss;
  oss << str;
  return 0;
}

Setting the global C++ locale solves the problem.
Comment 4 Murray Cumming 2011-10-21 12:44:28 UTC
Note that this causes an exception on some (strange?) systems. See bug #619445 , for instance.

I also seem to remember that we discussed doing something like this in glibmm or gtkmm's initialization, but I can't find the change or the discussion now. Can someone remember?
Comment 5 Kjell Ahlstedt 2011-10-23 13:51:34 UTC
Created attachment 199758 [details]
More complicated test case

I tested with the attached test case on my Ubuntu 11.04 system and different
values of the environment variable LANG.

LANG=sv_SE.utf8
---------------
The test case in comment 3 throws a Glib::ConvertError exception (Invalid byte
sequence in conversion input), and crashes since the exception is not caught.

oss.imbue(std::locale("")), as recommended in the present ustring
documentation, is of no avail. The same exception.

std::locale::global(std::locale("")), as recommended in this bug, or
setlocale(LC_ALL, ""), are better. No exception.

new Gtk::Main(argc, argv) is fine. No exception.
Gtk::Main's constructor calls gtk_init(), which calls setlocale(LC_ALL, "").

LANG=C
------
The Glib::ConvertError exception is thrown in all cases.

LANG=abc or LANG=hu_HU.utf8 (non-existent language)
---------------------------
The Glib::ConvertError exception is thrown, and there are also other errors.

gtk_init() prints
  (process:2056): Gtk-WARNING **: Locale not supported by C library.
       Using the fallback 'C' locale.

setlocale(LC_ALL, "") returns NULL, indicating failure.

std::locale("") throws a std::runtime_error exception, saying
  locale::facet::_S_create_c_locale name not valid


Conclusions:
- If the environment variable LANG specifies a language that is not installed
  in the system, there's probably no better alternative than to keep the
  "C" locale, with which every C or C++ program starts.
- Provided LANG is correctly set, there's no problem in a gtkmm program,
  initialized in the usual way by creating an instance of Gtk::Main.
- In a pure glibmm program, the locale used by C functions like
  g_locale_from_utf8() and g_locale_to_utf8() must be set, if a Glib::ustring
  with non-Ascii characters shall be sent to a stream.
  The locale can be set with std::locale::global(std::locale("")) or
  setlocale(LC_ALL, ""). Be aware that std::locale("") can throw an exception.

A solution that breaks ABI and API: Change the Glib::init() prototype from
Glib::init() to Glib::init(bool set_locale = true).
Comment 6 Kjell Ahlstedt 2012-11-08 15:59:32 UTC
Created attachment 228484 [details] [review]
patch: Glib::init(): Set global locale.

This patch makes Glib::init() set the global C++ and C locale to the user's
preferred locale, usually found in the environment variable LANG.
It also corrects the description of Glib::ustring.

It's very reasonable to do this, but I wonder if it counts as an API break.
The behaviour of glibmm after calling Glib::init() will not be exactly the same
as without the patch, and the present behaviour can't be called a bug. Nor can
it be called a feature.

If it's considered an API break, it can't be pushed now. Then Debarshi's patch
in comment 1 should be pushed instead. It only corrects the description of
Glib::ustring.
Comment 7 Kjell Ahlstedt 2012-11-14 09:52:59 UTC
I've pushed Debarshi's patch (actually a very similar patch) that fixes the
ustring description.

I suppose that the proposed modification of Glib::init() shall wait until the
next API break. Therefore I keep this bug open, but change its title and
component.
Comment 8 Kjell Ahlstedt 2016-07-25 11:15:27 UTC
Created attachment 332095 [details]
testinit.cc

This program shows the C and C++ global locales before Glib::init(), after
Glib::init(), and after Gtk::Application::create(). The result on my system is

  Before Glib::init()
  std::setlocale(LC_ALL, nullptr)=C
  std::locale().name()=C

  After Glib::init()
  std::setlocale(LC_ALL, nullptr)=C
  std::locale().name()=C

  After Gtk::Application::create()
  std::setlocale(LC_ALL, nullptr)=sv_SE.UTF-8
  std::locale().name()=C

As Bjarne Stroustrup says: "In a mixed C and C++ program, having the C global
locale differ from global() is error prone." (The C++ Programming Language,
4th ed, section 39.2)
That's the situation after a call to Gtk::Application::create().

The most important modification is perhaps to have Gtk::Application::create()
set the C++ global locale to what gtk_init() has set the C global locale, rather
than to have Glib::init() set the global locale to the user's preferred locale.

See also gtkmm bug 765044 comment 8 and some following comments.
Comment 9 Murray Cumming 2016-12-02 09:38:41 UTC
I guess we need to look at this again now that we are breaking glibmm API.
Comment 10 Kjell Ahlstedt 2016-12-04 18:05:18 UTC
Glib and gtk+ have different approaches to setlocale().

The glib documentation says: "A number of interfaces in GLib depend on the
current locale in which an application is running. Therefore, most GLib-using
applications should call setlocale (LC_ALL, "") to set up the current locale."
https://developer.gnome.org/glib/stable/glib-running.html

gtk_init(), on the other hand, calls setlocale(LC_ALL, "") unless
gtk_disable_setlocale() is called before gtk_init().

I suggest that we let glibmm behave similarly to gtk+: Let Glib::init() call
std::locale::global(std::locale("")) unless an appropriate function is called
before Glib::init(). We can add
  void Glib::set_init_to_users_preferred_locale(bool state);
  bool Glib::get_init_to_users_preferred_locale();
with state == true, if the set-function is not called.
(Better function names are welcome. It's difficult to find names that are not
misleading. These functions don't set or get a locale, they just tell what
other functions shall do.)

The constructors of Gtk::Application should do
  if (!Glib::get_init_to_users_preferred_locale())
    gtk_disable_setlocale();

In any case both glibmm and gtkmm should initialize the C++ global locale to be
the same as the C global locale.

I can make patches, one for glibmm and one for gtkmm, if you think this is the
way to go.
Comment 11 Murray Cumming 2016-12-06 12:19:57 UTC
Thanks. That seems reasonable.

How might this affect existing applications that are ported to gtkmm 4? If developers need to do something, maybe you can suggest some text for this part of a porting guide. We should put that here:
https://wiki.gnome.org/Projects/gtkmm
Comment 12 Kjell Ahlstedt 2016-12-14 09:04:58 UTC
I have pushed patches to glibmm and gtkmm.
It remains to add some info to the gtkmm wiki and the gtkmm tutorial.
Comment 13 Kjell Ahlstedt 2016-12-15 16:00:15 UTC
I have added a "Changes in gtkmm 4" chapter to the gtkmm tutorial. It contains
a paragraph that explains the change in locale handling.
That's perhaps enough for now. I suppose that the wiki and the tutorial will be
synchronized later on.

I'm no longer allowed to modify the wiki pages. Only persons on the list of
Trusted Editors can do that. Perhaps someone can add me to that list?
The info in the wiki says that anyone already on the list can add other persons
to the list.