[california] Default to system/locale's first day of week (Mon/Sun): Bug #734377



commit b402d5ae0719ce1b4443562eb21139a04024393c
Author: Jim Nelson <jim yorba org>
Date:   Wed Aug 6 17:02:33 2014 -0700

    Default to system/locale's first day of week (Mon/Sun): Bug #734377

 configure.ac                             |   13 ++++
 data/org.yorba.california.gschema.xml    |    4 +-
 src/Makefile.am                          |    7 ++-
 src/application/california-settings.vala |   15 ++++-
 src/calendar/calendar-first-of-week.vala |    9 +++-
 src/calendar/calendar-system.vala        |   82 ++++++++++++++++++++++--
 vapi/langinfo.vapi                       |  100 ++++++++++++++++++++++++++++++
 7 files changed, 219 insertions(+), 11 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index bee3010..5cbb475 100644
--- a/configure.ac
+++ b/configure.ac
@@ -54,6 +54,19 @@ AC_SUBST(CALIFORNIA_LIBS)
 GLIB_GSETTINGS
 
 #
+# system capabilities
+#
+
+# _NL_TIME_FIRST_WEEKDAY is an enum and not a define
+AC_MSG_CHECKING([for _NL_TIME_FIRST_WEEKDAY])
+AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <langinfo.h>]],
+                                [[char c;
+                                  c = *((unsigned char *)  nl_langinfo(_NL_TIME_FIRST_WEEKDAY));]])],
+               [california_ok=yes], [california_ok=no])
+AC_MSG_RESULT($california_ok)
+AM_CONDITIONAL(HAVE__NL_TIME_FIRST_WEEKDAY, test "$california_ok" = "yes")
+
+#
 # configure switches
 #
 # Unity support
diff --git a/data/org.yorba.california.gschema.xml b/data/org.yorba.california.gschema.xml
index 5dfd453..123394a 100644
--- a/data/org.yorba.california.gschema.xml
+++ b/data/org.yorba.california.gschema.xml
@@ -48,10 +48,10 @@
     </key>
     
     <key name="first-of-week" type="s">
-        <default>"sunday"</default>
+        <default>"system"</default>
         <summary>The first day of the week</summary>
         <description>
-            For now, the only two respected values are "sunday" and "monday".
+            For now, the only respected values are "sunday", "monday", and "system".
         </description>
     </key>
 </schema>
diff --git a/src/Makefile.am b/src/Makefile.am
index a858b9a..2f1d536 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -206,6 +206,10 @@ if IS_GTK_312
 california_OPTIONAL_VALAFLAGS += --define GTK_312
 endif
 
+if HAVE__NL_TIME_FIRST_WEEKDAY
+california_OPTIONAL_VALAFLAGS += --define HAVE__NL_TIME_FIRST_WEEKDAY
+endif
+
 california_VALAFLAGS = \
        --fatal-warnings --debug --enable-checking --vapidir $(top_srcdir)/vapi --target-glib=2.38 \
        --enable-deprecated \
@@ -220,7 +224,8 @@ california_VALAFLAGS = \
        --pkg libical \
        --pkg libsoup-2.4 \
        --pkg libgdata \
-       --pkg=Goa-1.0 \
+       --pkg Goa-1.0 \
+       --pkg langinfo \
        $(NULL)
 
 california_CFLAGS = \
diff --git a/src/application/california-settings.vala b/src/application/california-settings.vala
index 55d4986..6eba4a9 100644
--- a/src/application/california-settings.vala
+++ b/src/application/california-settings.vala
@@ -33,6 +33,7 @@ public class Settings : BaseObject {
     
     private const string VALUE_FIRST_OF_WEEK_SUNDAY = "sunday";
     private const string VALUE_FIRST_OF_WEEK_MONDAY = "monday";
+    private const string VALUE_FIRST_OF_WEEK_SYSTEM = "system";
     
     public static Settings instance { get; private set; }
     
@@ -155,6 +156,17 @@ public class Settings : BaseObject {
         Calendar.terminate();
     }
     
+    /**
+     * Reset settings to use system-defined (or locale-defined) first day of week.
+     *
+     * This is necessary because { link Settings} will monitor { link Calendar.System.first_of_week}
+     * for changes and save them to GSettings, but there's no way via that interface to specify
+     * "fall back on system's value".
+     */
+    public void use_system_first_of_week() {
+        settings.set_string(KEY_FIRST_OF_WEEK, VALUE_FIRST_OF_WEEK_SYSTEM);
+    }
+    
     private void on_setting_changed(string key) {
         switch (key.casefold()) {
             case KEY_FIRST_OF_WEEK:
@@ -174,8 +186,9 @@ public class Settings : BaseObject {
                 to_set = Calendar.FirstOfWeek.SUNDAY;
             break;
             
+            case VALUE_FIRST_OF_WEEK_SYSTEM:
             default:
-                to_set = Calendar.FirstOfWeek.DEFAULT;
+                to_set = Calendar.System.instance.system_first_of_week;
             break;
         }
         
diff --git a/src/calendar/calendar-first-of-week.vala b/src/calendar/calendar-first-of-week.vala
index ed87f5e..f164125 100644
--- a/src/calendar/calendar-first-of-week.vala
+++ b/src/calendar/calendar-first-of-week.vala
@@ -16,8 +16,11 @@ public enum FirstOfWeek {
     
     /**
      * Default { link FirstOfWeek}.
+     *
+     * Default in the sense that some value must be chosen if there's no available external
+     * reference.
      */
-    DEFAULT = SUNDAY;
+    DEFAULT = MONDAY;
     
     /**
      * Converts the { link FirstOfWeek} into an actual { link DayOfWeek}.
@@ -34,6 +37,10 @@ public enum FirstOfWeek {
                 assert_not_reached();
         }
     }
+    
+    public string to_string() {
+        return as_day_of_week().to_string();
+    }
 }
 
 }
diff --git a/src/calendar/calendar-system.vala b/src/calendar/calendar-system.vala
index fce063a..b97545a 100644
--- a/src/calendar/calendar-system.vala
+++ b/src/calendar/calendar-system.vala
@@ -16,6 +16,8 @@ namespace California.Calendar {
  */
 
 public class System : BaseObject {
+    public const string PROP_SYSTEM_FIRST_OF_WEEK = "system-first-of-week";
+    
     private const string CLOCK_FORMAT_SCHEMA = "org.gnome.desktop.interface";
     private const string CLOCK_FORMAT_KEY = "clock-format";
     private const string CLOCK_FORMAT_24H = "24h";
@@ -64,12 +66,18 @@ public class System : BaseObject {
      * The user's preferred start of the week.
      *
      * Unlike most of the other properties here (which are determined by examining and monitoring
-     * the system), this is strictly a user preference that should be configured by the outer
-     * application.  It's stored here because it's something that many components in { link Calendar}
-     * need access to and passing it around is often inconvenient.  However, many of the "basic"
-     * classes (such as { link Date} and { link DayOfWeek}) still ask for it as a parameter to
-     * remain flexible.  In the case of { link Week}, it ''must'' store it, as its span of days is
-     * strictly determined by the decision, which can change at runtime.
+     * the system), this is a combination of a user preference (configured by the outer application)
+     * and a system/locale setting.  It's stored here because it's something that many components
+     * in { link Calendar} need access to and passing it around throughout the stack is
+     * inconvenient.  However, many of the "basic" classes (such as { link Date} and
+     * { link DayOfWeek}) still ask for it as a parameter to remain flexible.  In the case of
+     * { link Week}, it ''must'' store it, as its span of days is strictly determined by the
+     * decision, which can change at runtime.
+     *
+     * When { link Calendar.System} is first created, it's initialized to
+     * { link system_first_of_week}.  The outer application may pull an overriding value from the
+     * configuration and override the original value.  (The outer application may want to have some
+     * way to store "use system default" as a possible value.)
      *
      * @see first_of_week_changed
      */
@@ -90,6 +98,13 @@ public class System : BaseObject {
         }
     }
     
+    /**
+     * System-defined (or locale-defined) start of the week.
+     *
+     * @see first_of_week
+     */
+    public FirstOfWeek system_first_of_week { get; private set; }
+    
     private static DBus.timedated timedated_service;
     private static DBus.Properties timedated_properties;
     
@@ -155,6 +170,57 @@ public class System : BaseObject {
         today = new Date.now(Timezone.local);
         scheduled_date_timer = new Scheduled.once_after_sec(next_check_today_interval_sec(),
             check_today_changed, CHECK_DATE_PRIORITY);
+        
+        // Borrowed liberally (but not exactly) from GtkCalendar; see gtk_calendar_init
+#if HAVE__NL_TIME_FIRST_WEEKDAY
+        // 1-based day (1 == Sunday)
+        int first_weekday = Langinfo.lookup_int(Langinfo.Item.INT_TIME_FIRST_WEEKDAY);
+        
+        // I haven't the foggiest what this is returning, but note that Nov 30 1997 is a Sunday and
+        // Dec 01 1997 is a Monday.
+        int week_origin = (int) Langinfo.lookup(Langinfo.Item.TIME_WEEK_1STDAY);
+        
+        // values are translated into 0-based day (as per gtkcalendar.c), 0 == Sunday
+        int week_1stday;
+        switch (week_origin) {
+            case 19971130:
+                week_1stday = 0;
+            break;
+            
+            case 19971201:
+                week_1stday = 1;
+            break;
+            
+            default:
+                warning("Unknown value of _NL_TIME_WEEK_1STDAY: %d (%Xh)", week_origin, week_origin);
+                week_1stday = 0;
+            break;
+        }
+        
+        // this yields a 0-based value, 0 == Sunday
+        int week_start = (week_1stday + first_weekday - 1) % 7;
+        
+        // convert into our first day of week value
+        switch (week_start) {
+            case 0:
+                system_first_of_week = FirstOfWeek.SUNDAY;
+            break;
+            
+            case 1:
+                system_first_of_week = FirstOfWeek.MONDAY;
+            break;
+            
+            default:
+                warning("Unknown week start value, using default: %d", week_start);
+                system_first_of_week = FirstOfWeek.DEFAULT;
+            break;
+        }
+#else
+        // For now, just use the default.  Later, user will be able to configure this.
+        system_first_of_week = FirstOfWeek.DEFAULT;
+#endif
+        
+        debug("System first day of week: %s", system_first_of_week.to_string());
     }
     
     internal static void preinit() throws IOError {
@@ -166,6 +232,10 @@ public class System : BaseObject {
     
     internal static void init() {
         instance = new System();
+        
+        // initialize, application may override (can't do this in ctor due to how first_of_week
+        // setter is built)
+        first_of_week = instance.system_first_of_week;
     }
     
     internal static void terminate() {
diff --git a/vapi/langinfo.vapi b/vapi/langinfo.vapi
new file mode 100644
index 0000000..972fd5c
--- /dev/null
+++ b/vapi/langinfo.vapi
@@ -0,0 +1,100 @@
+/**
+ * nl_langinfo bindings.
+ */
+
+[CCode (cprefix = "")]
+namespace Langinfo {
+
+[CCode (cheader_filename = "langinfo.h", cname = "nl_langinfo")]
+public unowned string lookup(Langinfo.Item item);
+
+/**
+ * Use for { link Langinfo.Item}s prefixed with INT_.
+ */
+public int lookup_int(Langinfo.Item item) {
+    char *ptr = (char *) lookup(item);
+    
+    return (ptr != null) ? *ptr : 0;
+}
+
+[CCode (cheader_filename = "langinfo.h", cname = "nl_item", cprefix = "", has_type_id = false)]
+public enum Item {
+  /* Abbreviated days of the week. */
+  ABDAY_1,          /* Sunday */
+  ABDAY_2,
+  ABDAY_3,
+  ABDAY_4,
+  ABDAY_5,
+  ABDAY_6,
+  ABDAY_7,
+
+  /* Long-named (unabbreviated) days of the week. */
+  DAY_1,                       /* Sunday */
+  DAY_2,                       /* Monday */
+  DAY_3,                       /* Tuesday */
+  DAY_4,                       /* Wednesday */
+  DAY_5,                       /* Thursday */
+  DAY_6,                       /* Friday */
+  DAY_7,                       /* Saturday */
+
+  /* Abbreviated month names.  */
+  ABMON_1,                     /* Jan */
+  ABMON_2,
+  ABMON_3,
+  ABMON_4,
+  ABMON_5,
+  ABMON_6,
+  ABMON_7,
+  ABMON_8,
+  ABMON_9,
+  ABMON_10,
+  ABMON_11,
+  ABMON_12,
+
+  /* Long (unabbreviated) month names.  */
+  MON_1,                       /* January */
+  MON_2,
+  MON_3,
+  MON_4,
+  MON_5,
+  MON_6,
+  MON_7,
+  MON_8,
+  MON_9,
+  MON_10,
+  MON_11,
+  MON_12,
+
+  AM_STR,                      /* Ante meridiem string. (may be empty)  */
+  PM_STR,                      /* Post meridiem string. (may be empty)  */
+
+  ERA,
+
+  /**
+   * The following are not official and therefore not portable.
+   * Those prefixed with INT_ should use lookup_int() rather than lookup().
+   */
+  
+  [CCode (cname = "_NL_TIME_WEEK_NDAYS")]
+  INT_TIME_WEEK_NDAYS,
+  /**
+   * TIME_WEEK_1STDAY returns a straight machine word as a constant indicating a first day (not a
+   * pointer) that is interpreted as follows:
+   * 19971130 == Sunday
+   * 19971201 == Monday
+   */
+  [CCode (cname = "_NL_TIME_WEEK_1STDAY")]
+  TIME_WEEK_1STDAY,
+  [CCode (cname = "_NL_TIME_WEEK_1STWEEK")]
+  INT_TIME_WEEK_1STWEEK,
+  [CCode (cname = "_NL_TIME_FIRST_WEEKDAY")]
+  INT_TIME_FIRST_WEEKDAY,
+  [CCode (cname = "_NL_TIME_FIRST_WORKDAY")]
+  INT_TIME_FIRST_WORKDAY,
+  [CCode (cname = "_NL_TIME_CAL_DIRECTION")]
+  INT_TIME_CAL_DIRECTION,
+  [CCode (cname = "_NL_TIME_TIMEZONE")]
+  TIME_TIMEZONE
+}
+
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]