Internationalisation

Martin Tharby Jones <[email protected]> Thu, 27 Feb 2014 20:47:40 +0000
Newsgroups gmane.comp.sysutils.lcdproc
Message-ID <[email protected]>
This is a multi-part message in MIME format.
--------------080905080408080904090902
Content-Type: multipart/alternative;
 boundary="------------010606020407020602040109"


--------------010606020407020602040109
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

Hello,

I've attached a patch which provides a first step towards 
internationalisation of LCDproc.

I'm a British English speaker with minimal second language skills so I 
apologise that I have only addressed those areas that are relevant to 
me. My problem was that I have a number of Celtic &  Gaelic tracks in my 
music collection and the accented characters used in those languages 
were not being displayed correctly.

UTF-8 characters greater than 0x7F were displayed as two or more strange 
characters:



With the patch and a display that supports ISO-8859-1 most western 
European languages can be displayed:



I've also added string support for Unicode on graphic displays:



I've not done title or scroller widgets because I feel graphic displays 
should support pixel level scrolling and proportional spaced fonts which 
would require more work than I am prepared for (I don't have a graphic 
display). Basic string support was coded as proof of concept and as a 
test case.

There is obviously more to do but the code in the patch meets my 
requirements and I hope will be of use to others.

Further work I have thought of:

  * Conversion of menu text
  * Use of gettext() and conversion for system screens
  * Use of gettext() and conversion for lcdproc screens

Regards

Martin


--------------010606020407020602040109
Content-Type: multipart/related;
 boundary="------------060202050607080408030502"


--------------060202050607080408030502
Content-Type: text/html; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    Hello,<br>
    <br>
    I've attached a patch which provides a first step towards
    internationalisation of LCDproc.<br>
    <br>
    I'm a British English speaker with minimal second language skills so
    I apologise that I have only addressed those areas that are relevant
    to me. My problem was that I have a number of Celtic &amp;&nbsp; Gaelic
    tracks in my music collection and the accented characters used in
    those languages were not being displayed correctly.<br>
    <br>
    UTF-8 characters greater than 0x7F were displayed as two or more
    strange characters:<br>
    <br>
    <img alt="" src="cid:[email protected]"
      height="168" width="488"><br>
    <br>
    With the patch and a display that supports ISO-8859-1 most western
    European languages can be displayed:<br>
    <br>
    <img alt="" src="cid:[email protected]"
      height="168" width="488"><br>
    <br>
    I've also added string support for Unicode on graphic displays:<br>
    <br>
    &nbsp;<img alt="" src="cid:[email protected]"
      height="168" width="488"><br>
    <br>
    I've not done title or scroller widgets because I feel graphic
    displays should support pixel level scrolling and proportional
    spaced fonts which would require more work than I am prepared for (I
    don't have a graphic display). Basic string support was coded as
    proof of concept and as a test case.<br>
    <br>
    There is obviously more to do but the code in the patch meets my
    requirements and I hope will be of use to others.<br>
    <br>
    Further work I have thought of:<br>
    <ul>
      <li>Conversion of menu text</li>
      <li>Use of gettext() and conversion for system screens</li>
      <li>Use of gettext() and conversion for lcdproc screens<br>
      </li>
    </ul>
    Regards<br>
    <br>
    Martin<br>
    <br>
  </body>
</html>

--------------060202050607080408030502
Content-Type: image/png;
 name="2014-02-12~16:38:56.png"
Content-Transfer-Encoding: base64
Content-ID: <[email protected]>
Content-Disposition: inline;
 filename="2014-02-12~16:38:56.png"

iVBORw0KGgoAAAANSUhEUgAAAegAAACoAQMAAAARse+XAAAABlBMVEUoUShmzGahqbSDAAAB
yElEQVRoge2XDXrDIAiGcwVPwP2Pxwkc8Kmxafqz4kb6PLCMGvQtQoukW/XI9sV0KSTXkyVY
cH+F0x6ZfB92wP3ukW/mYHpR3HSYeuVbrlh6XdxUiUstLEa9kfFvdv7f9KK4xZ98fcSnSu1/
7+48gF4UN/65qGvkfNTeeY2VYHpd3JJzybNdtWX8yZlKwfSiuEVbjTXfktLnNRZO++KGsKX5
IMN4OnsR+jPpNPGNmSYj6yfR6u2C9GfygB5+NNkEy/u+I+k3ZdNColFO3AbUjdpdrJnKQYup
69C+uMkcIaWte8omhrG3Uyp0n/ZY2hu3Xq2d0OgrBCNyXlpjPdt5HO2NG3W0uxwD1W2OxtR1
aI+gxibfvW/uRlvQHpIuRfviboVD9uNPvlamK8/n6om2h+lo2iFbPzVZG6WOebIg53rQWrHV
OnQxHUv74lahXeMnPzcDJlBqN8IXoT8VqzHUD1s51d5GUVptYA2UaZ/C4ljaFzcOEa2uMtVY
xUFDGOgzci9CWLAsmF4TN9501oWa7/5scVwQTDtkO/cKjdeXOw+jHTLVWK31oOFCb+l8QSzt
izvppJNOOumkk0466aSTTjrppJNO+m/oHzPn9c7uBVDPAAAAAElFTkSuQmCC
--------------060202050607080408030502
Content-Type: image/png;
 name="2014-02-12~17:50:50.png"
Content-Transfer-Encoding: base64
Content-ID: <[email protected]>
Content-Disposition: inline;
 filename="2014-02-12~17:50:50.png"

iVBORw0KGgoAAAANSUhEUgAAAegAAACoAQMAAAARse+XAAAAZ3pUWHRSYXcgcHJvZmlsZSB0
eXBlIGV4aWYAAHjaVcjBDcAgDEPRe6boCCYJJoyDUJG6QcdvBKe+w5dlud9nybV5iNcW7CSS
d+86cgSOAljJ6p7nGvipxuBqLq2xcnIqDHpbMc0aIB8cQxc4NhOZPgAAAAZQTFRFKFEoZsxm
oam0gwAAAVpJREFUaIHtlg0OgzAIhXuFnuDd/3icgNHSdsv8mUozXMazM0r9guCgTWxR+mE6
Z8jYeUQfWA532qIX329vQP1uyzeRMz0pbrxNffItw5eeFzcYlDmTGMuNXJ9582/Tk+IWf/L3
EZ9F3I+jb+5AT4pbf5SLa835qL31GsvO9Ly4JeeS5zq4ZXynp8KZnhS3nGuNNd+S0v0ac6dt
catoOYWtiXvR1zRoLJxSXUbBO7oFfUlrNFaufoM+rlQKCbWcZOnUokK16FIyKu2GtEWpeMja
R3XplGbSLXpgO/W+tEVJt0q1oWIsKgA3z6N93pC2KA1P7eLpm9qmadOzN22R1hjrGX3RrBZA
C+xjhXrRFv0vPRI70nvc4kvb4u6bYoz2edziS9vibn3lOU5YvOnrSnUX/Dr4hMWZtsWNyyn3
pg36YxrxvYMOOuiggw466KCDDjrooIMOOuig59EPUGF7adK5XaAAAAAASUVORK5CYII=
--------------060202050607080408030502
Content-Type: image/png;
 name="2014-02-24~17:16:11.png"
Content-Transfer-Encoding: base64
Content-ID: <[email protected]>
Content-Disposition: inline;
 filename="2014-02-24~17:16:11.png"

iVBORw0KGgoAAAANSUhEUgAAAegAAACoAQMAAAARse+XAAAABlBMVEUoUShmzGahqbSDAAAB
3UlEQVRoge2YAXKEMAhFvQIn4P7H4wQ0gaDJmnR3TUbsFDqzVczzA5XIduMZ2/4uTQAMgPk4
Hb3Y4UhLysoK8KW/S/TFam08XaUvIr+d/jTFrr1oU/pIJ4TyK2sTDrQRnOlleednLT9dxEQp
CBJtpIE2gDO9LO/8kW5IUGuXxutoozO9Om9sa84DbepHfh+9LO90lHus1Fx6TM4G2t70srxb
a13vd+Tb6TeZ/W679kk9O8q7hN5G7kFfzJhbmmqvnaC20imuR9GXrE/XgQyFH0l/apuMCvry
BLLpkMorJQujvmC6IfjSM7bl8pIOS4hIWmLZWtm05Ro9jl6TN6g29LTLhPQwek3ezFpz7mjz
qNNc6e8SPdFlDNCac6k5sDml+fYR4lH0jAX9D2nrLNzdZSZqHrDqsj157vRlExr1rlj5UWOq
XdVEYUfu9GXbsnAeCeVnLzbpnFhtrcVJ5pS/hy89lTeRCloIaigTFOl+S8dXBCQbnCUgV3o+
73LHXFAwlaq81lGE+0quIveil+bNPe3i1SVS+kHkt9JzeTM2/760zVRlcrHReizHAnCsdKfn
8ubma74ZnjzmZj5Wu9OXbaBN52gabXwIfdmCDjrooIMOOuiggw466KCD9qF/ANZQ9kozh3Rv
AAAAAElFTkSuQmCC
--------------060202050607080408030502--

--------------010606020407020602040109--

--------------080905080408080904090902
Content-Type: text/x-patch;
 name="internationalisation.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
 filename="internationalisation.patch"

Index: LCDd.conf
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/LCDd.conf,v
retrieving revision 1.171
diff -u -r1.171 LCDd.conf
--- LCDd.conf	29 Jan 2014 21:48:03 -0000	1.171
+++ LCDd.conf	27 Feb 2014 18:37:05 -0000
@@ -35,6 +35,7 @@
 #            function properly.
 # NOTE: Always place a slash as last character !
 DriverPath=server/drivers/
+# DriverPath=/usr/lib/lcdproc/
 
 # Tells the server to load the given drivers. Multiple lines can be given.
 # The name of the driver is case sensitive and determines the section
@@ -50,7 +51,36 @@
 #   mdm166a, ms6931, mtc_s16209x, MtxOrb, mx5000, NoritakeVFD, picolcd,
 #   pyramid, sdeclcd, sed1330, sed1520, serialPOS, serialVFD, shuttleVFD, sli,
 #   stv5730, svga, t6963, text, tyan, ula200, vlsys_m428, xosd
-Driver=curses
+#Driver=curses
+#Driver=picolcd
+#Driver=lirc
+Driver=glcd
+
+
+# Configure how LCDd interprets text sent to it prior sending to the display.
+# The locale setting is used in character conversion routines. It may need to
+# be set here if the LCDd deamon is started before the enviroment value has
+# been set. Use the command `locale -a` to list available options.
+Locale=en_GB.utf8
+# System character encoding; input to LCDd, default from locale.
+# The command `iconv --list` will list all coded character sets on your system.
+# The command `locale charmap` will list the one your system is using.
+#SystemCharEncode=UTF-8
+# Display character encoding; the default is the same as the system character
+# encoding which will disable character encoding conversion.
+# This is probably incorrect most modern locales use UTF-8, most displays use
+# an eight bit code with at most 256 glyphs. 
+# The glcd driver with the built in font uses:
+#DisplayCharEncode=ISO-8859-1
+# This will work with displays based on the HD44780UA02 and compatable chips
+# although not all characters are mapped correctly. Other parts of the ISO-8859
+# series of standards may be more appropriate for example -5 for Latin/Cyrillic.
+# As a minimal fall-back which just supports ASCII you can use:
+#DisplayCharEncode=ANSI_X3.4-1968
+# To be able to display any glyph provided by a font with the glcd driver & FreeType use:
+#
+DisplayCharEncode=UTF-8
+
 
 # Tells the driver to bind to the given interface. [default: 127.0.0.1]
 Bind=127.0.0.1
@@ -116,8 +146,8 @@
 ToggleRotateKey=Enter
 PrevScreenKey=Left
 NextScreenKey=Right
-#ScrollUpKey=Up
-#ScrollDownKey=Down
+ScrollUpKey=Up
+ScrollDownKey=Down
 
 
 ## The menu section. The menu is an internal LCDproc client. ##
@@ -129,11 +159,12 @@
 # EnterKey (to select values) and at least one movement keys are required.
 # These are the default key assignments:
 MenuKey=Escape
+#MenuKey=Minus+Plus
 EnterKey=Enter
 UpKey=Up
 DownKey=Down
-#LeftKey=Left
-#RightKey=Right
+LeftKey=Left
+RightKey=Right
 
 
 ### Driver sections are below this line, in alphabetical order  ###
@@ -355,7 +386,7 @@
 ## glcd generic graphical display driver
 [glcd]
 # Select what type of connection. See documentation for types.
-ConnectionType=t6963
+ConnectionType=x11
 
 # Width and height of the display in pixel. The supported sizes may depend on
 # the ConnectionType. [default: 128x64; legal: 1x1 - 640x480]
@@ -365,6 +396,7 @@
 # the driver has been compiled with FreeType and it is enabled. Otherwise the
 # default 6x8 cell is used.
 #CellSize=12x16
+CellSize=7x9
 
 # If LCDproc has been compiled with FreeType 2 support this option can be used
 # to turn if off intentionally. [default: yes; legal: yes, no]
@@ -374,6 +406,7 @@
 # and should contain some special Unicode characters like arrows (Andale Mono
 # is recommended and can be fetched at http://corefonts.sf.net).
 #normal_font=/usr/local/lib/X11/fonts/TTF/andalemo.ttf
+normal_font=/home/martin/Downloads/Fonts/AndaleMono.ttf
 
 # Some fonts miss the Unicode characters used to represent icons. In this case
 # the built-in 5x8 font can used if this option is turned off. [default: yes;
@@ -390,7 +423,7 @@
 
 # Set brightness of the backlight if the backlight is switched 'off'. Set this
 # to zero to completely turn off the backlight. [default: 100; legal: 0 - 1000]
-#OffBrightness=0
+OffBrightness=200
 
 # Time (ms) from first key report to first repeat. Set to 0 to disable repeated
 # key reports. [default: 500; legal: 0 - 3000]
@@ -404,8 +437,10 @@
 # By default keys 'A' to 'F' are assigned Up, Down, Left, Right, Enter, Escape.
 KeyMap_A=Up
 KeyMap_B=Down
-KeyMap_C=Enter
-KeyMap_D=Escape
+KeyMap_C=Left
+KeyMap_D=Right
+KeyMap_E=Enter
+KeyMap_F=Escape
 
 # --- t6963 options ---
 
@@ -439,7 +474,8 @@
 # --- x11 options ---
 
 # PixelSize is size of each dot in pixels + a pixel gap. [default: 3+1]
-#x11_PixelSize=3+1
+x11_PixelSize=3+1
+#x11_PixelSize=2+1
 
 # Colors are in RRGGBB format prefixed with "0x".
 # PixelColor: The color of each dot at full contrast. [default: 0x000000]
@@ -452,6 +488,7 @@
 # Border: Adds a border (empty space) around the LCD portion of X11 window.
 # [default: 20]
 #x11_Border=20
+x11_Border=4
 
 # Inverted: inverts the pixels [default: no; legal: yes, no]
 #x11_Inverted=no
@@ -803,9 +840,10 @@
 
 # Specify an alternative location of the lircrc file [default: ~/.lircrc]
 #lircrc=/etc/lircrc.lcdproc
+lircrc=/etc/lirc/lircrc
 
 # Must be the same as in your lircrc
-#prog=lcdd
+prog=lcdd
 
 
 
@@ -998,11 +1036,11 @@
 
 # Sets the initial state of the backlight upon start-up.
 # [default: on; legal: on, off]
-#Backlight=on
+Backlight=on
 
 # Set the initial brightness [default: 1000; legal: 0 - 1000]. Works only
 # with the 20x4 device
-Brightness=1000
+Brightness=999
 
 # Set the brightness while the backlight is 'off' [default: 0; legal: 0 - 1000].
 # Works only with the 20x4 device.
@@ -1012,7 +1050,7 @@
 Contrast=1000
 
 # Link the key lights to the backlight? [default: on; legal: on, off]
-#LinkLights=off
+LinkLights=off
 
 # Light the keys? [default: on; legal: on, off]
 Keylights=on
@@ -1030,7 +1068,7 @@
 
 # Host name or IP address of the LIRC instance that is to receive IR codes
 # If not set, or set to an empty value, IR support is disabled.
-#LircHost=127.0.0.1
+LircHost=127.0.0.1
 
 # UDP port on which LIRC is listening [default: 8765; legal: 1 - 65535]
 LircPort=8765
Index: server/commands/server_commands.c
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/commands/server_commands.c,v
retrieving revision 1.10
diff -u -r1.10 server_commands.c
--- server/commands/server_commands.c	22 Feb 2012 22:25:32 -0000	1.10
+++ server/commands/server_commands.c	27 Feb 2014 18:37:05 -0000
@@ -88,11 +88,16 @@
 	/* Makes sense to me to set the output immediately;
 	 * however, the outputs are currently set in
 	 * draw_screen(screen *s, int timer)
-	 * Whatever for? */
+	 * Whatever for?
+	 * On one driver at least the output controls the
+	 * key pad illumination which may depend on which
+	 * screen is displayed. It ought to be an attribute
+	 * of the screen.
+	 */
 
 	/* drivers_output(output_state); */
 
-	report(RPT_NOTICE, "output states changed");
+	report(RPT_DEBUG, "output states changed");
 	return 0;
 }
 
Index: server/commands/widget_commands.c
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/commands/widget_commands.c,v
retrieving revision 1.16
diff -u -r1.16 widget_commands.c
--- server/commands/widget_commands.c	22 Feb 2012 22:25:32 -0000	1.16
+++ server/commands/widget_commands.c	27 Feb 2014 18:37:06 -0000
@@ -34,6 +34,93 @@
 #include "widget_commands.h"
 
 
+#ifdef INTERNATIONAL_CHAR
+/* TODO: Review international character set conversion.
+ * Initialise character encoding for display */
+#include <iconv.h>
+#include <locale.h>
+#include <langinfo.h>
+#include "shared/configfile.h"
+
+/** Descriptor for character set conversion  */
+iconv_t cd;
+
+/**
+ * Initialise widget character encoding conversion.
+ * Parameter strings passed to widget_set_func will probably be encoded using
+ * the system locale (commonly utf-8), displays usually have a simple eight bit
+ * character encoding often a slightly modified superset of ISO-8859-1 or ASCII.
+ *
+ * \retval  <0            error
+ * \retval   0            success
+ */
+int
+widget_init(void)
+{
+    /* Local string */
+    char* locale;
+    /* Character encoding locale for system. */
+    char* system_char_encode;
+    /* Character encoding locale for display. */
+    char* display_char_encode;
+    /* Set result to fail to start. */
+    int result = -1;
+
+    /*
+     * Need to set program locale character classification as well as the source
+     * and destination character set for the conversion, a classification that
+     * supports Unicode should give best results.
+     */
+//    report(RPT_NOTICE, "%s() initial locale %s", __FUNCTION__, setlocale(LC_ALL, NULL));
+//    report(RPT_NOTICE, "%s() initial codeset %s", __FUNCTION__, nl_langinfo(CODESET));
+    report(RPT_NOTICE, "%s() locale set from enviroment %s", __FUNCTION__, setlocale(LC_ALL, ""));
+    locale = strdup(config_get_string("server", "Locale", 0, ""));
+    report(RPT_NOTICE, "%s() setting locale returns %s", __FUNCTION__, setlocale(LC_ALL, locale));
+    system_char_encode =  nl_langinfo(CODESET);
+    report(RPT_NOTICE, "%s() program codeset %s", __FUNCTION__, system_char_encode);
+    system_char_encode = strdup(config_get_string("server", "SystemCharEncode", 0, system_char_encode));
+    display_char_encode = strdup(config_get_string("server", "DisplayCharEncode", 0, system_char_encode));
+    if (system_char_encode != NULL && *system_char_encode != '\0'
+            && display_char_encode != NULL && *display_char_encode != '\0')
+    {
+        if (strcmp(system_char_encode, display_char_encode) == 0)
+        {
+            cd = NULL;
+        }
+        else
+        {
+            /* Append "//TRANSLIT" to allow replacement characters for those not in the display set.
+             * TODO: Change this to defining custom characters if supported by the display see
+             * widget_set_text().
+             */
+            display_char_encode = realloc(display_char_encode, strlen(display_char_encode) + strlen("//TRANSLIT") + 1);
+            display_char_encode = strcat(display_char_encode, "//TRANSLIT");
+            cd = iconv_open(display_char_encode, system_char_encode);
+        }
+
+        if (cd == (iconv_t)-1)
+        {
+            report(RPT_WARNING, "%s() failed to open character conversion %s", __FUNCTION__, strerror(errno));
+        }
+        else
+        {
+            report(RPT_NOTICE, "%s() initialised character conversion %s to %s",
+        		    __FUNCTION__, system_char_encode, display_char_encode);
+            result = 0;
+        }
+    }
+    else
+    {
+        report(RPT_WARNING, "%s() failed to initialise character conversion", __FUNCTION__);
+    }
+    display_uses_utf8 = (strcmp(display_char_encode, "UTF-8") == 0);
+    free(locale);
+    free(system_char_encode);
+    free(display_char_encode);
+    return result;
+}
+#endif
+
 /**
  * Adds a widget to a screen, but doesn't give it a value
  *
@@ -173,6 +260,58 @@
 	return 0;
 }
 
+#ifdef INTERNATIONAL_CHAR
+/** TODO: Review international character set conversion.
+ * Convert parameter string from locale to display character string
+ * format and allocate storage for it.
+ */
+void widget_set_text(Widget * w, iconv_t cd, char* string)
+{
+    if (cd)
+    {
+        /* Length of parameter string in system encoding */
+        size_t inl = strlen(string);
+        /* Length of string in display encoding, we expect it to be the same
+         * or shorter but we won't know until the conversion has completed. */
+        size_t outl = (inl + 1);
+        char *result = malloc(outl);
+        /* Number of characters replaced (for debug). */
+        size_t count;
+        /* Number of bytes input (for debug). */
+        int incount = inl;
+        /* Input buffer pointer to the string argument */
+        char *inbuf = string;
+        /* Output buffer pointer to the memory allocated */
+        char *outbuf = result;
+        /* Initalise the converter */
+        iconv(cd, NULL, 0, &outbuf, &outl);
+        /* Convert the parameter character set ready to display.
+         * TODO: Change this to defining custom characters if supported by the
+         * display see the //TRANSLIT parameter to iconv_open() in widget_init().
+         */
+        if ((count = iconv(cd, &inbuf, &inl, &outbuf, &outl)) == -1) {
+            report(RPT_WARNING, "%s: Conversion error %s",
+                    __FUNCTION__, strerror(errno));
+        }
+        report(RPT_INFO,
+                "%s: Replaced %d characters, bytes in %d/%d out %d ",
+                __FUNCTION__, count, incount - inl, incount, incount + 1 - outl);
+        /* TODO
+         * Is it worth resizing with realloc()? My use case is UTF-8 to ANSI_X3.4
+         * so would only save a few bytes when accented characters are converted.
+         */
+        *outbuf = '\0'; /* add null terminator */
+        w->text = result;
+        report(RPT_INFO, "%s %s", __FUNCTION__,  w->text);
+    }
+    else
+    {
+        /* No conversion so just allocate a copy of the parameter. */
+        w->text = strdup(string);
+    }
+}
+#endif
+
 /**
  * Configures information about a widget, such as its size, shape,
  * contents, position, speed, etc.
@@ -248,7 +387,12 @@
 				w->y = y;
 				if (w->text != NULL)
 					free(w->text);
+#ifdef INTERNATIONAL_CHAR
+				/* TODO: Review international character set conversion. */
+				widget_set_text(w, cd, argv[i + 2]);
+#else
 				w->text = strdup(argv[i + 2]);
+#endif
 				if (w->text == NULL) {
 					report(RPT_WARNING, "widget_set_func: Allocation error");
 					return -1;
@@ -327,7 +471,12 @@
 		else {
 			if (w->text != NULL)
 				free(w->text);
+#ifdef INTERNATIONAL_CHAR
+			/* TODO: Review international character set conversion. */
+			widget_set_text(w, cd, argv[i]);
+#else
 			w->text = strdup(argv[i]);
+#endif
 			if (w->text == NULL) {
 				report(RPT_WARNING, "widget_set_func: Allocation error");
 				return -1;
@@ -369,7 +518,12 @@
 					w->speed = speed;
 					if (w->text != NULL)
 						free(w->text);
+#ifdef INTERNATIONAL_CHAR
+					/* TODO: Review international character set conversion. */
+					widget_set_text(w, cd, argv[i + 6]);
+#else
 					w->text = strdup(argv[i + 6]);
+#endif
 					if (w->text == NULL) {
 						sock_send_error(c->sock, "Allocation error\n");
 						return -1;
Index: server/commands/widget_commands.h
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/commands/widget_commands.h,v
retrieving revision 1.5
diff -u -r1.5 widget_commands.h
--- server/commands/widget_commands.h	5 Jan 2011 23:34:37 -0000	1.5
+++ server/commands/widget_commands.h	27 Feb 2014 18:37:06 -0000
@@ -12,6 +12,12 @@
 #ifndef COMMANDS_WIDGET_H
 #define COMMANDS_WIDGET_H
 
+#ifdef INTERNATIONAL_CHAR
+/* TODO: Review international character set conversion.
+ * Initialise character encoding locale for display */
+int widget_init(void);
+#endif
+
 int widget_add_func(Client *c, int argc, char **argv);
 int widget_del_func(Client *c, int argc, char **argv);
 int widget_set_func(Client *c, int argc, char **argv);
Index: server/drivers/glcd_drv.c
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/drivers/glcd_drv.c,v
retrieving revision 1.9
diff -u -r1.9 glcd_drv.c
--- server/drivers/glcd_drv.c	4 May 2013 14:31:15 -0000	1.9
+++ server/drivers/glcd_drv.c	27 Feb 2014 18:37:06 -0000
@@ -406,11 +406,34 @@
 
 	if ((y < 1) || (y > p->height))
 		return;
-
-	for (i = 0; (string[i] != '\0') && (x <= p->width); i++, x++) {
+            for (i = 0; (string[i] != '\0') && (x <= p->width); i++, x++) {
 #ifdef HAVE_FT2
 		if (p->use_ft2)
+#define USE_WIDE_CHAR
+#ifdef USE_WIDE_CHAR
+/*
+ * TODO: Review international UTF-8 string processing.
+ * Do any other drivers support Unicode? 
+ */
+		{
+		    wchar_t wc;
+		    int consumed;
+
+		    consumed = mbtowc(&wc, &string[i], strlen(&string[i]));
+		    if (consumed > 0)
+		    {
+		        glcd_render_char_unicode(drvthis, x, y, wc, 1, 1);
+		        i += consumed - 1;
+		    }
+		    else
+		    {
+		        report(RPT_DEBUG, "%s failed to convert character '%c'", __FUNCTION__, string[i]);
+		    }
+
+		}
+#else /* USE_WIDE_CHAR */
 			glcd_render_char_unicode(drvthis, x, y, string[i] & 0xFF, 1, 1);
+#endif /* USE_WIDE_CHAR */
 		else
 #endif
 			glcd_render_char(drvthis, x, y, string[i]);
Index: server/main.c
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/main.c,v
retrieving revision 1.99
diff -u -r1.99 main.c
--- server/main.c	10 Feb 2014 07:19:20 -0000	1.99
+++ server/main.c	27 Feb 2014 18:37:05 -0000
@@ -59,6 +59,11 @@
 #include "clients.h"
 #include "screen.h"
 #include "screenlist.h"
+#ifdef INTERNATIONAL_CHAR
+/* TODO: Review international character set conversion.
+ * Initialise encoding locale for display */
+#include "commands/widget_commands.h"
+#endif
 #include "parse.h"
 #include "render.h"
 #include "serverscreens.h"
@@ -126,6 +131,7 @@
 char *drivernames[MAX_DRIVERS];
 int num_drivers = 0;
 
+
 /* End of configuration variables */
 
 /* Local variables */
@@ -238,7 +244,15 @@
 	CHAIN(e, clients_init());
 	CHAIN(e, input_init());
 	CHAIN(e, menuscreens_init());
+#ifdef INTERNATIONAL_CHAR
+	/* TODO: Review international character set conversion.
+	 * Character encoding locale for display needs initialising
+	 * in widget_commands.
+	 */
+	CHAIN(e, widget_init());
+#endif
 	CHAIN(e, server_screen_init());
+
 	CHAIN_END(e, "Critical error while initializing, abort.");
 	if (!foreground_mode) {
 		/* Tell to parent that startup went OK. */
@@ -490,7 +504,6 @@
 	return 0;
 }
 
-
 static void
 set_default_settings(void)
 {
Index: server/render.c
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/render.c,v
retrieving revision 1.55
diff -u -r1.55 render.c
--- server/render.c	19 Jan 2013 10:25:04 -0000	1.55
+++ server/render.c	27 Feb 2014 18:37:05 -0000
@@ -312,6 +312,9 @@
 	    (w->x > 0) && (w->y > 0) && (w->y > fy) && (w->y <= bottom - top)) {
 		int length;
 		char str[BUFSIZE];
+#ifdef INTERNATIONAL_CHAR
+		wchar_t w_str[BUFSIZE];
+#endif
 
 		/*
 		 * FIXME: Could be a bug here? w->x is recalculated (On first
@@ -321,8 +324,35 @@
 		 */
 		w->x = min(w->x, right - left);
 		length = min(right - left - w->x + 1, sizeof(str)-1);
+#ifdef INTERNATIONAL_CHAR
+		/*
+		 * TODO: Review international string copy.
+		 * This is just a proof of concept example, UTF-8 will also need
+		 * to be handled in render_title() and render_scroller(). Before
+		 * further changes are made we need to decide if there will be
+		 * support for pixel scrolling and proportional fonts on graphic
+		 * displays.
+		 */
+
+		if (display_uses_utf8)
+		{
+		/* Convert to wide character string so that one character uses
+		 * one storage unit so that string can be easily set to the
+		 * required length.
+		 */
+		    mbstowcs(w_str, w->text, length);
+		    w_str[length] = '\0';
+		    wcstombs(str, w_str, sizeof(str));
+		}
+		else
+		{
+		    strncpy(str, w->text, length);
+		    str[length] = '\0';
+		}
+#else
 		strncpy(str, w->text, length);
 		str[length] = '\0';
+#endif
 		drivers_string(w->x + left, w->y + top, str);
 	}
 	return 0;
@@ -408,7 +438,7 @@
 		length = min(length, sizeof(str)-1);
 		if ((length <= width) || (delay == 0)) {
 
-			/* copy test starting from the beginning */
+			/* copy text starting from the beginning */
 			length = min(length, width);
 			strncpy(str, w->text, length);
 			str[length] = '\0';
@@ -479,14 +509,15 @@
 		screen_width = abs(w->right - w->left + 1);
 		screen_width = min(screen_width, sizeof(str)-1);
 
-		switch (w->length) {	/* actually, direction... */
-			case 'm': // Marquee
-				length = strlen(w->text);
-				if (length <= screen_width) {
-					/* it fits within the box, just render it */
-					drivers_string(w->left, w->top, w->text);
-				}
-				else {
+		length = strlen(w->text);
+		if (length <= screen_width) {
+			/* it fits within the box, just render it */
+			drivers_string(w->left, w->top, w->text);
+		}
+		else {
+			switch (w->length) {	/* actually, direction... */
+				case 'm': // Marquee
+				{
 					int necessaryTimeUnits = 0;
 
 					if (w->speed > 0) {
@@ -518,15 +549,10 @@
 						str[0] = '\0';
 					}
 					drivers_string(w->left, w->top, str);
+					break;
 				}
-				break;
-			case 'h':
-				length = strlen(w->text) + 1;
-				if (length <= screen_width) {
-					/* it fits within the box, just render it */
-					drivers_string(w->left, w->top, w->text);
-				}
-				else {
+				case 'h':
+				{
 					int effLength = length - screen_width;
 					int necessaryTimeUnits = 0;
 
@@ -568,18 +594,14 @@
 						str[0] = '\0';
 					}
 					drivers_string(w->left, w->top, str);
+					break;
 				}
-				break;
+
 				/* FIXME:  Vert scrollers don't always seem to scroll */
 				/* back up after hitting the bottom.  They jump back to */
 				/* the top instead...  (nevermind?) */
-			case 'v':
-				length = strlen(w->text);
-				if (length <= screen_width) {
-					/* no scrolling required... */
-					drivers_string(w->left, w->top, w->text);
-				}
-				else {
+				case 'v':
+				{
 					int lines_required = (length / screen_width)
 						 + (length % screen_width ? 1 : 0);
 					int available_lines = (w->bottom - w->top + 1);
@@ -634,13 +656,14 @@
 						for (i = begin; i < begin + available_lines; i++) {
 							strncpy(str, &((w->text)[i * (screen_width)]), screen_width);
 							str[screen_width] = '\0';
-							/*debug(RPT_DEBUG, "rendering: '%s' of %s", */
-							/*str,w->text); */
+							/* debug(RPT_DEBUG, "rendering: '%s' of %s", str,w->text); */
+
 							drivers_string(w->left, w->top + (i - begin), str);
 						}
 					}
+					break;
 				}
-				break;
+			}
 		}
 	}
 	return 0;
Index: server/widget.h
===================================================================
RCS file: /cvsroot/lcdproc/lcdproc/server/widget.h,v
retrieving revision 1.18
diff -u -r1.18 widget.h
--- server/widget.h	22 Feb 2012 22:25:32 -0000	1.18
+++ server/widget.h	27 Feb 2014 18:37:05 -0000
@@ -13,6 +13,18 @@
 #ifndef WIDGET_H
 #define WIDGET_H
 
+/* TODO: Review international character set conversion.
+ * International character definition should come from the configuration
+ * if the code is to be kept conditional. I've used conditional code for
+ * ease of testing and review.
+ */
+#define INTERNATIONAL_CHAR
+
+#ifdef INTERNATIONAL_CHAR
+    /** Character encoding for display. */
+    int display_uses_utf8;
+#endif
+
 #define INC_TYPES_ONLY 1
 #include "screen.h"
 #undef INC_TYPES_ONLY

--------------080905080408080904090902
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
LCDproc mailing list
[email protected]
http://lists.omnipotent.net/mailman/listinfo/lcdproc

--------------080905080408080904090902--