LCOV - code coverage report
Current view: top level - intl/locale/gtk - OSPreferences_gtk.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 6 72 8.3 %
Date: 2017-07-14 16:53:18 Functions: 1 4 25.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
       2             :  *
       3             :  * This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "OSPreferences.h"
       8             : #include "dlfcn.h"
       9             : #include "glib.h"
      10             : #include "gio/gio.h"
      11             : 
      12             : using namespace mozilla::intl;
      13             : 
      14             : bool
      15           2 : OSPreferences::ReadSystemLocales(nsTArray<nsCString>& aLocaleList)
      16             : {
      17           2 :   MOZ_ASSERT(aLocaleList.IsEmpty());
      18             : 
      19           4 :   nsAutoCString defaultLang(uloc_getDefault());
      20             : 
      21           2 :   if (CanonicalizeLanguageTag(defaultLang)) {
      22           2 :     aLocaleList.AppendElement(defaultLang);
      23           2 :     return true;
      24             :   }
      25           0 :   return false;
      26             : }
      27             : 
      28             : /*
      29             :  * This looks up into gtk settings for hourCycle format.
      30             :  *
      31             :  * This works for all GUIs that use gtk settings like Gnome, Elementary etc.
      32             :  * Ubuntu does not use those settings so we'll want to support them separately.
      33             :  *
      34             :  * We're taking the current 12/24h settings irrelevant of the locale, because
      35             :  * in the UI user selects this setting for all locales.
      36             :  */
      37             : typedef GVariant* (*get_value_fn_t)(GSettings*, const gchar*);
      38             : 
      39             : static get_value_fn_t
      40           0 : FindGetValueFunction()
      41             : {
      42             :   get_value_fn_t fn = reinterpret_cast<get_value_fn_t>(
      43           0 :     dlsym(RTLD_DEFAULT, "g_settings_get_user_value")
      44           0 :   );
      45           0 :   return fn ? fn : &g_settings_get_value;
      46             : }
      47             : 
      48             : static int
      49           0 : HourCycle()
      50             : {
      51           0 :   int rval = 0;
      52             : 
      53             :   const char* schema;
      54             :   const char* key;
      55           0 :   const char* env = getenv("XDG_CURRENT_DESKTOP");
      56           0 :   if (env && strcmp(env, "Unity") == 0) {
      57           0 :     schema = "com.canonical.indicator.datetime";
      58           0 :     key = "time-format";
      59             :   } else {
      60           0 :     schema = "org.gnome.desktop.interface";
      61           0 :     key = "clock-format";
      62             :   }
      63             : 
      64             :   // This is a workaround for old GTK versions.
      65             :   // Once we bump the minimum version to 2.40 we should replace
      66             :   // this with g_settings_schme_source_lookup.
      67             :   // See bug 1356718 for details.
      68           0 :   const char* const* schemas = g_settings_list_schemas();
      69           0 :   GSettings* settings = nullptr;
      70             : 
      71           0 :   for (uint32_t i = 0; schemas[i] != nullptr; i++) {
      72           0 :     if (strcmp(schemas[i], schema) == 0) {
      73           0 :       settings = g_settings_new(schema);
      74           0 :       break;
      75             :     }
      76             :   }
      77             : 
      78           0 :   if (settings) {
      79             :     // We really want to use g_settings_get_user_value which will
      80             :     // only want to take it if user manually changed the value.
      81             :     // But this requires glib 2.40, and we still support older glib versions,
      82             :     // so we have to check whether it's available and fall back to the older
      83             :     // g_settings_get_value if not.
      84           0 :     static get_value_fn_t sGetValueFunction = FindGetValueFunction();
      85           0 :     GVariant* value = sGetValueFunction(settings, key);
      86           0 :     if (value) {
      87           0 :       if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
      88           0 :         const char* strVal = g_variant_get_string(value, nullptr);
      89           0 :         if (strncmp("12", strVal, 2) == 0) {
      90           0 :           rval = 12;
      91           0 :         } else if (strncmp("24", strVal, 2) == 0) {
      92           0 :           rval = 24;
      93             :         }
      94             :       }
      95           0 :       g_variant_unref(value);
      96             :     }
      97           0 :     g_object_unref(settings);
      98             :   }
      99           0 :   return rval;
     100             : }
     101             : 
     102             : /**
     103             :  * Since Gtk does not provide a way to customize or format date/time patterns,
     104             :  * we're reusing ICU data here, but we do modify it according to the only
     105             :  * setting Gtk gives us - hourCycle.
     106             :  *
     107             :  * This means that for gtk we will return a pattern from ICU altered to
     108             :  * represent h12/h24 hour cycle if the user modified the default value.
     109             :  *
     110             :  * In short, this should work like this:
     111             :  *
     112             :  *  * gtk defaults, pl: 24h
     113             :  *  * gtk defaults, en: 12h
     114             :  *
     115             :  *  * gtk 12h, pl: 12h
     116             :  *  * gtk 12h, en: 12h
     117             :  *
     118             :  *  * gtk 24h, pl: 24h
     119             :  *  * gtk 12h, en: 12h
     120             :  */
     121             : bool
     122           0 : OSPreferences::ReadDateTimePattern(DateTimeFormatStyle aDateStyle,
     123             :                                    DateTimeFormatStyle aTimeStyle,
     124             :                                    const nsACString& aLocale, nsAString& aRetVal)
     125             : {
     126           0 :   nsAutoString skeleton;
     127           0 :   if (!GetDateTimeSkeletonForStyle(aDateStyle, aTimeStyle, aLocale, skeleton)) {
     128           0 :     return false;
     129             :   }
     130             : 
     131             :   // Customize the skeleton if necessary to reflect user's 12/24hr pref
     132           0 :   switch (HourCycle()) {
     133             :     case 12: {
     134             :       // If skeleton contains 'H' or 'k', replace with 'h' or 'K' respectively,
     135             :       // and add 'a' unless already present.
     136           0 :       if (skeleton.FindChar('H') == -1 && skeleton.FindChar('k') == -1) {
     137           0 :         break; // nothing to do
     138             :       }
     139           0 :       bool foundA = false;
     140           0 :       for (size_t i = 0; i < skeleton.Length(); ++i) {
     141           0 :         switch (skeleton[i]) {
     142             :           case 'a':
     143           0 :             foundA = true;
     144           0 :             break;
     145             :           case 'H':
     146           0 :             skeleton.SetCharAt('h', i);
     147           0 :             break;
     148             :           case 'k':
     149           0 :             skeleton.SetCharAt('K', i);
     150           0 :             break;
     151             :         }
     152             :       }
     153           0 :       if (!foundA) {
     154           0 :         skeleton.Append(char16_t('a'));
     155             :       }
     156           0 :       break;
     157             :     }
     158             :     case 24:
     159             :       // If skeleton contains 'h' or 'K', replace with 'H' or 'k' respectively,
     160             :       // and delete 'a' if present.
     161           0 :       if (skeleton.FindChar('h') == -1 && skeleton.FindChar('K') == -1) {
     162           0 :         break; // nothing to do
     163             :       }
     164           0 :       for (int32_t i = 0; i < int32_t(skeleton.Length()); ++i) {
     165           0 :         switch (skeleton[i]) {
     166             :           case 'a':
     167           0 :             skeleton.Cut(i, 1);
     168           0 :             --i;
     169           0 :             break;
     170             :           case 'h':
     171           0 :             skeleton.SetCharAt('H', i);
     172           0 :             break;
     173             :           case 'K':
     174           0 :             skeleton.SetCharAt('k', i);
     175           0 :             break;
     176             :         }
     177             :       }
     178           0 :       break;
     179             :   }
     180             : 
     181           0 :   if (!GetPatternForSkeleton(skeleton, aLocale, aRetVal)) {
     182           0 :     return false;
     183             :   }
     184             : 
     185           0 :   return true;
     186             : }
     187             : 

Generated by: LCOV version 1.13